Code, changes and reviews

Version 4 · Updated

Deployments

Environments, deployments from workflow jobs and from outside, required tags, Deploy again, and requiring deployments.

A deployment records that a commit runs in an environment of the repository, such as staging or production: the tag or branch it came from, its status, a URL, who or what made it, and its history. Branchscope records deployments; your workflow's steps, or your own tools, do the deploying.

Environments#

An environment is made the first time something deploys to it. To protect one before then, add it under Settings → Environments (Add an environment).

  • Required tag: an administrator can give an environment a tag name or pattern, such as v* (see patterns). Deployments to it must then come from a tag that matches it and that an active tag ruleset stops being moved, by Restrict updates or Block force pushes, as Release tags does. Leave it empty to let any branch, tag or commit deploy.
  • What's refused: a deployment from a branch or a commit, from a tag that doesn't match, from a tag no ruleset protects, or from a tag that now names another commit. A job is refused before its first step, and its run says why; a deployment recorded through the API or the CLI is refused with the reason.
  • Only a person changes an environment's protection, never an agent, and not in an archived repository.
  • Required reviewers and a wait timer: deployments can also wait for a person to approve them, or for a while; see below.

Someone on a tag ruleset's bypass list can still move a protected tag, deliberately; the next deployment from it then deploys where it points now.

Required reviewers and wait timers#

An administrator can make deployments to an environment wait for a person, or for a while: Settings → Environments, then the environment, under Protection.

  • Required reviewers: up to 10 people who can read the repository. A job deploying to the environment waits until one of them approves it. Agents and apps can't be reviewers, and an agent can't approve, even one acting for a reviewer.
  • Prevent self-review: on by default. Whoever set off the run can't approve its deployment, even as a reviewer: the person who pushed, opened the change, started the run or ran it again, and, for an agent's run, the person it acted for.
  • Wait timer: 0 to 43,200 minutes (30 days). The job waits that long after it's approved, or, without reviewers, once it's ready. The wait doesn't count toward the job's timeout, which starts when a runner takes it.

What waits#

  • Only the deploying job, once the jobs it needs have passed. The run's other jobs carry on; the jobs that need it wait with it.
  • Before anything: it doesn't start, and gets no environment secrets and no identity tokens, until it's approved and its timer is over. The required tag is checked first: a job it refuses fails without asking anyone.
  • Its deployment is recorded as waiting, and the reviewers are told: a notification in Branchscope, the deployment.review_requested webhook event, and a message from the chat integrations that post it.
  • Expiry: a review nobody decides within 30 days expires, and the job fails.
  • Added later: reviewers or a timer added to an environment apply to a job that's already queued: it isn't started, and goes back to waiting for them.

Approving and rejecting#

A reviewer approves or rejects on the run's page, with an optional comment:

  • Approve and deploy: the wait timer starts, and the page counts it down; when it's over, the job runs.
  • Reject: the job fails with "Rejected by bob: …", its deployment fails, and the jobs that need it are cancelled.
  • The first decision counts. Those who can decide are the reviewers the environment lists when they do. If none are left, cancel the run and run it again.
  • Start now: a repository administrator can end a running wait timer early. Administrators can't approve unless they're listed reviewers.
  • Approvals, rejections and Start now are on the audit log, with the comment.

From the CLI: bscope deploy approve 12 -m "Ship it" for deployment 12 (as deploy list shows it), bscope deploy approve run/34 for every deployment in run 34 that's waiting for you (--environment narrows it), and bscope deploy reject 12 -m "Not on a Friday".

Agents' runs#

A run an agent set off has its secrets withheld until an administrator approves it (Approve and run, see secrets). A job deploying to a protected environment then waits for both. When the reviewer who approves its deployment is also an administrator of the repository, that approval also gives this one job its secrets. Another reviewer's approval clears only the review, and the job still waits for Approve and run.

From a workflow job#

A job with environment: records a deployment from its run:

version: 1
name: Release
on:
  release: { types: [published] }
jobs:
  deploy:
    runs-on: hosted
    environment: production
    secrets: [DEPLOY_TOKEN]
    steps:
      - run: ./deploy.sh "$BRANCHSCOPE_TAG"
  • When: once the job is queued, not while it waits for the jobs it needs. A job cancelled or refused before then records nothing.
  • Its status follows the job: queued, then in progress while it runs, then succeeded if it passed, or failed if it failed, was cancelled or timed out.
  • The tag: a run started from a tag or a release records the tag, so the environment reads "production: v1.4.0". Other runs record their branch.
  • Its steps see BRANCHSCOPE_ENVIRONMENT, the environment's name (see Branchscope actions).
  • Waiting: a job its environment's reviewers or wait timer hold records its deployment as soon as it starts waiting, as waiting. It's queued when the wait ends, or failed if it's rejected or the review expires.

Environment secrets#

An environment can have secrets of its own, such as production's deploy key: Settings → Environments, then the environment, then Secrets. They're kept as repository and organization secrets are: encrypted, never read back, and set only by repository administrators, as people (agents and apps can't see, set or list them).

jobs:
  deploy:
    runs-on: hosted
    environment: production
    secrets: [DEPLOY_KEY]
    steps:
      - run: ./deploy.sh
  • Only jobs deploying there: a job gets an environment's secret only if its environment: is that environment and it names the secret in secrets:. The run's other jobs, and jobs deploying elsewhere, don't.
  • After its protection: the environment's required tag is checked first, and again when a runner takes the job. A refused job gets no secrets at all.
  • After its reviewers: with required reviewers or a wait timer, not before the job is approved and its timer is over.
  • Which wins: an environment's secret wins over the repository's of the same name, and the repository's over the organization's.
  • Untrusted runs: a run set off by an agent (unless at the latest commit of a branch or tag agents can't update) or by someone without write access gets none until an administrator approves it, as for any secret.
  • On the run's page: each job lists the secrets it was given and where each came from (names only), and the identity tokens it was issued.
  • Deleting the repository deletes its environments and their secrets.

From the CLI: bscope secret set DEPLOY_KEY --env production < key.txt, bscope secret list --env production, bscope secret delete DEPLOY_KEY --env production. For AWS, Google Cloud and Azure, an identity token can replace a stored key.

Statuses#

Status
waitingits job waits for the environment's reviewers or wait timer
queuedwaiting to start
in progressunder way
succeededit's running there now
failedit didn't work
inactiveit ran there once, and something newer replaced it

A successful deployment replaces what ran in the environment before: the previous successful one becomes inactive ("Replaced by deployment 12"). Each deployment keeps the history of its statuses.

The Deployments tab#

  • Environments: each with what's Running now (its latest successful deployment), its earlier deployments, and whether it only takes protected tags.
  • A deployment's page: its environment, tag or branch and commit, who deployed it and when, the run and job it came from (or that it was recorded through the API or bscope deploy record), and its history.
  • Elsewhere: a commit's page, the Releases tab and each release say where they're Deployed to.
  • Waiting: a deployment waiting for its environment's reviewers or wait timer shows above what's running, saying which. It's decided on its run's page.

Deploy again#

Deploy again on a deployment's page runs its workflow again, by hand, on its tag (or branch) at its commit. On an earlier deployment, that's a rollback. The environment's protection applies as to any run, and a tag that names another commit now is refused. It needs write access, and only works for deployments a workflow made.

From outside Branchscope#

Deployments made by other tools can be recorded too, by a person with write access (with a session or a write token), or an OAuth app granted deployments:write:

bscope deploy record production --ref v1.4.0 --url https://example.com
bscope deploy record staging --ref main --status in_progress -m "Rolling out"
bscope deploy status 12 succeeded
  • --ref is a branch, a tag (v1.4.0 or refs/tags/v1.4.0) or a full commit SHA. The status is succeeded unless --status says queued, in_progress or failed.
  • deploy status <id> <status> sets a later status, any of the five, with --url and -m.
  • deploy list [--environment e] [--limit n] lists a repository's deployments, newest first: the environment, tag or branch, commit, status, who and when.
  • A deployment a workflow job made follows its job; its status can't be set by hand.

The API: POST /repos/{owner}/{name}/deployments with {environment, ref, status, url, description}, then POST …/deployments/{id}/statuses with {status, description, url}.

Requiring deployments#

A branch or tag ruleset can Require deployments to succeed in the environments it names:

  • For a branch: the latest deployment of a change's head to each of them must have succeeded before the change merges. Direct pushes are refused, as for required checks. There's no Merge anyway for deployments.
  • For a tag: the latest deployment of its commit must have succeeded. The tag is made by publishing a release, which checks them; a push of it is refused.

A deployment that succeeded and was later replaced (inactive) still counts. Those on the ruleset's bypass list are exempt.

Agents, webhooks and the API#

  • Webhooks: deployment.created when a deployment is recorded, and deployment.status when its status changes: its job moved, it was set through the API, or a newer deployment made it inactive.
  • MCP: agents read environments and deployments with list_deployments and get_deployment, which are read only.
GET /repos/{owner}/{name}/environments, GET …/environments/{environment}environments, with what's running in each
PUT …/environments/{environment}set its required tag ({requiredTag}; null for none): administrators, never agents
GET …/deployments?environment=&sha=&tag=, GET …/deployments/{id}deployments, newest first; one, with its history
POST …/deployments, POST …/deployments/{id}/statusesrecord one; set its status (deployments:write for apps)
POST …/deployments/{id}/redeployDeploy again
PUT …/environments/{environment} with {reviewers, preventSelfReview, waitTimerMinutes}its reviewers (usernames), Prevent self-review and wait timer; each left as it is if left out
GET …/environments/{environment}/secrets, PUT, DELETE …/secrets/{secret}its secrets, by name; values are never returned (administrators, as people)
POST …/runs/{id}/review, POST …/deployments/{id}/reviewapprove or reject ({decision, comment}): listed reviewers, as people
POST …/runs/{id}/start-nowStart now: administrators, as people