name: Post-Release Formula Update
permissions:
contents: write
pull-requests: write
on:
workflow_run:
workflows: ["Release"]
types: [completed]
jobs:
update-formula:
if: ${{ github.event.workflow_run.conclusion == 'success' && startsWith(github.event.workflow_run.head_branch, 'v') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
- name: Resolve release tag
id: tag
env:
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
set -euo pipefail
# HEAD_BRANCH is the tag name (e.g. "v0.15.2") for tag-triggered runs.
# Validate strictly so an attacker who pushed a malformed tag can't
# smuggle anything downstream. Allow only `v<digits>.<digits>.<digits>`
# with optional pre-release/build metadata.
if ! [[ "$HEAD_BRANCH" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$ ]]; then
echo "::error::Refusing to run with non-semver tag '$HEAD_BRANCH'"
exit 1
fi
{
echo "tag=$HEAD_BRANCH"
echo "version=${HEAD_BRANCH#v}"
} >> "$GITHUB_OUTPUT"
- name: Fetch sha256 sidecars from release
id: shas
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.tag.outputs.tag }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
fetch() {
gh release download "$TAG" -p "$1.sha256" -R "$REPO" -O - \
| awk '{print $1}'
}
# Validate each sha is exactly 64 hex chars before exporting — the
# sidecar files are attacker-influenceable (an attacker who
# compromises the release pipeline could replace them).
validate() {
local sha="$1"
if ! [[ "$sha" =~ ^[0-9a-fA-F]{64}$ ]]; then
echo "::error::Invalid sha256 from sidecar: '$sha'"
exit 1
fi
printf '%s' "$sha"
}
{
echo "macos_aarch64=$(validate "$(fetch fledge-macos-aarch64)")"
echo "macos_x86_64=$(validate "$(fetch fledge-macos-x86_64)")"
echo "linux_x86_64=$(validate "$(fetch fledge-linux-x86_64)")"
} >> "$GITHUB_OUTPUT"
- name: Rewrite Formula/fledge.rb
env:
NEW_VERSION: ${{ steps.tag.outputs.version }}
MACOS_AARCH64: ${{ steps.shas.outputs.macos_aarch64 }}
MACOS_X86_64: ${{ steps.shas.outputs.macos_x86_64 }}
LINUX_X86_64: ${{ steps.shas.outputs.linux_x86_64 }}
run: |
set -euo pipefail
python3 - <<'PY'
import os, re, sys, pathlib
p = pathlib.Path("Formula/fledge.rb")
src = p.read_text()
src = re.sub(
r'(?m)^(\s*version\s+")(\d+\.\d+\.\d+)(")',
rf'\g<1>{os.environ["NEW_VERSION"]}\g<3>',
src,
count=1,
)
shas = [
os.environ["MACOS_AARCH64"],
os.environ["MACOS_X86_64"],
os.environ["LINUX_X86_64"],
]
parts = re.split(r'(sha256\s+"[0-9a-fA-F]{64}")', src)
if len(parts) - 1 != 6:
sys.exit(
f"Expected 3 sha256 lines in Formula/fledge.rb, found {(len(parts) - 1) // 2}"
)
for i, sha in enumerate(shas):
parts[2 * i + 1] = f'sha256 "{sha}"'
p.write_text("".join(parts))
PY
- name: Open PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NEW_VERSION: ${{ steps.tag.outputs.version }}
run: |
set -euo pipefail
BRANCH="formula/v$NEW_VERSION"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
if git diff --quiet -- Formula/fledge.rb; then
echo "Formula/fledge.rb already at v$NEW_VERSION — nothing to do."
exit 0
fi
git add Formula/fledge.rb
git commit -m "chore: update Homebrew formula to v$NEW_VERSION"
git push -u origin "$BRANCH"
gh pr create \
--title "chore: update Homebrew formula to v$NEW_VERSION" \
--body "Automated by post-release-formula.yml. Pulls the v$NEW_VERSION sha256 sidecars from the release and writes them into \`Formula/fledge.rb\` along with the version bump." \
--base main