ReviewOS

stacks/buddy

Implement functional auto-merge for update PRs

#1369
Closed chris opened this 9 days ago ·
9 days ago

Part of #1367 (Phase 0 — Foundation).

Problem

pullRequest.autoMerge is documented in the README and validated in config (src/config-validation.ts:259-272) but is not implemented:

  • GitHubProvider.mergePullRequest exists (src/git/github-provider.ts:964) but is never called anywhere
  • The only "auto-merge" code is a placeholder step in the deprecated workflow templates, literally commented # This will be implemented when the PR creation logic is fully integrated (src/templates/github-actions.ts:150-152)
  • The current unified workflow (generateUnifiedWorkflow, src/setup.ts:1106-1651) emits no auto-merge logic at all

CodeRabbit gates merges (pre-merge checks); Renovate has full automerge. We advertise it and ship nothing.

Spec

Two complementary mechanisms, configurable via the existing autoMerge config shape (enabled, strategy: 'merge' | 'squash' | 'rebase', conditions: string[]):

  1. GitHub native auto-merge (preferred): after PR creation, when autoMerge.enabled and conditions match, call the GraphQL enablePullRequestAutoMerge mutation so GitHub merges when checks pass. Requires branch protection / merge queue to be meaningful; detect and warn when the repo has no required checks (native auto-merge fails with "Pull request is in clean status" — fall back to mechanism 2).
  2. Polling merge in update-check: extend the update-check command (bin/cli.ts:896) to find open Buddy Bot PRs that match auto-merge conditions with green combined status + no changes-requested reviews, and merge them via mergePullRequest.

Condition semantics (document precisely in docs/)

  • patch-only — every update in the PR manifest is type: "patch" (consume #1368's manifest, not title parsing)
  • minor-only — every update is minor or patch
  • security-only — PR carries the configured security.label
  • empty conditions array or omitted — all Buddy Bot PRs qualify (document as dangerous)
  • Never auto-merge PRs with major updates unless a new explicit condition all is set

Safety rails

  • Only merge PRs authored by the bot identity (check user.login + branch prefix buddy-bot/)
  • Respect an opt-out label (no-auto-merge)
  • Skip when required checks are pending/failing or the PR is a draft
  • Log every merge decision (merged / skipped + reason) — feeds #1387 notifications later

Tasks

  • enableAutoMerge(prNumber, strategy) via GraphQL in src/git/github-provider.ts
  • Condition evaluator src/pr/auto-merge.ts reading the PR manifest (#1368)
  • Wire into Buddy.createPullRequests (post-create) and update-check
  • Emit a gh pr merge-equivalent fallback path using REST PUT /pulls/{n}/merge (already wrapped by mergePullRequest)
  • Config: add optional autoMerge.requireGreenCI (default true) and autoMerge.optOutLabel (default no-auto-merge) to src/types.ts + validation + docs
  • Remove the placeholder comment block from src/templates/github-actions.ts
  • Tests: condition matrix (patch/minor/major/security), draft PRs, red CI, opt-out label, non-bot PRs

Acceptance criteria

  • With autoMerge: { enabled: true, strategy: 'squash', conditions: ['patch-only'] }, a patch-only PR merges automatically once CI is green; a minor PR does not
  • Works in both modes: repos with branch protection (native auto-merge) and without (polling)
  • README claims and actual behavior match; docs/ gains an Auto-Merge page with the condition table

Dependencies

  • #1368 (PR manifest) for reliable update-type detection
  • Enables half of #1382 (pre-merge checks integrate with the same gate)

Sign in to comment on this issue.