@prisma/cli 3.0.0-alpha.3 → 3.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/git.js +49 -0
- package/dist/adapters/local-state.js +38 -0
- package/dist/cli2.js +58 -4
- package/dist/commands/app/index.js +30 -19
- package/dist/commands/auth/index.js +1 -1
- package/dist/commands/env.js +25 -9
- package/dist/commands/git/index.js +36 -0
- package/dist/commands/project/index.js +8 -13
- package/dist/commands/version/index.js +18 -0
- package/dist/controllers/app-env.js +23 -21
- package/dist/controllers/app.js +159 -91
- package/dist/controllers/auth.js +2 -2
- package/dist/controllers/branch.js +1 -1
- package/dist/controllers/project.js +451 -161
- package/dist/controllers/version.js +12 -0
- package/dist/lib/app/env-config.js +13 -2
- package/dist/lib/auth/auth-ops.js +54 -9
- package/dist/lib/auth/client.js +2 -2
- package/dist/lib/auth/guard.js +1 -1
- package/dist/lib/project/resolution.js +151 -0
- package/dist/lib/version.js +55 -0
- package/dist/output/patterns.js +0 -1
- package/dist/presenters/app.js +9 -1
- package/dist/presenters/branch.js +6 -6
- package/dist/presenters/project.js +84 -44
- package/dist/presenters/version.js +29 -0
- package/dist/shell/command-meta.js +41 -11
- package/dist/shell/errors.js +4 -1
- package/dist/shell/global-flags.js +2 -1
- package/dist/use-cases/auth.js +4 -7
- package/dist/use-cases/branch.js +20 -20
- package/dist/use-cases/create-cli-gateways.js +3 -13
- package/dist/use-cases/project.js +2 -48
- package/package.json +1 -1
- package/dist/adapters/config.js +0 -74
package/dist/controllers/app.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { UnsafeConfigWriteError, assertLinkedProjectIdWritable, readLinkedProjectId, writeLinkedProjectId } from "../adapters/config.js";
|
|
2
1
|
import { SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
|
|
3
2
|
import { FileTokenStorage } from "../adapters/token-storage.js";
|
|
4
|
-
import { CliError, authRequiredError, featureUnavailableError, usageError } from "../shell/errors.js";
|
|
3
|
+
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
5
4
|
import { renderCommandHeader } from "../shell/ui.js";
|
|
6
5
|
import { writeJsonEvent } from "../shell/output.js";
|
|
7
6
|
import { canPrompt } from "../shell/runtime.js";
|
|
8
7
|
import { textPrompt } from "../shell/prompt.js";
|
|
9
8
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
9
|
+
import { readAuthState } from "../lib/auth/auth-ops.js";
|
|
10
10
|
import { parseEnvAssignments } from "../lib/app/env-vars.js";
|
|
11
11
|
import { DEFAULT_LOCAL_DEV_PORT, resolveLocalBuildType, runLocalApp } from "../lib/app/local-dev.js";
|
|
12
|
-
import {
|
|
12
|
+
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
13
13
|
import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
|
|
14
14
|
import { PREVIEW_DEFAULT_REGION, createPreviewDeployInteraction } from "../lib/app/preview-interaction.js";
|
|
15
15
|
import { createPreviewDeployProgress, createPreviewPromoteProgress, createPreviewUpdateEnvProgress } from "../lib/app/preview-progress.js";
|
|
16
16
|
import { createPreviewAppProvider } from "../lib/app/preview-provider.js";
|
|
17
17
|
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
18
|
-
import
|
|
18
|
+
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
19
|
+
import { listRealWorkspaceProjects } from "./project.js";
|
|
19
20
|
import open from "open";
|
|
20
21
|
//#region src/controllers/app.ts
|
|
21
22
|
function isRealMode(context) {
|
|
@@ -83,8 +84,7 @@ async function runAppDeploy(context, appName, options) {
|
|
|
83
84
|
assertSupportedEntrypoint(buildType, options?.entrypoint, "deploy");
|
|
84
85
|
const portMapping = parseDeployPortMapping(options?.httpPort);
|
|
85
86
|
const envVars = toOptionalEnvVars(parseEnvAssignments(options?.envAssignments, { commandName: "deploy" }));
|
|
86
|
-
const provider = await
|
|
87
|
-
const projectId = await resolveProjectIdForDeploy(context, provider);
|
|
87
|
+
const { provider, target, projectId } = await requireProviderAndProjectContext(context, options?.projectRef, { allowCreate: true });
|
|
88
88
|
const selectedApp = await resolveDeploySelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
89
89
|
const deployResult = await provider.deployApp({
|
|
90
90
|
cwd: context.runtime.cwd,
|
|
@@ -109,7 +109,10 @@ async function runAppDeploy(context, appName, options) {
|
|
|
109
109
|
return {
|
|
110
110
|
command: "app.deploy",
|
|
111
111
|
result: {
|
|
112
|
-
|
|
112
|
+
workspace: target.workspace,
|
|
113
|
+
project: target.project,
|
|
114
|
+
branch: target.branch,
|
|
115
|
+
resolution: target.resolution,
|
|
113
116
|
app: {
|
|
114
117
|
id: deployResult.app.id,
|
|
115
118
|
name: deployResult.app.name
|
|
@@ -120,17 +123,16 @@ async function runAppDeploy(context, appName, options) {
|
|
|
120
123
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`]
|
|
121
124
|
};
|
|
122
125
|
}
|
|
123
|
-
async function runAppUpdateEnv(context, appName, envAssignments) {
|
|
126
|
+
async function runAppUpdateEnv(context, appName, envAssignments, projectRef) {
|
|
124
127
|
ensurePreviewAppMode(context);
|
|
125
128
|
emitLegacyEnvDeprecationWarning(context, "app update-env", "project env add");
|
|
126
129
|
const envVars = parseEnvAssignments(envAssignments, {
|
|
127
130
|
commandName: "update-env",
|
|
128
131
|
requireAtLeastOne: true
|
|
129
132
|
});
|
|
130
|
-
const projectId = await
|
|
131
|
-
const provider = await requirePreviewAppProvider(context);
|
|
133
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
132
134
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
133
|
-
if (!selectedApp) throw noDeploymentsError("No deployments available to update environment variables", "The
|
|
135
|
+
if (!selectedApp) throw noDeploymentsError("No deployments available to update environment variables", "The resolved project does not have any deployed app yet.");
|
|
134
136
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
135
137
|
throw deployFailedError("Failed to inspect app deployments", error, ["prisma-cli app list-deploys"]);
|
|
136
138
|
});
|
|
@@ -163,11 +165,10 @@ async function runAppUpdateEnv(context, appName, envAssignments) {
|
|
|
163
165
|
nextSteps: ["prisma-cli app list-env", `prisma-cli app show-deploy ${updateResult.deployment.id}`]
|
|
164
166
|
};
|
|
165
167
|
}
|
|
166
|
-
async function runAppListEnv(context, appName) {
|
|
168
|
+
async function runAppListEnv(context, appName, projectRef) {
|
|
167
169
|
ensurePreviewAppMode(context);
|
|
168
170
|
emitLegacyEnvDeprecationWarning(context, "app list-env", "project env list");
|
|
169
|
-
const projectId = await
|
|
170
|
-
const provider = await requirePreviewAppProvider(context);
|
|
171
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
171
172
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
172
173
|
if (!selectedApp) return {
|
|
173
174
|
command: "app.list-env",
|
|
@@ -252,10 +253,9 @@ async function runAppListEnv(context, appName) {
|
|
|
252
253
|
nextSteps: deployment.id ? [`prisma-cli app show-deploy ${deployment.id}`] : ["prisma-cli app deploy"]
|
|
253
254
|
};
|
|
254
255
|
}
|
|
255
|
-
async function runAppListDeploys(context, appName) {
|
|
256
|
+
async function runAppListDeploys(context, appName, projectRef) {
|
|
256
257
|
ensurePreviewAppMode(context);
|
|
257
|
-
const projectId = await
|
|
258
|
-
const provider = await requirePreviewAppProvider(context);
|
|
258
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
259
259
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
260
260
|
if (!selectedApp) return {
|
|
261
261
|
command: "app.list-deploys",
|
|
@@ -290,10 +290,9 @@ async function runAppListDeploys(context, appName) {
|
|
|
290
290
|
nextSteps: deployments.length > 0 ? [`prisma-cli app show-deploy ${deployments[0]?.id}`] : ["prisma-cli app deploy"]
|
|
291
291
|
};
|
|
292
292
|
}
|
|
293
|
-
async function runAppShow(context, appName) {
|
|
293
|
+
async function runAppShow(context, appName, projectRef) {
|
|
294
294
|
ensurePreviewAppMode(context);
|
|
295
|
-
const projectId = await
|
|
296
|
-
const provider = await requirePreviewAppProvider(context);
|
|
295
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
297
296
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
298
297
|
if (!selectedApp) return {
|
|
299
298
|
command: "app.show",
|
|
@@ -347,8 +346,9 @@ async function runAppShowDeploy(context, deploymentId) {
|
|
|
347
346
|
exitCode: 1,
|
|
348
347
|
nextSteps: ["prisma-cli app list-deploys"]
|
|
349
348
|
});
|
|
350
|
-
const
|
|
351
|
-
const
|
|
349
|
+
const workspaceId = deployment?.app ? await readCurrentWorkspaceId(context) : null;
|
|
350
|
+
const rememberedProject = workspaceId ? await context.stateStore.readRememberedProject(workspaceId) : null;
|
|
351
|
+
const knownLiveDeploymentId = deployment?.app && rememberedProject ? await context.stateStore.readKnownLiveDeployment(rememberedProject.id, deployment.app.id) : null;
|
|
352
352
|
const providerLiveDeploymentId = deployment.app?.liveDeploymentId ?? null;
|
|
353
353
|
return {
|
|
354
354
|
command: "app.show-deploy",
|
|
@@ -366,12 +366,11 @@ async function runAppShowDeploy(context, deploymentId) {
|
|
|
366
366
|
nextSteps: []
|
|
367
367
|
};
|
|
368
368
|
}
|
|
369
|
-
async function runAppOpen(context, appName) {
|
|
369
|
+
async function runAppOpen(context, appName, projectRef) {
|
|
370
370
|
ensurePreviewAppMode(context);
|
|
371
|
-
const projectId = await
|
|
372
|
-
const provider = await requirePreviewAppProvider(context);
|
|
371
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
373
372
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
374
|
-
if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The
|
|
373
|
+
if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The resolved project does not have any deployed app yet.");
|
|
375
374
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
376
375
|
throw deployFailedError("Failed to resolve app URL", error, ["prisma-cli app show"]);
|
|
377
376
|
});
|
|
@@ -401,10 +400,9 @@ async function runAppOpen(context, appName) {
|
|
|
401
400
|
nextSteps: ["prisma-cli app show", `prisma-cli app show-deploy ${liveDeployment.id}`]
|
|
402
401
|
};
|
|
403
402
|
}
|
|
404
|
-
async function runAppLogs(context, appName, deploymentId) {
|
|
403
|
+
async function runAppLogs(context, appName, deploymentId, projectRef) {
|
|
405
404
|
ensurePreviewAppMode(context);
|
|
406
|
-
const projectId = await
|
|
407
|
-
const provider = await requirePreviewAppProvider(context);
|
|
405
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
408
406
|
const target = deploymentId ? await resolveExplicitLogDeployment(context, provider, projectId, appName, deploymentId) : await resolveLiveLogDeployment(context, provider, projectId, appName);
|
|
409
407
|
if (!context.flags.json && !context.flags.quiet) {
|
|
410
408
|
const lines = renderCommandHeader(context.ui, {
|
|
@@ -438,7 +436,7 @@ async function runAppLogs(context, appName, deploymentId) {
|
|
|
438
436
|
async function resolveExplicitLogDeployment(context, provider, projectId, appName, deploymentId) {
|
|
439
437
|
if (appName) {
|
|
440
438
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
441
|
-
if (!selectedApp) throw noDeploymentsError("No deployments available to stream logs", "The
|
|
439
|
+
if (!selectedApp) throw noDeploymentsError("No deployments available to stream logs", "The resolved project does not have any deployed app yet.");
|
|
442
440
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
443
441
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
444
442
|
});
|
|
@@ -473,28 +471,28 @@ async function resolveExplicitLogDeployment(context, provider, projectId, appNam
|
|
|
473
471
|
exitCode: 1,
|
|
474
472
|
nextSteps: ["prisma-cli app list-deploys"]
|
|
475
473
|
});
|
|
476
|
-
const
|
|
477
|
-
if (!
|
|
474
|
+
const resolvedProjectApp = (await listApps(context, provider, projectId)).find((app) => app.id === shown.app?.id);
|
|
475
|
+
if (!resolvedProjectApp) throw new CliError({
|
|
478
476
|
code: "DEPLOYMENT_NOT_FOUND",
|
|
479
477
|
domain: "app",
|
|
480
|
-
summary: `Deployment "${deploymentId}" not found in the
|
|
481
|
-
why: "The requested deployment does not belong to an app in the
|
|
478
|
+
summary: `Deployment "${deploymentId}" not found in the resolved project`,
|
|
479
|
+
why: "The requested deployment does not belong to an app in the resolved project.",
|
|
482
480
|
fix: "Run prisma-cli app list-deploys to choose an available deployment id for this project.",
|
|
483
481
|
exitCode: 1,
|
|
484
482
|
nextSteps: ["prisma-cli app list-deploys"]
|
|
485
483
|
});
|
|
486
484
|
await context.stateStore.setSelectedApp(projectId, {
|
|
487
|
-
id:
|
|
488
|
-
name:
|
|
485
|
+
id: resolvedProjectApp.id,
|
|
486
|
+
name: resolvedProjectApp.name
|
|
489
487
|
});
|
|
490
488
|
return {
|
|
491
|
-
app:
|
|
489
|
+
app: resolvedProjectApp,
|
|
492
490
|
deployment: shown.deployment
|
|
493
491
|
};
|
|
494
492
|
}
|
|
495
493
|
async function resolveLiveLogDeployment(context, provider, projectId, appName) {
|
|
496
494
|
const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
|
|
497
|
-
if (!selectedApp) throw noDeploymentsError("No deployments available to stream logs", "The
|
|
495
|
+
if (!selectedApp) throw noDeploymentsError("No deployments available to stream logs", "The resolved project does not have any deployed app yet.");
|
|
498
496
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
499
497
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
500
498
|
});
|
|
@@ -526,10 +524,9 @@ function writeLogRecord(context, record) {
|
|
|
526
524
|
if (!record.text.endsWith("\n")) context.output.stdout.write("\n");
|
|
527
525
|
}
|
|
528
526
|
}
|
|
529
|
-
async function runAppPromote(context, deploymentId, appName) {
|
|
527
|
+
async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
530
528
|
ensurePreviewAppMode(context);
|
|
531
|
-
const projectId = await
|
|
532
|
-
const provider = await requirePreviewAppProvider(context);
|
|
529
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
533
530
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId), appName, "promote");
|
|
534
531
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
535
532
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
@@ -567,10 +564,9 @@ async function runAppPromote(context, deploymentId, appName) {
|
|
|
567
564
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
|
|
568
565
|
};
|
|
569
566
|
}
|
|
570
|
-
async function runAppRollback(context, appName, deploymentId) {
|
|
567
|
+
async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
571
568
|
ensurePreviewAppMode(context);
|
|
572
|
-
const projectId = await
|
|
573
|
-
const provider = await requirePreviewAppProvider(context);
|
|
569
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
574
570
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId), appName, "rollback");
|
|
575
571
|
const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
|
|
576
572
|
throw deployFailedError("Failed to list app deployments", error, ["prisma-cli app list-deploys"]);
|
|
@@ -610,10 +606,9 @@ async function runAppRollback(context, appName, deploymentId) {
|
|
|
610
606
|
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${targetDeployment.id}`]
|
|
611
607
|
};
|
|
612
608
|
}
|
|
613
|
-
async function runAppRemove(context, appName) {
|
|
609
|
+
async function runAppRemove(context, appName, projectRef) {
|
|
614
610
|
ensurePreviewAppMode(context);
|
|
615
|
-
const projectId = await
|
|
616
|
-
const provider = await requirePreviewAppProvider(context);
|
|
611
|
+
const { provider, projectId } = await requireProviderAndProjectContext(context, projectRef);
|
|
617
612
|
const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId), appName, "remove");
|
|
618
613
|
await confirmAppRemoval(context, selectedApp);
|
|
619
614
|
const removedApp = await provider.removeApp(selectedApp.id).catch((error) => {
|
|
@@ -654,7 +649,7 @@ async function resolveDeploySelection(context, projectId, apps, explicitAppName)
|
|
|
654
649
|
appId: matched.id,
|
|
655
650
|
useInteractiveSelection: false
|
|
656
651
|
};
|
|
657
|
-
if (!canPrompt(context)) throw usageError("Saved app selection is no longer available", "The locally selected app could not be found in the
|
|
652
|
+
if (!canPrompt(context)) throw usageError("Saved app selection is no longer available", "The locally selected app could not be found in the resolved project.", "Pass --app <name>, or rerun prisma-cli app deploy in a TTY to choose or create an app again.", ["prisma-cli app deploy"], "app");
|
|
658
653
|
}
|
|
659
654
|
if (!canPrompt(context)) throw usageError("App deploy requires an app selection in non-interactive mode", "This command cannot choose or create an app in the current mode.", "Pass --app <name>, or rerun prisma-cli app deploy in a TTY to choose or create an app.", ["prisma-cli app deploy --app hello-world"], "app");
|
|
660
655
|
return { useInteractiveSelection: true };
|
|
@@ -662,14 +657,14 @@ async function resolveDeploySelection(context, projectId, apps, explicitAppName)
|
|
|
662
657
|
async function resolveExistingAppSelection(context, projectId, apps, explicitAppName) {
|
|
663
658
|
if (explicitAppName) {
|
|
664
659
|
const matched = findAppByName(apps, explicitAppName);
|
|
665
|
-
if (!matched) throw usageError("Selected app does not exist in the
|
|
660
|
+
if (!matched) throw usageError("Selected app does not exist in the resolved project", `The app "${explicitAppName}" could not be found in resolved project "${projectId}".`, "Pass the name of an existing app, or rerun prisma-cli app list-deploys in a TTY to choose one.", ["prisma-cli app list-deploys"], "app");
|
|
666
661
|
return matched;
|
|
667
662
|
}
|
|
668
663
|
const savedSelection = await context.stateStore.readSelectedApp(projectId);
|
|
669
664
|
if (savedSelection) {
|
|
670
665
|
const matched = apps.find((app) => app.id === savedSelection.id) ?? findAppByName(apps, savedSelection.name);
|
|
671
666
|
if (matched) return matched;
|
|
672
|
-
if (!canPrompt(context)) throw usageError("Saved app selection is no longer available", "The locally selected app could not be found in the
|
|
667
|
+
if (!canPrompt(context)) throw usageError("Saved app selection is no longer available", "The locally selected app could not be found in the resolved project.", "Pass --app <name>, or rerun prisma-cli app list-deploys in a TTY to choose an available app.", ["prisma-cli app list-deploys"], "app");
|
|
673
668
|
}
|
|
674
669
|
if (apps.length === 0) return null;
|
|
675
670
|
if (!canPrompt(context)) throw usageError("App selection required in non-interactive mode", "This command cannot choose an app in the current mode.", "Pass --app <name>, or rerun prisma-cli app list-deploys in a TTY to choose an app.", ["prisma-cli app list-deploys"], "app");
|
|
@@ -685,7 +680,7 @@ async function resolveExistingAppSelection(context, projectId, apps, explicitApp
|
|
|
685
680
|
async function requireReleaseAppSelection(context, projectId, apps, explicitAppName, commandName) {
|
|
686
681
|
const selectedApp = await resolveExistingAppSelection(context, projectId, apps, explicitAppName);
|
|
687
682
|
if (selectedApp) return selectedApp;
|
|
688
|
-
throw usageError(`App ${commandName} requires an existing app`, "The
|
|
683
|
+
throw usageError(`App ${commandName} requires an existing app`, "The resolved project does not have an app that can be selected for this command.", `Deploy an app first, or rerun prisma-cli app ${commandName} with --app <name> after an app exists.`, ["prisma-cli app deploy", "prisma-cli app list-deploys"], "app");
|
|
689
684
|
}
|
|
690
685
|
async function confirmAppRemoval(context, app) {
|
|
691
686
|
if (context.flags.yes) return;
|
|
@@ -774,18 +769,29 @@ function resolveRollbackTarget(deployments, currentLiveDeploymentId) {
|
|
|
774
769
|
}
|
|
775
770
|
async function listApps(context, provider, projectId) {
|
|
776
771
|
return provider.listApps(projectId).then(sortApps).catch((error) => {
|
|
777
|
-
if (isMissingProjectError(error)) throw
|
|
778
|
-
|
|
779
|
-
"
|
|
780
|
-
"
|
|
781
|
-
|
|
772
|
+
if (isMissingProjectError(error)) throw new CliError({
|
|
773
|
+
code: "PROJECT_NOT_FOUND",
|
|
774
|
+
domain: "project",
|
|
775
|
+
summary: "Project not found",
|
|
776
|
+
why: `The resolved project "${projectId}" does not exist in the authenticated workspace or is no longer accessible.`,
|
|
777
|
+
fix: "Pass --project <id-or-name>, or run prisma-cli project show to inspect resolution for this directory.",
|
|
778
|
+
exitCode: 1,
|
|
779
|
+
nextSteps: ["prisma-cli project show", "prisma-cli app deploy --project <id-or-name>"]
|
|
780
|
+
});
|
|
782
781
|
throw deployFailedError("Failed to list apps", error, ["prisma-cli project show"]);
|
|
783
782
|
});
|
|
784
783
|
}
|
|
785
784
|
async function requirePreviewAppProvider(context) {
|
|
785
|
+
const { provider } = await requirePreviewAppProviderWithClient(context);
|
|
786
|
+
return provider;
|
|
787
|
+
}
|
|
788
|
+
async function requirePreviewAppProviderWithClient(context) {
|
|
786
789
|
const client = await requireComputeAuth(context.runtime.env);
|
|
787
790
|
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
788
|
-
return
|
|
791
|
+
return {
|
|
792
|
+
client,
|
|
793
|
+
provider: createPreviewAppProvider(client, createPreviewLogAuthOptions(context.runtime.env))
|
|
794
|
+
};
|
|
789
795
|
}
|
|
790
796
|
function createPreviewLogAuthOptions(env) {
|
|
791
797
|
const rawToken = env[SERVICE_TOKEN_ENV_VAR]?.trim();
|
|
@@ -803,42 +809,58 @@ function createPreviewLogAuthOptions(env) {
|
|
|
803
809
|
}
|
|
804
810
|
};
|
|
805
811
|
}
|
|
806
|
-
async function
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
nextSteps: ["prisma-cli project link"]
|
|
816
|
-
});
|
|
817
|
-
return projectId;
|
|
812
|
+
async function requireProviderAndProjectContext(context, explicitProject, options) {
|
|
813
|
+
const { client, provider } = await requirePreviewAppProviderWithClient(context);
|
|
814
|
+
const target = await resolveProjectContext(context, client, provider, explicitProject, options);
|
|
815
|
+
return {
|
|
816
|
+
client,
|
|
817
|
+
provider,
|
|
818
|
+
target,
|
|
819
|
+
projectId: target.project.id
|
|
820
|
+
};
|
|
818
821
|
}
|
|
819
|
-
async function
|
|
820
|
-
const
|
|
821
|
-
if (
|
|
822
|
-
await
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
822
|
+
async function resolveProjectContext(context, client, provider, explicitProject, options) {
|
|
823
|
+
const authState = await requireAuthenticatedAuthState(context);
|
|
824
|
+
if (!authState.workspace) throw workspaceRequiredError();
|
|
825
|
+
const resolved = await resolveProjectTarget({
|
|
826
|
+
context,
|
|
827
|
+
workspace: authState.workspace,
|
|
828
|
+
explicitProject,
|
|
829
|
+
listProjects: () => listRealWorkspaceProjects(client, authState.workspace),
|
|
830
|
+
createProject: options?.allowCreate ? async (name) => {
|
|
831
|
+
const project = await provider.createProject({ name }).catch((error) => {
|
|
832
|
+
throw createProjectOnFirstDeployError({
|
|
833
|
+
error,
|
|
834
|
+
inferredName: name,
|
|
835
|
+
workspaceName: authState.workspace.name
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
return {
|
|
839
|
+
id: project.id,
|
|
840
|
+
name: project.name,
|
|
841
|
+
workspace: authState.workspace
|
|
842
|
+
};
|
|
843
|
+
} : void 0,
|
|
844
|
+
allowCreate: options?.allowCreate,
|
|
845
|
+
prompt: createSelectPromptPort(context),
|
|
846
|
+
remember: true
|
|
826
847
|
});
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
848
|
+
const branchName = await context.stateStore.read().then((state) => state.branch.active);
|
|
849
|
+
return {
|
|
850
|
+
...resolved,
|
|
851
|
+
branch: {
|
|
852
|
+
name: branchName,
|
|
853
|
+
kind: toBranchKind(branchName)
|
|
854
|
+
}
|
|
855
|
+
};
|
|
834
856
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
857
|
+
function toBranchKind(name) {
|
|
858
|
+
return name === "production" ? "production" : "preview";
|
|
859
|
+
}
|
|
860
|
+
async function readCurrentWorkspaceId(context) {
|
|
861
|
+
const state = await context.stateStore.read();
|
|
862
|
+
if (state.auth?.workspaceId) return state.auth.workspaceId;
|
|
863
|
+
return (await readAuthState(context.runtime.env)).workspace?.id ?? null;
|
|
842
864
|
}
|
|
843
865
|
function normalizeBuildType(requestedBuildType) {
|
|
844
866
|
if (!requestedBuildType) return "auto";
|
|
@@ -875,7 +897,7 @@ function parseDeployPortMapping(requestedPort) {
|
|
|
875
897
|
}
|
|
876
898
|
function ensurePreviewAppMode(context) {
|
|
877
899
|
if (isRealMode(context)) return;
|
|
878
|
-
throw featureUnavailableError("App commands are not available in fixture mode", "Preview app commands require live app deployment integration.", "Rerun without fixture mode enabled to use preview app deployment workflows.", ["prisma-cli auth login", "prisma-cli project
|
|
900
|
+
throw featureUnavailableError("App commands are not available in fixture mode", "Preview app commands require live app deployment integration.", "Rerun without fixture mode enabled to use preview app deployment workflows.", ["prisma-cli auth login", "prisma-cli project show"], "app");
|
|
879
901
|
}
|
|
880
902
|
function deployFailedError(summary, error, nextSteps) {
|
|
881
903
|
return new CliError({
|
|
@@ -889,6 +911,52 @@ function deployFailedError(summary, error, nextSteps) {
|
|
|
889
911
|
nextSteps
|
|
890
912
|
});
|
|
891
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* `app deploy` falls into "create a new project on first deploy" when no
|
|
916
|
+
* existing project matches the package.json name (or the cwd basename as a
|
|
917
|
+
* fallback). When the create call fails the user often doesn't realise the
|
|
918
|
+
* CLI was attempting to create a project at all — they thought the deploy
|
|
919
|
+
* would find an existing project. Surface that context, and recommend the
|
|
920
|
+
* explicit `--project` flag as the unambiguous way out.
|
|
921
|
+
*/
|
|
922
|
+
function createProjectOnFirstDeployError(options) {
|
|
923
|
+
const { error, inferredName, workspaceName } = options;
|
|
924
|
+
const status = extractHttpStatus(error);
|
|
925
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
926
|
+
const inferredContext = `No existing project matched the package.json name \`${inferredName}\`, so the CLI attempted to create one.`;
|
|
927
|
+
const nextSteps = ["prisma-cli project list", "prisma-cli app deploy --project <id-or-name>"];
|
|
928
|
+
if (status === 401 || status === 403) return new CliError({
|
|
929
|
+
code: "AUTH_FORBIDDEN",
|
|
930
|
+
domain: "auth",
|
|
931
|
+
summary: "Could not create a new project for this deploy",
|
|
932
|
+
why: `${inferredContext} The platform rejected the create (HTTP ${status}).`,
|
|
933
|
+
fix: `Pass --project <id-or-name> to deploy into an existing project, or grant the service token project-create permission on workspace \`${workspaceName}\`.`,
|
|
934
|
+
debug: formatDebugDetails(error),
|
|
935
|
+
exitCode: 1,
|
|
936
|
+
nextSteps
|
|
937
|
+
});
|
|
938
|
+
return new CliError({
|
|
939
|
+
code: "DEPLOY_FAILED",
|
|
940
|
+
domain: "app",
|
|
941
|
+
summary: "Could not create a new project for this deploy",
|
|
942
|
+
why: `${inferredContext} ${errorMessage}`.trim(),
|
|
943
|
+
fix: "Pass --project <id-or-name> to deploy into an existing project, or retry after addressing the platform error above.",
|
|
944
|
+
debug: formatDebugDetails(error),
|
|
945
|
+
exitCode: 1,
|
|
946
|
+
nextSteps
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
function extractHttpStatus(error) {
|
|
950
|
+
if (!error || typeof error !== "object") return null;
|
|
951
|
+
const candidate = error;
|
|
952
|
+
if (typeof candidate.statusCode === "number") return candidate.statusCode;
|
|
953
|
+
if (typeof candidate.status === "number") return candidate.status;
|
|
954
|
+
if (typeof candidate.message === "string") {
|
|
955
|
+
const match = /\(HTTP (\d{3})\)/.exec(candidate.message);
|
|
956
|
+
if (match) return Number.parseInt(match[1], 10);
|
|
957
|
+
}
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
892
960
|
function noDeploymentsError(summary, why) {
|
|
893
961
|
return new CliError({
|
|
894
962
|
code: "NO_DEPLOYMENTS",
|
package/dist/controllers/auth.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { authRequiredError, usageError } from "../shell/errors.js";
|
|
2
2
|
import { canPrompt } from "../shell/runtime.js";
|
|
3
|
-
import {
|
|
3
|
+
import { performLogin, performLogout, readAuthState } from "../lib/auth/auth-ops.js";
|
|
4
4
|
import { createAuthUseCases } from "../use-cases/auth.js";
|
|
5
5
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
7
7
|
//#region src/controllers/auth.ts
|
|
8
8
|
function isRealMode(context) {
|
|
9
9
|
return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { featureUnavailableError, usageError } from "../shell/errors.js";
|
|
2
2
|
import { canPrompt } from "../shell/runtime.js";
|
|
3
|
-
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
4
3
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
4
|
+
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
5
5
|
import { createBranchUseCases } from "../use-cases/branch.js";
|
|
6
6
|
//#region src/controllers/branch.ts
|
|
7
7
|
const PREVIEW_BRANCH_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|