feat: add pr review (task 0013)
All checks were successful
CI / test (pull_request) Successful in 38s

Add `pr review <n>` with the three action switches --approve,
--request-changes, and --comment, plus --body/--body-file. Exactly one
action flag is required; zero or multiple raise VALIDATION_ERROR before
any API call, mirroring the merge shorthand-conflict rule. Body
requirements are left to Gitea: a body-less event it rejects surfaces its
422 as VALIDATION_ERROR carrying the server's message. Output is
`review: { number, action }`.
This commit is contained in:
2026-07-13 20:44:59 -04:00
parent 40859b9e6b
commit 7d72f94746
3 changed files with 263 additions and 5 deletions

View File

@@ -12,8 +12,35 @@ Output: `review: { number, action }`.
## Acceptance criteria
- [ ] Each action flag submits the corresponding review event and outputs `review: { number, action }`
- [ ] Zero action flags, or more than one, yield `VALIDATION_ERROR` (exit 2) with no API call
- [ ] A server-side 422 for a missing body surfaces as `VALIDATION_ERROR` carrying Gitea's message
- [ ] `--body-file` works as everywhere else
- [ ] Fixture-server tests cover all three actions, the flag-count validations, and the 422 passthrough
- [x] Each action flag submits the corresponding review event and outputs `review: { number, action }`
- [x] Zero action flags, or more than one, yield `VALIDATION_ERROR` (exit 2) with no API call
- [x] A server-side 422 for a missing body surfaces as `VALIDATION_ERROR` carrying Gitea's message
- [x] `--body-file` works as everywhere else
- [x] Fixture-server tests cover all three actions, the flag-count validations, and the 422 passthrough
## Implementation Notes
`pr review` follows the established `pr merge`/`pr comment` shape: `resolveReviewAction`
collects the set of action switches (`--approve`/`--request-changes`/`--comment`) mapped
through the `REVIEW_ACTIONS` record and raises `VALIDATION_ERROR` when the count is not
exactly one — the direct analogue of `resolveMergeMethod`'s conflicting-selector rule the
spec references, adapted from "at most one (with a default)" to "exactly one (no default)".
The action flag count is settled before `createClient`, so an invalid invocation never
reaches the API. The body flows through the shared `resolveBodySource`, so `--body`/
`--body-file` and their mutual exclusion behave as everywhere else, and no body requirement
is pre-validated locally: a body-less event Gitea rejects returns 422, which the shared
`classifyHttpError` already maps to `VALIDATION_ERROR` carrying the server's message.
Deviations from the literal spec, both deliberate:
- The success block appends a `pr view <n> --reviews` suggestion line via `renderDetail`'s
`help`. The spec's output contract names only `review: { number, action }`; the extra
hint is the house style every sibling mutation command (`merge`, `edit`, `close`, …)
already follows, so it was kept for consistency rather than trimmed to the bare contract.
- A named `ReviewAction` interface was introduced in place of a repeated inline
`{ event; action }` shape, following a Standards-axis review nit — it matches the local
convention of naming such types (`MergeMethod`, `UpdateStyle`).
Built test-first via the `test-driven-development` skill (test-writer sub-agent, one
behavior per RED→GREEN cycle); `test/pr-review.test.ts` holds 10 tests. Full suite: 311
passing, typecheck clean.