release: fix the homebrew cask so it loads at all - #640
Merged
Conversation
The generated cask used `pre_install` / `post_install`. Those are formula DSL methods; a cask has no such stanzas, so brew rejected the file at load time with Error: Cask 'gortex' definition is invalid: undefined method 'pre_install' Every brew command that touches the cask parses it, so `brew install` and `brew upgrade` both failed for every macOS user on both arches, starting with v0.63.7. Closes #639. Two further defects made a straight rename insufficient: * The cask DSL's `system_command` is `SystemCommand.run!`, which raises on a non-zero exit. `gortex daemon status` exits 1 exactly when no daemon is reachable, so `next unless status.success?` could never run — brew would have aborted the install outright on any machine without a live daemon. The probe now passes `must_succeed: false`. * `preflight` was the wrong hook for stopping the daemon. On upgrade brew unlinks the old cask's binary (`start_upgrade` -> `uninstall_artifacts`) before installing the new cask's artifacts, so by the time a preflight block runs there is no gortex on disk to ask. The stop half could never fire on the path it was written for. `postflight` handles both halves instead: after the new binary is linked, probe for a daemon and, only if one answers, `daemon restart` — which stops the old process (blocking until it exits, releasing the store lock) before starting the new one, so a store migration still runs alone. A fresh install and CI have no daemon answering and skip it. The cask body moves out of the release.yml heredoc into .github/homebrew/gortex.rb.tmpl, rendered by scripts/render-cask.sh. That makes it reviewable as Ruby, removes the shell-expansion hazards of an unquoted heredoc, and — the point — lets a real brew load it before publication. The renderer also refuses a malformed sha256, a version with a leading "v", or a placeholder that survived substitution. Rendered output is byte-identical to the published cask apart from the hook block. Nothing could have caught this: the file was valid Ruby, valid YAML, and the tap has no CI, so the first machine to evaluate the cask was a user's. scripts/validate-cask.sh renders the template with dummy values and loads it through a real brew. It runs on every PR that touches the cask (.github/workflows/homebrew-cask.yml) and again in build-darwin as the last gate before the release job pushes to the tap. Both are macOS-only — Homebrew on Linux cannot load casks. Verified by reintroducing `pre_install` in the template: the validator fails with the exact error users reported.
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 #639.
The bug
brew install/brew upgradefail for every macOS user on both arches since v0.63.7:The cask generated by
release.ymlusedpre_install/post_install. Those are formula DSL methods — a cask has no such stanzas (preflight/postflightare the equivalents). Brew evaluates the cask on every command that touches it, so install, upgrade and evenbrew infoall fail. The v0.63.6 cask is clean; the breakage arrived with the daemon stop/restart hooks and shipped to the tap on the 20th.Reproduced against the live tap file with a real
brew, and the fixed cask loads cleanly.Two more defects a plain rename would have left behind
The daemon probe would abort the install. The cask DSL's
system_commandisSystemCommand.run!—must_succeed: true, which raises on a non-zero exit.gortex daemon statusexits 1 exactly when no daemon is reachable, sonext unless status.success?was unreachable: brew would have hard-failed the install on any machine with gortex installed but no daemon running. The probe now passesmust_succeed: false(verified: the call returns a failedResultinstead of raising).preflightis the wrong hook. On upgrade,Cask::Upgraderunsold_cask_installer.start_upgrade→uninstall_artifacts→Artifact::Symlinked#uninstall_phase→unlinkbeforenew_cask_installer.install_artifacts, and the preflight block is a new-cask artifact. By the time it runs,$HOMEBREW_PREFIX/bin/gortexis already gone andFile.executable?(bin)is false — so the "stop the daemon" half could never fire on the very path it was written for.The fix
One
postflightblock does both halves. After the new binary is linked, probe for a live daemon and, only if one answers, rundaemon restart— which stops the old process (blocking until it exits, releasing the store lock) before starting the new one, so any store migration still runs alone. Fresh installs and CI have no daemon answering and skip it. Unlike anuninstall_preflighton the old cask, this works when upgrading from any already-released version, including the broken 0.63.7.The cask body moves out of the
release.ymlheredoc into.github/homebrew/gortex.rb.tmpl, rendered byscripts/render-cask.sh. Rendered output is byte-identical to the published cask apart from the hook block. The renderer also rejects a malformed sha256, a version with a leadingv, and any placeholder that survived substitution.Why it reached users, and what stops the next one
The file was valid Ruby and valid YAML, the Go suite can't see it, and the tap has no CI — so the first machine to evaluate the cask was a user's. Only a real
brewloading the DSL catches an unknown stanza.scripts/validate-cask.shrenders the template with dummy values and loads it throughbrewin a scratch tap. It runs:.github/workflows/homebrew-cask.yml)build-darwin, as the last gate before thereleasejob pushes to the tapBoth are macOS-only — Homebrew on Linux cannot load casks at all.
Verified by neutering the fix: putting
pre_installback in the template makes the validator fail with the exact error users reported, and exit 1.Follow-up outside this repo
The tap still serves the broken 0.63.7 cask, so macOS installs stay broken until either
zzet/homebrew-tapCasks/gortex.rbis patched by hand or a new release publishes over it. Until then the workaround isGORTEX_NO_BREW=1withscripts/install.sh, or the tarball directly.