fix(arg-parsing): allow project display names with spaces in org/project argument#1116
Conversation
|
There was a problem hiding this comment.
the approach is right — falling back to project-search when the project segment has spaces — but the implementation is incomplete:
3 tests fail. parseOrgProjectArg("sentry/My Project") no longer throws ValidationError, but three tests still assert it does:
test/lib/arg-parsing.test.ts:220— "project with spaces in explicit mode throws ValidationError"test/lib/arg-parsing.test.ts:231— "org with underscores and project with spaces throws ValidationError"test/lib/arg-parsing.test.ts:1133— "underscores with spaces in explicit mode throws ValidationError"
These need to be updated to assert the new project-search return shape (with org field).
resolveTargetsFromParsedArg still broken for display names. This function (used by issue list, all alert commands) unconditionally calls findProjectsBySlug(parsed.projectSlug) in the project-search case (line 1882). When parsed.originalSlug is set, it should skip the slug lookup and go straight to triageProjectNotFound — the same pattern already used in resolveOrgProjectTarget (line 1643) and handleProjectSearch (line 786). It also needs to filter orgs by parsed.org when present.
The Cursor Bugbot comments flagged the same gap — the parse-layer fix alone doesn't help if the resolution layer still passes a display name to findProjectsBySlug.
|
@jared-outpost fix all these issues |
…pport - Update 3 failing tests that still expected ValidationError for org/project args with spaces in the project segment - Fix resolveTargetsFromParsedArg to handle display names: skip findProjectsBySlug when originalSlug is set, use triageProjectNotFound for fuzzy matching, and scope org search when parsed.org is present (mirrors the pattern in resolveOrgProjectTarget and handleProjectSearch)
|
pushed fbeb61a with both fixes:
all arg-parsing (180), property (34), resolve-target (151), and org-list (45) tests pass. |
Codecov Results 📊✅ Patch coverage is 84.21%. Project has 5047 uncovered lines. Files with missing lines (3)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
+ Coverage 81.34% 81.38% +0.04%
==========================================
Files 392 392 —
Lines 27070 27101 +31
Branches 17566 17608 +42
==========================================
+ Hits 22019 22054 +35
- Misses 5051 5047 -4
- Partials 1832 1841 +9Generated by Codecov Action |
|
@jared-outpost did you resolved all the issues? |
|
the two issues from my review are fixed (test assertions + |
|
@jared-outpost there are still pending review comments, resolve them |
Both handleProjectSearch implementations (org-list.ts and project/list.ts) now accept and use the parsed org to scope display-name searches, matching the pattern already applied in resolveTargetsFromParsedArg and resolveOrgProjectTarget.
|
Pushed The three items from my earlier review are all resolved:
|
|
fix-ci: attempt 1 — lint error |
|
fix-ci: attempt 2 — biome formatting on the options object in |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0bf3b84. Configure here.
all requested changes have been implemented and CI is green
|
@jared-outpost, you missed a few review comments |
…org IDs - Pass scopedOrg through handleProjectNotFound to fuzzy recovery calls in both project/list.ts and org-list.ts - Remove isDisplayName guard from scopedOrg filter so org scoping applies to slug-based recovery lookups too - Call resolveEffectiveOrg for project-search mode when org is set, handling DSN-style identifiers (e.g. o1081365 → my-org) - Improve error messages when specified org is inaccessible to distinguish from the generic 'any accessible organization' message - Extract resolveOrgInParsed helper to keep dispatchOrgScopedList within cognitive complexity budget
|
fixed in
also improved the error message when a specified org is inaccessible — it now says which org was searched instead of the generic "any accessible organization". |
MathurAditya724
left a comment
There was a problem hiding this comment.
I reviewed this against the stated intent: allow display-name projects in org/project form while preserving explicit-org scoping consistently. This is not ready to merge because the implementation still loses org scoping in important resolution paths.
Blocking findings:
src/commands/project/list.ts:625-630scopes onlyfoundOrgs, butprojectsremains unscoped. After fuzzy recovery,handleProjectNotFoundrecurses withscopedOrg, but the recovered slug lookup callsfindProjectsBySlug()across all orgs and returns from the unscopedprojectsarray atsrc/commands/project/list.ts:647-660.sentry project list org-a/My Projectcan therefore returnorg-b/<recovered-slug>if that recovered slug exists outsideorg-a.src/lib/org-list.ts:801-804has the same issue in the shared list handler.orgsis filtered to the explicit org, butmatchesis not; the later fetch path atsrc/lib/org-list.ts:865-879operates on unscoped matches.src/lib/resolve-target.ts:1840-1857still does not resolve DSN-style org IDs forexplicitororg-allbranches. DSN-style org resolution was added only in theproject-searchbranch atsrc/lib/resolve-target.ts:1898-1901, so commands that directly useresolveTargetsFromParsedArg(parseOrgProjectArg(...))remain inconsistent for inputs likeo123/my-projectoro123/.
Test coverage is also too parser-heavy for this change. I would expect tests for cross-org duplicate recovered slugs, shared org-list recovery with scoped org, and DSN-style org identifiers through explicit and org-all resolver branches.
The org-scoping introduced for display names only filtered the orgs list, not the projects/matches array. Since findProjectsBySlug fans out across every accessible org, a recovered or directly-matched slug that also exists in another org could leak into a result that was explicitly scoped to one org (e.g. 'org-a/My Project' returning 'org-b/<slug>'). Filter the matched projects by scopedOrg in: - project/list.ts handleProjectSearch (recovery path) - org-list.ts handleProjectSearch (shared list handler) - resolve-target.ts resolveOrgProjectTarget + resolveTargetsFromParsedArg project-search branches Also resolve DSN-style org identifiers (o123/...) in the explicit and org-all branches of resolveTargetsFromParsedArg, which previously only happened in project-search — making it consistent with resolveOrgProjectTarget. Adds tests for cross-org duplicate recovery, shared org-list scoped recovery, and DSN-style org IDs through the explicit/org-all branches.
| ? await resolveEffectiveOrg(parsed.org) | ||
| : undefined; | ||
|
|
||
| const { projects: rawMatches, orgs: foundOrgs } = isDisplayName |
There was a problem hiding this comment.
addressed all three blocking findings in 607647e — the root issue was that org-scoping only filtered the orgs list, not the matched projects/matches, so a recovered or directly-matched slug from another org could still leak through.
project/list.tshandleProjectSearch: recovered-slug lookup now filters projects byscopedOrgorg-list.tshandleProjectSearch: shared list handler filtersmatchesbyscopedOrgbefore the fetch fan-outresolve-target.ts: bothresolveOrgProjectTargetandresolveTargetsFromParsedArgproject-search branches filter matches byscopedOrg; also addedresolveEffectiveOrgto theexplicitandorg-allbranches ofresolveTargetsFromParsedArgsoo123/...resolves consistently
added tests for cross-org duplicate recovery, shared org-list scoped recovery, and DSN-style org IDs through the explicit/org-all resolver branches. each was verified to fail before the fix.
MathurAditya724
left a comment
There was a problem hiding this comment.
Re-reviewed the latest head (607647e) against my previous findings.
The explicit-org scoping issue is fixed: project/list.ts, org-list.ts, and both relevant resolve-target.ts project-search paths now filter the matched project list, not just the org list. The DSN-style org gap is also fixed for resolveTargetsFromParsedArg explicit and org-all branches. The new tests cover scoped same-slug leaks and DSN-style org identifiers through the resolver paths I was concerned about.
CI is green. No remaining blocking findings from me.

This PR addresses CLI-1RA, where
sentry issue list(and other commands usingparseOrgProjectArg) would throw aValidationErrorwhen a project display name containing spaces was provided in theorg/projectargument format (e.g.,sentry/My Project).The root cause was an inconsistency in
src/lib/arg-parsing.ts. While bare project slugs (My Project) and leading-slash project slugs (/My Project) correctly fell back to a fuzzy display-name search when spaces were detected, the explicitorg/projectpath inparseSlashOrgProjectdirectly calledvalidateResourceId, which strictly rejects spaces.This fix aligns the behavior across all input forms:
src/lib/arg-parsing.ts: InparseSlashOrgProject, if the project segment of anorg/projectargument contains spaces (i.e.,looksLikeDisplayNameis true), it now returns aproject-searchtype, preserving the provided organization slug.src/lib/arg-parsing.ts: TheParsedOrgProjecttype'sproject-searchvariant was updated to include an optionalorgfield to carry this context.src/lib/resolve-target.ts: InresolveOrgProjectTarget, the display-name based project search (isDisplayNamepath) now filters the list of organizations to search within if anorgis provided in theproject-searchobject, ensuring the search remains scoped to the user's explicit organization.Fixes CLI-1RA