ci: publish to a Homebrew tap after each release (#313) - #322
Merged
Conversation
Adds Homebrew as a distribution channel. The formula lives in a dedicated
tap repo, mcpp-community/homebrew-mcpp; this side only pings it.
brew install mcpp-community/mcpp/mcpp-m
One command: a tap whose repo is named homebrew-<name> is cloned on demand
by `brew install <user>/<repo>/<formula>`, so no separate `brew tap` step is
needed. That auto-tap is also why the formula does not live in this repo —
tapping a repo that isn't named homebrew-* requires the user to pass its URL,
which turns installation into two commands and a URL nobody will remember.
Two things the tap had to get right, both learned from scripts/aur:
- mcpp derives MCPP_HOME from the *canonicalized* path of the running
binary (home.cppm + platform/fs.cppm resolve symlinks). Linked straight
into bin, that path is the Cellar, so the registry sandbox, caches and
every downloaded toolchain would land in a versioned directory that
`brew upgrade` deletes. The formula keeps the release tree under libexec
and ships a launcher that pins MCPP_HOME/MCPP_VENDORED_XLINGS, same shape
as scripts/aur/mcpp-bin/mcpp.sh.
- The name. homebrew-core owns `mcpp` (Matsui's C preprocessor, ~675
installs/yr, not deprecated), exactly as extra/mcpp does on Arch. The
formula is `mcpp-m`, with Aliases/{mcpp,mcpp-bin} pointing at it; the
installed command is still `mcpp`.
The workflow does not write the formula: it sends a repository_dispatch and
the tap rewrites itself from the release's .sha256 sidecars. It hangs off
`workflow_run: [release] completed` rather than `release: published` for the
reason aur-publish.yml already documents — the macOS and aarch64 assets are
uploaded by later jobs, and the tap needs every sidecar to exist.
HOMEBREW_TAP_TOKEN is optional by design: without it this job logs a notice
and exits 0, and the tap's daily schedule picks the release up within 24h.
A release should not fail over a credential it doesn't itself need.
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.
Closes part of #313 (the "增加 Homebrew 作为分发渠道" item).
What this adds
One command —
brew install <user>/<repo>/<formula>auto-taps a repo namedhomebrew-<repo>, so there is no separatebrew tapstep.The formula itself lives in a new dedicated tap repo,
mcpp-community/homebrew-mcpp
(already created and working). This PR is the upstream half: a workflow that
pings the tap after a release, plus docs.
Why the formula is not in this repo
Homebrew only scans three locations in a tap (
tap.rb:950):Formula/,HomebrewFormula/, repo root —scripts/is not one of them. And a tap whoserepo isn't named
homebrew-*can only be tapped by passing its URL, whichmakes installation two commands instead of one and kills the auto-tap path.
Why
mcpp-mand notmcpphomebrew-core owns
mcpp— Matsui's C preprocessor(675 installs/yr, not deprecated, autobump on). Same collision as
extra/mcppon Arch, same resolution as
scripts/aur: the formula ismcpp-m, withAliases/{mcpp,mcpp-bin}pointing at it. The installed command is stillmcpp.Why a launcher, not a symlink
mcpp resolves
MCPP_HOMEfrom the canonicalized path of the running binary(
src/home.cppm:77+src/platform/fs.cppm:97). Linked straight intobin,that path is the Cellar — the registry sandbox, caches and every downloaded
toolchain would live in a versioned directory that
brew upgraderemoves. Theformula keeps the tree under
libexecand ships a launcher pinningMCPP_HOME/MCPP_VENDORED_XLINGS, mirroringscripts/aur/mcpp-bin/mcpp.sh.How the sync works
homebrew-publish.ymlnever writes a formula. It sends arepository_dispatchand the tap rewrites itself from the release's.sha256sidecars. Trigger is
workflow_run: [release] completed, notrelease: published— the macOS/aarch64 assets are uploaded by later jobs(same reasoning
aur-publish.ymldocuments).repository_dispatchschedule(daily)workflow_dispatchConfiguration needed
Repository secret
HOMEBREW_TAP_TOKEN— fine-grained PAT scoped tomcpp-community/homebrew-mcpp, permission Contents: read and write.It is optional. Without it this job logs a notice and exits 0; the tap's
daily schedule lands the release within 24h. A release shouldn't fail over a
credential it doesn't itself need.
Verified
(
120000) survived the push.2026.7.30.2froma dispatch payload, then resolved and restored
2026.7.30.3from upstream'slatest release — commit and push both succeeded despite the org's read-only
default
GITHUB_TOKEN(the workflow declarespermissions: contents: write).update-formula.shrewrite is byte-identical to the hand-written formulaand idempotent on re-run; shellcheck clean;
ruby -cOK.(
1659be17…4e18), and the tarball layout matches what the formula installs.check_version_pins.shstill OK; both workflow files parse.Also verified by installing for real (throwaway Homebrew prefix, Linux x86_64):
The auto-tap path works from cold (no prior
brew tap), the layout comes outas intended (
bin/mcpplauncher,libexec/{bin,registry}), the launcher'sMCPP_HOMEdefaults to$HOME/.mcppand not the Cellar,mcpp --versionprints
mcpp 2026.7.30.3, andbrew uninstallis clean. All four assertionsin the formula's
testblock were evaluated by hand against the installed kegand pass. Fixing a
bin.mkpathbug (Homebrew'sPathname#writedoes notcreate parent directories) came out of this — it would have failed the very
first install.
Still unexercised: the macOS-specific lines (
depends_on arch: :arm64/macos: :sonomaand the arm64 asset), which need an Apple-silicon host.