@prisma/cli 3.0.0-alpha.5 → 3.0.0-alpha.7
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/local-state.js +1 -1
- package/dist/commands/app/index.js +9 -1
- package/dist/controllers/app.js +629 -54
- package/dist/lib/app/bun-project.js +1 -1
- package/dist/lib/app/local-dev.js +1 -1
- package/dist/lib/app/preview-build.js +1 -1
- package/dist/lib/app/preview-interaction.js +2 -35
- package/dist/lib/app/preview-provider.js +110 -22
- package/dist/lib/auth/client.js +1 -1
- package/dist/lib/project/local-pin.js +51 -0
- package/dist/lib/project/resolution.js +71 -21
- package/dist/presenters/app.js +5 -2
- package/dist/presenters/project.js +3 -0
- package/dist/shell/command-meta.js +4 -4
- package/dist/shell/prompt.js +12 -2
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readBunPackageEntrypoint, readBunPackageJson, resolveBunEntrypoint } from "./bun-project.js";
|
|
2
|
-
import path from "node:path";
|
|
3
2
|
import { access } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
//#region src/lib/app/local-dev.ts
|
|
6
6
|
const NEXT_CONFIG_FILENAMES = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveBunEntrypoint } from "./bun-project.js";
|
|
2
|
-
import path from "node:path";
|
|
3
2
|
import { cp, readdir, readlink, rm, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
4
|
import { AstroBuild, BunBuild, NextjsBuild, NuxtBuild, TanstackStartBuild } from "@prisma/compute-sdk";
|
|
5
5
|
//#region src/lib/app/preview-build.ts
|
|
6
6
|
const PREVIEW_BUILD_TYPES = [
|
|
@@ -1,38 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../../shell/prompt.js";
|
|
2
2
|
//#region src/lib/app/preview-interaction.ts
|
|
3
|
-
const CREATE_NEW_APP = "__create_new_app__";
|
|
4
3
|
const PREVIEW_DEFAULT_REGION = "eu-central-1";
|
|
5
|
-
function createPreviewDeployInteraction(context) {
|
|
6
|
-
return {
|
|
7
|
-
async selectService(services) {
|
|
8
|
-
const sorted = services.slice().sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id));
|
|
9
|
-
const selection = await selectPrompt({
|
|
10
|
-
input: context.runtime.stdin,
|
|
11
|
-
output: context.runtime.stderr,
|
|
12
|
-
message: "Select an app",
|
|
13
|
-
choices: [...sorted.map((service) => ({
|
|
14
|
-
label: service.name,
|
|
15
|
-
value: service.id
|
|
16
|
-
})), {
|
|
17
|
-
label: "Create a new app",
|
|
18
|
-
value: CREATE_NEW_APP
|
|
19
|
-
}]
|
|
20
|
-
});
|
|
21
|
-
return selection === CREATE_NEW_APP ? null : selection;
|
|
22
|
-
},
|
|
23
|
-
async provideServiceName() {
|
|
24
|
-
return textPrompt({
|
|
25
|
-
input: context.runtime.stdin,
|
|
26
|
-
output: context.runtime.stderr,
|
|
27
|
-
message: "App name",
|
|
28
|
-
placeholder: "hello-world",
|
|
29
|
-
validate: (value) => !value?.trim() ? "App name is required" : void 0
|
|
30
|
-
}).then((value) => value.trim());
|
|
31
|
-
},
|
|
32
|
-
async selectRegion(_regions) {
|
|
33
|
-
return PREVIEW_DEFAULT_REGION;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
4
|
//#endregion
|
|
38
|
-
export { PREVIEW_DEFAULT_REGION
|
|
5
|
+
export { PREVIEW_DEFAULT_REGION };
|
|
@@ -14,25 +14,11 @@ function createPreviewAppProvider(client, options) {
|
|
|
14
14
|
name: projectResult.value.name
|
|
15
15
|
};
|
|
16
16
|
},
|
|
17
|
-
async listApps(projectId) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return detailResult.isOk() ? detailResult.value : {
|
|
23
|
-
id: service.id,
|
|
24
|
-
name: service.name,
|
|
25
|
-
region: service.region,
|
|
26
|
-
latestVersionId: null,
|
|
27
|
-
serviceEndpointDomain: void 0
|
|
28
|
-
};
|
|
29
|
-
}))).map((service) => ({
|
|
30
|
-
id: service.id,
|
|
31
|
-
name: service.name,
|
|
32
|
-
region: service.region ?? null,
|
|
33
|
-
liveDeploymentId: service.latestVersionId ?? null,
|
|
34
|
-
liveUrl: toAbsoluteUrl(service.serviceEndpointDomain ?? null)
|
|
35
|
-
}));
|
|
17
|
+
async listApps(projectId, options) {
|
|
18
|
+
return listComputeServices(client, {
|
|
19
|
+
projectId,
|
|
20
|
+
branchGitName: options?.branchName
|
|
21
|
+
});
|
|
36
22
|
},
|
|
37
23
|
async removeApp(appId) {
|
|
38
24
|
const appResult = await sdk.showService({ serviceId: appId });
|
|
@@ -60,6 +46,20 @@ function createPreviewAppProvider(client, options) {
|
|
|
60
46
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
61
47
|
},
|
|
62
48
|
async deployApp(options) {
|
|
49
|
+
const resolvedApp = options.appId ? {
|
|
50
|
+
appId: options.appId,
|
|
51
|
+
appName: options.appName,
|
|
52
|
+
region: options.region
|
|
53
|
+
} : options.branchName && options.appName ? await createBranchApp(client, {
|
|
54
|
+
projectId: options.projectId,
|
|
55
|
+
branchName: options.branchName,
|
|
56
|
+
appName: options.appName,
|
|
57
|
+
region: options.region
|
|
58
|
+
}) : {
|
|
59
|
+
appId: void 0,
|
|
60
|
+
appName: options.appName,
|
|
61
|
+
region: options.region
|
|
62
|
+
};
|
|
63
63
|
const deployResult = await sdk.deploy({
|
|
64
64
|
strategy: new PreviewBuildStrategy({
|
|
65
65
|
appPath: path.resolve(options.cwd),
|
|
@@ -67,9 +67,9 @@ function createPreviewAppProvider(client, options) {
|
|
|
67
67
|
buildType: options.buildType
|
|
68
68
|
}),
|
|
69
69
|
projectId: options.projectId,
|
|
70
|
-
serviceId:
|
|
71
|
-
serviceName:
|
|
72
|
-
region:
|
|
70
|
+
serviceId: resolvedApp.appId,
|
|
71
|
+
serviceName: resolvedApp.appName,
|
|
72
|
+
region: resolvedApp.region,
|
|
73
73
|
portMapping: options.portMapping,
|
|
74
74
|
envVars: options.envVars,
|
|
75
75
|
timeoutSeconds: 120,
|
|
@@ -213,6 +213,94 @@ function createPreviewAppProvider(client, options) {
|
|
|
213
213
|
}
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
|
+
async function listBranches(client, options) {
|
|
217
|
+
const result = await client.GET("/v1/projects/{projectId}/branches", { params: {
|
|
218
|
+
path: { projectId: options.projectId },
|
|
219
|
+
query: { gitName: options.gitName }
|
|
220
|
+
} });
|
|
221
|
+
if (result.error || !result.data) throw apiCallError("Failed to list branches", result.response, result.error);
|
|
222
|
+
return result.data.data;
|
|
223
|
+
}
|
|
224
|
+
async function resolveOrCreateBranch(client, options) {
|
|
225
|
+
const existing = (await listBranches(client, options))[0];
|
|
226
|
+
if (existing) return existing;
|
|
227
|
+
const result = await client.POST("/v1/projects/{projectId}/branches", {
|
|
228
|
+
params: { path: { projectId: options.projectId } },
|
|
229
|
+
body: {
|
|
230
|
+
gitName: options.gitName,
|
|
231
|
+
isDefault: options.gitName === "main"
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
if (result.error || !result.data) {
|
|
235
|
+
if (result.response.status === 409) {
|
|
236
|
+
const raced = (await listBranches(client, options))[0];
|
|
237
|
+
if (raced) return raced;
|
|
238
|
+
}
|
|
239
|
+
throw apiCallError(`Failed to create branch "${options.gitName}"`, result.response, result.error);
|
|
240
|
+
}
|
|
241
|
+
return result.data.data;
|
|
242
|
+
}
|
|
243
|
+
async function listComputeServices(client, options) {
|
|
244
|
+
const services = [];
|
|
245
|
+
let cursor;
|
|
246
|
+
while (true) {
|
|
247
|
+
const result = await client.GET("/v1/compute-services", { params: { query: {
|
|
248
|
+
projectId: options.projectId,
|
|
249
|
+
branchGitName: options.branchGitName,
|
|
250
|
+
cursor
|
|
251
|
+
} } });
|
|
252
|
+
if (result.error || !result.data) throw apiCallError("Failed to list apps", result.response, result.error);
|
|
253
|
+
services.push(...result.data.data);
|
|
254
|
+
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
255
|
+
cursor = result.data.pagination.nextCursor;
|
|
256
|
+
}
|
|
257
|
+
return services.map((service) => ({
|
|
258
|
+
id: service.id,
|
|
259
|
+
name: service.name,
|
|
260
|
+
region: service.region.id ?? null,
|
|
261
|
+
branchId: service.branchId,
|
|
262
|
+
liveDeploymentId: service.latestVersionId ?? null,
|
|
263
|
+
liveUrl: toAbsoluteUrl(service.serviceEndpointDomain ?? null)
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
async function createBranchApp(client, options) {
|
|
267
|
+
const branch = await resolveOrCreateBranch(client, {
|
|
268
|
+
projectId: options.projectId,
|
|
269
|
+
gitName: options.branchName
|
|
270
|
+
});
|
|
271
|
+
const result = await client.POST("/v1/compute-services", { body: {
|
|
272
|
+
projectId: options.projectId,
|
|
273
|
+
branchId: branch.id,
|
|
274
|
+
displayName: options.appName,
|
|
275
|
+
...options.region ? { regionId: options.region } : {}
|
|
276
|
+
} });
|
|
277
|
+
if (result.error || !result.data) {
|
|
278
|
+
if (result.response.status === 409) {
|
|
279
|
+
const matched = (await listComputeServices(client, {
|
|
280
|
+
projectId: options.projectId,
|
|
281
|
+
branchGitName: options.branchName
|
|
282
|
+
})).find((app) => app.name === options.appName);
|
|
283
|
+
if (matched) return {
|
|
284
|
+
appId: matched.id,
|
|
285
|
+
appName: matched.name,
|
|
286
|
+
region: matched.region ?? options.region
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
throw apiCallError(`Failed to create app "${options.appName}"`, result.response, result.error);
|
|
290
|
+
}
|
|
291
|
+
const service = result.data.data;
|
|
292
|
+
return {
|
|
293
|
+
appId: service.id,
|
|
294
|
+
appName: service.name,
|
|
295
|
+
region: service.region.id ?? options.region
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function apiCallError(summary, response, error) {
|
|
299
|
+
if (response.status === 404) return /* @__PURE__ */ new Error("Resource Not Found");
|
|
300
|
+
const message = error.error?.message ?? `Management API returned HTTP ${response.status}.`;
|
|
301
|
+
const hint = error.error?.hint ? ` ${error.error.hint}` : "";
|
|
302
|
+
return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
|
|
303
|
+
}
|
|
216
304
|
async function findAppForDeployment(sdk, deploymentId) {
|
|
217
305
|
const projectsResult = await sdk.listProjects();
|
|
218
306
|
if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
|
package/dist/lib/auth/client.js
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/lib/project/local-pin.ts
|
|
4
|
+
const LOCAL_RESOLUTION_PIN_RELATIVE_PATH = ".prisma/local.json";
|
|
5
|
+
async function readLocalResolutionPin(cwd) {
|
|
6
|
+
try {
|
|
7
|
+
const raw = await readFile(path.join(cwd, LOCAL_RESOLUTION_PIN_RELATIVE_PATH), "utf8");
|
|
8
|
+
const parsed = JSON.parse(raw);
|
|
9
|
+
if (!isLocalResolutionPin(parsed)) return { kind: "invalid" };
|
|
10
|
+
return {
|
|
11
|
+
kind: "present",
|
|
12
|
+
pin: parsed
|
|
13
|
+
};
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error.code === "ENOENT") return { kind: "missing" };
|
|
16
|
+
if (error instanceof SyntaxError) return { kind: "invalid" };
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function writeLocalResolutionPin(cwd, pin) {
|
|
21
|
+
const prismaDir = path.join(cwd, ".prisma");
|
|
22
|
+
await mkdir(prismaDir, { recursive: true });
|
|
23
|
+
const pinPath = path.join(cwd, LOCAL_RESOLUTION_PIN_RELATIVE_PATH);
|
|
24
|
+
const tmpPath = path.join(prismaDir, `local.${process.pid}.${Date.now()}.tmp`);
|
|
25
|
+
await writeFile(tmpPath, `${JSON.stringify(pin, null, 2)}\n`, "utf8");
|
|
26
|
+
await rename(tmpPath, pinPath);
|
|
27
|
+
}
|
|
28
|
+
async function ensureLocalResolutionPinGitignore(cwd) {
|
|
29
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
30
|
+
let existing = null;
|
|
31
|
+
try {
|
|
32
|
+
existing = await readFile(gitignorePath, "utf8");
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error.code !== "ENOENT") throw error;
|
|
35
|
+
}
|
|
36
|
+
if (existing === null) {
|
|
37
|
+
await writeFile(gitignorePath, ".prisma/\n", "utf8");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (existing.split(/\r?\n/).map((line) => line.trim()).some((line) => line === ".prisma/" || line === ".prisma/local.json")) return;
|
|
41
|
+
await writeFile(gitignorePath, existing.endsWith("\n") ? `${existing}.prisma/\n` : `${existing}\n.prisma/\n`, "utf8");
|
|
42
|
+
}
|
|
43
|
+
function isLocalResolutionPin(value) {
|
|
44
|
+
if (!value || typeof value !== "object") return false;
|
|
45
|
+
const keys = Object.keys(value);
|
|
46
|
+
if (keys.length !== 2 || !keys.includes("workspaceId") || !keys.includes("projectId")) return false;
|
|
47
|
+
const candidate = value;
|
|
48
|
+
return typeof candidate.workspaceId === "string" && candidate.workspaceId.trim().length > 0 && typeof candidate.projectId === "string" && candidate.projectId.trim().length > 0;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, ensureLocalResolutionPinGitignore, readLocalResolutionPin, writeLocalResolutionPin };
|
|
@@ -1,33 +1,44 @@
|
|
|
1
1
|
import { CliError } from "../../shell/errors.js";
|
|
2
2
|
import { canPrompt } from "../../shell/runtime.js";
|
|
3
|
-
import path from "node:path";
|
|
4
3
|
import { readFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
5
|
//#region src/lib/project/resolution.ts
|
|
6
6
|
async function resolveProjectTarget(options) {
|
|
7
7
|
const projects = await options.listProjects();
|
|
8
|
-
|
|
8
|
+
const inferredName = await inferTargetName(options.context.runtime.cwd);
|
|
9
|
+
if (options.explicitProject) return rememberIfRequested(options, resolveExplicitProject(options.explicitProject, projects, options.workspace), "explicit", {
|
|
10
|
+
targetName: options.explicitProject,
|
|
11
|
+
targetNameSource: "explicit"
|
|
12
|
+
});
|
|
9
13
|
const platformMapping = await resolveDurablePlatformMapping();
|
|
10
14
|
if (platformMapping) return rememberIfRequested(options, platformMapping, "platform-mapping");
|
|
11
|
-
const remembered = await options.context.stateStore.readRememberedProject(options.workspace.id);
|
|
12
15
|
let staleRemembered = false;
|
|
13
|
-
if (
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
staleRemembered =
|
|
16
|
+
if (!options.allowCreate) {
|
|
17
|
+
const rememberedResult = await resolveRememberedProject(options, projects);
|
|
18
|
+
if (rememberedResult.target) return rememberedResult.target;
|
|
19
|
+
staleRemembered = rememberedResult.stale;
|
|
17
20
|
}
|
|
18
|
-
const packageName =
|
|
21
|
+
const packageName = inferredName.source === "package-name" ? inferredName.name : null;
|
|
19
22
|
if (packageName) {
|
|
20
23
|
const matches = projects.filter((project) => projectMatchesPackageName(project, packageName));
|
|
21
|
-
if (matches.length === 1) return rememberIfRequested(options, matches[0], "package-name"
|
|
22
|
-
|
|
24
|
+
if (matches.length === 1) return rememberIfRequested(options, matches[0], "package-name", {
|
|
25
|
+
targetName: packageName,
|
|
26
|
+
targetNameSource: "package-name"
|
|
27
|
+
});
|
|
28
|
+
if (matches.length > 1) return resolveAmbiguousProject(options, matches, packageName, "package-name");
|
|
23
29
|
}
|
|
24
30
|
if (options.allowCreate && options.createProject) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
if (inferredName.name) {
|
|
32
|
+
const existing = projects.filter((project) => projectMatchesPackageName(project, inferredName.name));
|
|
33
|
+
if (existing.length === 1) return rememberIfRequested(options, existing[0], inferredName.source, {
|
|
34
|
+
targetName: inferredName.name,
|
|
35
|
+
targetNameSource: inferredName.source
|
|
36
|
+
});
|
|
37
|
+
if (existing.length > 1) return resolveAmbiguousProject(options, existing, inferredName.name, inferredName.source);
|
|
38
|
+
return rememberIfRequested(options, await options.createProject(inferredName.name), "created", {
|
|
39
|
+
targetName: inferredName.name,
|
|
40
|
+
targetNameSource: inferredName.source
|
|
41
|
+
});
|
|
31
42
|
}
|
|
32
43
|
}
|
|
33
44
|
if (options.prompt && canPrompt(options.context) && projects.length > 0) return rememberIfRequested(options, await options.prompt.select({
|
|
@@ -40,6 +51,25 @@ async function resolveProjectTarget(options) {
|
|
|
40
51
|
if (staleRemembered && projects.length > 1) throw localStateStaleError();
|
|
41
52
|
throw projectUnresolvedError();
|
|
42
53
|
}
|
|
54
|
+
async function resolveRememberedProject(options, projects) {
|
|
55
|
+
const remembered = await options.context.stateStore.readRememberedProject(options.workspace.id);
|
|
56
|
+
if (!remembered) return {
|
|
57
|
+
target: null,
|
|
58
|
+
stale: false
|
|
59
|
+
};
|
|
60
|
+
const matched = projects.find((project) => project.id === remembered.id);
|
|
61
|
+
if (!matched) return {
|
|
62
|
+
target: null,
|
|
63
|
+
stale: true
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
target: await rememberIfRequested(options, matched, "remembered-local", {
|
|
67
|
+
targetName: remembered.name,
|
|
68
|
+
targetNameSource: "remembered-local"
|
|
69
|
+
}),
|
|
70
|
+
stale: false
|
|
71
|
+
};
|
|
72
|
+
}
|
|
43
73
|
function projectNotFoundError(projectRef, workspace) {
|
|
44
74
|
return new CliError({
|
|
45
75
|
code: "PROJECT_NOT_FOUND",
|
|
@@ -104,6 +134,20 @@ async function readPackageName(cwd) {
|
|
|
104
134
|
throw error;
|
|
105
135
|
}
|
|
106
136
|
}
|
|
137
|
+
async function inferTargetName(cwd) {
|
|
138
|
+
const packageName = await readPackageName(cwd);
|
|
139
|
+
if (packageName && isValidInferredTargetName(packageName)) return {
|
|
140
|
+
name: packageName,
|
|
141
|
+
source: "package-name"
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
name: path.basename(cwd),
|
|
145
|
+
source: "directory-name"
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function isValidInferredTargetName(value) {
|
|
149
|
+
return /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(value);
|
|
150
|
+
}
|
|
107
151
|
function sortProjects(projects) {
|
|
108
152
|
return projects.slice().sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id));
|
|
109
153
|
}
|
|
@@ -113,14 +157,17 @@ function resolveExplicitProject(projectRef, projects, workspace) {
|
|
|
113
157
|
if (matches.length > 1) throw projectAmbiguousError(projectRef, matches);
|
|
114
158
|
throw projectNotFoundError(projectRef, workspace);
|
|
115
159
|
}
|
|
116
|
-
function resolveAmbiguousProject(options, matches, projectRef) {
|
|
160
|
+
function resolveAmbiguousProject(options, matches, projectRef, targetNameSource) {
|
|
117
161
|
if (options.prompt && canPrompt(options.context)) return options.prompt.select({
|
|
118
162
|
message: "Select a project",
|
|
119
163
|
choices: sortProjects(matches).map((project) => ({
|
|
120
164
|
label: `${project.name} (${project.id})`,
|
|
121
165
|
value: project
|
|
122
166
|
}))
|
|
123
|
-
}).then((selected) => rememberIfRequested(options, selected, "prompt"
|
|
167
|
+
}).then((selected) => rememberIfRequested(options, selected, "prompt", {
|
|
168
|
+
targetName: projectRef,
|
|
169
|
+
targetNameSource
|
|
170
|
+
}));
|
|
124
171
|
throw projectAmbiguousError(projectRef, matches);
|
|
125
172
|
}
|
|
126
173
|
function projectMatchesPackageName(project, packageName) {
|
|
@@ -129,7 +176,7 @@ function projectMatchesPackageName(project, packageName) {
|
|
|
129
176
|
async function resolveDurablePlatformMapping() {
|
|
130
177
|
return null;
|
|
131
178
|
}
|
|
132
|
-
async function rememberIfRequested(options, project, projectSource) {
|
|
179
|
+
async function rememberIfRequested(options, project, projectSource, resolutionDetails) {
|
|
133
180
|
if (options.remember) await options.context.stateStore.setRememberedProject({
|
|
134
181
|
id: project.id,
|
|
135
182
|
name: project.name,
|
|
@@ -138,7 +185,10 @@ async function rememberIfRequested(options, project, projectSource) {
|
|
|
138
185
|
return {
|
|
139
186
|
workspace: options.workspace,
|
|
140
187
|
project: toProjectSummary(project),
|
|
141
|
-
resolution: {
|
|
188
|
+
resolution: {
|
|
189
|
+
projectSource,
|
|
190
|
+
...resolutionDetails
|
|
191
|
+
}
|
|
142
192
|
};
|
|
143
193
|
}
|
|
144
194
|
function toProjectSummary(project) {
|
|
@@ -148,4 +198,4 @@ function toProjectSummary(project) {
|
|
|
148
198
|
};
|
|
149
199
|
}
|
|
150
200
|
//#endregion
|
|
151
|
-
export { resolveProjectTarget, sortProjects };
|
|
201
|
+
export { inferTargetName, projectNotFoundError, resolveProjectTarget, sortProjects };
|
package/dist/presenters/app.js
CHANGED
|
@@ -25,7 +25,7 @@ function serializeAppBuild(result) {
|
|
|
25
25
|
return result;
|
|
26
26
|
}
|
|
27
27
|
function renderAppDeploy(context, descriptor, result) {
|
|
28
|
-
|
|
28
|
+
const lines = renderShow({
|
|
29
29
|
title: "Deploying the selected app.",
|
|
30
30
|
descriptor,
|
|
31
31
|
fields: [
|
|
@@ -61,9 +61,12 @@ function renderAppDeploy(context, descriptor, result) {
|
|
|
61
61
|
}] : []
|
|
62
62
|
]
|
|
63
63
|
}, context.ui);
|
|
64
|
+
if (result.localPin?.written) lines.push(`Bound this directory in ${result.localPin.path}. Subsequent commands target the same Project.`);
|
|
65
|
+
return lines;
|
|
64
66
|
}
|
|
65
67
|
function serializeAppDeploy(result) {
|
|
66
|
-
|
|
68
|
+
const { localPin: _localPin, ...serialized } = result;
|
|
69
|
+
return serialized;
|
|
67
70
|
}
|
|
68
71
|
function renderAppUpdateEnv(context, descriptor, result) {
|
|
69
72
|
return renderShow({
|
|
@@ -105,9 +105,12 @@ function renderGitDisconnect(context, descriptor, result) {
|
|
|
105
105
|
function formatProjectSource(source) {
|
|
106
106
|
switch (source) {
|
|
107
107
|
case "explicit": return "explicit";
|
|
108
|
+
case "env": return "environment";
|
|
109
|
+
case "local-pin": return "local pin";
|
|
108
110
|
case "platform-mapping": return "platform mapping";
|
|
109
111
|
case "remembered-local": return "remembered local context";
|
|
110
112
|
case "package-name": return "package name";
|
|
113
|
+
case "directory-name": return "directory name";
|
|
111
114
|
case "created": return "created";
|
|
112
115
|
case "prompt": return "prompt";
|
|
113
116
|
}
|
|
@@ -60,7 +60,7 @@ const DESCRIPTORS = [
|
|
|
60
60
|
id: "app",
|
|
61
61
|
path: ["prisma", "app"],
|
|
62
62
|
description: "Manage apps and deployments for a project",
|
|
63
|
-
examples: ["prisma-cli app deploy", "prisma-cli app deploy --app
|
|
63
|
+
examples: ["prisma-cli app deploy", "prisma-cli app deploy --app my-app --framework nextjs --http-port 3000"]
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
id: "branch",
|
|
@@ -182,9 +182,9 @@ const DESCRIPTORS = [
|
|
|
182
182
|
description: "Creates a new deployment for the app",
|
|
183
183
|
examples: [
|
|
184
184
|
"prisma-cli app deploy",
|
|
185
|
-
"prisma-cli app deploy --app
|
|
186
|
-
"prisma-cli app deploy --app
|
|
187
|
-
"prisma-cli app deploy --
|
|
185
|
+
"prisma-cli app deploy --app my-app --env DATABASE_URL=postgresql://example",
|
|
186
|
+
"prisma-cli app deploy --app my-app --framework nextjs --http-port 3000",
|
|
187
|
+
"prisma-cli app deploy --branch feat-login --framework hono"
|
|
188
188
|
]
|
|
189
189
|
},
|
|
190
190
|
{
|
package/dist/shell/prompt.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { usageError } from "./errors.js";
|
|
2
|
-
import { isCancel, select, text } from "@clack/prompts";
|
|
2
|
+
import { confirm, isCancel, select, text } from "@clack/prompts";
|
|
3
3
|
//#region src/shell/prompt.ts
|
|
4
4
|
async function selectPrompt(options) {
|
|
5
5
|
const promptOptions = options.choices.map((choice) => ({
|
|
@@ -26,6 +26,16 @@ async function textPrompt(options) {
|
|
|
26
26
|
if (isCancel(response)) throw usageError("Interactive prompt canceled", "The command was canceled before a value was entered.", "Re-run the command and provide a value to continue.");
|
|
27
27
|
return response;
|
|
28
28
|
}
|
|
29
|
+
async function confirmPrompt(options) {
|
|
30
|
+
const response = await confirm({
|
|
31
|
+
input: options.input,
|
|
32
|
+
output: options.output,
|
|
33
|
+
message: options.message,
|
|
34
|
+
initialValue: options.initialValue ?? false
|
|
35
|
+
});
|
|
36
|
+
if (isCancel(response)) throw usageError("Interactive prompt canceled", "The command was canceled before a confirmation was made.", "Re-run the command and choose an option to continue.");
|
|
37
|
+
return response;
|
|
38
|
+
}
|
|
29
39
|
function disposePromptState(_input) {}
|
|
30
40
|
//#endregion
|
|
31
|
-
export { disposePromptState, selectPrompt, textPrompt };
|
|
41
|
+
export { confirmPrompt, disposePromptState, selectPrompt, textPrompt };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/cli",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.7",
|
|
4
4
|
"description": "Preview of the unified Prisma CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@clack/prompts": "^1.2.0",
|
|
39
|
-
"@prisma/compute-sdk": "^0.
|
|
39
|
+
"@prisma/compute-sdk": "^0.18.0",
|
|
40
40
|
"c12": "4.0.0-beta.4",
|
|
41
41
|
"@prisma/credentials-store": "^7.7.0",
|
|
42
42
|
"@prisma/management-api-sdk": "^1.27.0",
|