Releasing
Pushing a v* tag runs the release workflow: it tests, cross-compiles four platforms, builds the notes, publishes a GitHub release with the tarballs and checksums.txt, renders the Homebrew formula from those checksums, and commits it to the tap.
The work is in what happens before the tag.
Before tagging
Section titled “Before tagging”1. Move the changelog section. Rename ## [Unreleased] to ## [X.Y.Z] - YYYY-MM-DD, add a fresh empty [Unreleased] above it, and update the link definitions at the bottom. That section becomes the release body, so write it for someone deciding whether to upgrade.
2. Check whether the shell output changed.
git diff v<previous> HEAD -- testdata/goldenNon-empty means every user must run loadout apply after upgrading, or their shell keeps the old aliases and they will not know why. The notes detect this automatically, but the changelog is what explains it.
3. Preview the notes.
make notes VERSION=vX.Y.ZConfirm the “run loadout apply” section appears if and only if the golden files changed.
4. Green gate.
make checkmake release VERSION=vX.Y.Z # all four platforms buildmake tap VERSION=vX.Y.Z # formula renders and is valid rubymake cleanTagging
Section titled “Tagging”git push origin main # let CI go green firstgit tag -a vX.Y.Z -m "loadout vX.Y.Z"git push origin vX.Y.ZCI on main runs the macOS job. Tests here have a history of passing on Linux and mattering on macOS, so wait for it before tagging.
Versioning
Section titled “Versioning”vMAJOR.MINOR.PATCH, and the comparison in selfupdate accepts nothing else — a pre-release suffix or a commit SHA reports as not comparable rather than being coerced into a wrong ordering.
| Bump | For |
|---|---|
| Patch | Fixes, no change to generated shell or config schema |
| Minor | New aliases, functions, packs, commands, or config fields |
| Major | A config schema change users must act on, or a removal |
Afterwards
Section titled “Afterwards”loadout versionloadout update --checkbrew upgrade loadoutVerify the tap formula’s checksums match the published release. Locally built tarballs never hash the same as the ones CI produced, so compare against the published checksums.txt, not your dist/.
When something is wrong
Section titled “When something is wrong”install.sh says it cannot determine the latest version. No published release, or the tag has no GitHub Release attached. install.sh resolves latest through the /releases/latest redirect, so a bare tag is not enough.
brew still installs the old version. The tap was not updated. Without TAP_GITHUB_TOKEN the workflow warns rather than fails, on purpose, so a missing tap does not block the release everyone else uses. Publish dist/loadout.rb by hand in that case.
loadout update says “not a release version”. The running build is a development build, or the server returned something unparseable. The message distinguishes the two.
The formula fails to install. Its checksums must match the published artefacts, which CI built.
Rewriting a published tag
Section titled “Rewriting a published tag”Possible, and occasionally right while the project is young: force-push the tag and the release survives with its assets.
Two things to know. The tag must actually move, or the old commit stays reachable and the exercise is pointless. And the published binaries were built from the old commit, so confirm nothing that reaches the binary changed — comments, documentation and tests do not.
Updating this site after a release
Section titled “Updating this site after a release”The reference pages are generated from the catalog, so a release that changed aliases or functions needs them refreshed:
npm run gengit commit -am "Refresh reference for vX.Y.Z"The diff is a useful review in itself: it is exactly what changed in the shipped set.