diff --git a/.github/workflows/homebrew-tap.yml b/.github/workflows/homebrew-tap.yml index 6418f720..18985f5a 100644 --- a/.github/workflows/homebrew-tap.yml +++ b/.github/workflows/homebrew-tap.yml @@ -76,6 +76,10 @@ jobs: TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} run: | set -euxo pipefail + if [ -z "${TAP_TOKEN:-}" ]; then + echo "::error::HOMEBREW_TAP_TOKEN secret is empty or unset — cannot push to ${TAP_OWNER}/${TAP_REPO}. Add a fine-grained PAT (Contents: Read and write on the tap repo) as the HOMEBREW_TAP_TOKEN secret, then re-run this workflow." >&2 + exit 1 + fi # We do NOT use actions/checkout for the tap repo because on the # very first run the tap is empty and has no refs/heads/main yet. # `git init` + `git fetch || true` + `git push -u origin main` diff --git a/packages/homebrew-tap/pythinker-code.rb.tmpl b/packages/homebrew-tap/pythinker-code.rb.tmpl index 56214017..8786d46d 100644 --- a/packages/homebrew-tap/pythinker-code.rb.tmpl +++ b/packages/homebrew-tap/pythinker-code.rb.tmpl @@ -41,6 +41,23 @@ class PythinkerCode < Formula bin.write_exec_script libexec/"pythinker" end + def caveats + # Static settled frame of the curl/PowerShell installers' "Tetris" logo + # (install.sh / install.ps1). Homebrew renders caveats as plain text, so + # this is the uncoloured robot-head. The squiggly heredoc strips the common + # leading indent, so the art sits one column left of the curl banner. + <<~EOS + + ● + │ + ▛▀▀▀▀▀▀▀▜ + ◖█ ◉ ◉ █◗ + ▙▄▄▄≡▄▄▄▟ + + pythinker code · your next CLI agent + EOS + end + test do assert_path_exists libexec/".pythinker-native" assert_match version.to_s, shell_output("#{bin}/pythinker --version") diff --git a/tests/test_homebrew_formula.py b/tests/test_homebrew_formula.py index 581bf145..513befa5 100644 --- a/tests/test_homebrew_formula.py +++ b/tests/test_homebrew_formula.py @@ -20,16 +20,22 @@ def load_generator() -> ModuleType: return module -def test_native_homebrew_formula_renders_release_tarballs() -> None: - generator = load_generator() - version = "1.2.3" - assets = {} +def _fake_assets(generator: ModuleType, version: str) -> dict[str, dict[str, str]]: + """Build a fake GitHub release-asset map covering every native target.""" + assets: dict[str, dict[str, str]] = {} for target in generator.NATIVE_TARGETS: name = target.asset_name(version) assets[name] = { "browser_download_url": f"https://example.invalid/{name}", "digest": "sha256:" + ("a" * 64), } + return assets + + +def test_native_homebrew_formula_renders_release_tarballs() -> None: + generator = load_generator() + version = "1.2.3" + assets = _fake_assets(generator, version) formula = generator.render_formula( TEMPLATE.read_text(encoding="utf-8"), generator.native_replacements(version, assets) @@ -59,3 +65,20 @@ def test_native_homebrew_formula_fails_when_asset_missing() -> None: assert "release asset missing" in str(exc) else: raise AssertionError("expected missing native asset to fail formula generation") + + +def test_native_homebrew_formula_caveats_show_logo() -> None: + generator = load_generator() + version = "1.2.3" + assets = _fake_assets(generator, version) + + formula = generator.render_formula( + TEMPLATE.read_text(encoding="utf-8"), generator.native_replacements(version, assets) + ) + + # Homebrew prints `caveats` after install — this is where the static robot + # logo (parity with install.sh / install.ps1) must live. + assert "def caveats" in formula + assert "pythinker code · your next CLI agent" in formula + # The robot-head mouth row is the most distinctive line of the art. + assert "▙▄▄▄≡▄▄▄▟" in formula