Skip to content

Catch up with old sentry-cli #600

@BYK

Description

@BYK

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 delete
  • issue 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/delete
  • api (generic authenticated API requests, like gh api)
  • schema (API schema browser)
  • init (AI-powered project setup wizard)
  • auth whoami, auth refresh, auth token
  • cli feedback, cli fix
  • team 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 resolve subcommand for validating/debugging sourcemap linkage

New CLI's approach: Strictly uses file naming convention only (foo.jsfoo.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) ⚠️ Complex: --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:

  • ReleaseSchema exists (partial, needs expansion for full release objects)
  • Authenticated API client supports all needed HTTP methods
  • resolveOrgAndProject() for target resolution
  • buildCommand pattern 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) ⚠️ Complex: Must spawn child process, forward stdin/stdout/stderr, handle signals (SIGTERM, SIGINT), capture exit code, send check-in envelope on start + finish/error. Uses DSN (not auth token) to send check-in envelopes. Need envelope construction.

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
  • --schedule flag 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 ⚠️ Partially feasible — see below

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:

  1. WASM compilation of symbolic — Theoretically possible but symbolic uses goblin, gimli, pdb crates which may not all compile cleanly to WASM. Memory overhead and performance would be significant. Effort: months.
  2. 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.
  3. 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions