Skip to content

feat(action): add event-driven CI-ready signaling to replace publish polling#789

Closed
BYK wants to merge 1 commit intomasterfrom
feat/ci-ready-signal
Closed

feat(action): add event-driven CI-ready signaling to replace publish polling#789
BYK wants to merge 1 commit intomasterfrom
feat/ci-ready-signal

Conversation

@BYK
Copy link
Copy Markdown
Member

@BYK BYK commented Apr 1, 2026

Summary

  • Add ci_ready input to the prepare action and reusable workflow (default true, opt-out with 'false')
  • When enabled, the publish issue is created with a ci-pending label and a check-ci-status dispatch is sent to the publish repo to trigger the CI status poller immediately
  • New publish_issue_number output for downstream use

Context

craft publish currently 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-pending label 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.

Label Meaning
ci-pending CI signal expected but not yet received
ci-ready CI passed, ready to publish
accepted Approved for publishing (unchanged)

ci_ready defaults to true — all repos using the reusable workflow get the new behavior automatically. Repos that need the legacy polling can opt out with ci_ready: 'false'.

Cross-Repo Dependency

Works with getsentry/publish#7674 (centralized CI status poller).

BYK added a commit to getsentry/publish that referenced this pull request Apr 1, 2026
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.
BYK added a commit to getsentry/publish that referenced this pull request Apr 1, 2026
## 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.
@BYK BYK marked this pull request as ready for review April 1, 2026 18:49
@BYK BYK force-pushed the feat/ci-ready-signal branch from c08e42c to a856fd2 Compare April 1, 2026 18:51
Comment on lines +53 to +54
required: false
default: 'true'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@BYK
Copy link
Copy Markdown
Member Author

BYK commented Apr 1, 2026

Closing — the publish repo's self-contained poller (getsentry/publish#7674) handles everything: adds ci-pending on issue creation, checks CI status via self-dispatch, flips to ci-ready when green. No craft changes needed.

@BYK BYK closed this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant