Repository navigation
feat: publish prebuilt CLI binaries with GoReleaser - #72
Merged
Merged
Conversation
The CLI could only be installed with a Go toolchain, which excludes the people it was written for: a CI step or a shell script that wants an installation token without building anything. A tagged release now produces archives for Linux, macOS and Windows on amd64 and arm64, plus checksums.txt. Verified locally with a snapshot build: six archives, the extracted binary mints a JWT, and the checksums check out. The release workflow skips any v2 tag. The /v2 module path was published by accident and is permanently retracted, but v2.0.1 and v2.0.2 have to stay in the repository because v2.0.2 carries the retract block, so those tags can always be re-pushed by mistake. A release built from one would publish binaries for a module path that go get cannot resolve. Also fixes the version the CLI reports. It read the module version from the build info, which a release binary does not carry, so every downloaded binary would have claimed a pseudo-version. The release build now stamps the tag through -ldflags, and a build from a checkout falls back to the commit.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #72 +/- ##
==========================================
- Coverage 98.88% 96.96% -1.92%
==========================================
Files 5 5
Lines 447 462 +15
==========================================
+ Hits 442 448 +6
- Misses 5 14 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
brew install is what reaches the people the CLI was written for: the
ones who will never run go install. A tagged release now writes a cask
into jferrl/homebrew-tap.
brew install jferrl/tap/githubauth
A cask rather than a formula: brews is deprecated in GoReleaser v2,
and Homebrew expects a formula to build from source, which is the
opposite of shipping a prebuilt binary. The cask carries a postflight
hook that clears the quarantine attribute, because the binary is not
notarized and Gatekeeper would otherwise refuse to run it.
Pushing the cask writes to another repository, which the workflow's
GITHUB_TOKEN cannot reach, so it needs HOMEBREW_TAP_GITHUB_TOKEN. A
failed tap push fails the entire release, binaries included, so
skip_upload is templated on the token being present: without the
secret the release still publishes everything else and skips only the
cask.
A missing or empty HOMEBREW_TAP_GITHUB_TOKEN skips the cask rather than failing the release, which is the right trade: archives and checksums still publish. It is also invisible, and a secret cannot be read back to check it, so "brew install" quietly staying on an old version would be the first symptom. The run now states which of the two happened, and annotates a warning when the token is missing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The CLI could only be installed with a Go toolchain, which excludes the people it was
written for: a CI step or a shell script that wants an installation token without building
anything.
A tagged release now produces archives for Linux, macOS and Windows on amd64 and arm64,
plus
checksums.txt. Verified with a local snapshot build before opening this:The extracted binary reports its stamped version and mints a JWT;
shasum -c checksums.txtpasses;goreleaser checkvalidates the config.v2 tags cannot trigger a release
The
/v2module path was published by accident and is permanently retracted, butv2.0.1andv2.0.2have to stay in the repository becausev2.0.2is what carries theretractblock. That means a v2 tag can always be re-pushed by mistake, and a releasebuilt from one would publish binaries for a module path
go getcannot resolve.The workflow skips them:
v1.9.0v2.0.1,v2.0.2,v2.1.0v3.0.0Guarding on
v2.rather than allowing onlyv1.means a future major version workswithout editing the workflow, while the retracted path stays blocked.
The version fix
githubauth versionread the module version out of the build info. A binary built from acheckout — which is what GoReleaser produces — does not carry one, so every downloaded
release would have reported a pseudo-version.
v1.9.0(the tag, via-ldflags)go install ...@v1.9.0v1.9.0(module version from build info)go buildfrom a checkoutv1.8.1-0.2026...-69b5dd9+dirty(devel)Type of Change
Testing
go test ./...passes,golangci-lint run ./...reports 0 issues,goreleaser checkvalidates, and a full
goreleaser release --snapshot --cleanwas run and its outputexercised.
Documentation
Checklist
go.modand the CI matrixHomebrew
A cask, not a formula.
brews:is deprecated in GoReleaser v2, and a Homebrew formulais expected to build from source, which is the opposite of shipping a prebuilt binary. The
cask carries a
postflighthook clearing the quarantine attribute, since the binary isnot notarized and Gatekeeper would otherwise refuse to run it.
jferrl/homebrew-tap has been created and seeded
with a README, so it has a default branch for GoReleaser to push to.
One thing needed before the first release
Pushing the cask writes to that other repository, which this workflow's
GITHUB_TOKENcannot reach. It needs a secret named
HOMEBREW_TAP_GITHUB_TOKENon this repository — atoken with
contents: writeonjferrl/homebrew-tap.A failed tap push fails the entire release, binaries included, so
skip_uploadistemplated on the token being present:
Without the secret the release still publishes the archives and checksums and skips only
the cask. Verified:
goreleaser checkpasses both with and without the variable set, anda snapshot build generates the cask either way.