Skip to content

Commit 3ec4497

Browse files
feat(init): show message when reusing an existing Sentry project
Add optional message field to LocalOpResult so local-ops can surface user-facing feedback without doing UI work directly. When create-sentry-project detects a duplicate, the spinner now shows 'Using existing project "slug" in org' instead of silently reusing.
1 parent 7443f41 commit 3ec4497

File tree

5 files changed

+49
-1
lines changed

5 files changed

+49
-1
lines changed

src/lib/init/local-ops.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,10 @@ async function createSentryProject(
835835
if (options.org && options.project) {
836836
const existing = await tryGetExistingProject(orgSlug, slug);
837837
if (existing) {
838-
return existing;
838+
return {
839+
...existing,
840+
message: `Using existing project "${slug}" in ${orgSlug}`,
841+
};
839842
}
840843
}
841844

src/lib/init/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ export type CreateSentryProjectPayload = {
9494
export type LocalOpResult = {
9595
ok: boolean;
9696
error?: string;
97+
/** Optional user-facing message (e.g. "Using existing project 'foo'"). */
98+
message?: string;
9799
data?: unknown;
98100
};
99101

src/lib/init/wizard-runner.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ async function handleSuspendedStep(
191191

192192
const localResult = await handleLocalOp(payload, options);
193193

194+
if (localResult.message) {
195+
spin.stop(localResult.message);
196+
spin.start("Processing...");
197+
}
198+
194199
const history = stepHistory.get(stepId) ?? [];
195200
history.push(localResult);
196201
stepHistory.set(stepId, history);

test/lib/init/local-ops.create-sentry-project.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ describe("create-sentry-project", () => {
433433
);
434434

435435
expect(result.ok).toBe(true);
436+
expect(result.message).toBe(
437+
'Using existing project "my-app" in acme-corp'
438+
);
436439
const data = result.data as { orgSlug: string; projectSlug: string };
437440
expect(data.orgSlug).toBe("acme-corp");
438441
expect(data.projectSlug).toBe("my-app");

test/lib/init/wizard-runner.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,41 @@ describe("runWizard", () => {
638638
}
639639
});
640640

641+
test("displays message from LocalOpResult via spin.stop", async () => {
642+
handleLocalOpSpy.mockResolvedValue({
643+
ok: true,
644+
message: 'Using existing project "my-app" in acme',
645+
data: { orgSlug: "acme", projectSlug: "my-app" },
646+
});
647+
648+
mockStartResult = {
649+
status: "suspended",
650+
suspended: [["ensure-sentry-project"]],
651+
steps: {
652+
"ensure-sentry-project": {
653+
suspendPayload: {
654+
type: "local-op",
655+
operation: "create-sentry-project",
656+
cwd: "/app",
657+
params: { name: "my-app", platform: "python" },
658+
},
659+
},
660+
},
661+
};
662+
mockResumeResults = [{ status: "success" }];
663+
664+
await runWizard(makeOptions());
665+
666+
expect(spinnerMock.stop).toHaveBeenCalledWith(
667+
'Using existing project "my-app" in acme'
668+
);
669+
// Spinner should restart after showing the message
670+
const startCalls = spinnerMock.start.mock.calls.map(
671+
(c: string[]) => c[0]
672+
);
673+
expect(startCalls).toContain("Processing...");
674+
});
675+
641676
test("dispatches interactive payload to handleInteractive", async () => {
642677
mockStartResult = {
643678
status: "suspended",

0 commit comments

Comments
 (0)