@prisma/cli 3.0.0-dev.63.1 → 3.0.0-dev.65.1
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/cli2.js +2 -3
- package/dist/controllers/app-env-file.js +4 -2
- package/dist/controllers/app-env.js +23 -17
- package/dist/controllers/app.js +30 -1
- package/dist/controllers/branch.js +5 -0
- package/dist/lib/diagnostics.js +15 -0
- package/dist/lib/git/local-status.js +57 -0
- package/dist/presenters/app-env.js +137 -43
- package/dist/presenters/app.js +140 -20
- package/dist/presenters/branch.js +10 -3
- package/dist/presenters/project.js +26 -1
- package/dist/presenters/verbose-context.js +64 -0
- package/dist/shell/command-runner.js +17 -1
- package/dist/shell/diagnostics-output.js +63 -0
- package/dist/shell/output.js +10 -1
- package/dist/shell/runtime.js +1 -1
- package/dist/shell/ui.js +20 -1
- package/package.json +3 -3
package/dist/cli2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError } from "./shell/errors.js";
|
|
2
2
|
import { createShellUi } from "./shell/ui.js";
|
|
3
|
-
import { writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
|
|
3
|
+
import { formatUnexpectedError, writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
|
|
4
4
|
import { attachCommandDescriptor } from "./shell/command-meta.js";
|
|
5
5
|
import { addCompactGlobalFlags } from "./shell/global-flags.js";
|
|
6
6
|
import { configureRuntimeCommand, createCommandContext } from "./shell/runtime.js";
|
|
@@ -33,8 +33,7 @@ async function runCli(options = {}) {
|
|
|
33
33
|
return process.exitCode ?? 0;
|
|
34
34
|
} catch (error) {
|
|
35
35
|
if (error instanceof CommanderError) return error.code === "commander.helpDisplayed" ? 0 : 2;
|
|
36
|
-
|
|
37
|
-
runtime.stderr.write(`${message}\n`);
|
|
36
|
+
runtime.stderr.write(formatUnexpectedError(error, runtime.argv.includes("--trace")));
|
|
38
37
|
return 1;
|
|
39
38
|
} finally {
|
|
40
39
|
runtime.stdin;
|
|
@@ -2,7 +2,7 @@ import { CliError } from "../shell/errors.js";
|
|
|
2
2
|
import { formatScopeLabel } from "../lib/app/env-config.js";
|
|
3
3
|
import { apiCallError, findVariableByNaturalKey, toMetadata } from "./app-env-api.js";
|
|
4
4
|
//#region src/controllers/app-env-file.ts
|
|
5
|
-
async function runEnvAddFile(context, client, projectId, resolved, filePath, assignments) {
|
|
5
|
+
async function runEnvAddFile(context, client, projectId, resolved, filePath, assignments, verboseContext) {
|
|
6
6
|
const existing = await findVariablesByNaturalKey(client, projectId, assignments.map((assignment) => assignment.key), resolved, context.runtime.signal);
|
|
7
7
|
const existingKeys = assignments.map((assignment) => assignment.key).filter((key) => existing.has(key));
|
|
8
8
|
if (existingKeys.length > 0) throw new CliError({
|
|
@@ -40,6 +40,7 @@ async function runEnvAddFile(context, client, projectId, resolved, filePath, ass
|
|
|
40
40
|
command: "project.env.add",
|
|
41
41
|
result: {
|
|
42
42
|
projectId,
|
|
43
|
+
verboseContext,
|
|
43
44
|
scope: resolved.descriptor,
|
|
44
45
|
variables,
|
|
45
46
|
file: {
|
|
@@ -51,7 +52,7 @@ async function runEnvAddFile(context, client, projectId, resolved, filePath, ass
|
|
|
51
52
|
nextSteps: []
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
|
-
async function runEnvUpdateFile(context, client, projectId, resolved, filePath, assignments) {
|
|
55
|
+
async function runEnvUpdateFile(context, client, projectId, resolved, filePath, assignments, verboseContext) {
|
|
55
56
|
const existing = await findVariablesByNaturalKey(client, projectId, assignments.map((assignment) => assignment.key), resolved, context.runtime.signal);
|
|
56
57
|
const missingKeys = assignments.map((assignment) => assignment.key).filter((key) => !existing.has(key));
|
|
57
58
|
if (missingKeys.length > 0) throw new CliError({
|
|
@@ -87,6 +88,7 @@ async function runEnvUpdateFile(context, client, projectId, resolved, filePath,
|
|
|
87
88
|
command: "project.env.update",
|
|
88
89
|
result: {
|
|
89
90
|
projectId,
|
|
91
|
+
verboseContext,
|
|
90
92
|
scope: resolved.descriptor,
|
|
91
93
|
variables,
|
|
92
94
|
file: {
|
|
@@ -17,12 +17,12 @@ async function runEnvAdd(context, rawAssignment, flags) {
|
|
|
17
17
|
});
|
|
18
18
|
if (!scope) throw usageError(`prisma-cli project env add requires --role or --branch`, "Writing without an explicit scope is rejected.", "Pass --role production, --role preview, or --branch <git-name>.", ["prisma-cli project env add KEY=value --role production"], "app");
|
|
19
19
|
const input = await resolveEnvWriteInput(context, source, "add");
|
|
20
|
-
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env add");
|
|
20
|
+
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env add");
|
|
21
21
|
const resolved = await resolveScopeToApi(client, projectId, scope, {
|
|
22
22
|
createBranchIfMissing: true,
|
|
23
23
|
signal: context.runtime.signal
|
|
24
24
|
});
|
|
25
|
-
if (input.kind === "file") return runEnvAddFile(context, client, projectId, resolved, input.filePath, input.assignments);
|
|
25
|
+
if (input.kind === "file") return runEnvAddFile(context, client, projectId, resolved, input.filePath, input.assignments, verboseContext);
|
|
26
26
|
if (await findVariableByNaturalKey(client, projectId, input.key, resolved, context.runtime.signal)) throw new CliError({
|
|
27
27
|
code: "ENV_VARIABLE_ALREADY_EXISTS",
|
|
28
28
|
domain: "app",
|
|
@@ -33,10 +33,6 @@ async function runEnvAdd(context, rawAssignment, flags) {
|
|
|
33
33
|
nextSteps: [`prisma-cli project env update ${input.key}=<new-value> ${formatScopeFlag(scope)}`]
|
|
34
34
|
});
|
|
35
35
|
const warnings = scope.kind === "branch" && !await findVariableByNaturalKey(client, projectId, input.key, {
|
|
36
|
-
scope: {
|
|
37
|
-
kind: "role",
|
|
38
|
-
role: "preview"
|
|
39
|
-
},
|
|
40
36
|
descriptor: {
|
|
41
37
|
kind: "role",
|
|
42
38
|
role: "preview"
|
|
@@ -61,6 +57,7 @@ async function runEnvAdd(context, rawAssignment, flags) {
|
|
|
61
57
|
command: "project.env.add",
|
|
62
58
|
result: {
|
|
63
59
|
projectId,
|
|
60
|
+
verboseContext,
|
|
64
61
|
scope: resolved.descriptor,
|
|
65
62
|
variable: toMetadata(data.data, resolved.descriptor)
|
|
66
63
|
},
|
|
@@ -76,12 +73,12 @@ async function runEnvUpdate(context, rawAssignment, flags) {
|
|
|
76
73
|
});
|
|
77
74
|
if (!scope) throw usageError(`prisma-cli project env update requires --role or --branch`, "Writing without an explicit scope is rejected.", "Pass --role production, --role preview, or --branch <git-name>.", ["prisma-cli project env update KEY=value --role production"], "app");
|
|
78
75
|
const input = await resolveEnvWriteInput(context, source, "update");
|
|
79
|
-
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env update");
|
|
76
|
+
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env update");
|
|
80
77
|
const resolved = await resolveScopeToApi(client, projectId, scope, {
|
|
81
78
|
createBranchIfMissing: false,
|
|
82
79
|
signal: context.runtime.signal
|
|
83
80
|
});
|
|
84
|
-
if (input.kind === "file") return runEnvUpdateFile(context, client, projectId, resolved, input.filePath, input.assignments);
|
|
81
|
+
if (input.kind === "file") return runEnvUpdateFile(context, client, projectId, resolved, input.filePath, input.assignments, verboseContext);
|
|
85
82
|
const existing = await findVariableByNaturalKey(client, projectId, input.key, resolved, context.runtime.signal);
|
|
86
83
|
if (!existing) throw new CliError({
|
|
87
84
|
code: "ENV_VARIABLE_NOT_FOUND",
|
|
@@ -102,6 +99,7 @@ async function runEnvUpdate(context, rawAssignment, flags) {
|
|
|
102
99
|
command: "project.env.update",
|
|
103
100
|
result: {
|
|
104
101
|
projectId,
|
|
102
|
+
verboseContext,
|
|
105
103
|
scope: resolved.descriptor,
|
|
106
104
|
variable: toMetadata(data.data, resolved.descriptor)
|
|
107
105
|
},
|
|
@@ -140,8 +138,8 @@ async function runEnvList(context, flags) {
|
|
|
140
138
|
requireExplicit: false,
|
|
141
139
|
command: "list"
|
|
142
140
|
});
|
|
143
|
-
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env list");
|
|
144
|
-
const resolved = await resolveListScopeToApi(client, projectId, explicit, {
|
|
141
|
+
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env list");
|
|
142
|
+
const resolved = await resolveListScopeToApi(client, projectId, explicit ?? void 0, {
|
|
145
143
|
cwd: context.runtime.cwd,
|
|
146
144
|
signal: context.runtime.signal
|
|
147
145
|
});
|
|
@@ -154,6 +152,7 @@ async function runEnvList(context, flags) {
|
|
|
154
152
|
command: "project.env.list",
|
|
155
153
|
result: {
|
|
156
154
|
projectId,
|
|
155
|
+
verboseContext,
|
|
157
156
|
scope: resolved.descriptor,
|
|
158
157
|
target: resolved.target,
|
|
159
158
|
variables: variables.map((row) => toMetadata(row, resolved.descriptor))
|
|
@@ -169,7 +168,7 @@ async function runEnvRemove(context, key, flags) {
|
|
|
169
168
|
command: "remove"
|
|
170
169
|
});
|
|
171
170
|
if (!scope) throw usageError("prisma-cli project env remove requires --role or --branch", "Writing without an explicit scope is rejected.", "Pass --role production, --role preview, or --branch <git-name>.", [`prisma-cli project env remove ${key} --role production`], "app");
|
|
172
|
-
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env remove");
|
|
171
|
+
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env remove");
|
|
173
172
|
const resolved = await resolveScopeToApi(client, projectId, scope, {
|
|
174
173
|
createBranchIfMissing: false,
|
|
175
174
|
signal: context.runtime.signal
|
|
@@ -193,6 +192,7 @@ async function runEnvRemove(context, key, flags) {
|
|
|
193
192
|
command: "project.env.remove",
|
|
194
193
|
result: {
|
|
195
194
|
projectId,
|
|
195
|
+
verboseContext,
|
|
196
196
|
scope: resolved.descriptor,
|
|
197
197
|
key
|
|
198
198
|
},
|
|
@@ -205,15 +205,21 @@ async function requireClientAndProject(context, explicitProject, commandName) {
|
|
|
205
205
|
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
206
206
|
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
207
207
|
if (!authState.workspace) throw workspaceRequiredError();
|
|
208
|
+
const target = await resolveProjectTarget({
|
|
209
|
+
context,
|
|
210
|
+
workspace: authState.workspace,
|
|
211
|
+
explicitProject,
|
|
212
|
+
listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
|
|
213
|
+
commandName
|
|
214
|
+
});
|
|
208
215
|
return {
|
|
209
216
|
client,
|
|
210
|
-
projectId:
|
|
211
|
-
|
|
217
|
+
projectId: target.project.id,
|
|
218
|
+
verboseContext: {
|
|
212
219
|
workspace: authState.workspace,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
})).project.id
|
|
220
|
+
project: target.project,
|
|
221
|
+
resolution: target.resolution
|
|
222
|
+
}
|
|
217
223
|
};
|
|
218
224
|
}
|
|
219
225
|
async function resolveScopeToApi(client, projectId, scope, options) {
|
package/dist/controllers/app.js
CHANGED
|
@@ -7,7 +7,7 @@ import { canPrompt } from "../shell/runtime.js";
|
|
|
7
7
|
import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
|
|
8
8
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
9
9
|
import { readAuthState } from "../lib/auth/auth-ops.js";
|
|
10
|
-
import { parseEnvAssignments } from "../lib/app/env-vars.js";
|
|
10
|
+
import { envVarNames, parseEnvAssignments } from "../lib/app/env-vars.js";
|
|
11
11
|
import { renderDeployOutputRows, renderDeploySettingsPreview } from "../lib/app/deploy-output.js";
|
|
12
12
|
import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
|
|
13
13
|
import { DEFAULT_LOCAL_DEV_PORT, resolveLocalBuildType, runLocalApp } from "../lib/app/local-dev.js";
|
|
@@ -213,6 +213,18 @@ async function runAppDeploy(context, appName, options) {
|
|
|
213
213
|
name: deployResult.app.name
|
|
214
214
|
},
|
|
215
215
|
deployment: deployResult.deployment,
|
|
216
|
+
deploySettings: {
|
|
217
|
+
framework: {
|
|
218
|
+
key: framework.key,
|
|
219
|
+
buildType,
|
|
220
|
+
name: framework.displayName,
|
|
221
|
+
source: framework.annotation
|
|
222
|
+
},
|
|
223
|
+
entrypoint: entrypoint ?? null,
|
|
224
|
+
httpPort: runtime.port,
|
|
225
|
+
region: selectedApp.region ?? null,
|
|
226
|
+
envVars: envVarNames(envVars)
|
|
227
|
+
},
|
|
216
228
|
durationMs: deployDurationMs,
|
|
217
229
|
localPin: localPinResult
|
|
218
230
|
},
|
|
@@ -228,6 +240,7 @@ async function runAppListDeploys(context, appName, projectRef) {
|
|
|
228
240
|
command: "app.list-deploys",
|
|
229
241
|
result: {
|
|
230
242
|
projectId,
|
|
243
|
+
verboseContext: toAppVerboseContext(target),
|
|
231
244
|
app: null,
|
|
232
245
|
deployments: []
|
|
233
246
|
},
|
|
@@ -247,6 +260,7 @@ async function runAppListDeploys(context, appName, projectRef) {
|
|
|
247
260
|
command: "app.list-deploys",
|
|
248
261
|
result: {
|
|
249
262
|
projectId,
|
|
263
|
+
verboseContext: toAppVerboseContext(target),
|
|
250
264
|
app: {
|
|
251
265
|
id: deploymentsResult.app.id,
|
|
252
266
|
name: deploymentsResult.app.name
|
|
@@ -265,6 +279,7 @@ async function runAppShow(context, appName, projectRef) {
|
|
|
265
279
|
command: "app.show",
|
|
266
280
|
result: {
|
|
267
281
|
projectId,
|
|
282
|
+
verboseContext: toAppVerboseContext(target),
|
|
268
283
|
app: null,
|
|
269
284
|
liveDeployment: null,
|
|
270
285
|
liveUrl: null,
|
|
@@ -287,6 +302,7 @@ async function runAppShow(context, appName, projectRef) {
|
|
|
287
302
|
command: "app.show",
|
|
288
303
|
result: {
|
|
289
304
|
projectId,
|
|
305
|
+
verboseContext: toAppVerboseContext(target),
|
|
290
306
|
app: {
|
|
291
307
|
id: deploymentsResult.app.id,
|
|
292
308
|
name: deploymentsResult.app.name
|
|
@@ -360,6 +376,7 @@ async function runAppOpen(context, appName, projectRef) {
|
|
|
360
376
|
command: "app.open",
|
|
361
377
|
result: {
|
|
362
378
|
projectId,
|
|
379
|
+
verboseContext: toAppVerboseContext(target),
|
|
363
380
|
app: {
|
|
364
381
|
id: deploymentsResult.app.id,
|
|
365
382
|
name: deploymentsResult.app.name
|
|
@@ -650,6 +667,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
|
|
|
650
667
|
command: "app.promote",
|
|
651
668
|
result: {
|
|
652
669
|
projectId,
|
|
670
|
+
verboseContext: toAppVerboseContext(target),
|
|
653
671
|
app: {
|
|
654
672
|
id: deploymentsResult.app.id,
|
|
655
673
|
name: deploymentsResult.app.name
|
|
@@ -692,6 +710,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
|
|
|
692
710
|
command: "app.rollback",
|
|
693
711
|
result: {
|
|
694
712
|
projectId,
|
|
713
|
+
verboseContext: toAppVerboseContext(target),
|
|
695
714
|
app: {
|
|
696
715
|
id: deploymentsResult.app.id,
|
|
697
716
|
name: deploymentsResult.app.name
|
|
@@ -720,6 +739,7 @@ async function runAppRemove(context, appName, projectRef) {
|
|
|
720
739
|
command: "app.remove",
|
|
721
740
|
result: {
|
|
722
741
|
projectId,
|
|
742
|
+
verboseContext: toAppVerboseContext(target),
|
|
723
743
|
app: {
|
|
724
744
|
id: removedApp.id,
|
|
725
745
|
name: removedApp.name
|
|
@@ -1464,10 +1484,19 @@ function toBranchKind(name) {
|
|
|
1464
1484
|
}
|
|
1465
1485
|
function toResultBranch(branch) {
|
|
1466
1486
|
return {
|
|
1487
|
+
id: branch.id,
|
|
1467
1488
|
name: branch.name,
|
|
1468
1489
|
kind: branch.kind
|
|
1469
1490
|
};
|
|
1470
1491
|
}
|
|
1492
|
+
function toAppVerboseContext(target) {
|
|
1493
|
+
return {
|
|
1494
|
+
workspace: target.workspace,
|
|
1495
|
+
project: target.project,
|
|
1496
|
+
branch: target.branch,
|
|
1497
|
+
resolution: target.resolution
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1471
1500
|
function toBranchDatabaseDeployBranch(branch) {
|
|
1472
1501
|
if (!branch.id) throw new Error(`Deploy branch "${branch.name}" was not resolved remotely.`);
|
|
1473
1502
|
return {
|
|
@@ -41,6 +41,11 @@ async function listRealBranches(context) {
|
|
|
41
41
|
return {
|
|
42
42
|
projectId: target.project.id,
|
|
43
43
|
projectName: target.project.name,
|
|
44
|
+
verboseContext: {
|
|
45
|
+
workspace,
|
|
46
|
+
project: target.project,
|
|
47
|
+
resolution: target.resolution
|
|
48
|
+
},
|
|
44
49
|
branches: sortBranches(branches.map(toBranchSummary))
|
|
45
50
|
};
|
|
46
51
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { resolveLocalStateFilePath } from "../adapters/local-state.js";
|
|
2
|
+
import { resolveStateDir } from "../shell/runtime.js";
|
|
3
|
+
import { readLocalGitState } from "./git/local-status.js";
|
|
4
|
+
//#region src/lib/diagnostics.ts
|
|
5
|
+
async function collectCommandDiagnostics(context, options = {}) {
|
|
6
|
+
const stateDir = resolveStateDir(context.runtime);
|
|
7
|
+
return {
|
|
8
|
+
cwd: context.runtime.cwd,
|
|
9
|
+
stateFilePath: resolveLocalStateFilePath(stateDir),
|
|
10
|
+
git: await readLocalGitState(context.runtime.cwd, context.runtime.signal),
|
|
11
|
+
durationMs: options.durationMs
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { collectCommandDiagnostics };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
//#region src/lib/git/local-status.ts
|
|
3
|
+
async function readLocalGitState(cwd, signal) {
|
|
4
|
+
signal.throwIfAborted();
|
|
5
|
+
if ((await runGit(cwd, ["rev-parse", "--is-inside-work-tree"], signal))?.trim() !== "true") return null;
|
|
6
|
+
const [ref, sha, status] = await Promise.all([
|
|
7
|
+
runGit(cwd, [
|
|
8
|
+
"symbolic-ref",
|
|
9
|
+
"--quiet",
|
|
10
|
+
"--short",
|
|
11
|
+
"HEAD"
|
|
12
|
+
], signal),
|
|
13
|
+
runGit(cwd, [
|
|
14
|
+
"rev-parse",
|
|
15
|
+
"--short",
|
|
16
|
+
"HEAD"
|
|
17
|
+
], signal),
|
|
18
|
+
runGit(cwd, ["status", "--porcelain"], signal)
|
|
19
|
+
]);
|
|
20
|
+
return {
|
|
21
|
+
ref: cleanGitValue(ref),
|
|
22
|
+
sha: cleanGitValue(sha),
|
|
23
|
+
dirty: status === null ? null : status.trim().length > 0
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function runGit(cwd, args, signal) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
signal.throwIfAborted();
|
|
29
|
+
execFile("git", args, {
|
|
30
|
+
cwd,
|
|
31
|
+
signal,
|
|
32
|
+
timeout: 2e3
|
|
33
|
+
}, (error, stdout) => {
|
|
34
|
+
if (signal.aborted) {
|
|
35
|
+
reject(error);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (error) {
|
|
39
|
+
resolve(null);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
resolve(stdout);
|
|
43
|
+
}).on("error", (error) => {
|
|
44
|
+
if (signal.aborted) {
|
|
45
|
+
reject(error);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
resolve(null);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function cleanGitValue(value) {
|
|
53
|
+
const cleaned = value?.trim();
|
|
54
|
+
return cleaned ? cleaned : null;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { readLocalGitState };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { renderVerboseBlock } from "../shell/ui.js";
|
|
1
2
|
import { renderList, renderShow, serializeList } from "../output/patterns.js";
|
|
3
|
+
import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
|
|
2
4
|
//#region src/presenters/app-env.ts
|
|
3
5
|
function scopeLabel(scope) {
|
|
4
6
|
if (scope.kind === "role") return scope.role ?? "unknown";
|
|
@@ -14,23 +16,102 @@ function listTargetLabel(result) {
|
|
|
14
16
|
}
|
|
15
17
|
return scopeLabel(result.scope);
|
|
16
18
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
function renderEnvVerboseBlocks(context, result) {
|
|
20
|
+
return [...renderEnvResolvedContextBlock(context, result.verboseContext), ...renderEnvTargetBlock(context, result)];
|
|
21
|
+
}
|
|
22
|
+
function renderEnvResolvedContextBlock(context, verboseContext) {
|
|
23
|
+
return renderResolvedProjectContextBlock(context.ui, verboseContext);
|
|
24
|
+
}
|
|
25
|
+
function renderEnvTargetBlock(context, result) {
|
|
26
|
+
return renderVerboseBlock(context.ui, envTargetRows(result), { title: "Env target" });
|
|
27
|
+
}
|
|
28
|
+
function envTargetRows(result) {
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
key: "project id",
|
|
32
|
+
value: result.projectId,
|
|
33
|
+
tone: "dim"
|
|
24
34
|
},
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
{
|
|
36
|
+
key: "scope",
|
|
37
|
+
value: scopeLabel(result.scope)
|
|
38
|
+
},
|
|
39
|
+
...envListTargetRows(result),
|
|
40
|
+
...envFileRows(result),
|
|
41
|
+
{
|
|
42
|
+
key: "keys",
|
|
43
|
+
value: formatKeyNames(envResultKeys(result)),
|
|
44
|
+
tone: envResultKeys(result).length > 0 ? "default" : "dim"
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
function envListTargetRows(result) {
|
|
49
|
+
if (!("target" in result)) return [];
|
|
50
|
+
return [
|
|
51
|
+
{
|
|
52
|
+
key: "target source",
|
|
53
|
+
value: result.target.source
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: "env map",
|
|
57
|
+
value: result.target.envMap
|
|
58
|
+
},
|
|
59
|
+
...result.target.branchName ? [{
|
|
60
|
+
key: "branch",
|
|
61
|
+
value: result.target.branchName
|
|
62
|
+
}] : [],
|
|
63
|
+
...result.target.branchId ? [{
|
|
64
|
+
key: "branch id",
|
|
65
|
+
value: result.target.branchId,
|
|
66
|
+
tone: "dim"
|
|
67
|
+
}] : [],
|
|
68
|
+
...result.target.branchExists === false ? [{
|
|
69
|
+
key: "branch state",
|
|
70
|
+
value: "not created yet",
|
|
71
|
+
tone: "warning"
|
|
72
|
+
}] : []
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
function envFileRows(result) {
|
|
76
|
+
if (!("file" in result) || !result.file) return [];
|
|
77
|
+
return [{
|
|
78
|
+
key: "file",
|
|
79
|
+
value: result.file.path
|
|
80
|
+
}, {
|
|
81
|
+
key: "file count",
|
|
82
|
+
value: String(result.file.count)
|
|
83
|
+
}];
|
|
84
|
+
}
|
|
85
|
+
function envResultKeys(result) {
|
|
86
|
+
if ("variables" in result && result.variables) return result.variables.map((variable) => variable.key).sort((left, right) => left.localeCompare(right));
|
|
87
|
+
if ("variable" in result && result.variable) return [result.variable.key];
|
|
88
|
+
if ("key" in result) return [result.key];
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
function formatKeyNames(keys) {
|
|
92
|
+
return keys.length > 0 ? keys.join(", ") : "none";
|
|
93
|
+
}
|
|
94
|
+
function renderEnvAdd(context, descriptor, result) {
|
|
95
|
+
if (result.variables !== void 0) {
|
|
96
|
+
const lines = renderList({
|
|
97
|
+
title: "Setting new environment variables from file.",
|
|
98
|
+
descriptor,
|
|
99
|
+
parentContext: {
|
|
100
|
+
key: "target",
|
|
101
|
+
value: `${scopeLabel(result.scope)} from ${result.file.path}`
|
|
102
|
+
},
|
|
103
|
+
items: result.variables.map((variable) => ({
|
|
104
|
+
noun: "variable",
|
|
105
|
+
label: `${variable.key} (${variable.source})`,
|
|
106
|
+
id: variable.id,
|
|
107
|
+
status: variable.isManagedBySystem ? "default" : null
|
|
108
|
+
})),
|
|
109
|
+
emptyMessage: "No environment variables imported."
|
|
110
|
+
}, context.ui);
|
|
111
|
+
lines.push(...renderEnvVerboseBlocks(context, result));
|
|
112
|
+
return lines;
|
|
113
|
+
}
|
|
114
|
+
const lines = renderShow({
|
|
34
115
|
title: "Setting a new environment variable.",
|
|
35
116
|
descriptor,
|
|
36
117
|
fields: [
|
|
@@ -58,27 +139,33 @@ function renderEnvAdd(context, descriptor, result) {
|
|
|
58
139
|
}
|
|
59
140
|
]
|
|
60
141
|
}, context.ui);
|
|
142
|
+
lines.push(...renderEnvVerboseBlocks(context, result));
|
|
143
|
+
return lines;
|
|
61
144
|
}
|
|
62
145
|
function serializeEnvAdd(result) {
|
|
63
|
-
return result;
|
|
146
|
+
return stripVerboseContext(result);
|
|
64
147
|
}
|
|
65
148
|
function renderEnvUpdate(context, descriptor, result) {
|
|
66
|
-
if (result.variables !== void 0)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
149
|
+
if (result.variables !== void 0) {
|
|
150
|
+
const lines = renderList({
|
|
151
|
+
title: "Replacing environment variable values from file.",
|
|
152
|
+
descriptor,
|
|
153
|
+
parentContext: {
|
|
154
|
+
key: "target",
|
|
155
|
+
value: `${scopeLabel(result.scope)} from ${result.file.path}`
|
|
156
|
+
},
|
|
157
|
+
items: result.variables.map((variable) => ({
|
|
158
|
+
noun: "variable",
|
|
159
|
+
label: `${variable.key} (${variable.source})`,
|
|
160
|
+
id: variable.id,
|
|
161
|
+
status: variable.isManagedBySystem ? "default" : null
|
|
162
|
+
})),
|
|
163
|
+
emptyMessage: "No environment variables updated."
|
|
164
|
+
}, context.ui);
|
|
165
|
+
lines.push(...renderEnvVerboseBlocks(context, result));
|
|
166
|
+
return lines;
|
|
167
|
+
}
|
|
168
|
+
const lines = renderShow({
|
|
82
169
|
title: "Replacing the environment variable's value.",
|
|
83
170
|
descriptor,
|
|
84
171
|
fields: [
|
|
@@ -106,12 +193,14 @@ function renderEnvUpdate(context, descriptor, result) {
|
|
|
106
193
|
}
|
|
107
194
|
]
|
|
108
195
|
}, context.ui);
|
|
196
|
+
lines.push(...renderEnvVerboseBlocks(context, result));
|
|
197
|
+
return lines;
|
|
109
198
|
}
|
|
110
199
|
function serializeEnvUpdate(result) {
|
|
111
|
-
return result;
|
|
200
|
+
return stripVerboseContext(result);
|
|
112
201
|
}
|
|
113
202
|
function renderEnvList(context, descriptor, result) {
|
|
114
|
-
|
|
203
|
+
const lines = renderList({
|
|
115
204
|
title: "Listing environment variables for the selected scope.",
|
|
116
205
|
descriptor,
|
|
117
206
|
parentContext: {
|
|
@@ -126,26 +215,29 @@ function renderEnvList(context, descriptor, result) {
|
|
|
126
215
|
})),
|
|
127
216
|
emptyMessage: "No environment variables defined in this scope."
|
|
128
217
|
}, context.ui);
|
|
218
|
+
lines.push(...renderEnvVerboseBlocks(context, result));
|
|
219
|
+
return lines;
|
|
129
220
|
}
|
|
130
221
|
function serializeEnvList(result) {
|
|
222
|
+
const serializable = stripVerboseContext(result);
|
|
131
223
|
return {
|
|
132
|
-
projectId:
|
|
133
|
-
scope:
|
|
134
|
-
target:
|
|
224
|
+
projectId: serializable.projectId,
|
|
225
|
+
scope: serializable.scope,
|
|
226
|
+
target: serializable.target,
|
|
135
227
|
...serializeList({
|
|
136
|
-
context: { target: listTargetLabel(
|
|
137
|
-
items:
|
|
228
|
+
context: { target: listTargetLabel(serializable) },
|
|
229
|
+
items: serializable.variables.map((variable) => ({
|
|
138
230
|
noun: "variable",
|
|
139
231
|
label: `${variable.key} (${variable.source})`,
|
|
140
232
|
id: variable.id,
|
|
141
233
|
status: variable.isManagedBySystem ? "default" : null
|
|
142
234
|
}))
|
|
143
235
|
}),
|
|
144
|
-
variables:
|
|
236
|
+
variables: serializable.variables
|
|
145
237
|
};
|
|
146
238
|
}
|
|
147
239
|
function renderEnvRm(context, descriptor, result) {
|
|
148
|
-
|
|
240
|
+
const lines = renderShow({
|
|
149
241
|
title: "Removing the environment variable from the scope.",
|
|
150
242
|
descriptor,
|
|
151
243
|
fields: [
|
|
@@ -163,9 +255,11 @@ function renderEnvRm(context, descriptor, result) {
|
|
|
163
255
|
}
|
|
164
256
|
]
|
|
165
257
|
}, context.ui);
|
|
258
|
+
lines.push(...renderEnvVerboseBlocks(context, result));
|
|
259
|
+
return lines;
|
|
166
260
|
}
|
|
167
261
|
function serializeEnvRm(result) {
|
|
168
|
-
return result;
|
|
262
|
+
return stripVerboseContext(result);
|
|
169
263
|
}
|
|
170
264
|
//#endregion
|
|
171
265
|
export { renderEnvAdd, renderEnvList, renderEnvRm, renderEnvUpdate, serializeEnvAdd, serializeEnvList, serializeEnvRm, serializeEnvUpdate };
|
package/dist/presenters/app.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { renderVerboseBlock } from "../shell/ui.js";
|
|
1
2
|
import { renderDeployOutputRows } from "../lib/app/deploy-output.js";
|
|
2
3
|
import { formatDomainFailureFix } from "../lib/app/domain-guidance.js";
|
|
3
4
|
import { renderList, renderShow, serializeList } from "../output/patterns.js";
|
|
5
|
+
import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
|
|
4
6
|
//#region src/presenters/app.ts
|
|
5
7
|
function renderAppBuild(context, descriptor, result) {
|
|
6
8
|
return renderShow({
|
|
@@ -35,12 +37,18 @@ function renderAppDeploy(context, descriptor, result) {
|
|
|
35
37
|
...renderDeployOutputRows(context.ui, [{
|
|
36
38
|
label: "Logs",
|
|
37
39
|
value: "prisma-cli app logs"
|
|
38
|
-
}])
|
|
40
|
+
}]),
|
|
41
|
+
...renderDeployResolvedContextBlock(context, result),
|
|
42
|
+
...renderDeploySettingsBlock(context, result)
|
|
39
43
|
];
|
|
40
44
|
}
|
|
41
45
|
function serializeAppDeploy(result) {
|
|
42
|
-
const { localPin: _localPin, ...serialized } = result;
|
|
43
|
-
|
|
46
|
+
const { deploySettings: _deploySettings, localPin: _localPin, ...serialized } = result;
|
|
47
|
+
const { id: _branchId, ...branch } = serialized.branch;
|
|
48
|
+
return {
|
|
49
|
+
...serialized,
|
|
50
|
+
branch
|
|
51
|
+
};
|
|
44
52
|
}
|
|
45
53
|
function renderBranchDatabaseDeploySummary(context, result) {
|
|
46
54
|
if (!result.branchDatabase || result.branchDatabase.status !== "created") return [];
|
|
@@ -70,8 +78,107 @@ function formatDuration(durationMs) {
|
|
|
70
78
|
if (durationMs < 1e3) return `${durationMs}ms`;
|
|
71
79
|
return `${(durationMs / 1e3).toFixed(1)}s`;
|
|
72
80
|
}
|
|
81
|
+
function renderDeployResolvedContextBlock(context, result) {
|
|
82
|
+
return renderResolvedProjectContextBlock(context.ui, {
|
|
83
|
+
workspace: result.workspace,
|
|
84
|
+
project: result.project,
|
|
85
|
+
resolution: result.resolution,
|
|
86
|
+
branch: {
|
|
87
|
+
id: result.branch.id,
|
|
88
|
+
name: result.branch.name,
|
|
89
|
+
kind: result.branch.kind
|
|
90
|
+
}
|
|
91
|
+
}, { extraRows: [
|
|
92
|
+
{
|
|
93
|
+
key: "app",
|
|
94
|
+
value: result.app.name
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
key: "app id",
|
|
98
|
+
value: result.app.id,
|
|
99
|
+
tone: "dim"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: "deployment id",
|
|
103
|
+
value: result.deployment.id,
|
|
104
|
+
tone: "dim"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
key: "deployment status",
|
|
108
|
+
value: result.deployment.status
|
|
109
|
+
},
|
|
110
|
+
...result.localPin ? [{
|
|
111
|
+
key: "local pin",
|
|
112
|
+
value: result.localPin.path
|
|
113
|
+
}] : [],
|
|
114
|
+
{
|
|
115
|
+
key: "deploy duration",
|
|
116
|
+
value: formatDuration(result.durationMs)
|
|
117
|
+
}
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
function renderDeploySettingsBlock(context, result) {
|
|
121
|
+
return renderVerboseBlock(context.ui, [...deploySettingsRows(result.deploySettings), ...branchDatabaseRows(result.branchDatabase)], { title: "Deploy settings" });
|
|
122
|
+
}
|
|
123
|
+
function deploySettingsRows(settings) {
|
|
124
|
+
return [
|
|
125
|
+
{
|
|
126
|
+
key: "framework",
|
|
127
|
+
value: `${settings.framework.name} (${settings.framework.buildType})`
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
key: "framework source",
|
|
131
|
+
value: settings.framework.source,
|
|
132
|
+
tone: "dim"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
key: "entrypoint",
|
|
136
|
+
value: settings.entrypoint ?? "derived from build output",
|
|
137
|
+
tone: settings.entrypoint ? "default" : "dim"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
key: "http port",
|
|
141
|
+
value: String(settings.httpPort)
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
key: "region",
|
|
145
|
+
value: settings.region ?? "existing app region",
|
|
146
|
+
tone: settings.region ? "default" : "dim"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
key: "env vars",
|
|
150
|
+
value: formatEnvVarNames(settings.envVars),
|
|
151
|
+
tone: settings.envVars.length > 0 ? "default" : "dim"
|
|
152
|
+
}
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
function branchDatabaseRows(branchDatabase) {
|
|
156
|
+
if (!branchDatabase) return [{
|
|
157
|
+
key: "branch db",
|
|
158
|
+
value: "not configured",
|
|
159
|
+
tone: "dim"
|
|
160
|
+
}];
|
|
161
|
+
return [
|
|
162
|
+
{
|
|
163
|
+
key: "branch db",
|
|
164
|
+
value: branchDatabase.status === "created" ? `created${branchDatabase.database ? ` (${branchDatabase.database.name})` : ""}` : `skipped${branchDatabase.reason ? ` (${branchDatabase.reason})` : ""}`,
|
|
165
|
+
tone: branchDatabase.status === "created" ? "success" : "dim"
|
|
166
|
+
},
|
|
167
|
+
...branchDatabase.envVars.length > 0 ? [{
|
|
168
|
+
key: "branch db env",
|
|
169
|
+
value: branchDatabase.envVars.join(", ")
|
|
170
|
+
}] : [],
|
|
171
|
+
...branchDatabase.schema ? [{
|
|
172
|
+
key: "branch db schema",
|
|
173
|
+
value: `${formatBranchDatabaseSchemaCommand(branchDatabase.schema.command)} (${branchDatabase.schema.source}, ${branchDatabase.schema.path})`
|
|
174
|
+
}] : []
|
|
175
|
+
];
|
|
176
|
+
}
|
|
177
|
+
function formatEnvVarNames(envVars) {
|
|
178
|
+
return envVars.length > 0 ? envVars.join(", ") : "none";
|
|
179
|
+
}
|
|
73
180
|
function renderAppListDeploys(context, descriptor, result) {
|
|
74
|
-
|
|
181
|
+
const lines = renderList({
|
|
75
182
|
title: "Listing deployments for the selected app.",
|
|
76
183
|
descriptor,
|
|
77
184
|
parentContext: {
|
|
@@ -86,20 +193,23 @@ function renderAppListDeploys(context, descriptor, result) {
|
|
|
86
193
|
})),
|
|
87
194
|
emptyMessage: result.app ? "No deployments found." : "No apps found."
|
|
88
195
|
}, context.ui);
|
|
196
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
197
|
+
return lines;
|
|
89
198
|
}
|
|
90
199
|
function serializeAppListDeploys(result) {
|
|
91
|
-
|
|
92
|
-
|
|
200
|
+
const { verboseContext: _verboseContext, ...serializable } = result;
|
|
201
|
+
if (!serializable.app) return {
|
|
202
|
+
projectId: serializable.projectId,
|
|
93
203
|
app: null,
|
|
94
204
|
items: [],
|
|
95
205
|
count: 0
|
|
96
206
|
};
|
|
97
207
|
return {
|
|
98
|
-
projectId:
|
|
99
|
-
app:
|
|
208
|
+
projectId: serializable.projectId,
|
|
209
|
+
app: serializable.app,
|
|
100
210
|
...serializeList({
|
|
101
|
-
context: { app:
|
|
102
|
-
items:
|
|
211
|
+
context: { app: serializable.app.name },
|
|
212
|
+
items: serializable.deployments.map((deployment) => ({
|
|
103
213
|
noun: "deployment",
|
|
104
214
|
label: deployment.id,
|
|
105
215
|
id: deployment.id,
|
|
@@ -109,7 +219,7 @@ function serializeAppListDeploys(result) {
|
|
|
109
219
|
};
|
|
110
220
|
}
|
|
111
221
|
function renderAppShow(context, descriptor, result) {
|
|
112
|
-
|
|
222
|
+
const lines = renderShow({
|
|
113
223
|
title: "Showing the selected app state.",
|
|
114
224
|
descriptor,
|
|
115
225
|
fields: [
|
|
@@ -139,9 +249,11 @@ function renderAppShow(context, descriptor, result) {
|
|
|
139
249
|
}
|
|
140
250
|
]
|
|
141
251
|
}, context.ui);
|
|
252
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
253
|
+
return lines;
|
|
142
254
|
}
|
|
143
255
|
function serializeAppShow(result) {
|
|
144
|
-
return result;
|
|
256
|
+
return stripVerboseContext(result);
|
|
145
257
|
}
|
|
146
258
|
function renderAppShowDeploy(context, descriptor, result) {
|
|
147
259
|
return renderShow({
|
|
@@ -183,7 +295,7 @@ function serializeAppShowDeploy(result) {
|
|
|
183
295
|
return result;
|
|
184
296
|
}
|
|
185
297
|
function renderAppOpen(context, descriptor, result) {
|
|
186
|
-
|
|
298
|
+
const lines = renderShow({
|
|
187
299
|
title: result.opened ? "Opening the live URL for the selected app." : "Resolving the live URL for the selected app.",
|
|
188
300
|
descriptor,
|
|
189
301
|
fields: [
|
|
@@ -207,9 +319,11 @@ function renderAppOpen(context, descriptor, result) {
|
|
|
207
319
|
}
|
|
208
320
|
]
|
|
209
321
|
}, context.ui);
|
|
322
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
323
|
+
return lines;
|
|
210
324
|
}
|
|
211
325
|
function serializeAppOpen(result) {
|
|
212
|
-
return result;
|
|
326
|
+
return stripVerboseContext(result);
|
|
213
327
|
}
|
|
214
328
|
function renderAppDomainAdd(context, descriptor, result) {
|
|
215
329
|
return renderShow({
|
|
@@ -311,7 +425,7 @@ function serializeAppDomainRetry(result) {
|
|
|
311
425
|
return result;
|
|
312
426
|
}
|
|
313
427
|
function renderAppPromote(context, descriptor, result) {
|
|
314
|
-
|
|
428
|
+
const lines = renderShow({
|
|
315
429
|
title: "Switching the live deployment for the selected app.",
|
|
316
430
|
descriptor,
|
|
317
431
|
fields: [
|
|
@@ -349,12 +463,14 @@ function renderAppPromote(context, descriptor, result) {
|
|
|
349
463
|
}
|
|
350
464
|
]
|
|
351
465
|
}, context.ui);
|
|
466
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
467
|
+
return lines;
|
|
352
468
|
}
|
|
353
469
|
function serializeAppPromote(result) {
|
|
354
|
-
return result;
|
|
470
|
+
return stripVerboseContext(result);
|
|
355
471
|
}
|
|
356
472
|
function renderAppRollback(context, descriptor, result) {
|
|
357
|
-
|
|
473
|
+
const lines = renderShow({
|
|
358
474
|
title: "Restoring the selected app to an earlier deployment.",
|
|
359
475
|
descriptor,
|
|
360
476
|
fields: [
|
|
@@ -397,9 +513,11 @@ function renderAppRollback(context, descriptor, result) {
|
|
|
397
513
|
}] : []
|
|
398
514
|
]
|
|
399
515
|
}, context.ui);
|
|
516
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
517
|
+
return lines;
|
|
400
518
|
}
|
|
401
519
|
function serializeAppRollback(result) {
|
|
402
|
-
return result;
|
|
520
|
+
return stripVerboseContext(result);
|
|
403
521
|
}
|
|
404
522
|
function renderAppRun(_context, _descriptor, _result) {
|
|
405
523
|
return [];
|
|
@@ -408,7 +526,7 @@ function serializeAppRun(result) {
|
|
|
408
526
|
return result;
|
|
409
527
|
}
|
|
410
528
|
function renderAppRemove(context, descriptor, result) {
|
|
411
|
-
|
|
529
|
+
const lines = renderShow({
|
|
412
530
|
title: "Removing the selected app.",
|
|
413
531
|
descriptor,
|
|
414
532
|
fields: [
|
|
@@ -427,9 +545,11 @@ function renderAppRemove(context, descriptor, result) {
|
|
|
427
545
|
}
|
|
428
546
|
]
|
|
429
547
|
}, context.ui);
|
|
548
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
549
|
+
return lines;
|
|
430
550
|
}
|
|
431
551
|
function serializeAppRemove(result) {
|
|
432
|
-
return result;
|
|
552
|
+
return stripVerboseContext(result);
|
|
433
553
|
}
|
|
434
554
|
function toneForStatus(status) {
|
|
435
555
|
if (status === "running" || status === "ready" || status === "healthy") return "success";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { formatColumns } from "../shell/ui.js";
|
|
2
2
|
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
3
|
+
import { renderResolvedProjectContextBlock } from "./verbose-context.js";
|
|
3
4
|
//#region src/presenters/branch.ts
|
|
4
5
|
function renderBranchList(context, descriptor, result) {
|
|
5
6
|
const ui = context.ui;
|
|
@@ -9,6 +10,7 @@ function renderBranchList(context, descriptor, result) {
|
|
|
9
10
|
lines.push(rail);
|
|
10
11
|
if (result.branches.length === 0) {
|
|
11
12
|
lines.push(`${rail} ${ui.dim("No branches found.")}`);
|
|
13
|
+
lines.push(...renderBranchResolvedContextBlock(context, result));
|
|
12
14
|
return lines;
|
|
13
15
|
}
|
|
14
16
|
const widths = [
|
|
@@ -26,14 +28,19 @@ function renderBranchList(context, descriptor, result) {
|
|
|
26
28
|
branch.role,
|
|
27
29
|
branch.envMap
|
|
28
30
|
], widths)}`);
|
|
31
|
+
lines.push(...renderBranchResolvedContextBlock(context, result));
|
|
29
32
|
return lines;
|
|
30
33
|
}
|
|
31
34
|
function serializeBranchList(result) {
|
|
35
|
+
const { verboseContext: _verboseContext, ...serializable } = result;
|
|
32
36
|
return {
|
|
33
|
-
projectId:
|
|
34
|
-
projectName:
|
|
35
|
-
branches:
|
|
37
|
+
projectId: serializable.projectId,
|
|
38
|
+
projectName: serializable.projectName,
|
|
39
|
+
branches: serializable.branches
|
|
36
40
|
};
|
|
37
41
|
}
|
|
42
|
+
function renderBranchResolvedContextBlock(context, result) {
|
|
43
|
+
return renderResolvedProjectContextBlock(context.ui, result.verboseContext);
|
|
44
|
+
}
|
|
38
45
|
//#endregion
|
|
39
46
|
export { renderBranchList, serializeBranchList };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { padDisplay, renderNextSteps, renderSummaryLine } from "../shell/ui.js";
|
|
1
|
+
import { padDisplay, renderNextSteps, renderSummaryLine, renderVerboseBlock } from "../shell/ui.js";
|
|
2
2
|
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
3
3
|
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
4
4
|
import { renderMutate, renderShow, serializeList } from "../output/patterns.js";
|
|
5
|
+
import { renderResolvedProjectContextBlock } from "./verbose-context.js";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import stringWidth from "string-width";
|
|
7
8
|
//#region src/presenters/project.ts
|
|
@@ -50,6 +51,25 @@ function renderProjectShow(context, descriptor, result) {
|
|
|
50
51
|
tone: "warning"
|
|
51
52
|
}]
|
|
52
53
|
}, context.ui);
|
|
54
|
+
lines.push(...renderVerboseBlock(context.ui, [
|
|
55
|
+
{
|
|
56
|
+
key: "workspace",
|
|
57
|
+
value: result.workspace.name
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: "workspace id",
|
|
61
|
+
value: result.workspace.id,
|
|
62
|
+
tone: "dim"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
key: "project source",
|
|
66
|
+
value: "unbound"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: "suggested name",
|
|
70
|
+
value: `${result.suggestedProjectName} (${result.suggestedProjectNameSource})`
|
|
71
|
+
}
|
|
72
|
+
], { title: "Resolved context" }));
|
|
53
73
|
lines.push(...renderNextSteps(["Link an existing Project you choose: prisma-cli project link <id-or-name>", `Create a new Project: prisma-cli project create ${formatCommandArgument(result.suggestedProjectName)}`]));
|
|
54
74
|
return lines;
|
|
55
75
|
}
|
|
@@ -132,6 +152,11 @@ function renderBoundProjectShow(context, descriptor, result) {
|
|
|
132
152
|
lines.push(rail);
|
|
133
153
|
lines.push(`${rail} ${ui.dim("→")} ${ui.link(result.project.url)}`);
|
|
134
154
|
}
|
|
155
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, {
|
|
156
|
+
workspace: result.workspace,
|
|
157
|
+
project: result.project,
|
|
158
|
+
resolution: result.resolution
|
|
159
|
+
}));
|
|
135
160
|
return lines;
|
|
136
161
|
}
|
|
137
162
|
function formatLocalRepoPath(cwd, env) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { renderVerboseBlock } from "../shell/ui.js";
|
|
2
|
+
//#region src/presenters/verbose-context.ts
|
|
3
|
+
function renderResolvedProjectContextBlock(ui, context, options = {}) {
|
|
4
|
+
if (!context) return [];
|
|
5
|
+
return renderVerboseBlock(ui, [...projectResolutionRows(context), ...options.extraRows ?? []], { title: options.title ?? "Resolved context" });
|
|
6
|
+
}
|
|
7
|
+
function projectResolutionRows(context) {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
key: "workspace",
|
|
11
|
+
value: context.workspace.name
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: "workspace id",
|
|
15
|
+
value: context.workspace.id,
|
|
16
|
+
tone: "dim"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
key: "project",
|
|
20
|
+
value: context.project.name
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
key: "project id",
|
|
24
|
+
value: context.project.id,
|
|
25
|
+
tone: "dim"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "project source",
|
|
29
|
+
value: formatProjectSource(context.resolution.projectSource)
|
|
30
|
+
},
|
|
31
|
+
...context.resolution.targetName ? [{
|
|
32
|
+
key: "target name",
|
|
33
|
+
value: formatTargetName(context.resolution)
|
|
34
|
+
}] : [],
|
|
35
|
+
...context.branch ? [{
|
|
36
|
+
key: "branch",
|
|
37
|
+
value: `${context.branch.name} (${context.branch.kind})`
|
|
38
|
+
}, ...context.branch.id ? [{
|
|
39
|
+
key: "branch id",
|
|
40
|
+
value: context.branch.id,
|
|
41
|
+
tone: "dim"
|
|
42
|
+
}] : []] : []
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
function stripVerboseContext(result) {
|
|
46
|
+
const { verboseContext: _verboseContext, ...serialized } = result;
|
|
47
|
+
return serialized;
|
|
48
|
+
}
|
|
49
|
+
function formatProjectSource(source) {
|
|
50
|
+
switch (source) {
|
|
51
|
+
case "explicit": return "--project";
|
|
52
|
+
case "env": return "environment";
|
|
53
|
+
case "local-pin": return ".prisma/local.json";
|
|
54
|
+
case "platform-mapping": return "platform mapping";
|
|
55
|
+
case "created": return "created";
|
|
56
|
+
case "prompt": return "prompt";
|
|
57
|
+
case "unbound": return "unbound";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function formatTargetName(resolution) {
|
|
61
|
+
return resolution.targetNameSource ? `${resolution.targetName} (${resolution.targetNameSource})` : String(resolution.targetName);
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { renderResolvedProjectContextBlock, stripVerboseContext };
|
|
@@ -3,6 +3,8 @@ import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, write
|
|
|
3
3
|
import { getCommandDescriptor } from "./command-meta.js";
|
|
4
4
|
import { resolveGlobalFlags } from "./global-flags.js";
|
|
5
5
|
import { createCommandContext } from "./runtime.js";
|
|
6
|
+
import { collectCommandDiagnostics } from "../lib/diagnostics.js";
|
|
7
|
+
import { renderCommandDiagnostics } from "./diagnostics-output.js";
|
|
6
8
|
import { AuthError } from "@prisma/management-api-sdk";
|
|
7
9
|
//#region src/shell/command-runner.ts
|
|
8
10
|
function toCliError(error, runtime) {
|
|
@@ -19,6 +21,7 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
|
|
|
19
21
|
const flags = resolveGlobalFlags(runtime.argv, options);
|
|
20
22
|
const context = await createCommandContext(runtime, flags);
|
|
21
23
|
const descriptor = getCommandDescriptor(commandName);
|
|
24
|
+
const startedAt = Date.now();
|
|
22
25
|
try {
|
|
23
26
|
const success = await handler(context);
|
|
24
27
|
if (flags.json) {
|
|
@@ -29,7 +32,12 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
|
|
|
29
32
|
return;
|
|
30
33
|
}
|
|
31
34
|
if (flags.quiet) return;
|
|
32
|
-
|
|
35
|
+
const rendered = presenter.renderHuman(context, descriptor, success.result);
|
|
36
|
+
const diagnostics = await renderBestEffortCommandDiagnostics(context, {
|
|
37
|
+
enabled: flags.verbose && rendered.length > 0,
|
|
38
|
+
durationMs: Date.now() - startedAt
|
|
39
|
+
});
|
|
40
|
+
writeHumanLines(context.output, [...rendered, ...diagnostics]);
|
|
33
41
|
} catch (error) {
|
|
34
42
|
const cliError = toCliError(error, runtime);
|
|
35
43
|
if (cliError) {
|
|
@@ -41,6 +49,14 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
|
|
|
41
49
|
throw error;
|
|
42
50
|
}
|
|
43
51
|
}
|
|
52
|
+
async function renderBestEffortCommandDiagnostics(context, options) {
|
|
53
|
+
if (!options.enabled) return [];
|
|
54
|
+
try {
|
|
55
|
+
return renderCommandDiagnostics(context, await collectCommandDiagnostics(context, { durationMs: options.durationMs }));
|
|
56
|
+
} catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
44
60
|
async function runStreamingCommand(runtime, commandName, options, handler) {
|
|
45
61
|
const flags = resolveGlobalFlags(runtime.argv, options);
|
|
46
62
|
const context = await createCommandContext(runtime, flags);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { renderVerboseBlock } from "./ui.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/shell/diagnostics-output.ts
|
|
4
|
+
function renderCommandDiagnostics(context, diagnostics, rows = [], options = {}) {
|
|
5
|
+
if (!diagnostics) return [];
|
|
6
|
+
const { env } = context.runtime;
|
|
7
|
+
const git = diagnostics.git;
|
|
8
|
+
return renderVerboseBlock(context.ui, [
|
|
9
|
+
...rows,
|
|
10
|
+
...diagnostics.durationMs === void 0 ? [] : [{
|
|
11
|
+
key: "duration",
|
|
12
|
+
value: formatDuration(diagnostics.durationMs)
|
|
13
|
+
}],
|
|
14
|
+
{
|
|
15
|
+
key: "cwd",
|
|
16
|
+
value: formatLocalPath(diagnostics.cwd, env)
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
key: "state file",
|
|
20
|
+
value: formatLocalPath(diagnostics.stateFilePath, env)
|
|
21
|
+
},
|
|
22
|
+
...git ? [
|
|
23
|
+
{
|
|
24
|
+
key: "git ref",
|
|
25
|
+
value: git.ref ?? "detached",
|
|
26
|
+
tone: git.ref ? "default" : "dim"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: "git sha",
|
|
30
|
+
value: git.sha ?? "unknown",
|
|
31
|
+
tone: git.sha ? "default" : "dim"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: "git dirty",
|
|
35
|
+
value: formatDirtyState(git.dirty),
|
|
36
|
+
tone: git.dirty ? "warning" : "dim"
|
|
37
|
+
}
|
|
38
|
+
] : [{
|
|
39
|
+
key: "git",
|
|
40
|
+
value: "not detected",
|
|
41
|
+
tone: "dim"
|
|
42
|
+
}]
|
|
43
|
+
], { title: options.title ?? "Local context" });
|
|
44
|
+
}
|
|
45
|
+
function formatLocalPath(value, env) {
|
|
46
|
+
const resolved = path.resolve(value);
|
|
47
|
+
const home = env.HOME ? path.resolve(env.HOME) : null;
|
|
48
|
+
if (home && (resolved === home || resolved.startsWith(`${home}${path.sep}`))) {
|
|
49
|
+
const relative = path.relative(home, resolved);
|
|
50
|
+
return relative ? `~/${relative}` : "~";
|
|
51
|
+
}
|
|
52
|
+
return resolved;
|
|
53
|
+
}
|
|
54
|
+
function formatDirtyState(dirty) {
|
|
55
|
+
if (dirty === null) return "unknown";
|
|
56
|
+
return dirty ? "yes" : "no";
|
|
57
|
+
}
|
|
58
|
+
function formatDuration(durationMs) {
|
|
59
|
+
if (durationMs < 1e3) return `${durationMs}ms`;
|
|
60
|
+
return `${(durationMs / 1e3).toFixed(1)}s`;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { renderCommandDiagnostics };
|
package/dist/shell/output.js
CHANGED
|
@@ -23,6 +23,15 @@ function cliErrorToJson(error) {
|
|
|
23
23
|
docsUrl: error.docsUrl
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
function formatUnexpectedError(error, trace) {
|
|
27
|
+
const debug = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
28
|
+
if (trace) return `${debug}\n`;
|
|
29
|
+
return [
|
|
30
|
+
`Unexpected CLI error: ${error instanceof Error && error.message ? error.message : String(error)}`,
|
|
31
|
+
"More: Re-run with --trace for deeper diagnostics",
|
|
32
|
+
""
|
|
33
|
+
].join("\n");
|
|
34
|
+
}
|
|
26
35
|
function writeJsonError(output, command, error) {
|
|
27
36
|
output.stdout.write(`${JSON.stringify({
|
|
28
37
|
ok: false,
|
|
@@ -70,4 +79,4 @@ function writeHumanError(output, ui, error, options) {
|
|
|
70
79
|
writeHumanLines(output, lines);
|
|
71
80
|
}
|
|
72
81
|
//#endregion
|
|
73
|
-
export { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
|
|
82
|
+
export { cliErrorToJson, formatUnexpectedError, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
|
package/dist/shell/runtime.js
CHANGED
|
@@ -48,4 +48,4 @@ function canPrompt(context) {
|
|
|
48
48
|
return Boolean(context.runtime.stdin.isTTY && context.runtime.stderr.isTTY);
|
|
49
49
|
}
|
|
50
50
|
//#endregion
|
|
51
|
-
export { canPrompt, configureRuntimeCommand, createCommandContext };
|
|
51
|
+
export { canPrompt, configureRuntimeCommand, createCommandContext, resolveStateDir };
|
package/dist/shell/ui.js
CHANGED
|
@@ -48,6 +48,17 @@ function renderNextSteps(steps) {
|
|
|
48
48
|
...steps.map((step) => `- ${step}`)
|
|
49
49
|
];
|
|
50
50
|
}
|
|
51
|
+
function renderVerboseBlock(ui, rows, options = {}) {
|
|
52
|
+
if (!ui.verbose || rows.length === 0) return [];
|
|
53
|
+
const title = options.title ?? "Details";
|
|
54
|
+
const keyWidth = Math.max(...rows.map((row) => stringWidth(`${row.key}:`)));
|
|
55
|
+
const rail = ui.dim("│");
|
|
56
|
+
return [
|
|
57
|
+
"",
|
|
58
|
+
`${ui.dim(title)}:`,
|
|
59
|
+
...rows.map((row) => `${rail} ${ui.accent(padDisplay(`${row.key}:`, keyWidth))} ${formatVerboseValue(ui, row)}`)
|
|
60
|
+
];
|
|
61
|
+
}
|
|
51
62
|
function formatColumns(columns, widths) {
|
|
52
63
|
return columns.map((value, index) => padDisplay(value, widths[index])).join(" ").trimEnd();
|
|
53
64
|
}
|
|
@@ -76,5 +87,13 @@ function formatHeaderValue(ui, row) {
|
|
|
76
87
|
if (row.tone === "link") return ui.link(value);
|
|
77
88
|
return value;
|
|
78
89
|
}
|
|
90
|
+
function formatVerboseValue(ui, row) {
|
|
91
|
+
const value = row.sensitive ? maskValue(row.value) : row.value;
|
|
92
|
+
if (row.tone === "dim") return ui.dim(value);
|
|
93
|
+
if (row.tone === "success") return ui.success(value);
|
|
94
|
+
if (row.tone === "warning") return ui.warning(value);
|
|
95
|
+
if (row.tone === "link") return ui.link(value);
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
79
98
|
//#endregion
|
|
80
|
-
export { createShellUi, formatColumns, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, wrapText };
|
|
99
|
+
export { createShellUi, formatColumns, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, renderVerboseBlock, wrapText };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/cli",
|
|
3
|
-
"version": "3.0.0-dev.
|
|
3
|
+
"version": "3.0.0-dev.65.1",
|
|
4
4
|
"description": "Command-line interface for the Prisma Developer Platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@clack/prompts": "^1.5.0",
|
|
39
|
-
"@prisma/compute-sdk": "^0.
|
|
39
|
+
"@prisma/compute-sdk": "^0.21.0",
|
|
40
40
|
"@prisma/credentials-store": "^7.8.0",
|
|
41
|
-
"@prisma/management-api-sdk": "^1.
|
|
41
|
+
"@prisma/management-api-sdk": "^1.37.0",
|
|
42
42
|
"c12": "4.0.0-beta.5",
|
|
43
43
|
"colorette": "^2.0.20",
|
|
44
44
|
"commander": "^14.0.3",
|