Skip to content

Commit 995fd40

Browse files
feat(list): add pagination and consistent target parsing to all list commands (#262)
## Summary Extends the pagination and flexible target parsing pattern introduced in #221 for \`project list\` to all remaining list commands: \`issue list\`, \`team list\`, \`repo list\`, \`trace list\`, and \`log list\`. Also introduces a shared \`dispatchOrgScopedList\` infrastructure that all four list commands now use. ## Changes ### Shared infrastructure - **\`src/lib/arg-parsing.ts\`**: Added \`validateLimit(value, min, max)\` — shared limit validation, replaces duplicate implementations in \`trace/list.ts\` and \`log/list.ts\` - **\`src/lib/resolve-target.ts\`**: Added \`resolveOrgsForListing()\` (deduplicates identical logic from \`team/list.ts\` and \`repo/list.ts\`), \`resolveOrgProjectTarget()\`, and \`resolveOrgProjectFromArg()\` — replaces local \`resolveTraceTarget\`/\`resolveLogTarget\` in trace/log commands - **\`src/lib/api-client.ts\`**: Added \`listIssuesPaginated()\`, \`listTeamsPaginated()\`, \`listRepositoriesPaginated()\`, \`listProjectTeams()\` using \`orgScopedRequestPaginated()\` for cursor-based pagination with Link header support - **\`src/lib/org-list.ts\`**: New shared dispatch infrastructure — \`ListCommandMeta\`, \`OrgListConfig\`, \`ModeHandlerMap\`, \`dispatchOrgScopedList\` — all list commands use this - **\`src/lib/list-command.ts\`**: Shared Stricli parameter constants and \`buildOrgListCommand\` factory for simple org-scoped commands ### Command changes | Command | What changed | |---|---| | \`issue list\` | Added \`--cursor/-c\` flag; org-all mode now uses \`listIssuesPaginated\` and returns \`{ data, hasMore, nextCursor? }\` in JSON output | | \`team list\` | Full rewrite: 4-mode handler via \`dispatchOrgScopedList\`, \`--cursor/-c\` flag, project-scoped team listing via \`listProjectTeams\` for \`org/project\` mode | | \`repo list\` | Full rewrite: 4-mode handler via \`dispatchOrgScopedList\`, \`--cursor/-c\` flag, org-scoped fallback with note for \`org/project\` mode | | \`project list\` | Migrated to \`dispatchOrgScopedList\` with mode overrides (no behavior change) | | \`trace list\` | Replaced local \`resolveTraceTarget\` + \`validateLimit\` with shared versions from \`resolve-target.ts\` / \`arg-parsing.ts\` | | \`log list\` | Replaced local \`resolveLogTarget\` + \`validateLimit\` with shared versions from \`resolve-target.ts\` / \`arg-parsing.ts\` | ### Tests - \`test/commands/team/list.test.ts\`: Covers all 4 modes including project-scoped team listing and bare-slug project search - \`test/commands/repo/list.test.ts\`: Covers all 4 modes including bare-slug project search with org-scoped fallback - \`test/lib/org-list.test.ts\`: 36 tests covering the shared dispatch infrastructure - \`test/e2e/issue.test.ts\`: Updated org-all JSON output assertion to match new \`{ data, hasMore }\` shape ## Behavior notes - **\`issue list\` org-all JSON output shape changed**: was a plain array \`[...]\`, now \`{ data: [...], hasMore: bool, nextCursor?: string }\` — consistent with \`project list\` - **Target parsing convention**: org-all mode requires a trailing slash (\`<org>/\`). A bare slug (no slash) is always treated as a project slug and triggers a cross-org project search via \`findProjectsBySlug\` — consistent across \`project list\`, \`issue list\`, \`team list\`, and \`repo list\` - **\`team list org/project\`**: fetches teams scoped to that project (via \`listProjectTeams\` endpoint) - **\`repo list org/project\`**: repos are org-scoped; shows all repos in the org with a note that the project part is ignored - All 1874 unit tests pass; typecheck and lint clean --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 7b1c9a9 commit 995fd40

File tree

27 files changed

+4736
-1218
lines changed

27 files changed

+4736
-1218
lines changed

AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ import type { SentryContext } from "../../context.js";
319319
import { getAuthToken } from "../../lib/config.js";
320320
```
321321
322+
### List Command Infrastructure
323+
324+
Two abstraction levels exist for list commands:
325+
326+
1. **`src/lib/list-command.ts`** — `buildOrgListCommand` factory + shared Stricli parameter constants (`LIST_TARGET_POSITIONAL`, `LIST_JSON_FLAG`, `LIST_CURSOR_FLAG`, `buildListLimitFlag`). Use this for simple entity lists like `team list` and `repo list`.
327+
328+
2. **`src/lib/org-list.ts`** — `dispatchOrgScopedList` with `OrgListConfig` and a 4-mode handler map: `auto-detect`, `explicit`, `org-all`, `project-search`. Complex commands (`project list`, `issue list`) call `dispatchOrgScopedList` with an `overrides` map directly instead of using `buildOrgListCommand`.
329+
330+
Key rules when writing overrides:
331+
- Each mode handler receives a `HandlerContext<T>` with the narrowed `parsed` plus shared I/O (`stdout`, `cwd`, `flags`). Access parsed fields via `ctx.parsed.org`, `ctx.parsed.projectSlug`, etc. — no manual `Extract<>` casts needed.
332+
- Commands with extra fields (e.g., `stderr`, `setContext`) spread the context and add them: `(ctx) => handle({ ...ctx, flags, stderr, setContext })`. Override `ctx.flags` with the command-specific flags type when needed.
333+
- `resolveCursor()` must be called **inside** the `org-all` override closure, not before `dispatchOrgScopedList`, so that `--cursor` validation errors fire correctly for non-org-all modes.
334+
- `handleProjectSearch` errors must use `"Project"` as the `ContextError` resource, not `config.entityName`.
335+
322336
## Commenting & Documentation (JSDoc-first)
323337
324338
### Default Rule

plugins/sentry-cli/skills/sentry-cli/SKILL.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,10 @@ List issues in a project
194194

195195
**Flags:**
196196
- `-q, --query <value> - Search query (Sentry search syntax)`
197-
- `-n, --limit <value> - Maximum number of issues to return - (default: "10")`
197+
- `-n, --limit <value> - Maximum number of issues to list - (default: "10")`
198198
- `-s, --sort <value> - Sort by: date, new, freq, user - (default: "date")`
199-
- `--json - Output as JSON`
199+
- `--json - Output JSON`
200+
- `-c, --cursor <value> - Pagination cursor — only for <org>/ mode (use "last" to continue)`
200201

201202
**Examples:**
202203

@@ -433,25 +434,27 @@ Update the Sentry CLI to the latest version
433434

434435
Work with Sentry repositories
435436

436-
#### `sentry repo list <org>`
437+
#### `sentry repo list <target>`
437438

438439
List repositories
439440

440441
**Flags:**
441442
- `-n, --limit <value> - Maximum number of repositories to list - (default: "30")`
442443
- `--json - Output JSON`
444+
- `-c, --cursor <value> - Pagination cursor (use "last" to continue from previous page)`
443445

444446
### Team
445447

446448
Work with Sentry teams
447449

448-
#### `sentry team list <org>`
450+
#### `sentry team list <target>`
449451

450452
List teams
451453

452454
**Flags:**
453455
- `-n, --limit <value> - Maximum number of teams to list - (default: "30")`
454456
- `--json - Output JSON`
457+
- `-c, --cursor <value> - Pagination cursor (use "last" to continue from previous page)`
455458

456459
**Examples:**
457460

@@ -581,9 +584,10 @@ List issues in a project
581584

582585
**Flags:**
583586
- `-q, --query <value> - Search query (Sentry search syntax)`
584-
- `-n, --limit <value> - Maximum number of issues to return - (default: "10")`
587+
- `-n, --limit <value> - Maximum number of issues to list - (default: "10")`
585588
- `-s, --sort <value> - Sort by: date, new, freq, user - (default: "date")`
586-
- `--json - Output as JSON`
589+
- `--json - Output JSON`
590+
- `-c, --cursor <value> - Pagination cursor — only for <org>/ mode (use "last" to continue)`
587591

588592
### Orgs
589593

@@ -615,25 +619,27 @@ List projects
615619

616620
List repositories
617621

618-
#### `sentry repos <org>`
622+
#### `sentry repos <target>`
619623

620624
List repositories
621625

622626
**Flags:**
623627
- `-n, --limit <value> - Maximum number of repositories to list - (default: "30")`
624628
- `--json - Output JSON`
629+
- `-c, --cursor <value> - Pagination cursor (use "last" to continue from previous page)`
625630

626631
### Teams
627632

628633
List teams
629634

630-
#### `sentry teams <org>`
635+
#### `sentry teams <target>`
631636

632637
List teams
633638

634639
**Flags:**
635640
- `-n, --limit <value> - Maximum number of teams to list - (default: "30")`
636641
- `--json - Output JSON`
642+
- `-c, --cursor <value> - Pagination cursor (use "last" to continue from previous page)`
637643

638644
### Logs
639645

0 commit comments

Comments
 (0)