Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 <value>... - Features to enable: errors,tracing,logs,replay,metrics,profiling,sourcemaps,crons,attachments,agent-tracing,mcp-observability`
- `--features <value>... - Features to enable: errors,tracing,logs,replay,profiling,crons,agent-tracing,mcp-observability`
- `-t, --team <value> - Team slug to create the project under`
- `--app <value> - 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.`
Expand Down
15 changes: 7 additions & 8 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -68,11 +70,8 @@ const SUPPORTED_FEATURE_NAMES = [
"tracing",
"logs",
"replay",
"metrics",
"profiling",
"sourcemaps",
"crons",
"attachments",
"agent-tracing",
"mcp-observability",
] as const;
Expand Down Expand Up @@ -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,
},
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/src/lib/init/wizard-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,13 @@ export async function runWizard(initialOptions: WizardOptions): Promise<void> {

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`.
Expand Down
29 changes: 20 additions & 9 deletions packages/cli/test/commands/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]);
Expand All @@ -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",
]);
Expand All @@ -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();
Expand All @@ -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);
Expand Down
Loading