From 811d00302a38bdd06420b8a0959bbe3eb6b75e4b Mon Sep 17 00:00:00 2001 From: SASAGAWA Kiyoshi Date: Wed, 14 Oct 2026 08:40:27 +0900 Subject: [PATCH] fix: skip Manual Release for tags pushed by auto-tag (refs #278) auto-tag pushes tags with RELEASE_PAT, which also triggers release.yml. Both workflows then created the same release and raced on the SBOM upload. Add a guard job that skips push events whose annotated tag was created by github-actions[bot]; hand-pushed tags and workflow_dispatch are unaffected. Claude-Session: https://claude.ai/code/session_01Y29fBeRP344FME6de48wUv --- .github/workflows/release.yml | 42 +++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c952335..8ea3930f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Manual Release # Manual release workflow for: # - Hotfix releases (bypassing normal dev -> main flow) # - Re-creating failed releases -# - Creating releases from manually pushed tags +# - Creating releases from manually pushed tags (tags pushed by auto-tag.yml are skipped) # # For normal releases, use auto-tag.yml (triggered by version bump in package.json) @@ -29,15 +29,49 @@ permissions: contents: read jobs: + # 0. Skip tags pushed by auto-tag.yml. auto-tag pushes with RELEASE_PAT, which + # (unlike GITHUB_TOKEN) fires this workflow too; without this guard both + # workflows create the same release and race on the SBOM upload (#278). + # auto-tag creates annotated tags as github-actions[bot], so the tagger + # tells them apart from tags pushed by hand. + guard: + runs-on: ubuntu-latest + outputs: + skip: ${{ steps.check.outputs.skip }} + steps: + - name: Check tagger + id: check + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: | + if [ "${{ github.event_name }}" != "push" ]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + read -r TYPE SHA < <(gh api "repos/${{ github.repository }}/git/ref/tags/${TAG}" --jq '.object.type + " " + .object.sha') + TAGGER="" + if [ "$TYPE" = "tag" ]; then + TAGGER=$(gh api "repos/${{ github.repository }}/git/tags/${SHA}" --jq '.tagger.name') + fi + echo "Tag ${TAG}: type=${TYPE}, tagger=${TAGGER:-}" + if [ "$TAGGER" = "github-actions[bot]" ]; then + echo "Tag was created by auto-tag.yml, which handles the release. Skipping." + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + # 1. Run CI workflow first (unless skipped) call-ci: - if: ${{ github.event_name == 'push' || !inputs.skip_ci }} + needs: guard + if: ${{ needs.guard.outputs.skip != 'true' && (github.event_name == 'push' || !inputs.skip_ci) }} uses: ./.github/workflows/ci.yml # 2. Create release after CI passes create-release: - needs: call-ci - if: ${{ always() && (needs.call-ci.result == 'success' || needs.call-ci.result == 'skipped') }} + needs: [guard, call-ci] + if: ${{ always() && needs.guard.result == 'success' && needs.guard.outputs.skip != 'true' && (needs.call-ci.result == 'success' || needs.call-ci.result == 'skipped') }} runs-on: ubuntu-latest permissions: contents: write