Skip to content

chore(release): prepare 0.61.0 (#232) #45

chore(release): prepare 0.61.0 (#232)

chore(release): prepare 0.61.0 (#232) #45

Workflow file for this run

name: Update Homebrew tap
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
workflow_dispatch:
inputs:
version:
description: "Version to push to the tap (e.g. 0.27.0)"
required: true
type: string
concurrency:
group: homebrew-tap-${{ github.ref }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
update:
runs-on: ubuntu-latest
permissions:
contents: read
env:
TAP_OWNER: Pythoughts-labs
TAP_REPO: homebrew-pythinker
steps:
- name: Checkout source repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2
- name: Resolve version
id: ver
env:
GITHUB_REF: ${{ github.ref }}
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if [[ "$GITHUB_REF" =~ ^refs/tags/v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
version="${BASH_REMATCH[1]}"
elif [[ -n "$INPUT_VERSION" ]]; then
version="$INPUT_VERSION"
else
echo "::error::No version source available" >&2
exit 1
fi
echo "version=${version}" >> "$GITHUB_OUTPUT"
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0
with:
python-version: "3.13"
- name: Generate native formula
env:
PKG_VERSION: ${{ steps.ver.outputs.version }}
run: |
set -euxo pipefail
mkdir -p out/Formula
deadline=$(( $(date +%s) + 30 * 60 ))
until python packages/homebrew-tap/generate-formula.py \
--version "$PKG_VERSION" \
--template packages/homebrew-tap/pythinker-code.rb.tmpl \
--output out/Formula/pythinker-code.rb; do
if [ "$(date +%s)" -gt "$deadline" ]; then
echo "::error::Native release assets for ${PKG_VERSION} were not ready within 30 minutes" >&2
exit 1
fi
echo "Native release assets not ready for ${PKG_VERSION}; sleeping 30s"
sleep 30
done
echo "--- generated formula head ---"
head -40 out/Formula/pythinker-code.rb
# Mint a short-lived installation token for an org-owned GitHub App that
# has Contents: Read and write on the tap repo. This replaces a personal
# PAT: the App is owned by the org (survives member/org changes), its token
# expires in ~1h (minted fresh each run), and it is scoped to only the tap
# repo. owner/repositories are required because the App must reach a repo
# other than the one this workflow runs in.
- name: Mint GitHub App token for the tap repo
id: app-token
env:
APP_ID: ${{ secrets.HOMEBREW_TAP_APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }}
TAP_OWNER: ${{ env.TAP_OWNER }}
TAP_REPO: ${{ env.TAP_REPO }}
run: |
set -euo pipefail
if [ -z "${APP_ID:-}" ] || [ -z "${APP_PRIVATE_KEY:-}" ]; then
echo "::error::No tap GitHub App credentials available. Configure HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY, and install the App on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write." >&2
exit 1
fi
b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }
key_file=$(mktemp)
trap 'rm -f "$key_file"' EXIT
printf '%s\n' "$APP_PRIVATE_KEY" > "$key_file"
chmod 600 "$key_file"
now=$(date +%s)
header=$(printf '{"alg":"RS256","typ":"JWT"}' | b64url)
payload=$(jq -nc --argjson iat "$((now - 60))" --argjson exp "$((now + 540))" --arg iss "$APP_ID" '{iat:$iat,exp:$exp,iss:$iss}' | b64url)
unsigned="${header}.${payload}"
signature=$(printf '%s' "$unsigned" | openssl dgst -sha256 -sign "$key_file" | b64url)
jwt="${unsigned}.${signature}"
installation_id=$(curl --fail-with-body -sS \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${jwt}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${TAP_OWNER}/${TAP_REPO}/installation" \
| jq -er '.id')
token=$(jq -nc --arg repo "$TAP_REPO" '{repositories:[$repo],permissions:{contents:"write"}}' \
| curl --fail-with-body -sS \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${jwt}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/app/installations/${installation_id}/access_tokens" \
-d @- \
| jq -er '.token')
echo "::add-mask::$token"
echo "token=$token" >> "$GITHUB_OUTPUT"
- name: Sync formula into tap repo (handles empty repo on first run)
env:
PKG_VERSION: ${{ steps.ver.outputs.version }}
TAP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
set -euo pipefail
if [ -z "${TAP_TOKEN:-}" ]; then
echo "::error::No tap token available — the GitHub App token mint produced an empty value. Confirm HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY secrets are set and the App is installed on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write, then re-run this workflow." >&2
exit 1
fi
# We do NOT use actions/checkout for the tap repo because on the
# very first run the tap is empty and has no refs/heads/main yet.
# `git init` + `git fetch || true` + `git push -u origin main`
# works for both the empty case (creates main) and the populated
# case (fast-forwards to current main, then adds a new commit).
rm -rf tap-repo
mkdir tap-repo
cd tap-repo
git init -q -b main
git remote add origin \
"https://x-access-token:${TAP_TOKEN}@github.com/${TAP_OWNER}/${TAP_REPO}.git"
# Pull whatever's on main if anything (no-op on the inaugural run).
if git ls-remote --exit-code --heads origin main >/dev/null 2>&1; then
git fetch --depth 1 origin main
git reset --hard FETCH_HEAD
fi
mkdir -p Formula
cp ../out/Formula/pythinker-code.rb Formula/pythinker-code.rb
if [ ! -f README.md ]; then
cat > README.md <<EOF
# homebrew-pythinker
Homebrew tap for [Pythinker Code](https://github.com/Pythoughts-labs/pythinker-code).
\`\`\`sh
brew install Pythoughts-labs/pythinker/pythinker-code
\`\`\`
This tap is auto-updated by the
[homebrew-tap.yml](https://github.com/Pythoughts-labs/pythinker-code/blob/main/.github/workflows/homebrew-tap.yml)
workflow on every \`v*.*.*\` tag. Do not hand-edit \`Formula/*\` — your
edits will be overwritten on the next release.
EOF
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/pythinker-code.rb README.md
if git diff --cached --quiet; then
echo "Formula already up to date for ${PKG_VERSION}; nothing to push."
exit 0
fi
git commit -m "pythinker-code ${PKG_VERSION}" \
-m "Auto-updated by Pythinker-Code/.github/workflows/homebrew-tap.yml"
git push -u origin HEAD:main