Files
2026-07-13 13:05:33 +08:00

200 lines
7.2 KiB
YAML

name: Homebrew Cask Bump
# Why: keep the stablyai/homebrew-orca tap in sync with GitHub Releases.
# Triggers:
# - workflow_call → release-cut.yml finished publishing a stable tag
# - workflow_dispatch → manual backfill for a specific tag
#
# The job computes the sha256 of orca-macos-arm64.dmg + orca-macos-x64.dmg
# from the release, templates the channel-specific cask in this repo with the
# new version and hashes, then PRs the result into stablyai/homebrew-orca.
# Stable tags update Casks/orca.rb; RC tags update Casks/orca@rc.rb.
#
# Why no `release.published` trigger: other products shipped from this repo
# (e.g. mobile under `mobile-v*`) also publish GitHub Releases. A blanket
# `release.published` trigger would fire this workflow for any of them and
# attempt to download `orca-macos-*.dmg` from a non-desktop release, at
# best 404ing and at worst (if the filter were weaker) rewriting the cask
# to a non-desktop version. The tap is only ever bumped by the desktop
# release pipeline calling this workflow directly.
on:
workflow_call:
inputs:
tag:
description: Release tag to sync (e.g. v1.3.25)
required: true
type: string
workflow_dispatch:
inputs:
tag:
description: Release tag to sync (e.g. v1.3.25)
required: true
type: string
jobs:
bump-cask:
runs-on: ubuntu-latest
# Why: only desktop tags have the macOS DMGs this workflow downloads.
# A mobile tag such as `mobile-v0.0.1` must never rewrite either cask.
if: >
inputs.tag != '' &&
startsWith(inputs.tag, 'v')
permissions:
contents: read
steps:
- name: Checkout orca
uses: actions/checkout@v6
- name: Resolve tag and version
id: tag
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
INPUT_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
if [[ -n "$INPUT_TAG" ]]; then
tag="$INPUT_TAG"
else
tag="$RELEASE_TAG"
fi
version="${tag#v}"
echo "tag=$tag" >>"$GITHUB_OUTPUT"
echo "version=$version" >>"$GITHUB_OUTPUT"
- name: Resolve cask target
id: cask
env:
TAG: ${{ steps.tag.outputs.tag }}
VERSION: ${{ steps.tag.outputs.version }}
run: |
set -euo pipefail
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
token="orca@rc"
branch_token="orca-rc"
elif [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
token="orca"
branch_token="orca"
else
echo "::error::Unsupported desktop tag shape: $TAG" >&2
exit 1
fi
path="Casks/${token}.rb"
if [[ ! -f "$path" ]]; then
echo "::error::Missing cask template: $path" >&2
exit 1
fi
echo "token=$token" >>"$GITHUB_OUTPUT"
echo "path=$path" >>"$GITHUB_OUTPUT"
echo "branch=bump/${branch_token}-${VERSION}" >>"$GITHUB_OUTPUT"
echo "title=${token} ${VERSION}" >>"$GITHUB_OUTPUT"
- name: Download DMGs and compute sha256
id: hash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.tag.outputs.tag }}
run: |
set -euo pipefail
mkdir -p dmgs
gh release download "$TAG" \
--repo "${{ github.repository }}" \
--pattern 'orca-macos-arm64.dmg' \
--pattern 'orca-macos-x64.dmg' \
--dir dmgs
arm=$(sha256sum dmgs/orca-macos-arm64.dmg | awk '{print $1}')
intel=$(sha256sum dmgs/orca-macos-x64.dmg | awk '{print $1}')
echo "arm=$arm" >>"$GITHUB_OUTPUT"
echo "intel=$intel" >>"$GITHUB_OUTPUT"
- name: Render updated cask file
env:
VERSION: ${{ steps.tag.outputs.version }}
ARM_SHA: ${{ steps.hash.outputs.arm }}
INTEL_SHA: ${{ steps.hash.outputs.intel }}
CASK_PATH: ${{ steps.cask.outputs.path }}
run: |
set -euo pipefail
python3 - <<'PY'
import os, re, pathlib
p = pathlib.Path(os.environ["CASK_PATH"])
src = p.read_text()
src = re.sub(r'version "[^"]+"',
f'version "{os.environ["VERSION"]}"', src, count=1)
src = re.sub(r'sha256 arm:\s*"[0-9a-f]+",\s*\n\s*intel:\s*"[0-9a-f]+"',
'sha256 arm: "{arm}",\n intel: "{intel}"'.format(
arm=os.environ["ARM_SHA"],
intel=os.environ["INTEL_SHA"]),
src, count=1)
p.write_text(src)
print(src)
PY
# Why: reuse the existing buf0-bot GitHub App (also used by
# track-community-prs.yaml) instead of minting a new PAT. The app is
# installed org-wide, so it has access to stablyai/homebrew-orca
# automatically. GITHUB_TOKEN cannot push cross-repo; a short-lived
# installation token can.
- name: Generate buf0-bot token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: 2590194
private-key: ${{ secrets.BUFO_BOT_PRIVATE_KEY }}
owner: stablyai
repositories: homebrew-orca
- name: Checkout tap
uses: actions/checkout@v6
with:
repository: stablyai/homebrew-orca
path: tap
token: ${{ steps.app-token.outputs.token }}
- name: Copy cask into tap and open PR
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
VERSION: ${{ steps.tag.outputs.version }}
TAG: ${{ steps.tag.outputs.tag }}
CASK_PATH: ${{ steps.cask.outputs.path }}
BRANCH: ${{ steps.cask.outputs.branch }}
TITLE: ${{ steps.cask.outputs.title }}
run: |
set -euo pipefail
mkdir -p "tap/$(dirname "$CASK_PATH")"
cp "$CASK_PATH" "tap/$CASK_PATH"
cd tap
# Why: commit author must match the buf0-bot app so commits are
# attributed to the bot in the tap's history / PR UI.
git config user.name "buf0-bot[bot]"
git config user.email "252831055+buf0-bot[bot]@users.noreply.github.com"
if git diff --quiet; then
echo "Cask already up-to-date for $TAG; nothing to do."
exit 0
fi
branch="$BRANCH"
git checkout -b "$branch"
git add "$CASK_PATH"
git commit -m "$TITLE"
git push -u origin "$branch" --force
# Why: repeated backfills can race an existing PR branch, so edit
# the PR title if creation reports that one already exists.
gh pr create \
--title "$TITLE" \
--body "Automated bump of $CASK_PATH from stablyai/orca release $TAG." \
--base main \
--head "$branch" \
|| gh pr edit "$branch" --title "$TITLE"
# Why: squash-merge immediately rather than --auto. The tap has no
# required checks or branch protection, and `gh pr merge --auto`
# only activates when there's something to wait on — on a repo
# with no gates it silently no-ops, leaving the PR open forever.
gh pr merge "$branch" --squash --delete-branch