Skip to content

BBC2-15 add bb pr merge#22

Open
b2l wants to merge 1 commit into
mainfrom
bbc2-15-pr-merge
Open

BBC2-15 add bb pr merge#22
b2l wants to merge 1 commit into
mainfrom
bbc2-15-pr-merge

Conversation

@b2l
Copy link
Copy Markdown
Owner

@b2l b2l commented Apr 22, 2026

Summary

  • New bb pr merge [id] that merges an open PR. Flags: --strategy/-s, --message/-m, --delete. Defaults to the PR for the current branch.
  • getPullRequest now requests destination.branch.default_merge_strategy and destination.branch.merge_strategies additively via fields=+... — both are omitted from Bitbucket's default serialization (see docs/bb-notes.md → "Default merge strategy"). Exposed on PullRequestDetail as defaultMergeStrategy / allowedMergeStrategies.
  • --strategy is validated client-side against the branch's allow-list before the POST, so users get a clean message listing permitted strategies rather than an opaque 400.
  • Without --strategy, the destination branch's configured default is used; when the branch has none, we fall back to Bitbucket's own default merge_commit.
  • 202 responses are polled against the Location header's task-status URL with capped exponential backoff (15 attempts, 500ms → 4s). 409 and 555 surface as retry-friendly errors from the backend. No auto-retry.
  • --delete sends close_source_branch: true (remote-side cleanup) and, client-side, deletes the matching local branch with git branch -d. Guards: only when the local name matches the PR's source; switch to destination first when currently on the source; warn (non-fatal) if git refuses.
  • Extends GitRunner with hasLocalBranch, checkoutExistingBranch, deleteLocalBranch; adds GitError which carries git's stderr.

Test plan

  • bun test — 170 tests pass (13 new backend tests: merge happy path, message/delete body shaping, 202 + Location polling, 202 missing Location, 409, 555, task-status PENDING / SUCCESS / FAILED / malformed / non-2xx; 2 new fields-mapping tests on getPullRequest)
  • bun run lint clean
  • bunx tsc --noEmit clean
  • Manual: bb pr merge --help shows all flags
  • Manual: bb pr merge in a non-Bitbucket repo fails with the -R hint at the repo-resolve step (as expected)

Manual test path

Pick a throwaway open PR you're willing to merge. Replace <N> with its id.

  1. bb pr merge <N> — merges using the destination branch's default strategy. Expect Merged pull request #<N>: <url>.
  2. bb pr merge <N> --strategy squash — explicit strategy. If the branch allows squash, it merges. If not, expect Merge strategy 'squash' is not allowed on branch 'main'. Allowed: merge_commit.
  3. bb pr merge <N> --strategy bogus — expect Unknown merge strategy 'bogus'. Allowed: merge_commit, squash, fast_forward, squash_fast_forward, rebase_fast_forward, rebase_merge.
  4. bb pr merge <N> --message "custom merge msg" — merges with your message as the merge commit message.
  5. On a branch that is the PR's source branch, with a clean working tree: bb pr merge <N> --delete. Expect Merged pull request #<N>: <url> then Deleted local branch '<source>'. — you should end up on the destination branch.
  6. On a branch that is NOT the source, with the source branch present locally: bb pr merge <N> --delete. Same outcome; no branch switching.
  7. Without a local source branch: bb pr merge <N> --delete merges remotely and skips the local delete silently.
  8. With a dirty working tree: bb pr merge <N> --delete merges remotely, then the local delete fails with a clear Warning: could not clean up local branch '<source>': ... line; exit code still 0.
  9. Attempt to merge an already-merged or declined PR: expect Pull request #<N> is merged; cannot merge. (or declined) — no API call made.
  10. bb --json pr merge <N> emits the full merged PR detail object.

For the 202 path, no reliable manual setup — covered by backend tests. Keep an eye on timing if you do hit it in the wild; the polling budget is ~30s.

Closes BBC2-15.

Merges an open PR via POST /pullrequests/{id}/merge with the destination
branch's default strategy, or an override via --strategy. Supports
--message for a custom merge commit message and --delete for server-side
+ local source branch cleanup.

Strategy resolution:
- --strategy validates against the destination branch's merge_strategies
  allow-list (surfaced client-side with a helpful message listing the
  permitted set) before the POST, rather than taking an opaque 400 from
  the API.
- Without --strategy, use destination.branch.default_merge_strategy (set
  via the branch's merge settings in the web UI); fall back to the API's
  own default merge_commit when unset.

Both strategy fields are omitted from the default /pullrequests/{id}
serialization. Request them additively via fields=+... (see docs/bb-notes
under "Default merge strategy"). That's done in getPullRequest globally —
the extra fields are also useful to future consumers (e.g. BBC2-44) and
`+` additive syntax doesn't drop existing fields.

Response handling:
- 200 → synchronous success, print PR URL.
- 202 → poll task-status with capped exponential backoff (15 attempts,
  500ms → 4s), resolve to SUCCESS or FAILED or time out with a retry
  message.
- 409 / 555 → clean retry-friendly messages from the backend layer.

--delete local cleanup is best-effort. Guards: only delete when local
branch name matches the PR's source; switch to destination first when
currently on the source; fall back to a warning (non-fatal) if git
refuses (dirty tree, non-FF, etc.) — the server-side merge already
landed.

Extends GitRunner with the write primitives checkoutExistingBranch and
deleteLocalBranch (plus the hasLocalBranch query), and adds GitError
whose message carries git's stderr so users see git's own diagnostics.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant