Skip to content

Gating Promotions

Most environment promotion strategies will involve enforcing some kind of "gates" between promotions.

GitOps promoter uses the PromotionStrategy API to configure checks that must pass between environments. It uses the CommitStatus API to understand the state of the checks.

A "proposed commit status" is a check which must be passing on a proposed change before it can be merged. To set a CommitStatus to be used as a proposed commit status, set the spec.sha field to the commit hash of the proposed change in the proposed (-next) environment branch.

An "active commit status" is a check which must be passing on an active (already merged) change before the change can be merged for the next environment. To set a CommitStatus to be used as an active commit status, set the spec.sha field to the commit hash of the active change in the live environment branch.

Example

The following example demonstrates how to configure a PromotionStrategy to use CommitStatuses for both a proposed and an active commit status check.

kind: PromotionStrategy
spec:
  activeCommitStatuses:
    - key: healthy
  environments:
    - branch: environment/dev
    - branch: environment/test
    - branch: environment/prod
      proposedCommitStatuses:
        - key: deployment-freeze

In this example, the PromotionStrategy has three environments: environment/dev, environment/test, and environment/prod. All environments have a healthy active commit status check. The environment/prod environment has an additional deployment-freeze proposed commit status check.

Suppose the environment branches have been hydrated from the main branch and that the branches have the following commit SHAs:

Branch SHA
main b5d8f7
environment/dev a1b2c3
environment/dev-next d4e5f6
environment/test a7b8c9
environment/test-next d0e1f2
environment/prod a3b4c5
environment/prod-next d6e7f8

For a change to be promoted through all environments, the following CommitStatuses must exist:

kind: CommitStatus
metadata:
  labels:
    promoter.argoproj.io/commit-status: healthy
spec:
  sha: a1b2c3  # environment/dev
  phase: success
---
kind: CommitStatus
metadata:
  labels:
    promoter.argoproj.io/commit-status: healthy
spec:
  sha: a7b8c9  # environment/test
  phase: success
---
kind: CommitStatus
metadata:
  labels:
    promoter.argoproj.io/commit-status: healthy
spec:
  sha: a3b4c5  # environment/prod
  phase: success
---
kind: CommitStatus
metadata:
  labels:
    promoter.argoproj.io/commit-status: deployment-freeze
spec:
  sha: d6e7f8  # environment/prod-next
  phase: success

Note that all the active commit statuses have SHAs corresponding to the active environment branches, and the proposed commit status has a SHA corresponding to the proposed (-next) environment branch.

Any tool wanting to gate an active commit status must create and update CommitStatuses with the appropriate SHAs for the respective environments' live environment branches.

Any tool wanting to gate a proposed commit status must create and update CommitStatuses with the appropriate SHAs for the respective environments' proposed (-next) environment branches.

How Active Commit Statuses Work (Implementation Details)

The PromotionStrategy controller will create a ChangeTransferPolicy for each environment. The ChangeTransferPolicy controller does not actually "look back" at previous environments to enforce active commit status checks. Instead, the PromotionStrategy controller will inject a proposedCommitStatus to represent the active status of the previous environment. The PromotionStrategy controller will also create and maintain a CommitStatus for each non-zero-index environment, based on the aggregate active commit status check of the previous environment.

So for the above example, the stg environment's ChangeTransferPolicy CR will look like this:

kind: ChangeTransferPolicy
spec:
  sourceBranch: environment/test-next
  targetBranch: environment/test
  activeCommitStatuses:
    # The controller will monitor this CommitStatus for the active commit SHA, but it will not enforce it. The status 
    # will be stored on the 
    - key: healthy
  proposedCommitStatuses:
    - key: healthy
    - key: promoter-previous-environment

Assuming the environment/dev environment has a healthy active commit status check, the promoter-previous-environment CommitStatus will look like this:

kind: CommitStatus
metadata:
  labels:
    promoter.argoproj.io/commit-status: promoter-previous-environment
spec:
  sha: d0e1f2  # environment/test-next
  phase: success

Even though the CommitStatus is "about" the environment/dev branch, the SHA is the SHA of the environment/test-next branch. This is how the PromotionStrategy controller expresses its opinion of the proposed commit on the stg environment, i.e. that it is acceptable because the previous environment is healthy.

Previous Environment CommitStatus URL

Since the previous environment CommitStatus aggregates the active commit status checks of the previous environment, it is nontrivial to determine what URL to use for the aggregate CommitStatus.

For now, the previous environment CommitStatus will only be set if there is only one active commit status. Its URL will be set to the URL of the previous environment's active commit status. If there are multiple active commit statuses, no URL will be set. This behavior may change in the future.

Built-In Gates

GitOps Promoter ships built-in gate controllers that create and manage CommitStatus resources automatically. Each gate has a matching CRD kind (for example ArgoCDCommitStatus); configure them in your cluster and reference their spec.key in PromotionStrategy.

Argo CD Health Status

The ArgoCDCommitStatus controller monitors Argo CD Applications and creates CommitStatus resources based on application health. This enables gating promotions based on whether applications are healthy in their current environment.

Key features:

  • Monitors Argo CD Applications with specific labels
  • spec.key (default argocd-health when omitted; set explicitly, including the default value)
  • Reports application health status (Healthy, Progressing, Degraded, etc.)

Time-Based Gating

The TimedCommitStatus controller implements "soak time" or "bake time" requirements, ensuring changes run in lower environments for a minimum duration before being promoted.

Key features:

  • Monitors how long commits have been running in each environment
  • spec.key (default timer when omitted; set explicitly, including the default value)
  • Reports pending until the required duration is met
  • Prevents promotions when there are pending changes in lower environments

Web Request (HTTP) Validation

The WebRequestCommitStatus controller gates promotions on external HTTP/HTTPS APIs. It calls configurable endpoints, evaluates the response with expressions, and creates CommitStatus resources so the SCM shows success or pending.

Key features:

  • Polling or trigger mode: Poll at an interval or only when a trigger expression fires (e.g. when SHA changes)
  • Validation expression: Uses the expr language; true means validation passed (CommitStatus phase success), false means pending
  • Optional response expression: Extract a subset of the HTTP response into ResponseOutput for use in the next trigger evaluation and in description/URL templates
  • TriggerOutput: Trigger when.output expression can return extra fields that are stored and available on the next run and in templates
  • SuccessOutput: Success when.output expression can return extra fields that are stored and available on the next run in trigger, success expressions, and templates
  • Shared expr (when.variables): Optional map expression whose result is available as Variables to when.expression and when.output.expression on the same when block (trigger and success); see Web Request Commit Status
  • Templated URL, headers, body: Go templates with Branch, Phase, PromotionStrategy, WebRequestCommitStatus, TriggerOutput, ResponseOutput, SuccessOutput, namespace metadata, etc.
  • Authentication: Basic, Bearer, OAuth2, or mutual TLS via Secrets
  • reportOn: Report on the proposed commit (default) or the active (deployed) commit

Custom Controllers

You can also create your own controllers that manage CommitStatus resources. Any system that can create Kubernetes resources can participate in the gating logic by creating CommitStatus resources with the appropriate SHAs and phases.