From 2bb5a078cca361aee43a28b9aa7523c564caec82 Mon Sep 17 00:00:00 2001 From: inGitDB Dev Date: Thu, 11 Jun 2026 17:13:43 +0100 Subject: [PATCH] ci: harden Release workflow against tag races MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dispatch-triggered release ran on main HEAD and silently required the newest tag to point at it — releasing seconds before the version tag finished propagating failed goreleaser's git-state check (seen on run 27357782836: 'git tag v1.30.1 was not made against commit 26b63e6'). Now build-linux resolves the release tag once (an explicit workflow_dispatch 'tag' input, or the newest tag on the default branch), checks it out, and exposes it as a job output; the windows, homebrew, and snap jobs check out that same tag. All jobs therefore build the identical tagged commit regardless of when the dispatch happens or what lands on main mid-run. A concurrency group queues a second dispatch instead of letting two releases interleave. Deliberately NOT triggering on tag push: tags are minted on every merge to main, and auto-publishing each merge to brew/snap/AUR/choco would change release cadence. Releases stay manual. Co-Authored-By: Claude Fable 5 --- .github/workflows/release.yml | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 946b016..d1b16e3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,16 @@ name: Release on: workflow_dispatch: # Allows manual trigger from Actions tab. + inputs: + tag: + description: "Tag to release (e.g. v1.31.0). Empty = newest tag on the default branch." + required: false + type: string + +# One release at a time; a second dispatch queues instead of racing the first. +concurrency: + group: release + cancel-in-progress: false jobs: build-linux: @@ -9,6 +19,8 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + outputs: + tag: ${{ steps.tag.outputs.tag }} steps: - uses: actions/checkout@v6 @@ -18,6 +30,22 @@ jobs: - name: Fetch all tags run: git fetch --tags --force + # Resolve the release tag ONCE and check it out, so goreleaser's + # git-state check (tag must point at HEAD) cannot race a tag pushed + # around dispatch time, and all jobs release the same tag even if a + # newer one lands mid-run. + - name: Resolve and check out release tag + id: tag + shell: bash + run: | + TAG="${{ inputs.tag }}" + if [ -z "$TAG" ]; then + TAG="$(git describe --tags --abbrev=0)" + fi + echo "Releasing tag: $TAG" + git checkout --quiet "$TAG" + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + - uses: actions/setup-go@v6 with: go-version: "1.26.4" @@ -63,6 +91,10 @@ jobs: - name: Fetch all tags run: git fetch --tags --force + - name: Check out release tag + shell: bash + run: git checkout --quiet "${{ needs.build-linux.outputs.tag }}" + - uses: actions/setup-go@v6 with: go-version: "1.26.4" @@ -94,6 +126,10 @@ jobs: - name: Fetch all tags run: git fetch --tags --force + - name: Check out release tag + shell: bash + run: git checkout --quiet "${{ needs.build-linux.outputs.tag }}" + - uses: actions/setup-go@v6 with: go-version: "1.26.4" @@ -127,6 +163,10 @@ jobs: - name: Fetch all tags run: git fetch --tags --force + - name: Check out release tag + shell: bash + run: git checkout --quiet "${{ needs.build-linux.outputs.tag }}" + - uses: actions/setup-go@v6 with: go-version: "1.26.4"