Skip to content

feat(args): parse Sentry web URLs as CLI arguments#252

Merged
BYK merged 5 commits intomainfrom
byk/url-parsing
Feb 16, 2026
Merged

feat(args): parse Sentry web URLs as CLI arguments#252
BYK merged 5 commits intomainfrom
byk/url-parsing

Conversation

@BYK
Copy link
Member

@BYK BYK commented Feb 16, 2026

Summary

  • Users can now paste Sentry web URLs directly as CLI arguments (e.g., sentry issue view https://sentry.example.com/organizations/my-org/issues/32886/?project=2) instead of manually extracting org/project/issue IDs
  • Supports both SaaS (sentry.io) and self-hosted instances — self-hosted URLs automatically configure SENTRY_URL for the session
  • Fixes frozen module-level constants in oauth.ts and sentry-client.ts that prevented dynamic URL detection from working

URL Patterns Supported

Pattern Used By
/organizations/{org}/issues/{id}/ issue view, issue explain, issue plan
/organizations/{org}/issues/{id}/events/{eventId}/ event view
/settings/{org}/projects/{project}/ project view, project list
/organizations/{org}/traces/{traceId}/ trace view
/organizations/{org}/ org-scoped commands

Changes

New Files

  • src/lib/sentry-url-parser.ts — Pure URL parser (parseSentryUrl) + self-hosted env config (applySentryUrlContext)
  • test/lib/sentry-url-parser.test.ts — 30 unit tests covering all URL patterns, edge cases, and env var behavior
  • test/lib/sentry-url-parser.property.test.ts — Round-trip property tests verifying URLs built by sentry-urls.ts can be parsed back

Modified Files

  • src/lib/arg-parsing.ts — URL pre-parsing in parseIssueArg() and parseOrgProjectArg()
  • src/commands/event/view.ts — URL handling in parsePositionalArgs() for event URLs
  • src/lib/oauth.ts — Replaced frozen const SENTRY_URL with lazy getSentryUrl() function
  • src/lib/sentry-client.ts — Removed frozen const CONTROL_SILO_URL, made getControlSiloUrl() read env var lazily

Test Updates

  • test/lib/arg-parsing.test.ts — Added URL integration tests for both parsers
  • test/commands/event/view.test.ts — Added event URL handling tests

Fixes

Resolves CLI-66 (self-hosted users get confusing errors when pasting URLs)

@github-actions
Copy link
Contributor

github-actions bot commented Feb 16, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Build

  • Add hole-punch tool to reduce compressed binary size by BYK in #245
  • Add gzip-compressed binary downloads by BYK in #244

Other

  • (args) Parse Sentry web URLs as CLI arguments by BYK in #252

Bug Fixes 🐛

Telemetry

  • Reduce noise from version-check JSON parse errors by BYK in #253
  • Skip Sentry reporting for 4xx API errors by BYK in #251
  • Handle EPIPE errors from piped stdout gracefully by BYK in #250
  • Upgrade Sentry SDK to 10.39.0 and remove custom patches by BYK in #249

Other

  • (polyfill) Add exited promise and stdin to Bun.spawn Node.js polyfill by BYK in #248
  • (upgrade) Remove v prefix from release URLs and work around Bun.write streaming bug by BYK in #243

Internal Changes 🔧

  • (build) Replace local hole-punch script with binpunch package by BYK in #246
  • Use @sentry/api client for requests by MathurAditya724 in #226

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 16, 2026

Codecov Results 📊

✅ Patch coverage is 89.52%. Project has 4103 uncovered lines.
✅ Project coverage is 68.74%. Comparing base (base) to head (head).

Files with missing lines (71)
File Patch % Lines
human.ts 58.29% ⚠️ 395 Missing
resolve-target.ts 20.26% ⚠️ 366 Missing
list.ts 14.39% ⚠️ 345 Missing
api-client.ts 59.38% ⚠️ 262 Missing
list.ts 23.47% ⚠️ 212 Missing
oauth.ts 30.94% ⚠️ 183 Missing
list.ts 21.96% ⚠️ 167 Missing
plan.ts 19.37% ⚠️ 154 Missing
resolver.ts 3.23% ⚠️ 120 Missing
help.ts 19.85% ⚠️ 109 Missing
upgrade.ts 61.37% ⚠️ 107 Missing
view.ts 40.23% ⚠️ 104 Missing
interactive-login.ts 9.17% ⚠️ 99 Missing
errors.ts 5.94% ⚠️ 95 Missing
view.ts 25.81% ⚠️ 92 Missing
view.ts 39.44% ⚠️ 86 Missing
clipboard.ts 4.49% ⚠️ 85 Missing
status.ts 24.07% ⚠️ 82 Missing
migration.ts 47.44% ⚠️ 82 Missing
list.ts 27.18% ⚠️ 75 Missing
browser.ts 4.11% ⚠️ 70 Missing
login.ts 33.33% ⚠️ 64 Missing
span-tree.ts 5.00% ⚠️ 57 Missing
explain.ts 33.33% ⚠️ 56 Missing
api.ts 89.80% ⚠️ 47 Missing
upgrade.ts 66.91% ⚠️ 46 Missing
seer.ts 75.54% ⚠️ 45 Missing
schema.ts 89.56% ⚠️ 40 Missing
refresh.ts 40.63% ⚠️ 38 Missing
seer.ts 79.87% ⚠️ 30 Missing
preload.ts 53.23% ⚠️ 29 Missing
view.ts 87.27% ⚠️ 28 Missing
utils.ts 88.94% ⚠️ 25 Missing
view.ts 61.54% ⚠️ 25 Missing
detector.ts 90.10% ⚠️ 20 Missing
arg-parsing.ts 89.29% ⚠️ 18 Missing
binary.ts 88.67% ⚠️ 17 Missing
list.ts 91.16% ⚠️ 16 Missing
list.ts 90.70% ⚠️ 16 Missing
code-scanner.ts 95.00% ⚠️ 16 Missing
help.ts 57.14% ⚠️ 15 Missing
telemetry.ts 95.60% ⚠️ 14 Missing
sentry-client.ts 92.17% ⚠️ 13 Missing
dsn-cache.ts 94.62% ⚠️ 12 Missing
logout.ts 56.00% ⚠️ 11 Missing
token.ts 52.17% ⚠️ 11 Missing
fix.ts 83.61% ⚠️ 10 Missing
qrcode.ts 33.33% ⚠️ 10 Missing
fs-utils.ts 57.14% ⚠️ 9 Missing
view.ts 94.70% ⚠️ 7 Missing
project-root.ts 97.73% ⚠️ 7 Missing
version-check.ts 92.47% ⚠️ 7 Missing
feedback.ts 84.21% ⚠️ 6 Missing
auth.ts 95.52% ⚠️ 6 Missing
shell.ts 96.23% ⚠️ 6 Missing
app.ts 93.90% ⚠️ 5 Missing
region.ts 86.49% ⚠️ 5 Missing
setup.ts 97.84% ⚠️ 4 Missing
list.ts 97.33% ⚠️ 4 Missing
index.ts 95.96% ⚠️ 4 Missing
project-aliases.ts 97.40% ⚠️ 2 Missing
project-root-cache.ts 96.92% ⚠️ 2 Missing
output.ts 89.47% ⚠️ 2 Missing
alias.ts 99.42% ⚠️ 1 Missing
completions.ts 99.37% ⚠️ 1 Missing
env-file.ts 99.19% ⚠️ 1 Missing
parser.ts 98.63% ⚠️ 1 Missing
colors.ts 98.21% ⚠️ 1 Missing
trace.ts 99.16% ⚠️ 1 Missing
helpers.ts 97.62% ⚠️ 1 Missing
helpers.ts 94.74% ⚠️ 1 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    68.53%    68.74%    +0.21%
==========================================
  Files          109       110        +1
  Lines        13010     13124      +114
  Branches         0         0         —
==========================================
+ Hits          8916      9021      +105
- Misses        4094      4103        +9
- Partials         0         0         —

Generated by Codecov Action

Comment on lines 137 to 139
if (process.env.SENTRY_URL) {
return;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say the parsed URL should take precedence over any previously set env variable.

Users can now paste Sentry web URLs directly as CLI arguments instead
of manually extracting org/project/issue IDs. Supports both SaaS
(sentry.io) and self-hosted instances.

URL patterns supported:
- /organizations/{org}/issues/{id}/ (issue view/explain/plan)
- /organizations/{org}/issues/{id}/events/{eventId}/ (event view)
- /settings/{org}/projects/{project}/ (project commands)
- /organizations/{org}/traces/{traceId}/ (trace commands)
- /organizations/{org}/ (org-scoped commands)

For self-hosted URLs, automatically sets SENTRY_URL so that API calls,
OAuth device flow, and token refresh target the correct instance.

Also fixes frozen module-level constants in oauth.ts and sentry-client.ts
that captured SENTRY_URL at import time, preventing dynamic URL detection
from working.
- Event URLs no longer trigger OrgAll → ContextError; instead they
  auto-detect org/project after SENTRY_URL is set (HIGH)
- SaaS URLs now clear stale SENTRY_URL so API calls use default
  routing instead of a leftover self-hosted value (MEDIUM)
- Non-issue URLs (traces, project settings) in parseIssueArg now
  throw ValidationError instead of falling through to garbage
  slash-based parsing (LOW)
process.env.SENTRY_URL = undefined sets the string "undefined" in
Node.js (Bun handles it correctly). Use delete with a biome-ignore
to truly unset the env var when a SaaS URL is detected.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Instead of discarding the org extracted from event URLs, pass it
as OrgAll target and handle OrgAll in viewCommand by falling
through to auto-detect. This keeps the org context available while
resolving the project via DSN detection or config defaults.
@BYK BYK enabled auto-merge (squash) February 16, 2026 23:09
@BYK BYK merged commit 8aa9cf6 into main Feb 16, 2026
23 checks passed
@BYK BYK deleted the byk/url-parsing branch February 16, 2026 23:10
Comment on lines +215 to 220
// Org-only (e.g., from event URL that has no project slug).
// Fall through to auto-detect — SENTRY_URL is already set for
// self-hosted, and auto-detect will resolve the project from
// DSN, config defaults, or directory name inference.
// falls through
case ProjectSpecificationType.AutoDetect:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The event view command discards the organization parsed from an event URL, causing it to potentially fetch the event from the wrong organization based on auto-detection.
Severity: MEDIUM

Suggested Fix

In the ProjectSpecificationType.OrgAll case within src/commands/event/view.ts, pass the parsed organization to the resolveOrgAndProject function. The call should be updated to await resolveOrgAndProject({ org: parsed.org, cwd, usageHint: USAGE_HINT }) to ensure the project lookup is constrained to the correct organization.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/commands/event/view.ts#L215-L220

Potential issue: When the `event view` command is used with a full event URL, the
organization is correctly parsed from the URL but is subsequently discarded. The
`resolveOrgAndProject` function is then called without the `org` parameter. This
triggers an auto-detection mechanism that may resolve to a different organization based
on local configuration or environment variables. As a result, the command may attempt to
fetch the event from the wrong organization, leading to a failure to find the specified
event.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant