ci(release): auto-open Homebrew/core bump PR after npm publish#2087
Conversation
Adds a homebrew job to the Publish workflow that, after the npm publish and GitHub release are finalized, derives the version from the release tag, waits for the npm tarball to propagate, computes its sha256, and runs 'brew bump-formula-pr' to open a Homebrew/core update PR. This keeps the Homebrew formula from lagging behind GitHub/npm releases. The step is gated on a maintainer-provisioned HOMEBREW_BUMP_TOKEN secret (a PAT with public_repo scope; the default GITHUB_TOKEN cannot open cross-repo PRs) and is a no-op warning when the secret is absent. Untrusted workflow_run data is passed via env vars and the tag is validated, per the project's GitHub Actions script-injection guidance. Closes #2074 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dyoshikawa
left a comment
There was a problem hiding this comment.
This is a solid idea for automating the Homebrew bump, and the script-injection handling (passing HEAD_BRANCH through env: and regex-validating it) is done right. Two things below look like they'd actually break or misbehave in practice, though, so I'd want those addressed before merging. Also worth noting: since this job only runs on workflow_run after a real release merge, none of these issues would show up in this PR's own CI checks — they'd only surface (or silently misbehave) during an actual release.
|
|
||
| # Skip if Homebrew/core already has this exact version or an open bump PR | ||
| # for it; brew bump-formula-pr is idempotent and will refuse duplicates. | ||
| brew bump-formula-pr rulesync \ |
There was a problem hiding this comment.
GitHub-hosted ubuntu-latest runners have Homebrew preinstalled but it's not added to PATH by default (see the runner-images README: you need eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" or the Homebrew/actions/setup-homebrew action first). As written, this step will very likely fail with brew: command not found, meaning the whole point of this job wouldn't actually work on a real release run.
| needs: publish | ||
| runs-on: ubuntu-latest | ||
| # Mirror the publish job's gating so the bump only runs for real releases. | ||
| if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' && startsWith(github.event.workflow_run.head_branch, 'release/v') |
There was a problem hiding this comment.
Heads up: once a job defines its own if: that doesn't reference success() or needs.publish.result, that condition replaces the implicit "only run if publish succeeded" gate that needs: publish would otherwise provide — it doesn't add to it. This if: only re-checks the upstream workflow_run trigger fields, not whether the sibling publish job actually succeeded. So if publish fails after pnpm publish already succeeded (e.g. the gh release edit step errors out), this job would still run and could open a public Homebrew/core PR pointing at a release GitHub still shows as an unpublished draft. Adding success() && (or needs.publish.result == 'success' &&) to this condition would close that gap.
| fi | ||
| gh release edit "$TAG" --draft=false --latest | ||
|
|
||
| homebrew: |
There was a problem hiding this comment.
Minor: this job doesn't check out code or touch GITHUB_TOKEN/OIDC (it uses its own HOMEBREW_BUMP_TOKEN), but it still inherits the workflow-level permissions: id-token: write / contents: write. Might be worth adding permissions: {} here for least privilege, similar to the per-job overrides already used in draft-release.yml.
| exit 0 | ||
| fi | ||
|
|
||
| TAG="${HEAD_BRANCH#release/}" |
There was a problem hiding this comment.
Small DRY note: this TAG="${HEAD_BRANCH#release/}" + regex-validation block is now duplicated a third time (it already exists in the publish job above and in publish-assets.yml). Not blocking, but worth centralizing at some point so the three copies don't drift.
…vilege)
Address review findings on the new homebrew job:
- The custom `if:` replaced the implicit `needs: publish` success gate, so
the job could still run when publish failed after the npm tarball already
existed (e.g. `gh release edit` failing) — opening a Homebrew/core PR that
references an unpublished draft release. Add `success()` to restore the gate.
- GitHub-hosted runners ship Homebrew preinstalled but do not add it to PATH,
so `brew bump-formula-pr` would fail with command-not-found. Load Homebrew's
shell environment via `brew shellenv` before invoking brew.
- Scope the job to `permissions: {}`; it only opens a cross-repo PR with its
own HOMEBREW_BUMP_TOKEN and needs none of the workflow-level contents/id-token
grants.
Allowlist `linuxbrew` and `shellenv` in cspell for the new shellenv command.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Pushed 26336e1 to address the review findings:
Also allowlisted |
|
Thanks, dyoshikawa |
|
HOMEBREW_BUMP_TOKEN secret is not set; skipping Homebrew formula bump. https://github.com/dyoshikawa/rulesync/actions/runs/28786400981 https://github.com/dyoshikawa/rulesync/actions/runs/28786400981/job/85354216126 |
Summary
Resolves the Homebrew formula lagging behind GitHub/npm releases (#2074) by automating the formula bump from the release pipeline.
Adds a
homebrewjob to.github/workflows/publish.ymlthat runs after the npm publish + GitHub release are finalized and:release/v*tag (validated).https://registry.npmjs.org/rulesync/-/rulesync-<version>.tgz) to propagate.brew bump-formula-prto open a Homebrew/core update PR (idempotent — refuses duplicates).HOMEBREW_BUMP_TOKENsecret — a PAT withpublic_reposcope (the defaultGITHUB_TOKENcannot open cross-repository PRs againstHomebrew/homebrew-core). When the secret is absent the job is a no-op warning, so merging is safe but inert until the secret is added.dyoshikawa/homebrew-tapfor instant availability instead, that is a separate maintainer choice.Security
Untrusted
workflow_rundata (head_branch) is passed via env vars and the tag is regex-validated before use, per.claude/rules/github-actions-security.md.actionlintpasses locally.Notes
This is a GitHub Actions workflow change, so per this repo's autonomous-batch safety policy it is opened for manual maintainer review and merge, not auto-merged.
Closes #2074