Skip to content

feat(bundler-plugins)!: Migrate from @sentry/cli to the sentry CLI SDK - #23398

Draft
JPeer264 wants to merge 3 commits into
developfrom
jp/cli-v3-migration
Draft

feat(bundler-plugins)!: Migrate from @sentry/cli to the sentry CLI SDK#23398
JPeer264 wants to merge 3 commits into
developfrom
jp/cli-v3-migration

Conversation

@JPeer264

@JPeer264 JPeer264 commented Aug 13, 2026

Copy link
Copy Markdown
Member

closes #18518
closes #18518

This PR is removing @sentry/cli in favor of sentry.

Following was done:

  • Using a SentryCliAdapter to make the usage a little bit more comfortable (especially around uploading sourcemaps for more projects)
  • I was in between mocking the CLI and not mocking the CLI, as it would increase the CI 4 times by just using the real CLI. So I kept a mock like we had before
  • Removed sentryCliBinaryExists, because there is no binary anymore

Clanker description:

Replace the @sentry/cli v2 binary wrapper with the programmatic SDK (createSentrySDK) exposed by the new sentry CLI package. A SentryCliAdapter in src/core/cli.ts maps the plugin's structured option shapes onto the SDK's typed methods, keeping all translation in one place:

  • release create/finalize/set-commits/deploy and sourcemap upload now go through the SDK instead of spawning the CLI binary; one SDK client is created per (options, project) pair since project selection is bound at client creation time
  • the integration-test fixtures replace the @sentry__cli.patch with a local sentry-stub fixture recording CLI invocations to sentry-cli-mock.json, so upload assertions no longer depend on the binary's internals
  • remix's release/sourcemap scripts and react-router's buildEnd hook are migrated to the same SDK
  • add a react-router-7-sourcemaps e2e test app covering the new upload path against a mock Sentry server

Requires sentry >= 0.41.0: earlier 0.x builds had a link-fatal named import of Node 22.15+ zstd builtins in the ESM entry, which crashed the whole module on Node 18/20.

@JPeer264 JPeer264 self-assigned this Aug 13, 2026
@linear-code

linear-code Bot commented Aug 13, 2026

Copy link
Copy Markdown

JS-1312

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.57 kB - -
@sentry/browser - with treeshaking flags 26.92 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 26.82 kB - -
@sentry/browser (incl. Tracing) 48.33 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.35 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.24 kB - -
@sentry/browser (incl. Tracing, Replay) 87.73 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.19 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 92.44 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 105.12 kB - -
@sentry/browser (incl. Feedback) 45.81 kB - -
@sentry/browser (incl. sendFeedback) 33.36 kB - -
@sentry/browser (incl. FeedbackAsync) 38.47 kB - -
@sentry/browser (incl. Metrics) 29.52 kB - -
@sentry/browser (incl. Logs) 29.8 kB - -
@sentry/browser (incl. Metrics & Logs) 30.45 kB - -
@sentry/react 30.33 kB - -
@sentry/react (incl. Tracing) 50.51 kB - -
@sentry/vue 35.4 kB - -
@sentry/vue (incl. Tracing) 50.31 kB - -
@sentry/svelte 28.6 kB - -
CDN Bundle 30.32 kB - -
CDN Bundle (incl. Tracing) 48.87 kB - -
CDN Bundle (incl. Logs, Metrics) 32.54 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 50.74 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 72.91 kB - -
CDN Bundle (incl. Tracing, Replay) 86.33 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.16 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 92.07 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94 kB - -
CDN Bundle - uncompressed 89.94 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.13 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 96.23 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 151.81 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 225.18 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 265.4 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 271.07 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.09 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 284.76 kB - -
@sentry/nextjs (client) 53.05 kB - -
@sentry/sveltekit (client) 48.74 kB - -
@sentry/core/server 64.95 kB - -
@sentry/core/browser 52.11 kB - -
@sentry/node 117.49 kB +0.03% +24 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 85.18 kB - -
@sentry/node - without tracing 82.03 kB +0.03% +24 B 🔺
@sentry/aws-serverless 91.46 kB +0.03% +20 B 🔺
@sentry/cloudflare (withSentry) - minified 194.68 kB - -
@sentry/cloudflare (withSentry) 481.33 kB - -

View base workflow run

@JPeer264

Copy link
Copy Markdown
Member Author

This PR is currently blocked by getsentry/cli#1421

betegon pushed a commit to getsentry/cli that referenced this pull request Aug 14, 2026
I opened a PR that is using the new CLI instead of the old
`@sentry/cli@2`:
getsentry/sentry-javascript#23398

Some E2E tests failed with `TypeError: Bun.serve is not a function`,
because we actually check internally if `Bun` would be an option. With
that polyfill in this CLI this behavior is now forced, without Bun
actually being there. Idk why this actually exists, but exporting `Bun`
instead fixes it.

---

AI description:

The Node polyfills were installed with `globalThis.Bun = BunPolyfill`,
which broke consumers of the npm package in both directions.

Under Bun the global is readonly, so merely importing the package threw
"Attempted to assign to readonly property" and took the whole process
down. Under Node it left an object named `Bun` on the global, so
unrelated libraries that feature-detect `typeof Bun !== "undefined"`
took their Bun code path and called methods the polyfill does not
implement, failing with errors like "Bun.serve is not a function". Both
are reachable by anyone who merely depends on this package, since
importing it is enough.

The polyfills are already delivered through esbuild's `inject`, which
substitutes unbound identifiers with exported bindings, so exporting
`Bun` gives the bundle the same value lexically without touching the
global. The real Bun is preferred when present, so running under Bun
keeps the genuine implementation rather than shadowing it.

Verified by importing the built bundle in Node: `globalThis.Bun` stays
undefined, where it previously became an object whose `serve` and
`version` were missing.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@JPeer264
JPeer264 force-pushed the jp/cli-v3-migration branch 5 times, most recently from 2ebc1d7 to 9093933 Compare August 23, 2026 11:23
JPeer264 and others added 2 commits August 24, 2026 18:45
Replace the @sentry/cli v2 binary wrapper with the programmatic SDK
(createSentrySDK) exposed by the new sentry CLI package. A
SentryCliAdapter in src/core/cli.ts maps the plugin's structured option
shapes onto the SDK's typed methods, keeping all translation in one
place:

- release create/finalize/set-commits/deploy and sourcemap upload now
  go through the SDK instead of spawning the CLI binary; one SDK client
  is created per (options, project) pair since project selection is
  bound at client creation time
- the integration-test fixtures replace the @sentry__cli.patch with a
  local sentry-stub fixture recording CLI invocations to
  sentry-cli-mock.json, so upload assertions no longer depend on the
  binary's internals
- remix's release/sourcemap scripts and react-router's buildEnd hook
  are migrated to the same SDK
- add a react-router-7-sourcemaps e2e test app covering the new upload
  path against a mock Sentry server

Requires sentry >= 0.41.0: earlier 0.x builds had a link-fatal named
import of Node 22.15+ zstd builtins in the ESM entry, which crashed the
whole module on Node 18/20.

Co-Authored-By: Claude <noreply@anthropic.com>
The e2e workflow's Playwright setup runs for every test app and fails
with exit 127 when the app cannot resolve @playwright/test, even for
build-only apps that never launch a browser. react-router-sourcemaps
carries the dependency for the same reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@JPeer264
JPeer264 force-pushed the jp/cli-v3-migration branch from 0153d5f to d67c502 Compare August 24, 2026 15:45
@JPeer264

Copy link
Copy Markdown
Member Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6ddfabf. Configure here.

: ['.js', '.map', '.jsbundle', '.bundle'],
ignore: includeEntry.ignore ? arrayify(includeEntry.ignore) : undefined,
})),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Legacy upload drops urlPrefix

High Severity

When mapping release.uploadLegacySourcemaps entries into upload targets, urlPrefix from each IncludeEntry is never forwarded, even though UploadTarget and sourcemap.upload support it. Legacy uploads that rely on a custom URL prefix will associate artifacts under the wrong paths in Sentry.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ddfabf. Configure here.

project,
url: this.#options.url,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Headers option no longer applied

High Severity

The public headers option is still normalized and documented, but SentryCliAdapter never forwards it when creating the CLI SDK client. Self-hosted setups that depend on custom auth headers (IAP, Cloudflare Access, etc.) will lose those headers on every CLI request.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ddfabf. Configure here.

ext: includeEntry.ext
? includeEntry.ext.map(extension => `.${extension.replace(/^\./, '')}`)
: ['.js', '.map', '.jsbundle', '.bundle'],
ignore: includeEntry.ignore ? arrayify(includeEntry.ignore) : undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Legacy ignore default dropped

Medium Severity

IncludeEntry documents that ignore defaults to node_modules when unset, and inject still applies that default, but legacy sourcemap upload now passes undefined through and uploads without an ignore pattern. Builds that previously skipped node_modules can start uploading those files.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6ddfabf. Configure here.

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.

Update to Sentry CLI v4

1 participant