-
-
Notifications
You must be signed in to change notification settings - Fork 6
Catch up with old sentry-cli #600
Description
Gap Analysis: Old sentry-cli (Rust) vs New Sentry CLI (Bun/TS)
Executive Summary
The two CLIs serve fundamentally different audiences:
- Old CLI: CI/CD build tool — releases, deploys, debug files, sourcemaps, cron monitors
- New CLI: Developer observability tool — issues, traces, spans, logs, dashboards, AI analysis
~60% of old CLI commands are absent from the new CLI, almost all CI/CD-oriented. However, several are legacy/niche and not worth porting. The critical gaps are releases, deploys, and sourcemap upload enhancements.
The biggest unbridgeable gap is debug-files — it depends on the symbolic Rust crate for native binary parsing (Mach-O, ELF, PDB, DWARF) which has no JS equivalent.
1. Commands Fully Present in New CLI ✅
These are at parity or exceed the old CLI:
| Old CLI | New CLI | Notes |
|---|---|---|
login |
auth login |
Better — OAuth device flow + token auth |
info |
auth status |
Better — shows defaults, token metadata, org verification |
update |
cli upgrade |
Better — delta patching, stable/nightly channels |
completions |
cli setup |
Better — auto-detects shell, installs agent skills |
organizations list |
org list |
Better — multi-region support, cached |
projects list |
project list |
Better — 4-mode dispatch, auto-detect |
repos list |
repo list |
At parity |
events list |
issue list / trace list |
Better — old CLI's event list was very limited |
New CLI features with no old CLI equivalent:
org view,project view,project create,project deleteissue view,issue explain(Seer AI),issue plan(Seer AI)event view(with full stack trace, breadcrumbs, span tree)trace list/view/logs,span list/view,log list/view(with--follow)dashboard list/view/create,dashboard widget add/edit/deleteapi(generic authenticated API requests, likegh api)schema(API schema browser)init(AI-powered project setup wizard)auth whoami,auth refresh,auth tokencli feedback,cli fixteam list,trial list/start
2. Commands Partially Present ⚠️
2a. sourcemaps inject — Missing sourceMappingURL handling
Old CLI capabilities not in new CLI:
- Scans JS file contents for
//# sourceMappingURL=...directives - Follows external sourceMappingURL references to differently-named map files
- Handles inline base64-encoded sourcemaps (
data:application/json;base64,...) sourcemaps resolvesubcommand for validating/debugging sourcemap linkage
New CLI's approach: Strictly uses file naming convention only (foo.js → foo.js.map).
| Aspect | Priority | Effort | Feasibility |
|---|---|---|---|
Follow external sourceMappingURL references |
High | M (2-3 days) | ✅ Easy — regex parse last //# sourceMappingURL= line, resolve relative path, use as map path |
| Handle inline base64 sourcemaps | Medium | M (2-3 days) | ✅ Easy — detect data: URL, base64 decode, inject debug ID into decoded JSON, re-encode. Must handle decode failures gracefully (warn + skip, per PR #3243) |
sourcemaps resolve command |
Low | S (< 1 day) | ✅ Easy — read-only validation, reuse detection logic |
Performance impact: Negligible. Reading an extra line from each JS file to check for sourceMappingURL is trivial.
Key gotcha: When adding inline base64 support, base64 decode failures MUST be non-fatal (the exact issue from PR #3243). Template literals in bundled terser/babel code produce false-positive sourceMappingURL lines.
2b. sourcemaps upload — Missing flags
Old CLI flags not in new CLI:
| Flag | Priority | Effort | Notes |
|---|---|---|---|
--dist |
High | S | Add dist field to UploadOptions and assemble body. Trivial. |
--strip-prefix |
Medium | S | String manipulation on URL paths before upload |
--strip-common-prefix |
Medium | S | Compute common prefix of all files, strip it |
--ext |
Low | S | Already exists on inject, just forward to upload flow |
--ignore / --ignore-file |
Medium | S | Use existing ignore npm dep (already in deps for gitignore patterns) |
--validate |
Low | M | Parse sourcemaps, verify mappings point to valid sources |
--no-rewrite |
Low | S | Skip debug ID injection, upload files as-is |
--no-sourcemap-reference |
Low | S | Skip Sourcemap header in manifest |
--strict |
Low | S | Error on warnings instead of continuing |
--wait |
Low | S | Already waits by default (polls assemble); this would be a no-op or add --no-wait |
--decompress |
Low | S | Decompress .gz files before upload |
2c. issues — Missing mutations
Old CLI: issues mute, issues resolve, issues unresolve
New CLI: Has updateIssueStatus() API function already in src/lib/api/issues.ts — just needs command wrappers.
| Command | Priority | Effort | Notes |
|---|---|---|---|
issue resolve <id> |
High | S (hours) | API exists, just needs command + formatter |
issue unresolve <id> |
High | S (hours) | Same |
issue mute <id> |
Medium | S (hours) | Same, may want --duration flag |
3. Commands Completely Absent ❌
3a. Release Management — Critical Gap 🔴
The most-used CI/CD feature. Every JS project using Sentry in CI runs releases new + releases set-commits + releases finalize.
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
release new <VERSION> |
Critical | M (1-2 days) | ✅ @sentry/api SDK has typed functions. ReleaseSchema already partially defined in types/sentry.ts. |
release finalize <VERSION> |
Critical | S (hours) | ✅ Simple PUT with dateReleased |
release list |
High | M (1 day) | ✅ Standard list command pattern exists |
release info <VERSION> |
High | S (hours) | ✅ Standard view pattern |
release delete <VERSION> |
Medium | S (hours) | ✅ Simple DELETE |
release archive/restore |
Low | S (hours each) | ✅ Simple PUT mutations |
release set-commits |
Critical | L (3-5 days) | --auto uses repo integrations, --local shells out to git log --format, --initial-depth controls commit depth. Need git parsing logic. |
release propose-version |
Medium | S (hours) | ✅ Just git rev-parse HEAD via execSync |
Infrastructure already available:
ReleaseSchemaexists (partial, needs expansion for full release objects)- Authenticated API client supports all needed HTTP methods
resolveOrgAndProject()for target resolutionbuildCommandpattern for consistent output
Effort estimate: ~2 weeks for the full release group including set-commits.
3b. Deploy Management — High Gap 🟠
Deploys are typically used alongside releases in CI.
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
deploy new |
High | M (1 day) | ✅ Simple POST. Need new API module + Zod schemas. |
deploy list |
Medium | S (hours) | ✅ Standard list pattern |
Effort estimate: 2-3 days total.
3c. Monitors/Crons — High Gap 🟠
Cron monitoring is a growing Sentry feature. The monitors run command is the most useful — it wraps any CLI command with automatic check-in reporting.
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
monitor list |
Medium | M (1 day) | ✅ Standard list + new API module |
monitor run <slug> -- <cmd> |
High | L (3-5 days) |
Key technical challenge for monitor run:
- Needs to construct and send Sentry check-in envelopes directly via DSN (not the authenticated API)
- Signal handling: must forward SIGTERM/SIGINT to child, wait for graceful exit, then send error check-in
- Uses
Bun.spawn()for process management — Bun handles this well --scheduleflag auto-creates monitors if they don't exist
Effort estimate: ~1 week total.
3d. Debug Files (dSYM, ELF, PDB, Breakpad) — Not Feasible to Port 🔴
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
debug-files upload |
High (native) | XL | ❌ Blocked — see below |
debug-files check |
Medium | XL | ❌ Blocked |
debug-files find |
Low | XL | ❌ Blocked |
debug-files bundle-sources |
Medium | XL | ❌ Blocked |
debug-files print-sources |
Low | XL | ❌ Blocked |
debug-files bundle-jvm |
Medium | L |
Why it's blocked: The old CLI uses the symbolic Rust crate, which provides:
- Mach-O fat binary parsing and dSYM extraction
- ELF binary parsing (Linux native, Android NDK)
- PE/PDB parsing (Windows)
- DWARF debug info traversal
- Breakpad symbol file parsing
- BCSymbolMaps processing (Apple bitcode de-obfuscation)
- Debug identifier extraction (UUID, build ID, GNU build ID, code ID)
- Source reference extraction from DWARF/PDB for source context
No JavaScript equivalent exists. This is ~100K lines of Rust code handling low-level binary formats. Options:
- WASM compilation of
symbolic— Theoretically possible butsymbolicusesgoblin,gimli,pdbcrates which may not all compile cleanly to WASM. Memory overhead and performance would be significant. Effort: months. - FFI binding — Bun supports FFI to shared libraries, but this defeats the "pure JS, zero native deps" goal and creates platform-specific build complexity. Effort: weeks.
- Shell out to old sentry-cli — Use old CLI as a dependency for debug-file operations. Pragmatic but ugly.
Recommendation: Don't port debug-files. Users of native debug symbols should continue using the old sentry-cli, Xcode/Gradle plugins, or SDK-based uploads. These workflows are already well-served by platform-specific tooling.
Exception — bundle-jvm: This command doesn't parse native binaries — it bundles Java/Kotlin source files into a ZIP with a manifest. This is feasible to port as pure TS using the existing ZipWriter.
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
debug-files bundle-jvm |
Medium | M (2-3 days) | ✅ Pure file operations + ZIP, no native parsing |
3e. ProGuard Mapping Upload — Feasible 🟢
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
proguard upload |
Medium | M (2-3 days) | ✅ ProGuard mapping files are plain text. Just need: parse UUID from file header, build artifact bundle, upload via existing chunk protocol. No native deps. |
proguard uuid |
Low | S (hours) | ✅ Regex extraction from ProGuard file header |
3f. Send Event / Send Envelope — Feasible 🟢
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
send-event |
Medium | M (2-3 days) | ✅ Constructs event JSON from flags, sends via DSN. Need envelope construction logic (header + item). No native deps. |
send-envelope |
Low | S (1 day) | ✅ Reads raw envelope from stdin/file, forwards to DSN endpoint. |
Note: These use the DSN (not auth token) to send events, which means they work without sentry login. Need to implement the DSN-to-envelope-endpoint URL conversion (https://{host}/api/{project_id}/envelope/ with sentry_key header).
3g. React Native — Don't Port 🚫
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
react-native xcode |
N/A | XL | ❌ Deep Xcode build system integration. Already handled by @sentry/react-native SDK and Xcode build phases. |
react-native gradle |
N/A | XL | ❌ Gradle plugin integration. Already handled by sentry-android-gradle-plugin. |
Recommendation: Don't port. These are build system integrations that are better served by their respective platform plugins. The SDK packages already handle this. The old CLI commands exist as legacy glue code.
3h. Build Artifacts — Don't Port 🚫
| Command | Priority | Effort | Notes |
|---|---|---|---|
build upload/download/snapshots |
N/A | - | SaaS-only internal feature. Not documented for general use. |
3i. Code Mappings — Low Priority 🔵
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
code-mappings upload |
Low | M (1-2 days) | ✅ API call + file reading. Typically managed through the Sentry UI or GitHub integration. |
3j. Dart Symbol Maps — Feasible but Niche 🔵
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
dart-symbol-map upload |
Low | M (1-2 days) | ✅ Plain text files, similar to ProGuard. Uses chunk upload protocol. |
3k. Bash Hook — Low Priority 🔵
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
bash-hook |
Low | S (hours) | ✅ Outputs a bash script snippet. No deps. |
3l. Uninstall — Low Priority 🔵
| Command | Priority | Effort | Feasibility |
|---|---|---|---|
uninstall |
Low | M (1-2 days) | ✅ Reverse of setup — remove binary, completions, PATH entries, config dir. |
4. Intentionally Don't Port 🚫
| Feature | Reason |
|---|---|
| debug-files (all) | Requires symbolic Rust crate for native binary parsing. No JS equivalent. Users have Xcode/Gradle plugins and SDK integrations. |
| react-native xcode/gradle | Build system plugins already handle this. Legacy glue code. |
| build upload/download/snapshots | SaaS-only internal feature. |
| upload-dif / upload-dsym / upload-proguard | Legacy aliases — not needed in new CLI |
| derive-parser | Internal/hidden command |
| send-metric | Unregistered/dead code in old CLI |
.sentryclirc config format |
New CLI uses SQLite + env vars. Strictly better. |
5. Recommended Phased Approach
Phase 1: CI/CD Critical Path (3-4 weeks)
Goal: Enable the new CLI to replace the old one for the most common JS CI/CD pipeline.
| Task | Effort | What's Needed |
|---|---|---|
release group (new, finalize, list, info, delete) |
1 week | New API module, Zod schemas, 5 commands |
release set-commits |
3-5 days | Git log parsing, repo integration API |
release propose-version |
Hours | execSync("git rev-parse HEAD") |
deploy group (new, list) |
2-3 days | New API module, 2 commands |
issue resolve/unresolve/mute |
1-2 days | Wrappers around existing updateIssueStatus() |
Sourcemap --dist flag |
Hours | Add field to upload options |
Sourcemap --ignore/--ignore-file |
1 day | Use existing ignore dep |
Sourcemap --strip-prefix/--strip-common-prefix |
1 day | String manipulation |
Phase 2: Extended CI/CD (2-3 weeks)
| Task | Effort | What's Needed |
|---|---|---|
monitor group (list, run) |
1 week | Envelope construction, process management, signal handling |
proguard upload/uuid |
2-3 days | File parsing + chunk upload |
send-event |
2-3 days | Envelope construction, DSN endpoint resolution |
Sourcemap inject: follow sourceMappingURL |
2-3 days | Regex parsing of JS files |
| Sourcemap inject: inline base64 handling | 2-3 days | Base64 decode/encode with graceful failure |
sourcemaps resolve |
1 day | Read-only validation |
Phase 3: Polish & Niche (1-2 weeks)
| Task | Effort | What's Needed |
|---|---|---|
debug-files bundle-jvm |
2-3 days | ZIP builder (exists) + manifest |
uninstall |
1-2 days | Reverse of setup |
send-envelope |
1 day | Stdin/file reading + forwarding |
bash-hook |
Hours | Static script output |
code-mappings upload |
1-2 days | API call |
dart-symbol-map upload |
1-2 days | Chunk upload |
Remaining sourcemap flags (--validate, --no-rewrite, etc.) |
2-3 days | Various |
6. Key Technical Risks
No native dependency story
The new CLI is pure JS/TS — no native deps. This is a strength (simple distribution) but means debug-files is permanently out of scope unless we:
- Add WASM support (months of effort, uncertain feasibility)
- Add FFI bindings (defeats the "pure JS" goal)
- Ship the old CLI alongside for native operations
Envelope construction for DSN-based sending
send-event, send-envelope, and monitor run need to construct Sentry envelopes and send them via DSN (not the authenticated API). This is a new code path — the current CLI only uses authenticated API requests. The Sentry SDK's envelope format is well-documented but needs a lightweight implementation.
Process management for monitor run
Wrapping arbitrary commands requires robust signal handling (SIGTERM, SIGINT, SIGHUP forwarding), exit code preservation, and stdin/stdout/stderr piping. Bun's Bun.spawn() handles this well, but edge cases (zombie processes, killed-by-signal exit codes) need careful testing.
Git operations for release set-commits --local
Needs to parse git log output to extract commits for a release. The old CLI uses git log --format with specific format strings. This is straightforward with execSync but needs testing across git versions and edge cases (shallow clones, detached HEAD, missing remote).