From 6a836b0deb79eb0461be85256c0d0f75d13b225c Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 12:58:17 +0000 Subject: [PATCH 01/10] feat(workflow): add event-driven CI-ready gate for publish 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. --- .github/workflows/ci-ready.yml | 81 ++++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 65 +++++++++++++++++++++++---- 2 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/ci-ready.yml diff --git a/.github/workflows/ci-ready.yml b/.github/workflows/ci-ready.yml new file mode 100644 index 0000000..6eec651 --- /dev/null +++ b/.github/workflows/ci-ready.yml @@ -0,0 +1,81 @@ +name: CI Ready Signal + +on: + repository_dispatch: + types: [ci-ready] + +# client_payload schema: +# repo: "getsentry/sentry-native" (full owner/repo) +# version: "0.13.4" +# sha: "abc123..." (the release branch HEAD SHA) + +permissions: + contents: read + issues: write + +jobs: + signal: + runs-on: ubuntu-latest + name: Process CI-ready signal + steps: + - name: Find matching publish issue + id: find-issue + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.event.client_payload.repo }} + VERSION: ${{ github.event.client_payload.version }} + run: | + title="publish: ${REPO}@${VERSION}" + echo "Looking for issue: ${title}" + + # Find matching open issue by exact title match + issue=$(gh issue list -R "$GITHUB_REPOSITORY" \ + --state open \ + --json number,title,labels \ + | jq -r --arg t "$title" \ + '[.[] | select(.title == $t)] | first // empty') + + if [[ -z "$issue" ]]; then + # Retry a few times in case the issue hasn't been created yet + for i in 1 2 3; do + echo "Issue not found, retry ${i}/3 in 10s..." + sleep 10 + issue=$(gh issue list -R "$GITHUB_REPOSITORY" \ + --state open \ + --json number,title,labels \ + | jq -r --arg t "$title" \ + '[.[] | select(.title == $t)] | first // empty') + if [[ -n "$issue" ]]; then break; fi + done + fi + + if [[ -z "$issue" ]]; then + echo "::warning::No open issue found with title: ${title}" + exit 0 + fi + + number=$(echo "$issue" | jq -r '.number') + has_ci_pending=$(echo "$issue" | jq '[.labels[].name] | any(. == "ci-pending")') + + if [[ "$has_ci_pending" != "true" ]]; then + echo "::warning::Issue #${number} does not have ci-pending label. Ignoring signal." + exit 0 + fi + + echo "number=${number}" >> "$GITHUB_OUTPUT" + echo "Found issue #${number} with ci-pending label" + + - name: Add ci-ready label + if: steps.find-issue.outputs.number + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ steps.find-issue.outputs.number }} + SHA: ${{ github.event.client_payload.sha }} + REPO: ${{ github.event.client_payload.repo }} + run: | + gh issue edit "$ISSUE_NUMBER" -R "$GITHUB_REPOSITORY" \ + --remove-label "ci-pending" \ + --add-label "ci-ready" + + gh issue comment "$ISSUE_NUMBER" -R "$GITHUB_REPOSITORY" \ + --body "CI checks passed for ${REPO} (\`${SHA:0:8}\`). Publishing will start once the **accepted** label is also present." diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 426acc5..905b3da 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,6 +3,10 @@ on: issues: types: [labeled] +concurrency: + group: publish-${{ github.event.issue.number }} + cancel-in-progress: false + permissions: contents: read issues: write @@ -13,7 +17,9 @@ jobs: runs-on: ubuntu-latest environment: production name: Publish a new version - if: github.event.label.name == 'accepted' && github.event.issue.state == 'open' + if: >- + (github.event.label.name == 'accepted' || github.event.label.name == 'ci-ready') + && github.event.issue.state == 'open' timeout-minutes: 90 env: SENTRY_DSN: "https://303a687befb64dc2b40ce4c96de507c5@o1.ingest.sentry.io/6183838" @@ -71,9 +77,51 @@ jobs: private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} owner: getsentry # create token that have access to all repos + - name: Check publish readiness + id: gate + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + issue_number=${{ github.event.issue.number }} + labels=$(gh issue view "$issue_number" -R "$GITHUB_REPOSITORY" --json labels -q '.labels[].name') + + has_accepted=$(echo "$labels" | grep -c '^accepted$' || true) + has_ci_pending=$(echo "$labels" | grep -c '^ci-pending$' || true) + has_ci_ready=$(echo "$labels" | grep -c '^ci-ready$' || true) + + # Determine if this repo uses the ci-ready flow + uses_ci_ready=false + if [[ "$has_ci_pending" -gt 0 || "$has_ci_ready" -gt 0 ]]; then + uses_ci_ready=true + fi + + should_publish=false + skip_status_check=false + + if [[ "$has_accepted" -gt 0 ]]; then + if [[ "$uses_ci_ready" == "false" ]]; then + # Old-style repo: accepted is sufficient, craft will poll CI + should_publish=true + elif [[ "$has_ci_ready" -gt 0 ]]; then + # New-style repo: both conditions met, skip polling + should_publish=true + skip_status_check=true + else + # New-style repo: accepted but CI not ready yet + gh issue comment "$issue_number" -R "$GITHUB_REPOSITORY" \ + --body "Approved, but CI is still running on the release branch. Publishing will start automatically when CI passes." + fi + elif [[ "$has_ci_ready" -gt 0 ]]; then + # CI ready but not yet approved — nothing to do + echo "CI ready, waiting for accepted label." + fi + + echo "should_publish=${should_publish}" >> "$GITHUB_OUTPUT" + echo "skip_status_check=${skip_status_check}" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v6 name: Check out target repo - if: ${{ steps.inputs.outputs.result }} + if: steps.gate.outputs.should_publish == 'true' && steps.inputs.outputs.result with: path: __repo__ ref: ${{ steps.target-repo-branch.outputs.target_repo_branch || ''}} @@ -83,7 +131,7 @@ jobs: - name: Set targets shell: bash - if: fromJSON(steps.inputs.outputs.result).targets + if: steps.gate.outputs.should_publish == 'true' && fromJSON(steps.inputs.outputs.result).targets run: > jq -n --argjson source '${{ toJSON(fromJSON(steps.inputs.outputs.result).targets) }}' @@ -92,6 +140,7 @@ jobs: - uses: docker://getsentry/craft:latest name: Publish using Craft + if: steps.gate.outputs.should_publish == 'true' with: entrypoint: /bin/bash args: >- @@ -99,7 +148,7 @@ jobs: -c " export HOME=/root && cd __repo__/${{ fromJSON(steps.inputs.outputs.result).path }} && - exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} + exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} ${{ steps.gate.outputs.skip_status_check == 'true' && '--no-status-check' || '' }} " env: CRAFT_MERGE_TARGET: ${{ fromJSON(steps.inputs.outputs.result).merge_target }} @@ -138,28 +187,28 @@ jobs: PUBDEV_REFRESH_TOKEN: ${{ secrets.PUBDEV_REFRESH_TOKEN }} - name: Update completed targets and remove label - if: ${{ cancelled() || failure() }} + if: steps.gate.outputs.should_publish == 'true' && (cancelled() || failure()) env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node .__publish__/src/publish/update-issue.js - name: Inform about cancellation - if: ${{ cancelled() }} + if: steps.gate.outputs.should_publish == 'true' && cancelled() env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node .__publish__/src/publish/post-result.js cancelled - name: Inform about failure - if: ${{ failure() }} + if: steps.gate.outputs.should_publish == 'true' && failure() env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node .__publish__/src/publish/post-result.js failure - name: Close on success - if: ${{ success() }} + if: steps.gate.outputs.should_publish == 'true' && success() env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 399055e12d9193177d309458170fff0e80f56f88 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 13:33:54 +0000 Subject: [PATCH 02/10] chore: remove redundant GH_TOKEN env, gh uses GITHUB_TOKEN natively --- .github/workflows/ci-ready.yml | 2 -- .github/workflows/publish.yml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/ci-ready.yml b/.github/workflows/ci-ready.yml index 6eec651..3eafe42 100644 --- a/.github/workflows/ci-ready.yml +++ b/.github/workflows/ci-ready.yml @@ -21,7 +21,6 @@ jobs: - name: Find matching publish issue id: find-issue env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.event.client_payload.repo }} VERSION: ${{ github.event.client_payload.version }} run: | @@ -68,7 +67,6 @@ jobs: - name: Add ci-ready label if: steps.find-issue.outputs.number env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ steps.find-issue.outputs.number }} SHA: ${{ github.event.client_payload.sha }} REPO: ${{ github.event.client_payload.repo }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 905b3da..22bc5f8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -79,8 +79,6 @@ jobs: - name: Check publish readiness id: gate - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | issue_number=${{ github.event.issue.number }} labels=$(gh issue view "$issue_number" -R "$GITHUB_REPOSITORY" --json labels -q '.labels[].name') From 6e7fdb414d0644cc5d8db16debaa14a51bc0c802 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 13:35:34 +0000 Subject: [PATCH 03/10] fix: require accepted label on the issue before starting the publish job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use contains(labels, accepted) so the job only runs when accepted is present. The || still allows ci-ready to trigger the job, but only when accepted is already on the issue — preventing wasted runs. --- .github/workflows/publish.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 22bc5f8..c79d2c1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,8 +18,9 @@ jobs: environment: production name: Publish a new version if: >- - (github.event.label.name == 'accepted' || github.event.label.name == 'ci-ready') - && github.event.issue.state == 'open' + github.event.issue.state == 'open' + && contains(github.event.issue.labels.*.name, 'accepted') + && (github.event.label.name == 'accepted' || github.event.label.name == 'ci-ready') timeout-minutes: 90 env: SENTRY_DSN: "https://303a687befb64dc2b40ce4c96de507c5@o1.ingest.sentry.io/6183838" From 2de04ae9997293f36509cdcfa0725608a2b5641f Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 13:39:14 +0000 Subject: [PATCH 04/10] refactor: move gating logic to job-level if, remove gate step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All label state is available in github.event.issue.labels at event time. The publish job if-condition now directly encodes the decision matrix: - accepted + no ci-pending → run - accepted + ci-ready → run (with --no-status-check) - accepted + ci-pending → skip (waiting-for-ci job comments instead) - anything without accepted → skip This removes the gate step that was re-fetching labels via gh issue view and all the step-level should_publish guards. --- .github/workflows/publish.yml | 75 +++++++++++++---------------------- 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c79d2c1..f565e02 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,13 +13,33 @@ permissions: packages: write jobs: + # Lightweight job: comment when approved but CI hasn't finished yet + waiting-for-ci: + runs-on: ubuntu-latest + name: Waiting for CI + if: >- + github.event.label.name == 'accepted' + && github.event.issue.state == 'open' + && contains(github.event.issue.labels.*.name, 'ci-pending') + steps: + - name: Comment on issue + run: | + gh issue comment "${{ github.event.issue.number }}" \ + -R "$GITHUB_REPOSITORY" \ + --body "Approved, but CI is still running on the release branch. Publishing will start automatically when CI passes." + publish: runs-on: ubuntu-latest environment: production name: Publish a new version + # Run when: + # - accepted (with no ci-pending blocking), OR + # - ci-ready added (and accepted is already present) + # In all cases accepted must be present and ci-pending must not be. if: >- github.event.issue.state == 'open' && contains(github.event.issue.labels.*.name, 'accepted') + && !contains(github.event.issue.labels.*.name, 'ci-pending') && (github.event.label.name == 'accepted' || github.event.label.name == 'ci-ready') timeout-minutes: 90 env: @@ -78,49 +98,9 @@ jobs: private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} owner: getsentry # create token that have access to all repos - - name: Check publish readiness - id: gate - run: | - issue_number=${{ github.event.issue.number }} - labels=$(gh issue view "$issue_number" -R "$GITHUB_REPOSITORY" --json labels -q '.labels[].name') - - has_accepted=$(echo "$labels" | grep -c '^accepted$' || true) - has_ci_pending=$(echo "$labels" | grep -c '^ci-pending$' || true) - has_ci_ready=$(echo "$labels" | grep -c '^ci-ready$' || true) - - # Determine if this repo uses the ci-ready flow - uses_ci_ready=false - if [[ "$has_ci_pending" -gt 0 || "$has_ci_ready" -gt 0 ]]; then - uses_ci_ready=true - fi - - should_publish=false - skip_status_check=false - - if [[ "$has_accepted" -gt 0 ]]; then - if [[ "$uses_ci_ready" == "false" ]]; then - # Old-style repo: accepted is sufficient, craft will poll CI - should_publish=true - elif [[ "$has_ci_ready" -gt 0 ]]; then - # New-style repo: both conditions met, skip polling - should_publish=true - skip_status_check=true - else - # New-style repo: accepted but CI not ready yet - gh issue comment "$issue_number" -R "$GITHUB_REPOSITORY" \ - --body "Approved, but CI is still running on the release branch. Publishing will start automatically when CI passes." - fi - elif [[ "$has_ci_ready" -gt 0 ]]; then - # CI ready but not yet approved — nothing to do - echo "CI ready, waiting for accepted label." - fi - - echo "should_publish=${should_publish}" >> "$GITHUB_OUTPUT" - echo "skip_status_check=${skip_status_check}" >> "$GITHUB_OUTPUT" - - uses: actions/checkout@v6 name: Check out target repo - if: steps.gate.outputs.should_publish == 'true' && steps.inputs.outputs.result + if: ${{ steps.inputs.outputs.result }} with: path: __repo__ ref: ${{ steps.target-repo-branch.outputs.target_repo_branch || ''}} @@ -130,7 +110,7 @@ jobs: - name: Set targets shell: bash - if: steps.gate.outputs.should_publish == 'true' && fromJSON(steps.inputs.outputs.result).targets + if: fromJSON(steps.inputs.outputs.result).targets run: > jq -n --argjson source '${{ toJSON(fromJSON(steps.inputs.outputs.result).targets) }}' @@ -139,7 +119,6 @@ jobs: - uses: docker://getsentry/craft:latest name: Publish using Craft - if: steps.gate.outputs.should_publish == 'true' with: entrypoint: /bin/bash args: >- @@ -147,7 +126,7 @@ jobs: -c " export HOME=/root && cd __repo__/${{ fromJSON(steps.inputs.outputs.result).path }} && - exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} ${{ steps.gate.outputs.skip_status_check == 'true' && '--no-status-check' || '' }} + exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} ${{ contains(github.event.issue.labels.*.name, 'ci-ready') && '--no-status-check' || '' }} " env: CRAFT_MERGE_TARGET: ${{ fromJSON(steps.inputs.outputs.result).merge_target }} @@ -186,28 +165,28 @@ jobs: PUBDEV_REFRESH_TOKEN: ${{ secrets.PUBDEV_REFRESH_TOKEN }} - name: Update completed targets and remove label - if: steps.gate.outputs.should_publish == 'true' && (cancelled() || failure()) + if: ${{ cancelled() || failure() }} env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node .__publish__/src/publish/update-issue.js - name: Inform about cancellation - if: steps.gate.outputs.should_publish == 'true' && cancelled() + if: ${{ cancelled() }} env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node .__publish__/src/publish/post-result.js cancelled - name: Inform about failure - if: steps.gate.outputs.should_publish == 'true' && failure() + if: ${{ failure() }} env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: node .__publish__/src/publish/post-result.js failure - name: Close on success - if: steps.gate.outputs.should_publish == 'true' && success() + if: ${{ success() }} env: PUBLISH_ARGS: ${{ steps.inputs.outputs.result }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c796855974dd967e4a3d884da6f1fd5ca278a516 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 14:11:55 +0000 Subject: [PATCH 05/10] fix: use GitHub App token for label changes and increase issue list limit GITHUB_TOKEN events are suppressed by GitHub and would not trigger publish.yml. Use the sentry-internal-app token (same pattern as auto-approve.yml) so the ci-ready label addition fires the labeled event that publish.yml listens for. Also add --limit 200 to gh issue list to handle repos with many open issues (default is 30). --- .github/workflows/ci-ready.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-ready.yml b/.github/workflows/ci-ready.yml index 3eafe42..2d6952e 100644 --- a/.github/workflows/ci-ready.yml +++ b/.github/workflows/ci-ready.yml @@ -11,7 +11,6 @@ on: permissions: contents: read - issues: write jobs: signal: @@ -27,9 +26,11 @@ jobs: title="publish: ${REPO}@${VERSION}" echo "Looking for issue: ${title}" - # Find matching open issue by exact title match + # Find matching open issue by exact title match. + # Use --limit 200 to handle active repos with many open issues. issue=$(gh issue list -R "$GITHUB_REPOSITORY" \ --state open \ + --limit 200 \ --json number,title,labels \ | jq -r --arg t "$title" \ '[.[] | select(.title == $t)] | first // empty') @@ -41,6 +42,7 @@ jobs: sleep 10 issue=$(gh issue list -R "$GITHUB_REPOSITORY" \ --state open \ + --limit 200 \ --json number,title,labels \ | jq -r --arg t "$title" \ '[.[] | select(.title == $t)] | first // empty') @@ -64,9 +66,21 @@ jobs: echo "number=${number}" >> "$GITHUB_OUTPUT" echo "Found issue #${number} with ci-pending label" + # Use a GitHub App token so the label change triggers publish.yml. + # GITHUB_TOKEN events are deliberately suppressed by GitHub and + # would not create new workflow runs. + - name: Get auth token + if: steps.find-issue.outputs.number + id: token + uses: actions/create-github-app-token@v2.2.1 + with: + app-id: ${{ vars.SENTRY_INTERNAL_APP_ID }} + private-key: ${{ secrets.SENTRY_INTERNAL_APP_PRIVATE_KEY }} + - name: Add ci-ready label if: steps.find-issue.outputs.number env: + GH_TOKEN: ${{ steps.token.outputs.token }} ISSUE_NUMBER: ${{ steps.find-issue.outputs.number }} SHA: ${{ github.event.client_payload.sha }} REPO: ${{ github.event.client_payload.repo }} From a6fc6b57f8dba3d915478974ebd75a1447c1b80a Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 14:19:25 +0000 Subject: [PATCH 06/10] fix: make ci-ready comment reflect whether accepted label is already present --- .github/workflows/ci-ready.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-ready.yml b/.github/workflows/ci-ready.yml index 2d6952e..5102b29 100644 --- a/.github/workflows/ci-ready.yml +++ b/.github/workflows/ci-ready.yml @@ -63,8 +63,11 @@ jobs: exit 0 fi + has_accepted=$(echo "$issue" | jq '[.labels[].name] | any(. == "accepted")') + echo "number=${number}" >> "$GITHUB_OUTPUT" - echo "Found issue #${number} with ci-pending label" + echo "has_accepted=${has_accepted}" >> "$GITHUB_OUTPUT" + echo "Found issue #${number} with ci-pending label (accepted=${has_accepted})" # Use a GitHub App token so the label change triggers publish.yml. # GITHUB_TOKEN events are deliberately suppressed by GitHub and @@ -89,5 +92,9 @@ jobs: --remove-label "ci-pending" \ --add-label "ci-ready" - gh issue comment "$ISSUE_NUMBER" -R "$GITHUB_REPOSITORY" \ - --body "CI checks passed for ${REPO} (\`${SHA:0:8}\`). Publishing will start once the **accepted** label is also present." + if [[ "${{ steps.find-issue.outputs.has_accepted }}" == "true" ]]; then + comment="CI checks passed for ${REPO} (\`${SHA:0:8}\`). Publishing is starting now." + else + comment="CI checks passed for ${REPO} (\`${SHA:0:8}\`). Publishing will start once the **accepted** label is also present." + fi + gh issue comment "$ISSUE_NUMBER" -R "$GITHUB_REPOSITORY" --body "$comment" From 3d53901f618a222f212e517d7fedbd2bd85fb85c Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 14:30:29 +0000 Subject: [PATCH 07/10] fix: add missing GH_TOKEN and issues:read permission for gh CLI - ci-ready.yml: add issues:read permission and explicit GH_TOKEN for the find-issue step (repository_dispatch does not auto-expose the token to gh CLI) - publish.yml: add GH_TOKEN to waiting-for-ci job comment step --- .github/workflows/ci-ready.yml | 2 ++ .github/workflows/publish.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/ci-ready.yml b/.github/workflows/ci-ready.yml index 5102b29..010ccdc 100644 --- a/.github/workflows/ci-ready.yml +++ b/.github/workflows/ci-ready.yml @@ -11,6 +11,7 @@ on: permissions: contents: read + issues: read jobs: signal: @@ -20,6 +21,7 @@ jobs: - name: Find matching publish issue id: find-issue env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.event.client_payload.repo }} VERSION: ${{ github.event.client_payload.version }} run: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f565e02..e52219b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,6 +23,8 @@ jobs: && contains(github.event.issue.labels.*.name, 'ci-pending') steps: - name: Comment on issue + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh issue comment "${{ github.event.issue.number }}" \ -R "$GITHUB_REPOSITORY" \ From 423ba4131cbe375f984fd2933856c96cf745aea1 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 14:51:00 +0000 Subject: [PATCH 08/10] chore: remove redundant GH_TOKEN where gh uses GITHUB_TOKEN natively gh CLI auto-reads GITHUB_TOKEN in GitHub Actions. Only override with GH_TOKEN when we need a different token (the GitHub App token for label changes that must trigger downstream workflows). --- .github/workflows/ci-ready.yml | 4 +++- .github/workflows/publish.yml | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-ready.yml b/.github/workflows/ci-ready.yml index 010ccdc..9a00a94 100644 --- a/.github/workflows/ci-ready.yml +++ b/.github/workflows/ci-ready.yml @@ -21,7 +21,6 @@ jobs: - name: Find matching publish issue id: find-issue env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.event.client_payload.repo }} VERSION: ${{ github.event.client_payload.version }} run: | @@ -85,6 +84,9 @@ jobs: - name: Add ci-ready label if: steps.find-issue.outputs.number env: + # Override the default GITHUB_TOKEN with the app token so the + # label event triggers publish.yml (GITHUB_TOKEN events are + # suppressed by GitHub and would not start new workflow runs). GH_TOKEN: ${{ steps.token.outputs.token }} ISSUE_NUMBER: ${{ steps.find-issue.outputs.number }} SHA: ${{ github.event.client_payload.sha }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e52219b..f565e02 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,8 +23,6 @@ jobs: && contains(github.event.issue.labels.*.name, 'ci-pending') steps: - name: Comment on issue - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh issue comment "${{ github.event.issue.number }}" \ -R "$GITHUB_REPOSITORY" \ From c544155515ad5092d9f473f76142437bc5031e81 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 14:52:52 +0000 Subject: [PATCH 09/10] fix: use issue title as concurrency group to lock on repo@version Issue numbers are unique but do not prevent parallel publishes when duplicate issues exist for the same repo@version. The title ("publish: getsentry/foo@1.2.3") is the natural identity of the release and ensures only one publish runs per repo@version. --- .github/workflows/publish.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f565e02..a8f49b3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,9 @@ on: types: [labeled] concurrency: - group: publish-${{ github.event.issue.number }} + # Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate + # issues for the same repo@version share a concurrency group. + group: ${{ github.event.issue.title }} cancel-in-progress: false permissions: From d42256bb0de8ed089ebff2005e66594ecde96016 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Apr 2026 14:54:59 +0000 Subject: [PATCH 10/10] fix: remove --no-status-check, let craft verify CI status itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ci-ready signal is tied to a specific SHA but someone could push to the release branch after CI passes. Letting craft poll the status is safer — and since CI is already done by the time publish starts, the first poll iteration returns immediately anyway. --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a8f49b3..7d7e167 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -128,7 +128,7 @@ jobs: -c " export HOME=/root && cd __repo__/${{ fromJSON(steps.inputs.outputs.result).path }} && - exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} ${{ contains(github.event.issue.labels.*.name, 'ci-ready') && '--no-status-check' || '' }} + exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} " env: CRAFT_MERGE_TARGET: ${{ fromJSON(steps.inputs.outputs.result).merge_target }}