Release new versions of sidecar. Covers version tagging with semver, td dependency updates, go.mod validation, CHANGELOG updates, GoReleaser automation, Homebrew tap updates, and verification steps...
Operator contract: docs/guides/active/releasing.md. Enforcement lives in scripts/ and
BUMP=minor make release (or RELEASE_VERSION=vX.Y.Z make release for an explicit
version). Prefer the one-shot command over replaying this checklist by hand.
go.modmain identical to live origin/maincheck-release-state.sh now checks this itself via gh run list --workflow=go-ci.yml and fails closed if it's red/running/missing, so you
don't have to remember to lookmarcus/homebrew-tapreplace directives in go.modHOMEBREW_TAP_TOKEN secret present in the GitHub repo (CI tap job)Beware of go.work: always use GOWORK=off when updating dependencies and
when validating install paths.
Local lint must match CI's golangci-lint v2.12.2, or trust CI:
gh run list --workflow=go-ci.yml --limit=1
git tag -l 'v*' | sort -V | tail -1
SemVer: major / minor / patch as usual.
make sync-deps # pins every github.com/marcus/* requirement to its latest tag
check-release-state.sh enforces this and refuses to tag when one is behind.
go.work resolves those imports to the local checkouts, so drift is invisible
locally — both the gate and sync-deps use GOWORK=off. If a sibling jumped
several minors, decide deliberately (pin for a focused release vs take latest
and note it under Dependencies) and smoke its tab in the app.
## [Unreleased]
### Features
- …
### Bug Fixes
- …
### Dependencies
- …
Commit the changelog (and any dependency bump) on main, then push so
HEAD == origin/main. Leave the heading as ## [Unreleased] — make release
stamps it to ## [vX.Y.Z] - YYYY-MM-DD for you.
# Dry-run (optional but recommended for tooling changes)
make release-snapshot
./scripts/verify-release-archives.sh dist
./scripts/test-release-guards.sh dist
./scripts/test-release-publication.sh
make release-dry-run BUMP=minor # prints the derived version + plan, no mutation
# Cut the release: derive the version, stamp the changelog, commit, push,
# then the fail-closed preflight → tag → CI → formula verify/publish
BUMP=minor make release
The version is stated exactly once — via BUMP derived from the latest tag, or
by setting RELEASE_VERSION=vX.Y.Z yourself (also works if you stamped the
CHANGELOG heading by hand). scripts/release.sh refuses an empty [Unreleased]
section, a tree dirty beyond CHANGELOG.md, a tag that already exists, and a
RELEASE_VERSION that contradicts an already-stamped heading, before handing off
to scripts/publish-release.sh. What it enforces and does end to end is
documented in docs/guides/active/releasing.md.
Resume only the tap step if the tag/release already exists:
RELEASE_VERSION=vX.Y.Z make release-tap
verify — tag points at live main, tests, snapshot archives, release guardsrelease — GoReleaser publishes GitHub release + binariesupdate-homebrew-tap — renders packaging/homebrew/sidecar.rb.tmpl and
pushes Formula/sidecar.rb with downgrade/idempotency/race guardstd/nightshift formulas are not auto-bumped; edit them by hand when co-releasing.
gh run list --workflow=release.yml --limit=1
gh release view vX.Y.Z --json assets -q '.assets[].name'
GOBIN=$(mktemp -d) GOWORK=off go install github.com/marcus/sidecar/cmd/sidecar@vX.Y.Z
"$GOBIN/sidecar" --version
go install @vX.Y.Z can 500 from the checksum DB for a minute or two after the
tag — wait and retry. Prefer a throwaway GOBIN so verification does not
clobber a dev machine's sidecar.
# Return to the canonical main development build:
make install-local
# Or keep the released Homebrew build active:
make use-homebrew
# In either case, prove the managed link and both login-shell modes:
make install-status
Prefer a new patch release. Keep tags. Resume tap with make release-tap.
See docs/guides/active/releasing.md.
check-release-state.shmain == origin/mainreplace in go.mod; GOWORK=off build works## [Unreleased]BUMP=minor make release (or RELEASE_VERSION=vX.Y.Z make release) succeededgo install verified into throwaway GOBINmake install-status proves the dev machine is on the intended binary