ci: serialize release creation so the upload matrix never races #95
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Go | |
| on: | |
| push: | |
| branches: [ "main" ] | |
| tags: [ "v*" ] | |
| pull_request: | |
| branches: [ "main" ] | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: 'go.mod' | |
| - name: Cache Go build artifacts | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cache/go-build | |
| ~/go/pkg/mod | |
| key: ${{ runner.os }}-go-${{ hashFiles('**/go.mod') }} | |
| restore-keys: | | |
| ${{ runner.os }}-go- | |
| - name: Verify dependencies | |
| run: go mod verify | |
| - name: Build | |
| run: go build -v -buildvcs=false ./... | |
| - name: Test | |
| run: go test -v -race ./... | |
| - name: Run golangci-lint | |
| uses: golangci/golangci-lint-action@v9 | |
| with: | |
| version: latest | |
| # 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 | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| goos: linux | |
| goarch: amd64 | |
| artifact_name: subenum | |
| asset_name: subenum-linux-amd64 | |
| - os: windows-latest | |
| goos: windows | |
| goarch: amd64 | |
| artifact_name: subenum.exe | |
| asset_name: subenum-windows-amd64.exe | |
| - os: macos-latest | |
| goos: darwin | |
| goarch: arm64 | |
| artifact_name: subenum | |
| asset_name: subenum-macos-arm64 | |
| - os: ubuntu-latest | |
| goos: darwin | |
| goarch: amd64 | |
| artifact_name: subenum | |
| asset_name: subenum-macos-amd64 | |
| - os: ubuntu-latest | |
| goos: linux | |
| goarch: arm64 | |
| artifact_name: subenum | |
| asset_name: subenum-linux-arm64 | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: 'go.mod' | |
| - name: Cache Go build artifacts | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cache/go-build | |
| ~/go/pkg/mod | |
| key: ${{ runner.os }}-go-${{ hashFiles('**/go.mod') }} | |
| restore-keys: | | |
| ${{ runner.os }}-go- | |
| - name: Build | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| run: go build -v -buildvcs=false -o ${{ matrix.artifact_name }} | |
| - name: Rename for release | |
| shell: bash | |
| run: | | |
| if [ "${{ matrix.artifact_name }}" != "${{ matrix.asset_name }}" ]; then | |
| cp ${{ matrix.artifact_name }} ${{ matrix.asset_name }} | |
| fi | |
| - name: Generate checksum | |
| shell: bash | |
| run: sha256sum ${{ matrix.asset_name }} > ${{ matrix.asset_name }}.sha256 | |
| # 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 }} | |
| ${{ matrix.asset_name }}.sha256 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |