From 5d533c854ad481c31162c4e003cabe23ac5e900a Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 10:32:26 +0000 Subject: [PATCH] feat(action): add event-driven CI-ready signaling to replace publish polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .github/workflows/release.yml | 18 ++++++++++++++ action.yml | 46 +++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8285baa0..5c36acf8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,6 +56,15 @@ on: type: string required: false default: 'false' + ci_ready: + description: > + Use event-driven CI signaling instead of polling. + When true (the default), the publish issue is created with a + "ci-pending" label. The target repo should call the signal-ready + action after CI passes. Set to 'false' to fall back to legacy polling. + type: string + required: false + default: 'true' outputs: version: description: The resolved version being released @@ -72,6 +81,12 @@ on: changelog: description: The changelog for this release (may be truncated for large repos) value: ${{ jobs.release.outputs.changelog }} + issue_url: + description: The URL of the created publish request issue + value: ${{ jobs.release.outputs.issue_url }} + publish_issue_number: + description: The number of the created/updated publish issue + value: ${{ jobs.release.outputs.publish_issue_number }} jobs: # Build job only for Craft's own releases (dogfooding) @@ -96,6 +111,8 @@ jobs: sha: ${{ steps.craft-local.outputs.sha || steps.craft-action.outputs.sha }} previous_tag: ${{ steps.craft-local.outputs.previous_tag || steps.craft-action.outputs.previous_tag }} changelog: ${{ steps.craft-local.outputs.changelog || steps.craft-action.outputs.changelog }} + issue_url: ${{ steps.craft-local.outputs.issue_url || steps.craft-action.outputs.issue_url }} + publish_issue_number: ${{ steps.craft-local.outputs.publish_issue_number || steps.craft-action.outputs.publish_issue_number }} steps: # For Craft repo: use the release bot token - name: Get auth token @@ -140,3 +157,4 @@ jobs: git_user_email: ${{ inputs.git_user_email }} path: ${{ inputs.path }} craft_config_from_merge_target: ${{ inputs.craft_config_from_merge_target }} + ci_ready: ${{ inputs.ci_ready }} diff --git a/action.yml b/action.yml index 50cedd5f..b25ca550 100644 --- a/action.yml +++ b/action.yml @@ -41,6 +41,17 @@ inputs: Defaults to the action ref (e.g., "v2") if not specified. required: false default: '' + ci_ready: + description: > + Use event-driven CI signaling instead of polling. + When true (the default), the publish issue is created with a + "ci-pending" label, and the target repo is expected to send a + repository_dispatch event (via the signal-ready action) when CI + passes. The publish workflow will not start the job until CI + signals readiness, avoiding wasted runner minutes from idle + polling. Set to 'false' to fall back to the legacy polling behavior. + required: false + default: 'true' outputs: version: @@ -64,6 +75,9 @@ outputs: issue_url: description: The URL of the created publish request issue value: ${{ steps.request-publish.outputs.issue_url }} + publish_issue_number: + description: The number of the created/updated publish issue (for use with signal-ready) + value: ${{ steps.request-publish.outputs.issue_number }} runs: using: 'composite' @@ -202,6 +216,7 @@ runs: SUBDIRECTORY: ${{ inputs.path != '.' && format('/{0}', inputs.path) || '' }} MERGE_TARGET: ${{ inputs.merge_target || '(default)' }} PUBLISH_REPO: ${{ inputs.publish_repo || format('{0}/publish', github.repository_owner) }} + CI_READY: ${{ inputs.ci_ready }} run: | # Resolve "self" to the current repository if [[ "$PUBLISH_REPO" == "self" ]]; then @@ -307,6 +322,12 @@ runs: Checked targets will be skipped (either already published or user-requested skip). Uncheck to retry a target. ${CHANGELOG_SECTION}" + # Build label args for ci-ready opt-in + LABEL_ARGS="" + if [[ "$CI_READY" == "true" ]]; then + LABEL_ARGS="--label ci-pending" + fi + if [[ -n "$existing_issue_number" ]]; then # Try to update existing issue with fresh body (preserving checked target states) # This may fail if the token doesn't have permission to update issues in the publish repo @@ -315,10 +336,31 @@ runs: else echo "::warning::Could not update existing issue (permission denied). Using existing issue as-is." fi + + # For ci-ready opt-in: ensure ci-pending label is present (unless ci-ready already set) + if [[ "$CI_READY" == "true" ]]; then + existing_labels=$(gh issue view "$existing_issue_number" -R "$PUBLISH_REPO" --json labels -q '.labels[].name' 2>/dev/null || true) + if ! echo "$existing_labels" | grep -q '^ci-ready$'; then + gh issue edit "$existing_issue_number" -R "$PUBLISH_REPO" --add-label "ci-pending" 2>/dev/null || true + fi + fi + echo "issue_url=${existing_issue_url}" >> "$GITHUB_OUTPUT" + echo "issue_number=${existing_issue_number}" >> "$GITHUB_OUTPUT" else - # Create new issue - issue_url=$(gh issue create -R "$PUBLISH_REPO" --title "$title" --body "$body") + # Create new issue (with ci-pending label if ci_ready is enabled) + issue_url=$(gh issue create -R "$PUBLISH_REPO" --title "$title" --body "$body" $LABEL_ARGS) echo "::notice::Created publish request: ${issue_url}" echo "issue_url=${issue_url}" >> "$GITHUB_OUTPUT" + + # Extract issue number from the URL (last path segment) + issue_number=$(echo "$issue_url" | grep -oE '[0-9]+$') + echo "issue_number=${issue_number}" >> "$GITHUB_OUTPUT" + fi + + # Trigger the CI status poller so it checks immediately rather than + # waiting for the next scheduled run. + if [[ "$CI_READY" == "true" ]]; then + gh api -X POST "repos/${PUBLISH_REPO}/dispatches" \ + -f event_type=check-ci-status 2>/dev/null || true fi