From b383e3eb75c747e27884b9c15a1f8a975d814171 Mon Sep 17 00:00:00 2001 From: fOuttaMyPaint Date: Thu, 4 Jun 2026 19:57:37 -0400 Subject: [PATCH] ci: serialize release creation so the upload matrix never races Splits the tag release path in go.yml into two stages: - create-release: a single job (needs build) that ensures the GitHub release for the tag exists before any assets are uploaded, so exactly one job owns release creation. - upload-assets: the existing 5-way build matrix (needs create-release) that builds each binary plus its .sha256 and only adds files to the already existing release. This removes the concurrent-create race where all five matrix jobs tried to create the same release. It worked on action-gh-release@v2 only by luck and failed on @v3 with "already_exists (tag_name)". With creation serialized, v3 is safe to adopt. Preserves the same 5 platform targets, asset names, 10 total assets (5 binaries plus 5 .sha256), checksum generation, GITHUB_TOKEN usage, and contents: write only on the release stages. Still on @v2 in this commit; the @v3 bump lands separately after validation. Co-authored-by: Cursor --- .github/workflows/go.yml | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f8b5fd9..b791a2a 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -45,9 +45,27 @@ jobs: with: version: latest - release: + # Single job that owns release creation. It runs once (not a matrix), so + # exactly one job ever creates the release for the tag. The upload-assets + # matrix below then only adds files to this already-existing release and can + # never race to create it (the race that made action-gh-release v3 fail with + # "already_exists (tag_name)"). + create-release: needs: build if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Ensure release exists for tag + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + upload-assets: + needs: create-release + if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write @@ -113,20 +131,18 @@ jobs: cp ${{ matrix.artifact_name }} ${{ matrix.asset_name }} fi - - name: Upload binaries to release - uses: softprops/action-gh-release@v2 - with: - files: ${{ matrix.asset_name }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Generate checksum shell: bash run: sha256sum ${{ matrix.asset_name }} > ${{ matrix.asset_name }}.sha256 - - name: Upload checksum to release + # The release already exists (created by create-release), so each matrix leg + # only adds its binary and checksum. No matrix job creates the release, which + # avoids the concurrent-create race entirely. + - name: Upload assets to release uses: softprops/action-gh-release@v2 with: - files: ${{ matrix.asset_name }}.sha256 + files: | + ${{ matrix.asset_name }} + ${{ matrix.asset_name }}.sha256 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}