Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Trace
Other
Bug Fixes 🐛Api
Formatters
Setup
Other
Internal Changes 🔧Api
Other
🤖 This preview updates automatically when you update the PR. |
Codecov Results 📊✅ 2463 passed | Total: 2463 | Pass Rate: 100% | Execution Time: 0ms 📊 Comparison with Base Branch
All tests are passing successfully. ❌ Patch coverage is 79.82%. Project has 3226 uncovered lines. Files with missing lines (5)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
- Coverage 81.23% 81.19% -0.04%
==========================================
Files 121 123 +2
Lines 16711 17149 +438
Branches 0 0 —
==========================================
+ Hits 13574 13923 +349
- Misses 3137 3226 +89
- Partials 0 0 —Generated by Codecov Action |
BYK
left a comment
There was a problem hiding this comment.
Love that you both try to infer team and org automatically while supporting org/proj --team <team> syntax too.
See my comments and decide whether you wanna merge as it is or not. My 2 major concerns are the refactor (I may merge that before you see this) and the error when we find more than 1 team.
Add team schema/type and two new API functions needed for project
creation. Also adds TEAM_ENDPOINT_REGEX so /teams/{org}/... endpoints
route to the correct region.
Adds `sentry project create <name> <platform> [--team] [--json]`. Supports org/name syntax (like gh repo create owner/repo), auto-detects org from config/DSN, and auto-selects team when the org has exactly one. Fetches the DSN after creation so users can start sending events immediately. All error paths are actionable — wrong org lists your orgs, wrong team lists available teams, 409 links to the existing project.
When the API returns 400 for an invalid platform string, show the same helpful platform list instead of a raw JSON error body.
Replace the confusing 'Or: - Available platforms:' pattern with a cleaner 'Usage: ... Available platforms:' layout. Applies to both missing platform and invalid platform errors.
- tryGetPrimaryDsn() → api-client.ts (was duplicated in view + create) - resolveTeam() → resolve-team.ts (reusable for future team-dependent commands) - parseOrgPrefixedArg() → arg-parsing.ts (reusable org/name parsing) - writeKeyValue() for aligned key-value output in create.ts - project/view.ts now uses shared tryGetPrimaryDsn instead of local copy
The /teams/{org}/{team}/projects/ endpoint returns 404 for both a bad
org and a bad team. Previously we always blamed the team, which was
misleading when --team was explicit and the org was auto-detected wrong.
Now on 404 we call listTeams(orgSlug) to check:
- If it succeeds → team is wrong, show available teams
- If it fails → org is wrong, show user's actual organizations
Only adds an API call on the error path, never on the happy path.
The view command hint on 409 used the raw name ('My Cool App') instead
of the expected slug ('my-cool-app'), pointing to a non-existent target.
handleCreateProject404 was treating any listTeams failure as proof that the org doesn't exist. Now it checks the status code: only 404 triggers 'Organization not found'. Other failures (403, 5xx, network) get a generic message that doesn't misdiagnose the root cause.
Same class of bug as the previous fix in handleCreateProject404: resolveTeam was routing all ApiErrors from listTeams into the 'org not found' path. Now only 404 triggers that diagnosis. Other failures (403, 5xx) get a generic message that doesn't misdiagnose the cause.
- Extract shared fetchOrgListHint() in resolve-team.ts to deduplicate
org-list fetching logic (used by both resolve-team and create 404 handler)
- Use Writer type instead of inline { write } in writeKeyValue
- Simplify Awaited<ReturnType<typeof listTeams>> to SentryTeam[]
- Add fragility comment to isPlatformError (relies on API message wording)
- Fix test import to use barrel (types/index.js)
When a project slug is already taken, Sentry silently appends a random suffix (e.g., 'test1' becomes 'test1-0g'). This was confusing because the user had no indication why the slug differed from the name. Now shows: Note: Slug 'test1-0g' was assigned because 'test1' is already taken.
Previously, project create errored whenever an org had 2+ teams, requiring --team in every non-trivial org. Now filters teams by isMember and auto-selects when the user belongs to exactly one team. When multiple member teams exist, only those are shown in the error (not all org teams). Falls back to the full list when isMember data is unavailable (self-hosted, old API).
…ists handleCreateProject404 now checks if the teamSlug is actually present in the returned teams list before claiming it's not found. When the team exists (e.g., auto-selected by resolveTeam), the error correctly reports a permission issue instead of the contradictory message.
Add NFKD normalization to handle accented characters and ligatures, and preserve underscores to match Sentry's MIXED_SLUG_PATTERN.
Remove team view command and getTeam API function that were accidentally included in this branch. The code imported a non-existent buildTeamUrl, breaking typecheck. This work is preserved on feat/team-view-command. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-throw AuthError in handleCreateProject404 so auth errors propagate instead of being swallowed. Guard writeKeyValue against empty pairs to avoid Math.max(...[]) returning -Infinity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace `await` with `return` on `handleCreateProject404` and `buildOrgFailureError` calls so the `never` control flow is explicit and subsequent code is clearly unreachable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Error
ContextError means the user omitted a required value ("Organization is
required."), but buildOrgFailureError is reached when the org slug was
provided and returned a 404. Switch to ResolutionError so the message
reads "Organization 'my-org' not found." which matches the actual
scenario. Also drops the leaked internal detail about listTeams status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # src/lib/api-client.ts
…olveEffectiveOrg, UX improvements - resolveTeam now returns ResolvedTeam with source info (explicit/auto-selected/auto-created) - Auto-create team when org has zero teams (mirrors Sentry UI behavior) - Add createTeam() to api-client using @sentry/api SDK - Use resolveEffectiveOrg for DSN org ID resolution on 404 - Show team notes in output when not explicitly specified - Replace unhelpful docs.sentry.io/platforms link with inline usage hint - Add team slug to JSON output - Document 5-step flow and 6-step team resolution in JSDoc - Update tests: auto-create team test replaces error-on-no-teams test
- Rename resolveTeam → resolveOrCreateTeam (BYK review)
- Add current user as team member on auto-create via addMemberToTeam('me')
- Add addMemberToTeam() API function using @sentry/api SDK
- Fix missing await on return handleCreateProject404 (BugBot)
- Fix usageHint.replace no-op — use direct string interpolation (BugBot)
- Re-throw AuthError in autoCreateTeam to preserve auto-login flow (BugBot)
- Fix team notes: remove misleading 'Change with' command
- Auto-created: just show 'org had no teams' note
- Auto-selected: suggest 'sentry team list' instead of incorrect command
- Update test comments to match renamed function
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.
…apture Sentry exception - Deduplicate org-not-found handling: extract buildOrgNotFoundError from resolve-team.ts and reuse in handleCreateProject404 instead of duplicating with inconsistent behavior (BugBot Thread A) - Fix JSON output overwriting API team object: rename 'team' to 'teamSlug' so spreading the project response preserves the API's team object (BugBot Thread B) - Capture Sentry exception and warn user when auto-add to team fails, instead of silently swallowing the error (BYK Thread C) - Un-export fetchOrgListHint (now internal to resolve-team.ts) - Add biome-ignore for Sentry namespace import in api-client.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.
…ct404 Pass resolved.detectedFrom through createProjectWithErrors to handleCreateProject404 so buildOrgNotFoundError includes 'Org was auto-detected from...' context when the org came from DSN detection. Refactored both handleCreateProject404 and createProjectWithErrors to use options objects to stay within the 4-parameter lint limit.
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.
buildOrgNotFoundError was appending '--team <team-slug>' to the usage hint even though the error is about the org not being found. The user needs to fix the org, not the team. Now uses the base usage hint as-is.
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.
Summary
Adds
sentry project create <name> <platform>— the first write command in the CLI. Followsgh repo createconventions with org/name syntax, auto-detection of org and team, and actionable errors at every step.Changes
SentryTeamZod schema and typelistTeams()andcreateProject()API functions with region-aware routing (TEAM_ENDPOINT_REGEX)project createcommand with two required positionals,--team/-tflag, and--jsonoutputTest Plan
bun test test/commands/project/create.test.ts— 19 pass, 0 failbun run typecheck— cleanbun run lint— clean