From d4e4112d5ea0c09eb1e3368f437920e1466fce1c Mon Sep 17 00:00:00 2001 From: Razvan Dimescu Date: Wed, 8 Apr 2026 03:42:16 +0300 Subject: [PATCH] ci: auto-bump homebrew formula on release Add a workflow that runs on release:published (and via manual workflow_dispatch), fetches sha256 checksums from the published release assets, and rewrites razvandimescu/homebrew-tap/numa.rb in place: version, URL paths, and sha256 lines after each url. The formula's existing on_macos/on_linux structure is preserved. Uses HOMEBREW_TAP_GITHUB_TOKEN (already set as a repo secret) to push directly to the tap's main branch. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/homebrew-bump.yml | 76 +++++++++++++++++++++++++++++ scripts/update-homebrew-formula.py | 57 ++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 .github/workflows/homebrew-bump.yml create mode 100755 scripts/update-homebrew-formula.py diff --git a/.github/workflows/homebrew-bump.yml b/.github/workflows/homebrew-bump.yml new file mode 100644 index 0000000..5bcac57 --- /dev/null +++ b/.github/workflows/homebrew-bump.yml @@ -0,0 +1,76 @@ +name: Bump Homebrew Tap + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: 'Version to bump (e.g. 0.10.0 or v0.10.0)' + required: true + +permissions: + contents: read + +jobs: + bump: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Determine version + id: ver + run: | + if [ "${{ github.event_name }}" = "release" ]; then + V="${{ github.event.release.tag_name }}" + else + V="${{ github.event.inputs.version }}" + fi + V="${V#v}" + echo "version=$V" >> "$GITHUB_OUTPUT" + + - name: Fetch sha256 checksums from release assets + id: shas + env: + V: ${{ steps.ver.outputs.version }} + run: | + set -euo pipefail + base="https://github.com/razvandimescu/numa/releases/download/v${V}" + for t in macos-aarch64 macos-x86_64 linux-aarch64 linux-x86_64; do + sha=$(curl -fsSL "${base}/numa-${t}.tar.gz.sha256" | awk '{print $1}') + if [ -z "$sha" ]; then + echo "ERROR: failed to fetch sha256 for $t" >&2 + exit 1 + fi + key=$(echo "$t" | tr '[:lower:]-' '[:upper:]_') + echo "SHA_${key}=${sha}" >> "$GITHUB_ENV" + done + + - name: Clone homebrew-tap + env: + HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} + run: | + git clone "https://x-access-token:${HOMEBREW_TAP_GITHUB_TOKEN}@github.com/razvandimescu/homebrew-tap.git" tap + + - name: Update formula + env: + VERSION: ${{ steps.ver.outputs.version }} + run: | + python3 scripts/update-homebrew-formula.py tap/numa.rb + echo "--- updated numa.rb ---" + cat tap/numa.rb + + - name: Commit and push + working-directory: tap + env: + V: ${{ steps.ver.outputs.version }} + run: | + if git diff --quiet; then + echo "numa.rb already at v${V}, nothing to commit" + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add numa.rb + git commit -m "chore: bump numa to v${V}" + git push origin main diff --git a/scripts/update-homebrew-formula.py b/scripts/update-homebrew-formula.py new file mode 100755 index 0000000..c114784 --- /dev/null +++ b/scripts/update-homebrew-formula.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +"""Rewrite a Homebrew formula in place: bump version, URL paths, and sha256 lines. + +Reads the formula path from argv[1], and the following env vars: + VERSION e.g. "0.10.0" (no leading v) + SHA_MACOS_AARCH64 + SHA_MACOS_X86_64 + SHA_LINUX_AARCH64 + SHA_LINUX_X86_64 + +Assumptions about the formula: + - Has `version "X.Y.Z"` somewhere + - Has `url "...releases/download/vX.Y.Z/numa-.tar.gz"` lines + - May or may not already have `sha256 "..."` lines immediately after each url +""" +import os +import re +import sys + +formula_path = sys.argv[1] +version = os.environ["VERSION"].lstrip("v") +shas = { + "macos-aarch64": os.environ["SHA_MACOS_AARCH64"], + "macos-x86_64": os.environ["SHA_MACOS_X86_64"], + "linux-aarch64": os.environ["SHA_LINUX_AARCH64"], + "linux-x86_64": os.environ["SHA_LINUX_X86_64"], +} + +with open(formula_path) as f: + content = f.read() + +content = re.sub(r'version "[^"]*"', f'version "{version}"', content) +content = re.sub( + r"releases/download/v[\d.]+/numa-", + f"releases/download/v{version}/numa-", + content, +) +content = re.sub(r'\n[ \t]*sha256 "[^"]*"', "", content) + + +def add_sha(match: re.Match) -> str: + indent = match.group(1) + target = match.group(2) + if target not in shas: + return match.group(0) + return f'{match.group(0)}\n{indent}sha256 "{shas[target]}"' + + +content = re.sub( + r'^([ \t]+)url "[^"]*numa-([\w-]+)\.tar\.gz"', + add_sha, + content, + flags=re.MULTILINE, +) + +with open(formula_path, "w") as f: + f.write(content)