9449485dcf
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.
59 lines
2.2 KiB
Bash
Executable File
59 lines
2.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Prove the generated Homebrew cask actually loads before a release pushes it
|
|
# to zzet/homebrew-tap.
|
|
#
|
|
# This exists because issue #639 shipped a cask that was valid Ruby but used
|
|
# `pre_install` / `post_install` — formula-only DSL methods that the cask DSL
|
|
# rejects at load time. Nothing in the Go test suite or a YAML lint could see
|
|
# it, and the tap has no CI of its own, so every macOS user got
|
|
#
|
|
# Error: Cask 'gortex' definition is invalid: undefined method 'pre_install'
|
|
#
|
|
# on install AND upgrade. Only a real `brew` evaluating the DSL catches that
|
|
# class of bug, which is why this renders the template and loads it through
|
|
# brew rather than checking it with a linter.
|
|
#
|
|
# macOS only: Homebrew on Linux cannot load casks at all.
|
|
#
|
|
# Usage: validate-cask.sh (no arguments — renders with dummy values)
|
|
set -euo pipefail
|
|
|
|
if [ "$(uname -s)" != "Darwin" ]; then
|
|
echo "SKIP: casks can only be loaded by Homebrew on macOS (got $(uname -s))"
|
|
exit 0
|
|
fi
|
|
|
|
command -v brew >/dev/null 2>&1 || {
|
|
echo "FATAL: brew not on PATH; cannot validate the cask" >&2
|
|
exit 1
|
|
}
|
|
|
|
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
|
|
|
|
# Dummy but well-formed inputs. The DSL is evaluated, not downloaded, so the
|
|
# shas only have to satisfy render-cask.sh's shape check.
|
|
DUMMY_SHA="$(printf '0%.0s' $(seq 1 64))"
|
|
rendered="$("$repo_root/scripts/render-cask.sh" 0.0.0 \
|
|
"$DUMMY_SHA" "$DUMMY_SHA" "$DUMMY_SHA" "$DUMMY_SHA")"
|
|
|
|
# Load the cask the way a user's machine will: from a tap on disk. A scratch
|
|
# tap keeps the real zzet/tap (which may be installed on a dev machine)
|
|
# untouched, and the trap removes it even when brew fails.
|
|
tap_user="gortexcaskcheck"
|
|
tap_dir="$(brew --repository)/Library/Taps/$tap_user/homebrew-tap"
|
|
cleanup() { rm -rf "$(brew --repository)/Library/Taps/$tap_user"; }
|
|
trap cleanup EXIT
|
|
|
|
cleanup
|
|
mkdir -p "$tap_dir/Casks"
|
|
printf '%s\n' "$rendered" >"$tap_dir/Casks/gortex.rb"
|
|
|
|
echo "==> loading the rendered cask through brew"
|
|
# `brew info --cask` evaluates every stanza, so an unknown one (the #639 bug)
|
|
# fails here. Output is kept: a reviewer should see the artifact list change
|
|
# when the template changes.
|
|
HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_ENV_HINTS=1 \
|
|
brew info --cask "$tap_user/tap/gortex"
|
|
|
|
echo "==> cask loads cleanly"
|