build(goreleaser): publish a Homebrew formula via a tap#353
build(goreleaser): publish a Homebrew formula via a tap#353mvanhorn wants to merge 1 commit intoasciimoo:masterfrom
Conversation
Closes asciimoo#161 Adds a brews: block that pushes a `hister` formula to `asciimoo/homebrew-tap` on every stable release, and extends archives to emit tar.gz (needed by brew to download and extract) in addition to the existing raw binary output. The release workflow already passes GORELEASER_TOKEN; no workflow change is needed beyond granting that token write access to the tap repository. The tap repo itself has to be created once by the maintainer, after which every new tag will publish/update the formula automatically.
|
Thanks for the contribution and thanks for clarifying the AI use.
Isn't it possible to build the homebrew artifacts in this repo and simply add them to the release artifacts just as we do with the release binaries? |
|
Yes, goreleaser can generate the formula as a file artifact, so attaching it to the release alongside the binaries is straightforward. The tradeoff is the install UX. With a tap repo, a user runs: That works because Homebrew resolves formula names against tapped repositories. If the formula lives only as a release asset, there's no tap for Homebrew to look in, so the user has to either:
The tap-based flow is what most goreleaser projects ship. Happy to do both: keep the tap push so |
Why is this inferior to the
My preference is to keep it as simple as possible. The ideal would be to be part of the main homebrew "repo" I guess. |
|
Quick correction on my earlier framing -
If "simplest possible" means "one less repo in your org," the cleanest ending is homebrew-core. I did not propose it because:
In the meantime, if you would rather not stand up a tap repo at all, I can strip the What is your preference, land the tap approach, submit to homebrew-core instead, or drop the formula work from this PR? |
|
@mvanhorn thank you for explaining every option in detail. I don't use brew and I'm not familiar with the ecosystem at all.
Of course, the best would be to get bundled by homebrew-core. If I understand correctly, it would mean that we don't have to do the builds on our side, right? If there is a realistic chance to be part of homebrew-core, I'd try that direction and we can fallback to this
Hopefully we can grow big enough, to be eligible in the future even if we are below the bar currently. (To be fair, we have quite a few issues/PRs/contributions in relation to the projects age.) |
|
@asciimoo happy to dig in. Yes, homebrew-core handles the builds. Once a formula is accepted, their CI compiles from source on each platform and uploads pre-built bottles so users get fast binary installs. You wouldn't host or publish anything on your end. The "homebrew-core first, tap fallback" plan is reasonable. Quick reality check on eligibility:
Suggested sequence: I'll open a homebrew-core formula PR first. If it's accepted, we close this PR unchanged. If they decline (most likely reason: "come back in a few months"), we merge this goreleaser-tap PR so brew users aren't blocked in the meantime. Want me to draft the homebrew-core PR? |
|
@mvanhorn excellent, thanks! I'd appreciate a lot if you'd manage the homebrew-core dance. |
|
On it. Quick notability read first so you know what to expect:
Want me to get the homebrew-core PR drafted this week, or prefer I wait until #353 lands to avoid two open paths? |
I'm just about to release a new version which has plenty of massive changes compared to 0.12.0 (perhaps potential bugs as well). Not sure if it would be better to wait with the release or to submit it before starting the homebrew-core dance.
I'd prefer trying the core path first then fallback to this PR. It would save us one possible revert, but that's all the reasoning I have. If there are any stronger counter-argument, I'm fully open to do it differently. |
|
Good question. My recommendation: submit at Reasons:
So the plan would be:
Proceed? |
Alright. Then I'm delaying the release for a few days, we are not in a rush and users who like to live dangerously can use our rolling release until then.
Let's gooo! I'd like to thank you again your very professional approach of handling this topic. E> |
|
Thanks @asciimoo - drafting the homebrew-core formula against v0.12.0 now, will link the PR here once it's open. Formula test block will just exercise |
|
Opened Homebrew/homebrew-core#278900 with the v0.12.0 formula. Passing it to the Homebrew maintainers from here — I won't be actively shepherding the review, so ping me on the PR if anything needs an upstream change. |
|
@mvanhorn Thanks. I've subscribed to the PR. I'll ping you. |
Summary
Closes #161 by wiring hister into a Homebrew tap via goreleaser. On every stable release tag, goreleaser will now push a
histerformula toasciimoo/homebrew-tapin addition to producing the existing raw binaries.Why this matters
@SKalt opened #161 with a short, specific ask: ~10 lines of goreleaser config to publish a Homebrew formula, motivated by "MacOS refusing to run the binary from the releases page without a signature." Without a tap, macOS users have to either trust an unsigned binary from the releases page or build from source.
Investigating
.goreleaser.yml, the existingarchives:block emits onlyformats: ['binary'], which produces raw per-platform binaries with no tarball.goreleaser'sbrews:step expects tarballs so its generatedurl docan point at the.tar.gzon the release page, so the archive config needs to emittar.gzin addition to the currentbinary(keeping the raw binary available for anyone who wants it)..github/workflows/release.ymlalready runs goreleaser and already passessecrets.GORELEASER_TOKEN. The same token is reused for the tap push; no workflow edit is needed.Changes
All changes live in
.goreleaser.yml:archives:now emits['tar.gz', 'binary']with aname_templateso the tap can locate each platform's tarball. Raw binaries are preserved.brews:block pointing atasciimoo/homebrew-tap, with a minimalinstall/teststanza and metadata (description, homepage,AGPL-3.0-or-laterSPDX license). Thetest:block invokeshister --version, which is already wired inhister.go:85-89viacobra.Command.Version = Version.Maintainer prerequisites (one-time)
Shipping this requires two things outside of this PR, both flagged in the issue body:
asciimoo/homebrew-taprepository. It can start empty — goreleaser will populate the formula on the next release.secrets.GORELEASER_TOKENhas write access to the tap repo (read-only to this repo is fine, but it needs to push to the tap).If either of those names would be different in practice (e.g., a different tap repo naming convention), happy to adjust the
repository:block.Testing
version,builds,archives,brewsat the top level.goreleaser checknot available locally, so syntax is verified against goreleaser v2's documented schema at https://goreleaser.com/customization/homebrew/ (matches v2repository:/name:/install:/test:shape).hister --versionexists today, so the formula'stest:block is exercisable.Closes #161
This contribution was developed with AI assistance (Claude Code).