feat: add search commands (task 0016)
Some checks failed
CI / test (pull_request) Failing after 45s

Add `search issues <query>` and `search prs <query>`, the full-text escape
hatch the forbidden `--search` flag on the list commands redirects to.

Both hit Gitea's cross-repo issue-search endpoint with the query, a `type`
of issues or pulls, and the owner param, then filter results to the current
repository client-side via each result's `repository` field — the endpoint
has no repo-name filter. The count line reports `count: N of T total` with
`T` from the filtered set (ADR 0005), never the endpoint's cross-repo
`X-Total-Count`.

The positional query is required (VALIDATION_ERROR if missing). Flags:
`--state` (default open), `--label` (comma-separated names passed straight
through as the API `labels` param), `--limit` (default 30), and `--fields`.
Default output is the locator schema (`number`, `title`, `state`, `author`,
`created`) under `issues:` / `pull_requests:` blocks matching the list
commands — search finds the number, `issue view` / `pr view` load the detail.

Covered by fixture-server tests for both types, cross-repo filtering, the
count rule, each flag, the empty state, and missing-query validation, plus
end-to-end tests against a live Gitea instance.
This commit is contained in:
2026-07-14 09:55:20 -04:00
parent 6661239afe
commit 4c3dde26b4
5 changed files with 695 additions and 7 deletions

View File

@@ -13,10 +13,21 @@ Both commands use the locator schema (`number`, `title`, `state`, `author`, `cre
## Acceptance criteria
- [ ] `search issues "<query>"` and `search prs "<query>"` query the search endpoint with the right `type` and owner, then filter to the current repo client-side
- [ ] The count line reports `count: N of T total` with `T` from the client-side-filtered set
- [ ] A missing query yields `VALIDATION_ERROR` (exit 2)
- [ ] `--state`, `--label`, `--limit`, and `--fields` work; default fields are the locator schema
- [ ] Empty results emit the standard `<noun>[0]: (none)` empty state
- [ ] Fixture-server tests cover both types, cross-repo results being filtered out, and the missing-query validation
- [ ] End-to-end tests run `search issues` and `search prs` against a live Gitea instance and assert real matches are returned with the locator schema, confirming the live search-endpoint response shape and the `type`/`owner`/`q` query behavior the fixture server cannot attest to
- [x] `search issues "<query>"` and `search prs "<query>"` query the search endpoint with the right `type` and owner, then filter to the current repo client-side
- [x] The count line reports `count: N of T total` with `T` from the client-side-filtered set
- [x] A missing query yields `VALIDATION_ERROR` (exit 2)
- [x] `--state`, `--label`, `--limit`, and `--fields` work; default fields are the locator schema
- [x] Empty results emit the standard `<noun>[0]: (none)` empty state
- [x] Fixture-server tests cover both types, cross-repo results being filtered out, and the missing-query validation
- [x] End-to-end tests run `search issues` and `search prs` against a live Gitea instance and assert real matches are returned with the locator schema, confirming the live search-endpoint response shape and the `type`/`owner`/`q` query behavior the fixture server cannot attest to
## Implementation Notes
- Both variants live in one `src/commands/search.ts`, parameterised by a `SearchKind` config (`type`, output `noun`, the `view` command a match feeds into, and `--help` text) — the same config-object dispatch used elsewhere (`pr.ts`'s `DependencyGroup`).
`search issues` and `search prs` share the endpoint call, the client-side repo filter, and the render, differing only in that config.
- The repo filter is *always* client-side (the endpoint has no repo-name param), so every call fully paginates via `fetchAllPages` and then filters to the current repo by matching each result's `repository.owner`/`repository.name` case-insensitively.
The count-line total `T` is the filtered set's own size, so the endpoint's cross-repo `X-Total-Count` is never used — the ADR 0005 client-side-filtering rule.
- `--limit` caps the shown rows *after* filtering while `T` keeps the full filtered total, matching `pr list`'s client-filter behaviour.
- `--label` is passed straight through as the endpoint's `labels` param (comma-separated names): the search endpoint takes names directly, so there is no name→id lookup, unlike `pr list --label`.
- The `--fields` extra-field vocabulary (`body`, `closedAt`, `labels`, `milestone`, `updatedAt`, `url`) mirrors `issue list`'s, since search results are Issue-shaped for both types.
- Added, beyond the bare acceptance criteria, ordinary CLI hygiene consistent with the sibling commands: a `search` group help, per-variant `--help` text, an unknown-subcommand `VALIDATION_ERROR`, a too-many-positionals rejection, and top-level-help entries in `cli.ts`.