name: Sync Homebrew formula # On every version tag, recompute the release tarball checksum and push an # updated Formula/yellowjacket.rb into the Homebrew tap repo. Keeping the tap # in a separate repo (github.com/Shadow-Puppet/homebrew-yellowjacket) is what # lets users install with a single command: # # brew install shadow-puppet/yellowjacket/yellowjacket # # (`shadow-puppet/yellowjacket` is shorthand for the homebrew-yellowjacket repo; # brew auto-taps it, so no separate `brew tap` step is needed.) on: push: tags: - "v*" workflow_dispatch: inputs: version: description: "Version to sync (default: the pushed tag)" required: false concurrency: group: homebrew-${{ github.ref }} cancel-in-progress: true jobs: sync-formula: runs-on: ubuntu-latest env: # GitHub PAT (or fine-grained token) with write access to the tap repo. TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} # Gitea source that serves the release tarball referenced by the formula. SOURCE_TARBALL_BASE: https://git.ljones.me/yonlu/yellowjacket/archive # separate GitHub tap repo the formula is published to. TAP_REPO: Shadow-Puppet/homebrew-yellowjacket steps: - name: Check out source (for the canonical formula) uses: actions/checkout@v4 - name: Compute version and tarball checksum id: version run: | set -euo pipefail TAG="${{ inputs.version }}" [ -n "$TAG" ] || TAG="${GITHUB_REF_NAME}" # e.g. v0.0.1 case "$TAG" in v*) ;; *) TAG="v$TAG" ;; esac VERSION="${TAG#v}" # e.g. 0.0.1 # v0.0.0 is semantic-release's version floor, not a shipment — # see the bootstrap step in release.yml. Skipped cleanly rather # than failing: this one would otherwise push a formula for a # version that does not exist into a *public* tap. if [ "$VERSION" = "0.0.0" ]; then echo "v0.0.0 is the version floor, not a release; nothing to sync" echo "skip=true" >> "$GITHUB_OUTPUT" exit 0 fi # Nor is a prerelease, and this trigger is `v*`, which matches # `v0.4.0-beta.1`. It matters most here of the four: the tap # is public, and `brew upgrade` would offer a beta to everyone # on it. case "$VERSION" in *-*) echo "$TAG is a prerelease; not syncing it to a public tap" echo "skip=true" >> "$GITHUB_OUTPUT" exit 0 ;; esac echo "skip=false" >> "$GITHUB_OUTPUT" TARBALL="${SOURCE_TARBALL_BASE}/${TAG}.tar.gz" echo "Fetching ${TARBALL}" # Retry briefly: the tag archive can lag a few seconds behind the push. for attempt in 1 2 3 4 5; do if curl -fSsL "$TARBALL" -o release.tar.gz; then break fi echo "attempt ${attempt} failed, retrying..." sleep 5 done SHA256="$(sha256sum release.tar.gz | cut -d' ' -f1)" echo "version=${VERSION} sha256=${SHA256}" echo "VERSION=${VERSION}" >> "$GITHUB_ENV" echo "SHA256=${SHA256}" >> "$GITHUB_ENV" - name: Render the formula with the new version and checksum if: steps.version.outputs.skip == 'false' run: | set -euo pipefail src="packaging/homebrew/Formula/yellowjacket.rb" # Rewrite only the two managed lines; the interpolated url picks up the # new version automatically. sed -E \ -e "s|^ version \".*\"| version \"${VERSION}\"|" \ -e "s|^ sha256 \".*\"| sha256 \"${SHA256}\"|" \ "$src" > yellowjacket.rb echo "----- rendered formula -----" cat yellowjacket.rb - name: Push to the Homebrew tap repo if: steps.version.outputs.skip == 'false' run: | set -euo pipefail git clone "https://x-access-token:${TAP_TOKEN}@github.com/${TAP_REPO}.git" tap mkdir -p tap/Formula cp yellowjacket.rb tap/Formula/yellowjacket.rb cd tap git config user.name "yellowjacket-ci" git config user.email "yj@yellowjacket.app" if git diff --quiet; then echo "Formula already up to date; nothing to push." exit 0 fi git add Formula/yellowjacket.rb git commit -m "yellowjacket ${VERSION}" git push origin HEAD:main