.github/workflows/release.yml publishes releases with GoReleaser, dispatched
by hand against a release tag. The run builds, vets and tests before
publishing, so a green run is the provenance for that commit.
Archive names — revier_0.1.0_linux_x64.tar.gz — let installers such as
mise auto-detect the right asset.
One setting that looks wrong and is not: cosign is pinned to v2.6.5
because v3 defaults to --new-bundle-format, which the --output-signature
and --output-certificate flags in .goreleaser.yaml do not accept.
GoReleaser is pinned in three places: release.yml, the goreleaser check
step of .github/workflows/ci.yml, and the go install line of
Local fallback. Bump all three in one change; no check
compares them.
mise run quality:full gates every step. Drive the binary per
RUNNING.md as well when the release changes runtime behaviour.
-
Pick
vX.Y.Zand confirm it is free:git fetch --tags origin && git tag --list "v*". -
Write the
CHANGELOG.mdsection (see below) and land it like any other change: worktree, PR, merge (CHANGE-WORKFLOW.md). -
Create a worktree detached at the merged commit, and run the gate in it. Run steps 3 and 4 from the main checkout's root:
git fetch origin git worktree add --detach .claude/worktrees/release-vX.Y.Z origin/main mise -C .claude/worktrees/release-vX.Y.Z run quality:full
Check each commit since the last tag against the section, as What goes in the CHANGELOG section says. A change with no entry goes back to step 2.
git -C .claude/worktrees/release-vX.Y.Z log --no-merges --oneline \ "$(git describe --tags --abbrev=0 origin/main)"..HEAD -
Tag the worktree's commit, push the tag, then remove the worktree:
git -C .claude/worktrees/release-vX.Y.Z tag -a vX.Y.Z -m "revier vX.Y.Z" git push origin vX.Y.Z git worktree remove .claude/worktrees/release-vX.Y.Z -
Dispatch the workflow and watch it. The run takes a few seconds to register; re-run the lookup if it returns nothing. GoReleaser creates or updates the GitHub release itself. Its notes are the tag's
CHANGELOG.mdsection, printed byscripts/release-notes vX.Y.Z; a tag with no section fails the run before it publishes.gh workflow run release.yml --ref vX.Y.Z gh run watch "$(gh run list --workflow=release.yml --branch vX.Y.Z --limit 1 --json databaseId -q '.[0].databaseId')" --exit-status -
Verify. Expect 2 archives, 2
.sbom.json,…_checksums.txtand both…_checksums.txt.sigand…_checksums.txt.pem, and a body that is the tag's CHANGELOG section — an empty body means GoReleaser dropped the notes file, andgh release edit vX.Y.Z --notes-filerepairs it without a re-dispatch.gh release view vX.Y.Z --json assets,body -q '.body, (.assets[].name)' gh release download vX.Y.Z -p '*_linux_x64.tar.gz' gh attestation verify revier_X.Y.Z_linux_x64.tar.gz -R hk9890/revier
Then check the checksums signature with the
cosignandsha256sumlines in the user guide.
The dispatched ref must be the tagged commit. workflow_dispatch reads
the workflow file from the ref it runs on, and GoReleaser requires the
checked-out commit to be the tagged one. A release.yml change that a release
needs must live in the tagged commit. To move the tag onto such a fix:
-
Land the
release.ymlfix by PR (CHANGE-WORKFLOW.md). -
Create a new detached worktree at the new
origin/mainand run the gate, as in step 3 of Cut a release. -
From the main checkout's root, move the tag and remove the worktree:
git -C .claude/worktrees/release-vX.Y.Z tag -f -a vX.Y.Z -m "revier vX.Y.Z" git push -f origin vX.Y.Z git worktree remove .claude/worktrees/release-vX.Y.Z -
Dispatch and verify again, as in steps 5 and 6 of Cut a release.
Re-dispatching against an existing tag overwrites its assets instead of
failing (release.replace_existing_artifacts). To add a missing asset without
a new tag: gh release upload vX.Y.Z dist/* --clobber.
The section is the release text on GitHub. Write it for the operator, not for
this repository: its reader runs revier and has never opened the source.
Features, changed behaviour and fixes, never a commit list. An entry earns its place by telling them what
they must do, what they will see that they did not see before, or what was
wrong that is now fixed. State the symptom; the cause belongs in the commit
message.
- Never name an internal symbol, a Go package, a third-party library, or a
test.
Instances issued one list-panes per projectis a commit message;the TUI stalled for a second on every refreshis an entry. - A change with no user-visible effect gets no entry — a refactor, added coverage, a doc fix, a dependency bump nobody has to act on.
- Every other change the operator can see since the last tag gets an entry, each fix included. Several commits of one change share one entry. A fix of a defect that no tagged release had gets none.
- Anything that now refuses a project file, a config or a habit the operator already has leads with Action required and names the fix.
When Actions can't be used. Needs goreleaser v2 in PATH
(go install github.com/goreleaser/goreleaser/v2@v2.19.0, the version
release.yml pins), a clean tree on the tagged commit, and
mise run quality:full green there — that run substitutes for the CI
provenance.
scripts/release-notes vX.Y.Z > /tmp/release-notes.md
GITHUB_TOKEN=$(gh auth token) goreleaser release --clean --skip=sign --skip=sbom --release-notes /tmp/release-notes.mdThis produces binaries and checksums but no signing, SBOMs or provenance. Drop
--skip=sign with cosign installed — keyless signing locally needs an
interactive Sigstore flow, which the workflow avoids with its OIDC token — and
drop --skip=sbom with syft installed. SLSA provenance needs that same OIDC
token and cannot be produced locally. Verify as in step 6.