Skip to content

BBC2-18 add bb pr review (-a / -r / -w) + surface approvals in bb pr view#17

Merged
b2l merged 3 commits into
mainfrom
b2lpowa/bbc2-18-approve-unapprove-and-request-changes
Apr 15, 2026
Merged

BBC2-18 add bb pr review (-a / -r / -w) + surface approvals in bb pr view#17
b2l merged 3 commits into
mainfrom
b2lpowa/bbc2-18-approve-unapprove-and-request-changes

Conversation

@b2l
Copy link
Copy Markdown
Owner

@b2l b2l commented Apr 15, 2026

Summary

Four flat subcommands for recording your own review state on a PR. Each defaults to the open PR for the current branch when no id is given.

  • bb pr approve [<id>]
  • bb pr unapprove [<id>]
  • bb pr request-changes [<id>]
  • bb pr unrequest-changes [<id>]

Approve and request-changes are independent states in Bitbucket — a reviewer can carry both simultaneously across users; the same user can carry one or the other (toggling).

Naming choice — call it out

The ticket left the naming of the request-changes inverse open. I went with unrequest-changes for symmetry with unapprove (consistent un- prefix). Ugly, but self-evident and matches what's already there. If you'd prefer e.g. withdraw-changes or a flag-based bb pr request-changes --withdraw, easy to rename — say so before merge.

Idempotency caveat

The ticket AC says re-running an action on an already-matching state shouldn't error. The Bitbucket spec doesn't document what re-approving / re-requesting actually returns, so I haven't coded a swallow. Smoke-test will reveal the actual behavior:

  • If re-approve returns 200 → nothing to do, idempotent for free.
  • If it returns 4xx → I'll add a backend-level swallow in a follow-up commit.

Same for the DELETE-on-never-matching cases.

The one documented error path that IS handled cleanly: DELETE /approve returns 400 when the PR is already merged. Test covers it.

Implementation notes

  • Backend has 4 thin functions sharing two helpers (postParticipantAction / deleteParticipantAction) — keeps the per-action code minimal while typing the discriminated path correctly.
  • Command layer lives in one review.ts file with a shared runner; the 4 exported run functions just bind the action and the success message. 4 separate files would have been 90% duplication.

Test plan

  • On a real PR you didn't author: bun src/index.ts pr approve <id> — UI shows your approval. Run again — confirm whether it errors or no-ops (this is the smoke-test gating idempotency).
  • bun src/index.ts pr unapprove <id> — UI shows approval removed.
  • bun src/index.ts pr request-changes <id> — UI shows changes-requested.
  • bun src/index.ts pr unrequest-changes <id> — UI shows it cleared.
  • On a merged PR: bun src/index.ts pr unapprove <id> should fail with a clean message (not a stack trace).
  • No-id form: from a branch with an open PR, bun src/index.ts pr approve (no args) auto-detects.
  • Tests: bun test (151 passing, 6 new).
  • Lint: bun run lint.

Out of scope (per ticket)

  • Unified bb pr review command (could come later if the flat commands feel redundant).
  • Listing who approved / requested changes — already covered by bb pr view.

b2l added 3 commits April 15, 2026 12:00
Four flat commands, each defaulting to the current branch's PR when
no id is given:

- bb pr approve / bb pr unapprove
- bb pr request-changes / bb pr unrequest-changes

Approve and request-changes are independent review states in
Bitbucket — a reviewer can have an approval AND changes-requested
from different users on the same PR simultaneously. The four
commands wrap symmetric POST/DELETE pairs on /approve and
/request-changes.

Idempotency note: the spec doesn't document what re-approving an
already-approved PR returns. We let any non-2xx propagate. The
documented edge case — DELETE /approve returns 400 if the PR is
already merged — surfaces as a clean PullRequestError; the command
layer prints the message rather than a raw HTTP error.

See docs/bb-notes.md → Approve / Unapprove / Request-changes for
the endpoint details.
Two changes to make 'I approved it, now where did it go?' visible:

- Backend PullRequestDetail now carries participants[] alongside
  reviewers[]. reviewers[] stays strictly role=REVIEWER (formal
  reviewers, as before). participants[] covers role=PARTICIPANT —
  including ad-hoc approvers on PRs with no assigned reviewers
  (the Snyk auto-PR case). Pure commenters show up with
  state=pending.
- bb pr view gets a single APPROVALS entry on the top block with
  a one-line summary: 'N approved, M changes requested' aggregating
  both arrays. Minimal addition; the larger REVIEWERS vs
  PARTICIPANTS section split is deferred to its own ticket along
  with the full pr view redesign.
Replace the four flat commands (approve / unapprove / request-changes
/ unrequest-changes) with a single bb pr review taking mutually-
exclusive flags:

  -a, --approve
  -r, --request-changes
  -w, --withdraw

Matches gh's mental model of a single 'current review state' rather
than Bitbucket's two-independent-toggles API. --approve and
--request-changes implicitly clear the inverse state so the reviewer
can flip cleanly; --withdraw clears whichever state is set.

Backend functions unchanged — they remain the primitives the command
layer composes. The command layer's secondary cleanup calls are
best-effort (swallow PullRequestError) so a primary-action success
isn't masked by an expected 'not currently in that state' failure on
the cleanup DELETE.
@b2l b2l changed the title BBC2-18 add bb pr approve / unapprove / request-changes / unrequest-changes BBC2-18 add bb pr review (-a / -r / -w) + surface approvals in bb pr view Apr 15, 2026
@b2l b2l merged commit dd65274 into main Apr 15, 2026
@b2l b2l deleted the b2lpowa/bbc2-18-approve-unapprove-and-request-changes branch April 15, 2026 13:17
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