@prisma/cli 3.0.0-dev.62.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/lib/project/resolution.js +49 -4
- 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 +41 -17
- 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 };
|
|
@@ -5,8 +5,12 @@ import { readFile } from "node:fs/promises";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
//#region src/lib/project/resolution.ts
|
|
7
7
|
async function resolveProjectTarget(options) {
|
|
8
|
+
const localPin = await readImplicitLocalPin(options, { allowEnvProjectId: true });
|
|
8
9
|
const projects = await options.listProjects();
|
|
9
|
-
const target = await resolveBoundProjectTarget(options, projects, {
|
|
10
|
+
const target = await resolveBoundProjectTarget(options, projects, {
|
|
11
|
+
allowEnvProjectId: true,
|
|
12
|
+
localPin
|
|
13
|
+
});
|
|
10
14
|
if (target) return target;
|
|
11
15
|
throw await projectSetupRequiredError({
|
|
12
16
|
cwd: options.context.runtime.cwd,
|
|
@@ -16,8 +20,12 @@ async function resolveProjectTarget(options) {
|
|
|
16
20
|
});
|
|
17
21
|
}
|
|
18
22
|
async function inspectProjectBinding(options) {
|
|
23
|
+
const localPin = await readImplicitLocalPin(options, { allowEnvProjectId: false });
|
|
19
24
|
const projects = await options.listProjects();
|
|
20
|
-
const target = await resolveBoundProjectTarget(options, projects, {
|
|
25
|
+
const target = await resolveBoundProjectTarget(options, projects, {
|
|
26
|
+
allowEnvProjectId: false,
|
|
27
|
+
localPin
|
|
28
|
+
});
|
|
21
29
|
if (target) return target;
|
|
22
30
|
return {
|
|
23
31
|
workspace: options.workspace,
|
|
@@ -73,6 +81,28 @@ function localStateStaleError() {
|
|
|
73
81
|
nextSteps: ["prisma-cli project list", "prisma-cli project link <id-or-name>"]
|
|
74
82
|
});
|
|
75
83
|
}
|
|
84
|
+
function localProjectWorkspaceMismatchError(options) {
|
|
85
|
+
return new CliError({
|
|
86
|
+
code: "LOCAL_PROJECT_WORKSPACE_MISMATCH",
|
|
87
|
+
domain: "project",
|
|
88
|
+
summary: "Project link uses another workspace",
|
|
89
|
+
why: `${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} links this directory to project ${options.pinnedProjectId} in workspace ${options.pinnedWorkspaceId}, but your current CLI session is workspace "${options.activeWorkspace.name}" (${options.activeWorkspace.id}).`,
|
|
90
|
+
fix: "Sign in to the linked workspace, or relink this directory to a project in the current workspace.",
|
|
91
|
+
meta: {
|
|
92
|
+
pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH,
|
|
93
|
+
pinnedWorkspaceId: options.pinnedWorkspaceId,
|
|
94
|
+
pinnedProjectId: options.pinnedProjectId,
|
|
95
|
+
activeWorkspaceId: options.activeWorkspace.id,
|
|
96
|
+
activeWorkspaceName: options.activeWorkspace.name
|
|
97
|
+
},
|
|
98
|
+
exitCode: 1,
|
|
99
|
+
nextSteps: [
|
|
100
|
+
"prisma-cli auth login",
|
|
101
|
+
"prisma-cli project list",
|
|
102
|
+
"prisma-cli project link <id-or-name>"
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
76
106
|
async function buildProjectSetupSuggestion(options) {
|
|
77
107
|
const suggestedName = await inferTargetName(options.cwd, options.signal);
|
|
78
108
|
const candidates = sortProjects(options.projects.filter((project) => projectMatchesSuggestedName(project, suggestedName.name))).map(toProjectSummary);
|
|
@@ -192,10 +222,15 @@ async function resolveBoundProjectTarget(options, projects, settings) {
|
|
|
192
222
|
targetNameSource: "env"
|
|
193
223
|
});
|
|
194
224
|
}
|
|
195
|
-
const localPin =
|
|
225
|
+
const localPin = settings.localPin;
|
|
226
|
+
if (!localPin) return null;
|
|
196
227
|
if (localPin.kind === "invalid") throw localStateStaleError();
|
|
197
228
|
if (localPin.kind === "present") {
|
|
198
|
-
if (localPin.pin.workspaceId !== options.workspace.id) throw
|
|
229
|
+
if (localPin.pin.workspaceId !== options.workspace.id) throw localProjectWorkspaceMismatchError({
|
|
230
|
+
pinnedWorkspaceId: localPin.pin.workspaceId,
|
|
231
|
+
pinnedProjectId: localPin.pin.projectId,
|
|
232
|
+
activeWorkspace: options.workspace
|
|
233
|
+
});
|
|
199
234
|
const project = projects.find((candidate) => candidate.id === localPin.pin.projectId);
|
|
200
235
|
if (!project) throw localStateStaleError();
|
|
201
236
|
return resolvedTarget(options.workspace, project, "local-pin", {
|
|
@@ -210,6 +245,16 @@ async function resolveBoundProjectTarget(options, projects, settings) {
|
|
|
210
245
|
});
|
|
211
246
|
return null;
|
|
212
247
|
}
|
|
248
|
+
async function readImplicitLocalPin(options, settings) {
|
|
249
|
+
if (options.explicitProject || settings.allowEnvProjectId && options.envProjectId) return null;
|
|
250
|
+
const localPin = await readLocalResolutionPin(options.context.runtime.cwd, options.context.runtime.signal);
|
|
251
|
+
if (localPin.kind === "present" && localPin.pin.workspaceId !== options.workspace.id) throw localProjectWorkspaceMismatchError({
|
|
252
|
+
pinnedWorkspaceId: localPin.pin.workspaceId,
|
|
253
|
+
pinnedProjectId: localPin.pin.projectId,
|
|
254
|
+
activeWorkspace: options.workspace
|
|
255
|
+
});
|
|
256
|
+
return localPin;
|
|
257
|
+
}
|
|
213
258
|
function resolvedTarget(workspace, project, projectSource, resolutionDetails) {
|
|
214
259
|
return {
|
|
215
260
|
workspace,
|