diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/init.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/init.md index 2ae34b06f..50c0efe03 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/init.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/init.md @@ -18,7 +18,7 @@ Initialize Sentry in your project (experimental) **Flags:** - `-y, --yes - Accept non-interactive defaults (requires --features outside a TTY)` - `-n, --dry-run - Show what would happen without making changes` -- `--features ... - Features to enable: errors,tracing,logs,replay,metrics,profiling,sourcemaps,crons,attachments,agent-tracing,mcp-observability` +- `--features ... - Features to enable: errors,tracing,logs,replay,profiling,crons,agent-tracing,mcp-observability` - `-t, --team - Team slug to create the project under` - `--app - App to initialize in a monorepo (required with --yes when multiple apps are detected)` - `--tui - Use the Ink-based interactive UI (default). Pass --no-tui to fall back to plain log output.` diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 13f74dea3..383e01ea3 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -42,6 +42,12 @@ const FEATURE_DELIMITER = /[,+ ]+/; const NON_INTERACTIVE_USAGE_HINT = "sentry init --yes --features errors,tracing,replay [target] [directory]"; +// Only features backed by a Sentry SDK selector product are accepted here. +// Non-selector products (source maps, metrics, attachments) are intentionally +// not exposed via --features yet: their setup isn't fully automated — e.g. +// source-map upload needs an auth token this wizard does not provision — so +// accepting them would leave a half-configured integration. Re-add an alias +// (and its SUPPORTED_FEATURE_NAMES entry) once that flow is complete. const FEATURE_ALIASES = { errors: "errorMonitoring", errorMonitoring: "errorMonitoring", @@ -50,12 +56,8 @@ const FEATURE_ALIASES = { logs: "logs", replay: "sessionReplay", sessionReplay: "sessionReplay", - metrics: "metrics", profiling: "profiling", - sourcemaps: "sourceMaps", - sourceMaps: "sourceMaps", crons: "crons", - attachments: "attachments", aiMonitoring: "aiMonitoring", "agent-tracing": "aiMonitoring", agentTracing: "aiMonitoring", @@ -68,11 +70,8 @@ const SUPPORTED_FEATURE_NAMES = [ "tracing", "logs", "replay", - "metrics", "profiling", - "sourcemaps", "crons", - "attachments", "agent-tracing", "mcp-observability", ] as const; @@ -339,7 +338,7 @@ export const initCommand = buildCommand< kind: "parsed", parse: String, brief: - "Features to enable: errors,tracing,logs,replay,metrics,profiling,sourcemaps,crons,attachments,agent-tracing,mcp-observability", + "Features to enable: errors,tracing,logs,replay,profiling,crons,agent-tracing,mcp-observability", variadic: true, optional: true, }, diff --git a/packages/cli/src/lib/init/wizard-runner.ts b/packages/cli/src/lib/init/wizard-runner.ts index e14ea4637..9bdbc60e4 100644 --- a/packages/cli/src/lib/init/wizard-runner.ts +++ b/packages/cli/src/lib/init/wizard-runner.ts @@ -986,6 +986,13 @@ export async function runWizard(initialOptions: WizardOptions): Promise { const { directory, yes, dryRun, features, forceLegacyUi } = initialOptions; + // Tag the whole run's telemetry with dry-run mode. Dry runs plan changes but + // apply and install nothing, so post-apply verification (both this CLI's + // `verify-setup` runtime check and the server's `verify-changes` step) sees an + // unmodified project and reports expected "issues". This tag lets that + // expected noise be filtered out (`wizard.dry_run:false` isolates real runs). + setTag("wizard.dry_run", dryRun === true); + // Construct the UI once for the entire run; tear down on every exit // path via `await using`. The factory picks `InkUI` for interactive // runs and `LoggingUI` for CI / `--yes` / `--no-tui`. diff --git a/packages/cli/test/commands/init.test.ts b/packages/cli/test/commands/init.test.ts index fee6fd96c..f22a608bf 100644 --- a/packages/cli/test/commands/init.test.ts +++ b/packages/cli/test/commands/init.test.ts @@ -183,16 +183,12 @@ describe("init command func", () => { const ctx = makeContext(); await func.call(ctx, { ...DEFAULT_FLAGS, - features: [ - "errors,tracing,replay,sourcemaps,attachments,agent-tracing,mcp-observability", - ], + features: ["errors,tracing,replay,agent-tracing,mcp-observability"], }); expect(capturedArgs?.features).toEqual([ "errorMonitoring", "performanceMonitoring", "sessionReplay", - "sourceMaps", - "attachments", "aiMonitoring", "mcpObservability", ]); @@ -203,15 +199,13 @@ describe("init command func", () => { await func.call(ctx, { ...DEFAULT_FLAGS, features: [ - "errorMonitoring,performanceMonitoring,sessionReplay,sourceMaps,attachments,aiMonitoring,mcpObservability", + "errorMonitoring,performanceMonitoring,sessionReplay,aiMonitoring,mcpObservability", ], }); expect(capturedArgs?.features).toEqual([ "errorMonitoring", "performanceMonitoring", "sessionReplay", - "sourceMaps", - "attachments", "aiMonitoring", "mcpObservability", ]); @@ -225,7 +219,7 @@ describe("init command func", () => { }); await expect(promise).rejects.toThrow(ValidationError); await expect(promise).rejects.toThrow( - "Supported features: errors, tracing, logs, replay, metrics, profiling, sourcemaps, crons, attachments, agent-tracing, mcp-observability" + "Supported features: errors, tracing, logs, replay, profiling, crons, agent-tracing, mcp-observability" ); expect(runWizardSpy).not.toHaveBeenCalled(); expect(findProjectsSpy).not.toHaveBeenCalled(); @@ -248,6 +242,23 @@ describe("init command func", () => { expect(runWizardSpy).not.toHaveBeenCalled(); }); + test.each([ + "metrics", + "sourcemaps", + "attachments", + ])("rejects %s because init does not yet automate its setup", async (feature) => { + const ctx = makeContext(); + const promise = func.call(ctx, { + ...DEFAULT_FLAGS, + features: [feature], + }); + await expect(promise).rejects.toThrow(ValidationError); + await expect(promise).rejects.toThrow( + `Unknown init feature "${feature}"` + ); + expect(runWizardSpy).not.toHaveBeenCalled(); + }); + test("passes undefined when features not provided", async () => { const ctx = makeContext(); await func.call(ctx, DEFAULT_FLAGS);