Skip to content

ci: draft-then-publish releases to close the empty public window #99

ci: draft-then-publish releases to close the empty public window

ci: draft-then-publish releases to close the empty public window #99

Workflow file for this run

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)").
#
# The release is created as a draft so it is not publicly visible while the
# upload matrix is still attaching assets. The publish-release job flips it to
# published only after all assets are present, so the public never sees a
# partial or empty release.
create-release:
needs: build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Create draft release for tag
uses: softprops/action-gh-release@v3
with:
draft: true
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. draft: true is set explicitly
# so these update calls keep the release in draft (the action's draft input
# defaults to false and would otherwise publish it early).
- name: Upload assets to draft release
uses: softprops/action-gh-release@v3
with:
draft: true
files: |
${{ matrix.asset_name }}
${{ matrix.asset_name }}.sha256
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Single job that publishes the release once, only after the full asset set is
# attached. Flipping draft to false here is the moment the release becomes
# public, so there is no window where a partial or empty release is visible.
publish-release:
needs: upload-assets
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Publish release
uses: softprops/action-gh-release@v3
with:
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}