Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function classifyArgs(
*
* For `project-search` (bare slug), searches for an existing project first.
* If not found, treats the slug as a **new project name** to create —
* org will be resolved later by the wizard's `resolveOrgSlug()`.
* org will be resolved later by init preflight before the workflow starts.
* If the slug matches an org name, treats it as org-only (like `slug/`).
*/
async function resolveTarget(targetArg: string | undefined): Promise<{
Expand Down Expand Up @@ -154,7 +154,7 @@ async function resolveTarget(targetArg: string | undefined): Promise<{
}

// Truly not found — treat as the name for a new project to create.
// Org will be resolved later by the wizard via resolveOrgSlug().
// Org will be resolved later by init preflight before the workflow starts.
log.info(
`No existing project "${parsed.projectSlug}" found — will create a new project with this name.`
);
Expand Down
36 changes: 36 additions & 0 deletions src/lib/init/existing-project.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
getProject,
tryGetPrimaryDsn,
} from "../api-client.js";
import { ApiError } from "../errors.js";
import { buildProjectUrl } from "../sentry-urls.js";
import type { ExistingProjectData } from "./types.js";

/**
* Fetch Sentry metadata for an existing project.
*
* Returns `null` when the project does not exist, while allowing other API
* errors to propagate so callers can decide whether the lookup is best-effort
* or should fail the current operation.
*/
export async function tryGetExistingProjectData(
orgSlug: string,
projectSlug: string
): Promise<ExistingProjectData | null> {
try {
const project = await getProject(orgSlug, projectSlug);
const dsn = await tryGetPrimaryDsn(orgSlug, project.slug);
return {
orgSlug,
projectSlug: project.slug,
projectId: project.id,
dsn: dsn ?? "",
url: buildProjectUrl(orgSlug, project.slug),
};
} catch (error) {
if (error instanceof ApiError && error.status === 404) {
return null;
}
throw error;
}
}
10 changes: 5 additions & 5 deletions src/lib/init/interactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import {
import { REQUIRED_FEATURE } from "./constants.js";
import type {
ConfirmPayload,
InteractiveContext,
InteractivePayload,
MultiSelectPayload,
SelectPayload,
WizardOptions,
} from "./types.js";

export async function handleInteractive(
payload: InteractivePayload,
options: WizardOptions
options: InteractiveContext
): Promise<Record<string, unknown>> {
switch (payload.kind) {
case "select":
Expand All @@ -41,7 +41,7 @@ export async function handleInteractive(

async function handleSelect(
payload: SelectPayload,
options: WizardOptions
options: InteractiveContext
): Promise<Record<string, unknown>> {
const apps = payload.apps ?? [];
const items = payload.options ?? apps.map((a) => a.name);
Expand Down Expand Up @@ -78,7 +78,7 @@ async function handleSelect(

async function handleMultiSelect(
payload: MultiSelectPayload,
options: WizardOptions
options: InteractiveContext
): Promise<Record<string, unknown>> {
const available = payload.availableFeatures ?? payload.options ?? [];

Expand Down Expand Up @@ -137,7 +137,7 @@ async function handleMultiSelect(

async function handleConfirm(
payload: ConfirmPayload,
options: WizardOptions
options: InteractiveContext
): Promise<Record<string, unknown>> {
if (options.yes) {
log.info("Auto-confirmed: continuing");
Expand Down
Loading
Loading