fix(project-list): add pagination and flexible target parsing#221
Conversation
Semver Impact of This PR🟢 Patch (bug fixes) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Build
Other
Bug Fixes 🐛Telemetry
Other
Internal Changes 🔧
🤖 This preview updates automatically when you update the PR. |
Codecov Results 📊✅ Patch coverage is 86.87%. Project has 3963 uncovered lines. Files with missing lines (71)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
+ Coverage 69.12% 71.21% +2.09%
==========================================
Files 110 111 +1
Lines 13362 13764 +402
Branches 0 0 —
==========================================
+ Hits 9236 9801 +565
- Misses 4126 3963 -163
- Partials 0 0 —Generated by Codecov Action |
d09e97c to
8ca6cff
Compare
- Follow API cursor pagination so --limit >100 actually works - Add org/ prefix syntax to list projects for a specific org - Add org/project syntax to show a single project directly - Add --cursor/--prev flags for manual page navigation - Add pagination_cursors table (schema v5) with composite PK - Cache cursors per (command_key, context) for independent paging - Clear pagination cursors on auth logout - Regenerate SKILL.md for updated command help
- Property-based tests for parseLinkHeader (RFC 5988 Link header parsing) - Model-based tests for pagination cursor storage (composite PK, TTL, upsert) - Unit + property tests for project list helpers (buildContextKey, filterByPlatform, resolveCursor) - Handler tests for handleExplicit, handleOrgAll, handleProjectSearch with fetch mocking - Verify clearAuth cross-cutting invariant clears pagination cursors - Export parseLinkHeader and project list helpers for testability
…ONFIG_DIR Falls back to creating a temp directory when the env var is not set, which can happen due to test file ordering and worker isolation in CI.
…AutoDetect - Test displayProjectTable (table formatting orchestrator) - Test fetchOrgProjects (attaches orgSlug context) - Test fetchOrgProjectsSafe (swallows non-auth errors, propagates AuthError) - Test fetchAllOrgProjects (fans out across orgs, skips access errors) - Test handleAutoDetect (auto-detect mode with platform filter, limit, JSON output) - Export additional functions from list.ts for testability
Address review comments: - Use single-page listProjectsPaginated for single-org auto-detect without platform filter, avoiding unnecessary full pagination (up to 5000 items) - Remove no-op identity mapping in handleProjectSearch
…-duplicate ProjectWithOrg Address review comments: - Track hasMore from listProjectsPaginated response in auto-detect fast path so truncation message appears when server has more results - Make ProjectWithOrg in list.ts private to eliminate duplicate exported type with conflicting orgSlug optionality (canonical export in api-client.ts)
…earch handleProjectSearch now shows 'No project X found matching platform Y' when projects exist but are filtered out, matching handleExplicit behavior. Previously it misleadingly said 'No project X found in any accessible org.'
…ojects findProjectsBySlug now calls getProject(org, slug) per org (1 API call each) instead of listProjects which auto-paginates up to 50 pages per org. For a user with 5 orgs, this reduces worst-case from ~250 API calls to 5.
… listProjects
Tests now mock /projects/{org}/{slug}/ (direct lookup) instead of
/organizations/{org}/projects/ (list all) to match the implementation change.
Add compositePrimaryKey field to TableSchema so columnDefsToDDL can emit table-level PRIMARY KEY constraints. This eliminates all special-casing for pagination_cursors: CUSTOM_DDL_TABLES, PAGINATION_CURSORS_DDL, repairPaginationCursorsTable, and the hand-written DDL in test files. Net -67 lines of code removed.
…message - Lowercase platform in buildContextKey so --platform Python and --platform python resolve to the same cursor cache entry - When platform filter produces no results and there are no more pages, show "No projects matching platform 'X'" instead of the misleading "No projects found in organization"
…pollution Three test files (version-check, install-info, project-cache) were deleting process.env.SENTRY_CONFIG_DIR in afterEach without saving the original value set by preload.ts. When Bun's test runner shares a process across files, this poisons the env for subsequent tests that capture the var at module load time.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
When --platform is active in org-all mode, the next-page hints now include the flag so that following the hint preserves the filter and matches the correct cursor context key.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
…orrectly - Extract fetchPaginatedSafe() to handle non-auth API errors (403, network) in the single-org fast path, matching fetchOrgProjectsSafe behavior. Reduces handleAutoDetect complexity below lint threshold. - Fix createIsolatedDbContext cleanup to restore original env var value (including undefined) instead of leaking fallback path. - Add tests for fast-path error handling (non-auth swallowed, AuthError propagated).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
…nation-v2 # Conflicts: # test/lib/db/install-info.test.ts # test/lib/db/project-cache.test.ts # test/lib/version-check.test.ts
b576c7a to
1085d5a
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
…nation-v2 # Conflicts: # src/lib/api-client.ts # src/lib/region.ts
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
findProjectsBySlug now uses getProject (SDK retrieveAProject) per org
instead of listing all projects. The mock was returning an array for
the /projects/{org}/{project}/ endpoint, causing the SDK to parse it
incorrectly. Return 404 for non-existent project detail requests.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Remove dead fallback code for missing SENTRY_CONFIG_DIR (preload.ts always sets it) and the 'delete process.env' pattern that violates AGENTS.md rules.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Include the Sentry base URL in buildContextKey so cursors from different instances (SaaS vs self-hosted) are never mixed when multiple logins are supported.
Auto-detect mode now wraps JSON output in a {data, hasMore, hint}
envelope so JSON consumers can detect truncation. When results are
incomplete, the hint field tells consumers which paginated command
to use for full results.
Also extracted fetchAutoDetectProjects helper to reduce function
complexity.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
The API endpoint accepts project_id_or_slug, so numeric inputs could resolve by ID and return a project with a different slug. Add a post-fetch check to ensure the returned project actually matches the requested slug.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
…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>
Summary
Fixes three bugs in
sentry project list:--cursor/-cflag with alastmagic value that resumes from where you left off.-n 200still capped at 100 because the Sentry API paginates and we never followed cursor links. AddedorgScopedPaginateAll()solistProjects()transparently fetches all pages.project list sentry/sentrysaid "No projects found in organization 'sentry/sentry'" — now usesparseOrgProjectArg()(same asissue list) to handleorg/project,org/, and bare-word targets.Changes
src/lib/api-client.ts— Pagination infrastructurePaginatedResponse<T>type,parseLinkHeader(),orgScopedRequestPaginated(),orgScopedPaginateAll()listProjects()now auto-paginates transparently (all 6 callers unchanged)listProjectsPaginated()for explicit single-page fetches with cursor controlsrc/commands/project/list.ts— Rewritten commandauto-detect,explicit(org/project),org-all(org/),project-search(bare slug)--cursor/-cflag withlastmagic value for easy page navigation{ data, nextCursor?, hasMore }in paginated modesrc/lib/db/schema.ts— Schema v6pagination_cursorstable for cursor cachingsrc/lib/db/pagination.ts— New moduleTests
test/e2e/project.test.tsandtest/e2e/multiregion.test.tsfor neworg/syntax and paginated JSON format