Homebrew Formula PR #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Homebrew Formula PR | |
| on: | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Release tag to package (e.g. v0.1.0). Defaults to current ref name." | |
| required: false | |
| tap_repo: | |
| description: "Override tap repository (org/homebrew-foo). Defaults to repository variable HOMEBREW_TAP_REPO." | |
| required: false | |
| jobs: | |
| open-tap-pr: | |
| runs-on: ubuntu-latest | |
| env: | |
| DEFAULT_FORMULA_NAME: meta-ads-cli | |
| DEFAULT_FORMULA_PATH: Formula/meta-ads-cli.rb | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| steps: | |
| - name: Checkout source repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Resolve workflow configuration | |
| id: cfg | |
| env: | |
| GITHUB_EVENT_NAME: ${{ github.event_name }} | |
| INPUT_TAG: ${{ github.event.inputs.tag }} | |
| INPUT_TAP_REPO: ${{ github.event.inputs.tap_repo }} | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| REF_NAME: ${{ github.ref_name }} | |
| REPO_VAR_TAP_REPO: ${{ vars.HOMEBREW_TAP_REPO }} | |
| REPO_VAR_FORMULA_NAME: ${{ vars.HOMEBREW_FORMULA_NAME }} | |
| REPO_VAR_FORMULA_PATH: ${{ vars.HOMEBREW_FORMULA_PATH }} | |
| REPO_VAR_BASE_BRANCH: ${{ vars.HOMEBREW_TAP_BASE_BRANCH }} | |
| run: | | |
| set -euo pipefail | |
| TAG="${INPUT_TAG:-}" | |
| if [ -z "$TAG" ]; then | |
| TAG="${RELEASE_TAG:-}" | |
| fi | |
| if [ -z "$TAG" ] && [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]; then | |
| TAG="${REF_NAME:-}" | |
| fi | |
| if [ -z "$TAG" ]; then | |
| echo "Unable to resolve release tag. For manual runs, provide workflow input 'tag' (for example: v0.1.0)." | |
| exit 1 | |
| fi | |
| TAP_REPO="${INPUT_TAP_REPO:-}" | |
| if [ -z "$TAP_REPO" ]; then | |
| TAP_REPO="${REPO_VAR_TAP_REPO:-}" | |
| fi | |
| if [ -z "$TAP_REPO" ]; then | |
| echo "HOMEBREW_TAP_REPO is not configured. Set repository variable HOMEBREW_TAP_REPO or pass tap_repo input." | |
| exit 1 | |
| fi | |
| FORMULA_NAME="${REPO_VAR_FORMULA_NAME:-$DEFAULT_FORMULA_NAME}" | |
| FORMULA_PATH="${REPO_VAR_FORMULA_PATH:-$DEFAULT_FORMULA_PATH}" | |
| BASE_BRANCH="${REPO_VAR_BASE_BRANCH:-}" | |
| SOURCE_URL="https://github.com/${GITHUB_REPOSITORY}/archive/refs/tags/${TAG}.tar.gz" | |
| HOMEPAGE="https://github.com/${GITHUB_REPOSITORY}" | |
| { | |
| echo "tag=$TAG" | |
| echo "tap_repo=$TAP_REPO" | |
| echo "formula_name=$FORMULA_NAME" | |
| echo "formula_path=$FORMULA_PATH" | |
| echo "base_branch=$BASE_BRANCH" | |
| echo "source_url=$SOURCE_URL" | |
| echo "homepage=$HOMEPAGE" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Show resolved release configuration | |
| run: | | |
| echo "Tag: ${{ steps.cfg.outputs.tag }}" | |
| echo "Tap repo: ${{ steps.cfg.outputs.tap_repo }}" | |
| echo "Formula path: ${{ steps.cfg.outputs.formula_path }}" | |
| echo "Base branch: ${{ steps.cfg.outputs.base_branch }}" | |
| echo "Source URL: ${{ steps.cfg.outputs.source_url }}" | |
| - name: Validate tap repository access | |
| id: tap | |
| env: | |
| TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| TAP_REPO: ${{ steps.cfg.outputs.tap_repo }} | |
| CFG_BASE_BRANCH: ${{ steps.cfg.outputs.base_branch }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${TOKEN:-}" ]; then | |
| echo "HOMEBREW_TAP_TOKEN is not set. Add it in repository secrets." | |
| exit 1 | |
| fi | |
| STATUS_CODE="$(curl -sS -o tap_repo.json -w "%{http_code}" \ | |
| -H "Authorization: token ${TOKEN}" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "https://api.github.com/repos/${TAP_REPO}")" | |
| if [ "$STATUS_CODE" != "200" ]; then | |
| echo "Unable to access tap repo '${TAP_REPO}' with provided token (HTTP ${STATUS_CODE})." | |
| echo "Response:" | |
| cat tap_repo.json | |
| exit 1 | |
| fi | |
| python3 - <<'PY' | |
| import json | |
| import os | |
| from pathlib import Path | |
| payload = json.loads(Path('tap_repo.json').read_text()) | |
| name = payload.get('full_name') | |
| permissions = payload.get('permissions') or {} | |
| default_branch = (payload.get('default_branch') or '').strip() | |
| configured_branch = (os.getenv('CFG_BASE_BRANCH') or '').strip() | |
| resolved_branch = configured_branch or default_branch | |
| print(f"Verified tap repository access: {name}") | |
| print(f"Tap default branch: {default_branch or '<none>'}") | |
| print(f"Resolved base branch for PR: {resolved_branch or '<none>'}") | |
| if permissions and not permissions.get('push', False): | |
| raise SystemExit( | |
| "Token can read tap repo but has no push permission. " | |
| "Grant contents write access for PR branch creation." | |
| ) | |
| if not default_branch: | |
| raise SystemExit( | |
| "Tap repository has no default branch. " | |
| "Initialize it with an initial commit (for example README.md on main) " | |
| "and rerun the workflow." | |
| ) | |
| if not resolved_branch: | |
| raise SystemExit( | |
| "Could not resolve base branch for tap repository. " | |
| "Set HOMEBREW_TAP_BASE_BRANCH or initialize default branch." | |
| ) | |
| output_path = os.environ['GITHUB_OUTPUT'] | |
| with open(output_path, 'a', encoding='utf-8') as handle: | |
| handle.write(f"base_branch={resolved_branch}\n") | |
| PY | |
| - name: Compute source archive SHA256 | |
| id: sha | |
| env: | |
| SOURCE_URL: ${{ steps.cfg.outputs.source_url }} | |
| TAG: ${{ steps.cfg.outputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| echo "Downloading source archive: $SOURCE_URL" | |
| if ! curl -fLSs "$SOURCE_URL" -o source.tar.gz; then | |
| echo "Failed to download source archive for tag '$TAG'." | |
| echo "Confirm the tag exists in ${GITHUB_REPOSITORY} and is published." | |
| echo "URL attempted: $SOURCE_URL" | |
| exit 1 | |
| fi | |
| SOURCE_SHA256="$(sha256sum source.tar.gz | awk '{print $1}')" | |
| echo "source_sha256=$SOURCE_SHA256" >> "$GITHUB_OUTPUT" | |
| - name: Checkout Homebrew tap repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ steps.cfg.outputs.tap_repo }} | |
| token: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| path: tap | |
| ref: ${{ steps.tap.outputs.base_branch }} | |
| - name: Generate formula file | |
| env: | |
| FORMULA_NAME: ${{ steps.cfg.outputs.formula_name }} | |
| FORMULA_PATH: ${{ steps.cfg.outputs.formula_path }} | |
| HOMEPAGE: ${{ steps.cfg.outputs.homepage }} | |
| SOURCE_URL: ${{ steps.cfg.outputs.source_url }} | |
| SOURCE_SHA256: ${{ steps.sha.outputs.source_sha256 }} | |
| run: | | |
| set -euo pipefail | |
| python3 scripts/generate_brew_formula.py \ | |
| --formula-name "$FORMULA_NAME" \ | |
| --homepage "$HOMEPAGE" \ | |
| --source-url "$SOURCE_URL" \ | |
| --source-sha256 "$SOURCE_SHA256" \ | |
| --output "tap/$FORMULA_PATH" | |
| - name: Create pull request in tap repository | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| token: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| path: tap | |
| branch: automation/update-${{ steps.cfg.outputs.formula_name }}-${{ steps.cfg.outputs.tag }} | |
| base: ${{ steps.tap.outputs.base_branch }} | |
| delete-branch: true | |
| title: "chore(homebrew): update ${{ steps.cfg.outputs.formula_name }} for ${{ steps.cfg.outputs.tag }}" | |
| commit-message: "chore(homebrew): update ${{ steps.cfg.outputs.formula_name }} for ${{ steps.cfg.outputs.tag }}" | |
| body: | | |
| Automated update from `${{ github.repository }}`. | |
| - Tag: `${{ steps.cfg.outputs.tag }}` | |
| - Source URL: `${{ steps.cfg.outputs.source_url }}` | |
| - Source SHA256: `${{ steps.sha.outputs.source_sha256 }}` | |
| Generated via `scripts/generate_brew_formula.py`. |