You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: improve argument parsing for common user mistakes (#363)
## Fix ResolutionError UX: Argument Swapping + Smarter Fallbacks
Fixes CLI-BG, CLI-BB, CLI-BA, CLI-B9, CLI-B8
Users hit `ResolutionError`s because the CLI misinterprets their input
in several common scenarios:
| Issue | User Input | Root Cause |
|-------|-----------|------------|
| CLI-BG | `sentry log view a9b4ad2c mv-software/mvsoftware` | Args
reversed (ID first, target second) |
| CLI-B8 | `sentry event view CAM-82X 95fd7f5a` | First arg is issue
short ID, not a target |
| CLI-BB | `sentry issue view org/project/101149101` | Multi-slash
parsed incorrectly |
| CLI-BA | `sentry issues techdoctor-inc/selfbase_admin_backend` |
Underscores in project slug |
| CLI-B9 | `sentry issue list kaiko-systems-gmbh` | Bare org slug
misinterpreted as project-search |
### Changes
1. **Argument swap detection** — `detectSwappedViewArgs()` detects when
users reverse `<target> <id>` ordering in view commands. Auto-corrects
with a warning.
2. **Underscore normalization** — `normalizeSlug()` converts underscores
to dashes at the parsing layer since Sentry slugs never contain
underscores.
3. **Multi-slash issue arg** — `parseMultiSlashIssueArg()` correctly
splits `org/project/issueId` instead of producing a broken suffix.
4. **Org-as-project auto-redirect** — When a bare slug matches an
organization (not a project), list commands auto-redirect to org-all
mode. View commands show a clear "is an organization, not a project"
error. Refactored `findProjectsBySlug` to return `{ projects, orgs }` to
avoid double API calls.
5. **Issue short ID detection** — Suggests `sentry issue view X` when
the first arg in event/log/trace view matches the issue short ID pattern
(e.g., `CAM-82X`).
6. **Removed `stderr` threading** — Replaced all `stderr.write()` usage
in resolve-target and view commands with Consola logger (`log.warn()`),
simplifying function signatures.
### Tests
- 35 new unit + property tests for helpers (`normalizeSlug`,
`looksLikeIssueShortId`, `detectSwappedViewArgs`, underscore
normalization, multi-slash parsing)
- Updated 12 existing test files to accommodate return type and
signature changes
- All 2738 unit tests pass
* **All view subcommands should use \<target> \<id> positional pattern**: All \`\* view\` subcommands (\`event view\`, \`log view\`, \`trace view\`, etc.) should follow a consistent \`\<target> \<id>\` positional argument pattern where target is the optional \`org/project\` specifier. During migration, use opportunistic argument swapping with a stderr warning when the user provides args in the wrong order. This follows the CLI UX auto-correction pattern: safe when input is already invalid, no ambiguity, and warning goes to stderr.
* **Raw markdown output for non-interactive terminals, rendered for TTY**: Markdown-first output pipeline: custom renderer in \`src/lib/formatters/markdown.ts\` walks \`marked\` tokens to produce ANSI-styled output. Commands build CommonMark using helpers (\`mdKvTable()\`, \`mdRow()\`, \`colorTag()\`, \`escapeMarkdownCell()\`, \`safeCodeSpan()\`) and pass through \`renderMarkdown()\`. \`isPlainOutput()\` precedence: \`SENTRY\_PLAIN\_OUTPUT\` > \`NO\_COLOR\` > \`FORCE\_COLOR\` > \`!isTTY\`. \`--json\` always outputs JSON. Colors defined in \`COLORS\` object in \`colors.ts\`. Tests run non-TTY so assertions match raw CommonMark; use \`stripAnsi()\` helper for rendered-mode assertions.
* **whoami should be separate from auth status command**: The \`sentry auth whoami\` command should be a dedicated command separate from \`sentry auth status\`. They serve different purposes: \`status\` shows everything about auth state (token, expiry, defaults, org verification), while \`whoami\` just shows user identity (name, email, username, ID) by fetching live from \`/auth/\` endpoint. \`sentry whoami\` should be a top-level alias (like \`sentry issues\` → \`sentry issue list\`). \`whoami\` should support \`--json\` for machine consumption and be lightweight — no credential verification, no defaults listing.
* **Use -t (not -p) as shortcut alias for --period flag**: The --period flag on issue list uses -t (for 'time period') as its short alias, not -p. The rationale: -p could be confused with --platform from other CLI tools/contexts. -t maps naturally to 'time period' and avoids collision. This was a deliberate choice after initial implementation used -p.
* **Branch naming and commit message conventions for Sentry CLI**: Branch naming: \`feat/\<short-description>\` or \`fix/\<issue-number>-\<short-description>\` (e.g., \`feat/ghcr-nightly-distribution\`, \`fix/268-limit-auto-pagination\`). Commit message format: \`type(scope): description (#issue)\` (e.g., \`fix(issue-list): auto-paginate --limit beyond 100 (#268)\`, \`feat(nightly): distribute via GHCR instead of GitHub Releases\`). Types seen: fix, refactor, meta, release, feat. PRs are created as drafts via \`gh pr create --draft\`. Implementation plans are attached to commits via \`git notes add\` rather than in PR body or commit message.
* **PR workflow: wait for Seer and Cursor BugBot before resolving**: After pushing a PR in the getsentry/cli repo, the CI pipeline includes Seer Code Review and Cursor Bugbot as advisory checks. Both typically take 2-3 minutes but may not trigger on draft PRs — only ready-for-review PRs reliably get bot reviews. The workflow is: push → wait for all CI (including npm build jobs which test the actual bundle) → check for inline review comments from Seer/BugBot → fix if needed → repeat. Use \`gh pr checks \<PR> --watch\` to monitor. Review comments are fetched via \`gh api repos/OWNER/REPO/pulls/NUM/comments\` and \`gh api repos/OWNER/REPO/pulls/NUM/reviews\`.
* **Codecov patch coverage only counts test:unit and test:isolated, not E2E**: CI coverage merges \`test:unit\` (\`test/lib test/commands test/types --coverage\`) and \`test:isolated\` (\`test/isolated --coverage\`) into \`coverage/merged.lcov\`. E2E tests (\`test/e2e\`) are NOT included in coverage reports. So func tests that spy on exports (e.g., \`spyOn(apiClient, 'getLogs')\`) give zero coverage to the mocked function's body. To cover \`api-client.ts\` function bodies in unit tests, mock \`globalThis.fetch\` + \`setOrgRegion()\` + \`setAuthToken()\` and call the real function.
0 commit comments