Skip to main content

gh-wait-for-issue-state

info

This promotion step is only available in Kargo on the Akuity Platform, versions v1.11.0 and above.

The gh-wait-for-issue-state step polls a GitHub issue and holds the promotion until a successExpression evaluates to true. An optional failureExpression, checked on every poll before successExpression, fails the step immediately instead of continuing to wait.

This is useful for human-in-the-loop approval workflows where a reviewer signals readiness — or rejection — by applying a label or closing the issue.

GitHub Issues integration for Kargo is a group of promotion steps:

  1. gh-issue-add-comment
  2. gh-create-issue
  3. gh-issue-delete-comment
  4. gh-search-issues
  5. gh-issue-update-comment
  6. gh-update-issue
  7. gh-wait-for-issue-state

Credentials

These steps use the same repository credentials that git-clone and git-open-pr use for the same repository. If you have already configured a Git credential for the repoURL, no additional setup is required.

The GitHub token must have Issues: Read access for the repository (or the repo scope for a classic personal access token).

The issue variable

Both successExpression and failureExpression are evaluated with the issue available as issue, with the following fields:

FieldTypeDescription
numberintegerThe issue number.
titlestringThe issue title.
bodystringThe issue body.
statestringopen or closed.
labels[]stringLabel names currently applied to the issue.
assignees[]stringLogin names of assigned users.
urlstringThe issue's HTML URL.

labels and assignees are arrays of plain strings, not objects — check for a label with the in operator ("approved" in issue.labels), not by filtering on a .name field.

Configuration

NameTypeRequiredDescription
repoURLstringYThe URL of the GitHub repository (e.g. https://github.com/owner/repo).
insecureSkipTLSVerifybooleanNIf true, TLS verification of the GitHub server certificate is skipped. Use only for GitHub Enterprise Server instances with self-signed certificates.
issueNumberintegerYThe number of the issue to watch.
successExpressionstringYAn expression evaluated against issue on every poll. The step succeeds once this evaluates to true.
failureExpressionstringNAn expression evaluated against issue on every poll, before successExpression. If it evaluates to true, the step fails immediately instead of continuing to poll.
pollIntervalstringNHow often to check the issue state, specified as a Go duration string (e.g., 30s, 5m, 1.5h). Overrides the default controller reconciliation interval when set.

Output

This step does not produce any output.

Examples

Wait for label

Block promotion until a reviewer applies the approved label to signal readiness:

steps:
- uses: gh-wait-for-issue-state
config:
repoURL: https://github.com/myorg/myrepo
issueNumber: ${{ freightMetadata(ctx.targetFreight.name)['github-issue-number'] }}
successExpression: '"approved" in issue.labels'
pollInterval: 2m

# Promotion continues once the label is present
- uses: argocd-update
config:
apps:
- name: prod-app
namespace: argocd

Wait for closed state

Block promotion until the issue is closed:

steps:
- uses: gh-wait-for-issue-state
config:
repoURL: https://github.com/myorg/myrepo
issueNumber: ${{ freightMetadata(ctx.targetFreight.name)['github-issue-number'] }}
successExpression: 'issue.state == "closed"'

Wait for both label and closed state

Combine conditions with and:

steps:
- uses: gh-wait-for-issue-state
config:
repoURL: https://github.com/myorg/myrepo
issueNumber: ${{ freightMetadata(ctx.targetFreight.name)['github-issue-number'] }}
successExpression: 'issue.state == "closed" and "approved" in issue.labels'

Fail fast on rejection

Use failureExpression so a reviewer can reject immediately instead of the promotion waiting for pollInterval/timeout to elapse:

steps:
- uses: gh-wait-for-issue-state
config:
repoURL: https://github.com/myorg/myrepo
issueNumber: ${{ freightMetadata(ctx.targetFreight.name)['github-issue-number'] }}
successExpression: '"approved" in issue.labels'
failureExpression: '"rejected" in issue.labels'
pollInterval: 30s

Match against multiple labels

successExpression/failureExpression accept any expr-lang expression, so matching against more than one label doesn't require a different shape:

steps:
- uses: gh-wait-for-issue-state
config:
repoURL: https://github.com/myorg/myrepo
issueNumber: ${{ freightMetadata(ctx.targetFreight.name)['github-issue-number'] }}
successExpression: 'any(issue.labels, {# in ["approved", "lgtm"]})'
failureExpression: 'any(issue.labels, {# in ["rejected", "blocked"]})'