Skip to content

Latest commit

 

History

History
140 lines (111 loc) · 6.23 KB

RELEASING.md

File metadata and controls

140 lines (111 loc) · 6.23 KB

Releasing

.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.

Cut a release

mise run quality:full gates every step. Drive the binary per RUNNING.md as well when the release changes runtime behaviour.

  1. Pick vX.Y.Z and confirm it is free: git fetch --tags origin && git tag --list "v*".

  2. Write the CHANGELOG.md section (see below) and land it like any other change: worktree, PR, merge (CHANGE-WORKFLOW.md).

  3. 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
  4. 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
  5. 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.md section, printed by scripts/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
  6. Verify. Expect 2 archives, 2 .sbom.json, …_checksums.txt and both …_checksums.txt.sig and …_checksums.txt.pem, and a body that is the tag's CHANGELOG section — an empty body means GoReleaser dropped the notes file, and gh release edit vX.Y.Z --notes-file repairs 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 cosign and sha256sum lines 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:

  1. Land the release.yml fix by PR (CHANGE-WORKFLOW.md).

  2. Create a new detached worktree at the new origin/main and run the gate, as in step 3 of Cut a release.

  3. 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
  4. 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.

What goes in the CHANGELOG section

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 project is a commit message; the TUI stalled for a second on every refresh is 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.

Local fallback

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.md

This 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.