feat(action): add event-driven CI-ready signaling to replace publish polling#789
feat(action): add event-driven CI-ready signaling to replace publish polling#789
Conversation
Add a ci-ready.yml workflow that handles repository_dispatch events from target repos when their CI passes. It adds a "ci-ready" label to the publish issue, replacing the "ci-pending" label set at issue creation. Modify publish.yml with a gate step that checks label state: - Old repos (no ci-pending/ci-ready): publish with polling (unchanged) - New repos with both accepted + ci-ready: publish with --no-status-check - New repos with accepted but no ci-ready: comment and wait for CI - ci-ready without accepted: wait for approval Add concurrency control to prevent duplicate publish runs when both labels arrive near-simultaneously. This is Phase 1 of a cross-repo change. Phase 2 (getsentry/craft#789) adds the ci_ready input and signal-ready action.
## Summary - New `ci-ready.yml` workflow that handles `repository_dispatch` events from target repos when CI passes - Modified `publish.yml` with a gate step that checks label state before publishing - Added concurrency control to prevent duplicate publish runs - Created `ci-pending` and `ci-ready` labels ## Context `craft publish` currently polls GitHub's commit status API every 30 seconds for up to 60 minutes. This polling time is billed as GitHub Actions minutes and steals from our available capacity — a publish job that waits 45 minutes for CI burns 45 minutes of runner time doing nothing but `sleep 30` in a loop. For repos like sentry-native (~1h 23m CI), this also exhausts the 1-hour GitHub App token lifetime, causing expired-token failures. This PR replaces the polling wait with an event-driven label state machine. Instead of starting the publish runner and idling until CI passes, the job doesn't start at all until CI signals readiness — zero wasted runner minutes. | Label | Meaning | |---|---| | `ci-pending` | CI signal expected but not yet received | | `ci-ready` | CI passed, ready to publish | | `accepted` | Approved for publishing (unchanged) | ## Gate Decision Matrix | `accepted` | `ci-pending` | `ci-ready` | Action | |---|---|---|---| | yes | no | no | **Old repo**: publish with polling (unchanged) | | yes | yes | no | **Waiting for CI**: comment on issue, skip | | yes | — | yes | **Ready**: publish immediately | | no | — | yes | CI ready, waiting for approval: skip | ## Cross-Repo Dependency This is **Phase 1** of a three-phase rollout: 1. **Phase 1** (this PR): Gate logic + ci-ready.yml workflow — safe to deploy, no impact on existing repos 2. **Phase 2** ([getsentry/craft#789](getsentry/craft#789)): ci_ready input + signal-ready action 3. **Phase 3** (target repos): Opt-in one repo at a time Old repos (without ci_ready: true) are completely unaffected — they keep the existing polling behavior.
c08e42c to
a856fd2
Compare
| required: false | ||
| default: 'true' |
There was a problem hiding this comment.
Bug: The ci_ready input defaults to 'true' instead of the intended 'false', causing release workflows to stall for any repository that has not explicitly opted into the new CI signaling mechanism.
Severity: CRITICAL
Suggested Fix
Change the default value for the ci_ready input to 'false' in action.yml and the reusable workflow in .github/workflows/release.yml to align with the intended opt-in behavior. This ensures existing workflows are not affected unless they explicitly set ci_ready: 'true'.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: action.yml#L53-L54
Potential issue: The `ci_ready` input in `action.yml` defaults to `'true'`, but the
feature is designed to be opt-in with a default of `'false'`. This causes the action to
add a `ci-pending` label to publish issues for all repositories by default. Repositories
that have not adopted the corresponding `signal-ready` action will have their release
process blocked indefinitely, as they will be waiting for a signal that is never sent.
This affects both external repositories using the action and the project's own
dogfooding release workflow, which does not pass the `ci_ready` input and thus uses the
incorrect default.
Did we get this right? 👍 / 👎 to inform future reviews.
…polling Add opt-in ci_ready input (default true) to the prepare action and reusable workflow. When enabled, the publish issue is created with a "ci-pending" label and a repository_dispatch is sent to the publish repo to trigger the CI status poller immediately. The poller (in getsentry/publish) checks CI status for all ci-pending issues and adds the "ci-ready" label when checks pass. This replaces per-release idle polling inside the Docker container, which burned billed GitHub Actions minutes and stole from available capacity. Target repos need zero changes — the poller handles everything centrally.
a856fd2 to
5d533c8
Compare
|
Closing — the publish repo's self-contained poller (getsentry/publish#7674) handles everything: adds |
Summary
ci_readyinput to the prepare action and reusable workflow (defaulttrue, opt-out with'false')ci-pendinglabel and acheck-ci-statusdispatch is sent to the publish repo to trigger the CI status poller immediatelypublish_issue_numberoutput for downstream useContext
craft publishcurrently polls GitHub's commit status API every 30 seconds for up to 60 minutes (waitForTheBuildToSucceed) inside a Docker container. This idle polling is billed as GitHub Actions minutes and steals from our available capacity — a publish job that waits 45 minutes for CI burns 45 minutes of runner time doing nothing.This PR adds the
ci-pendinglabel at issue creation time and dispatches a signal to the publish repo's centralized CI status poller (getsentry/publish#7674). The publish job doesn't start at all until CI passes — zero wasted runner minutes. Target repos need zero changes.ci-pendingci-readyacceptedci_readydefaults totrue— all repos using the reusable workflow get the new behavior automatically. Repos that need the legacy polling can opt out withci_ready: 'false'.Cross-Repo Dependency
Works with getsentry/publish#7674 (centralized CI status poller).