From 00c80b4aaca39163a3b68ffbe54389531b3f0f88 Mon Sep 17 00:00:00 2001 From: Clint M Date: Thu, 16 Jul 2026 10:21:49 -0600 Subject: [PATCH 1/3] ci: split test/lint/build into parallel jobs, add brew package build+install+backup smoke check as rite build --- .github/workflows/ci.yml | 24 +++++++++++++++++-- Ritefile.yml | 6 +++++ ci/scripts/brew-build-test.sh | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100755 ci/scripts/brew-build-test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 409703b..d69b583 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,14 +18,34 @@ jobs: - name: Test run: rite test + lint: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - uses: jdx/mise-action@v2 + - name: Lint run: rite lint + # "Does it build": render the formula against a tarball of HEAD, brew + # install it, run the formula test block, then a real `macprefs backup` + # end-to-end on the runner. + build: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - uses: jdx/mise-action@v2 + + - name: Build, install, and smoke test the brew package + run: rite build + # Verifies the documented contributor workflow from a bare machine, # exactly as the README's "Getting started" section describes it: # curl-install mise -> mise install -> rite setup -> rite test lint. - # The `test` job above uses mise-action, which is faster but not the - # path a fresh contributor actually follows. + # The jobs above use mise-action, which is faster but not the path a + # fresh contributor actually follows. contrib-workflow: runs-on: macos-latest steps: diff --git a/Ritefile.yml b/Ritefile.yml index 9ad6895..a6bafae 100644 --- a/Ritefile.yml +++ b/Ritefile.yml @@ -48,6 +48,12 @@ tasks: cmds: - uv run pylint *.py + build: + desc: Build the brew package from committed HEAD, install, verify, uninstall + aliases: [b] + cmds: + - ./ci/scripts/brew-build-test.sh + clean: desc: Remove generated files aliases: [c] diff --git a/ci/scripts/brew-build-test.sh b/ci/scripts/brew-build-test.sh new file mode 100755 index 0000000..b77cb68 --- /dev/null +++ b/ci/scripts/brew-build-test.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Build the brew package from the committed tree (git archive HEAD), render +# the formula template against the local tarball, install it, verify the +# installed CLI end-to-end with a real backup, then uninstall. +# +# Refuses to run if macprefs is already installed via brew (it would clobber +# the real install) unless FORCE=1 is set. +set -euo pipefail + +VERSION=$(python3 -c "import version; print(version.__version__.lstrip('v'))") +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +if brew list macprefs &>/dev/null && [ "${FORCE:-0}" != "1" ]; then + echo "macprefs is already installed via brew - refusing to clobber it." >&2 + echo "Re-run with FORCE=1 to uninstall it and test anyway." >&2 + exit 1 +fi + +TARBALL="$TMP/macprefs-$VERSION.tar.gz" +git archive --prefix="macprefs-$VERSION/" -o "$TARBALL" HEAD +SHA=$(shasum -a 256 "$TARBALL" | cut -d' ' -f1) + +sed -e "s|url \".*\"|url \"file://$TARBALL\"|" \ + -e "s|###sha256###|$SHA|" \ + macprefs.template.rb > "$TMP/macprefs.rb" + +brew install --formula "$TMP/macprefs.rb" +trap 'brew uninstall --force macprefs >/dev/null 2>&1 || true; rm -rf "$TMP"' EXIT + +# Formula's own test block (runs `macprefs --help`). +brew test "$TMP/macprefs.rb" + +INSTALLED_VERSION=$(macprefs --version) +echo "installed: $INSTALLED_VERSION" +echo "$INSTALLED_VERSION" | grep -q "$VERSION" + +# End-to-end: a real backup into a throwaway dir. Backup only reads system +# state and writes to MACPREFS_BACKUP_DIR, so this is safe anywhere. +MACPREFS_BACKUP_DIR="$TMP/backup" macprefs backup +test -d "$TMP/backup/preferences" + +echo "brew package build + install + backup smoke test: OK" From 551b92e66fd513d554ef9a28401df950be58fd1f Mon Sep 17 00:00:00 2001 From: Clint M Date: Thu, 16 Jul 2026 10:25:10 -0600 Subject: [PATCH 2/3] ci: install formula via throwaway local tap (homebrew rejects out-of-tap formula files) --- ci/scripts/brew-build-test.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ci/scripts/brew-build-test.sh b/ci/scripts/brew-build-test.sh index b77cb68..576d453 100755 --- a/ci/scripts/brew-build-test.sh +++ b/ci/scripts/brew-build-test.sh @@ -25,11 +25,17 @@ sed -e "s|url \".*\"|url \"file://$TARBALL\"|" \ -e "s|###sha256###|$SHA|" \ macprefs.template.rb > "$TMP/macprefs.rb" -brew install --formula "$TMP/macprefs.rb" -trap 'brew uninstall --force macprefs >/dev/null 2>&1 || true; rm -rf "$TMP"' EXIT +# Homebrew requires formulae to live in a tap; use a throwaway local one. +TAP="macprefs-ci/local" +brew untap -f "$TAP" >/dev/null 2>&1 || true +brew tap-new --no-git "$TAP" >/dev/null +trap 'brew uninstall --force macprefs >/dev/null 2>&1 || true; brew untap -f "$TAP" >/dev/null 2>&1 || true; rm -rf "$TMP"' EXIT +cp "$TMP/macprefs.rb" "$(brew --repository "$TAP")/Formula/macprefs.rb" + +brew install "$TAP/macprefs" # Formula's own test block (runs `macprefs --help`). -brew test "$TMP/macprefs.rb" +brew test "$TAP/macprefs" INSTALLED_VERSION=$(macprefs --version) echo "installed: $INSTALLED_VERSION" From 49aef2b193a14f7208332c7d50083584d9353eb2 Mon Sep 17 00:00:00 2001 From: Clint M Date: Thu, 16 Jul 2026 10:54:01 -0600 Subject: [PATCH 3/3] ci: pass the workflow token to the contrib job so mise's github api calls aren't rate-limited --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d69b583..c3f374e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,13 @@ jobs: # fresh contributor actually follows. contrib-workflow: runs-on: macos-latest + # mise resolves github:clintmod/rite via the GitHub API; unauthenticated + # requests share the runner IP's 60/hr quota and 403 constantly. The + # other jobs get a token injected by mise-action; this one bootstraps + # bare, so pass the workflow token explicitly. (Locally, mise picks up + # your gh CLI auth instead.) + env: + GITHUB_TOKEN: ${{ github.token }} steps: - uses: actions/checkout@v4