@prisma/cli 3.0.0-dev.42.1 → 3.0.0-dev.46.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/commands/project/index.js +2 -2
- package/dist/controllers/app.js +31 -53
- package/dist/controllers/project.js +79 -10
- package/dist/lib/app/deploy-output.js +10 -1
- package/dist/lib/project/interactive-setup.js +56 -0
- package/dist/lib/project/resolution.js +1 -1
- package/dist/lib/project/setup.js +5 -1
- package/dist/presenters/project.js +2 -2
- package/dist/shell/command-meta.js +6 -2
- package/package.json +1 -1
|
@@ -31,10 +31,10 @@ function createProjectCreateCommand(runtime) {
|
|
|
31
31
|
}
|
|
32
32
|
function createProjectLinkCommand(runtime) {
|
|
33
33
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("link"), runtime), "project.link");
|
|
34
|
-
command.argument("
|
|
34
|
+
command.argument("[id-or-name]", "Project id or name");
|
|
35
35
|
addGlobalFlags(command);
|
|
36
36
|
command.action(async (projectRef, options) => {
|
|
37
|
-
await runCommand(runtime, "project.link", options, (context) => runProjectLink(context,
|
|
37
|
+
await runCommand(runtime, "project.link", options, (context) => runProjectLink(context, typeof projectRef === "string" ? projectRef : void 0), {
|
|
38
38
|
renderHuman: (context, descriptor, result) => renderProjectSetup(context, descriptor, result),
|
|
39
39
|
renderJson: (result) => serializeProjectSetup(result)
|
|
40
40
|
});
|
package/dist/controllers/app.js
CHANGED
|
@@ -8,13 +8,14 @@ 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
10
|
import { parseEnvAssignments } from "../lib/app/env-vars.js";
|
|
11
|
-
import { renderDeployOutputRows } from "../lib/app/deploy-output.js";
|
|
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";
|
|
14
14
|
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
15
15
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
16
16
|
import { buildProjectSetupNextActions, inferTargetName, projectNotFoundError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
17
17
|
import { bindProjectToDirectory, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
18
|
+
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
18
19
|
import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
|
|
19
20
|
import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction.js";
|
|
20
21
|
import { createPreviewDeployProgress, createPreviewDeployProgressState, createPreviewPromoteProgress } from "../lib/app/preview-progress.js";
|
|
@@ -1362,58 +1363,25 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
|
|
|
1362
1363
|
throw projectSetupRequiredError(projects, await inferTargetName(context.runtime.cwd));
|
|
1363
1364
|
}
|
|
1364
1365
|
async function resolveInteractiveDeployProjectSetup(context, provider, workspace, projects) {
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
kind: "project",
|
|
1375
|
-
project
|
|
1376
|
-
}
|
|
1377
|
-
})),
|
|
1378
|
-
{
|
|
1379
|
-
label: "Create a new Project",
|
|
1380
|
-
value: { kind: "create" }
|
|
1381
|
-
},
|
|
1382
|
-
{
|
|
1383
|
-
label: "Cancel",
|
|
1384
|
-
value: { kind: "cancel" }
|
|
1385
|
-
}
|
|
1386
|
-
]
|
|
1387
|
-
});
|
|
1388
|
-
if (choice.kind === "cancel") throw usageError("Project setup canceled", "Deploy needs a Project before it can continue.", "Choose an existing Project or create a new one, then rerun deploy.", ["prisma-cli app deploy --project <id-or-name>", "prisma-cli app deploy --create-project <name>"], "project");
|
|
1389
|
-
if (choice.kind === "project") return {
|
|
1390
|
-
workspace,
|
|
1391
|
-
project: toProjectSummary(choice.project),
|
|
1392
|
-
resolution: {
|
|
1393
|
-
projectSource: "prompt",
|
|
1394
|
-
targetName: choice.project.name,
|
|
1395
|
-
targetNameSource: "prompt"
|
|
1396
|
-
},
|
|
1397
|
-
localPinAction: "linked"
|
|
1398
|
-
};
|
|
1399
|
-
const suggestedName = await inferTargetName(context.runtime.cwd);
|
|
1400
|
-
const rawName = await textPrompt({
|
|
1401
|
-
input: context.runtime.stdin,
|
|
1402
|
-
output: context.runtime.stderr,
|
|
1403
|
-
message: "Project name",
|
|
1404
|
-
placeholder: suggestedName.name,
|
|
1405
|
-
validate: (value) => validateProjectSetupNameText(value, suggestedName.name)
|
|
1366
|
+
const setup = await promptForProjectSetupChoice({
|
|
1367
|
+
context,
|
|
1368
|
+
projects,
|
|
1369
|
+
createProject: (projectName) => createProjectForDeploySetup(provider, projectName, workspace),
|
|
1370
|
+
cancel: {
|
|
1371
|
+
why: "Deploy needs a Project before it can continue.",
|
|
1372
|
+
fix: "Choose an existing Project or create a new one, then rerun deploy.",
|
|
1373
|
+
nextSteps: ["prisma-cli app deploy --project <id-or-name>", "prisma-cli app deploy --create-project <name>"]
|
|
1374
|
+
}
|
|
1406
1375
|
});
|
|
1407
|
-
const projectName = rawName.trim() || suggestedName.name;
|
|
1408
1376
|
return {
|
|
1409
1377
|
workspace,
|
|
1410
|
-
project:
|
|
1378
|
+
project: setup.project,
|
|
1411
1379
|
resolution: {
|
|
1412
|
-
projectSource: "created",
|
|
1413
|
-
targetName:
|
|
1414
|
-
targetNameSource:
|
|
1380
|
+
projectSource: setup.action === "created" ? "created" : "prompt",
|
|
1381
|
+
targetName: setup.targetName,
|
|
1382
|
+
targetNameSource: setup.targetNameSource
|
|
1415
1383
|
},
|
|
1416
|
-
localPinAction:
|
|
1384
|
+
localPinAction: setup.action
|
|
1417
1385
|
};
|
|
1418
1386
|
}
|
|
1419
1387
|
async function createProjectForDeploySetup(provider, projectName, workspace) {
|
|
@@ -1459,10 +1427,6 @@ function assertExclusiveDeployProjectInputs(options) {
|
|
|
1459
1427
|
`unset ${PRISMA_PROJECT_ID_ENV_VAR}`
|
|
1460
1428
|
], "project");
|
|
1461
1429
|
}
|
|
1462
|
-
function validateProjectSetupNameText(value, fallback) {
|
|
1463
|
-
if ((value?.trim() || fallback).trim().length > 0) return;
|
|
1464
|
-
return "Enter a Project name.";
|
|
1465
|
-
}
|
|
1466
1430
|
async function resolveDeployBranch(context, explicitBranchName) {
|
|
1467
1431
|
if (explicitBranchName) return {
|
|
1468
1432
|
name: explicitBranchName,
|
|
@@ -1665,10 +1629,14 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
1665
1629
|
framework: options.framework,
|
|
1666
1630
|
runtime: options.runtime
|
|
1667
1631
|
};
|
|
1632
|
+
maybeRenderDeploySettingsPreview(context, {
|
|
1633
|
+
framework: options.framework,
|
|
1634
|
+
runtime: options.runtime
|
|
1635
|
+
});
|
|
1668
1636
|
if (!await confirmPrompt({
|
|
1669
1637
|
input: context.runtime.stdin,
|
|
1670
1638
|
output: context.runtime.stderr,
|
|
1671
|
-
message: "Customize settings?",
|
|
1639
|
+
message: "Customize build settings?",
|
|
1672
1640
|
initialValue: false
|
|
1673
1641
|
})) return {
|
|
1674
1642
|
framework: options.framework,
|
|
@@ -1713,6 +1681,16 @@ async function maybeCustomizeDeploySettings(context, options) {
|
|
|
1713
1681
|
runtime
|
|
1714
1682
|
};
|
|
1715
1683
|
}
|
|
1684
|
+
function maybeRenderDeploySettingsPreview(context, options) {
|
|
1685
|
+
if (context.flags.quiet || context.flags.json) return;
|
|
1686
|
+
context.output.stderr.write(`Detected ${options.framework.displayName}\n${renderDeploySettingsPreview(context.ui, [{
|
|
1687
|
+
key: "framework",
|
|
1688
|
+
value: options.framework.displayName
|
|
1689
|
+
}, {
|
|
1690
|
+
key: "runtime",
|
|
1691
|
+
value: `HTTP ${options.runtime.port}`
|
|
1692
|
+
}]).join("\n")}\n\n`);
|
|
1693
|
+
}
|
|
1716
1694
|
function frameworkDisplayName(framework) {
|
|
1717
1695
|
switch (framework) {
|
|
1718
1696
|
case "nextjs": return "Next.js";
|
|
@@ -2,9 +2,11 @@ import { CliError, authRequiredError, featureUnavailableError, usageError, works
|
|
|
2
2
|
import { renderSummaryLine } from "../shell/ui.js";
|
|
3
3
|
import { canPrompt } from "../shell/runtime.js";
|
|
4
4
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
5
|
+
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
5
6
|
import { readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
6
|
-
import { buildProjectSetupNextActions, inspectProjectBinding, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
7
|
+
import { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
7
8
|
import { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
9
|
+
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
8
10
|
import { createPreviewAppProvider } from "../lib/app/preview-provider.js";
|
|
9
11
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
10
12
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
@@ -60,7 +62,10 @@ async function runProjectList(context) {
|
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
64
|
function buildProjectListNextActions(localBinding) {
|
|
63
|
-
return localBinding?.status === "linked" ? [] : buildProjectSetupNextActions({
|
|
65
|
+
return localBinding?.status === "linked" ? [] : buildProjectSetupNextActions({
|
|
66
|
+
createCommand: "prisma-cli project create <name>",
|
|
67
|
+
reason: localBinding?.status === "invalid" ? "This directory has an invalid local Project binding. Ask the user which Prisma Project to link before running Project-scoped commands." : "This directory is not linked to a Prisma Project. Project list shows available Projects, but none is selected for this directory."
|
|
68
|
+
});
|
|
64
69
|
}
|
|
65
70
|
async function runProjectShow(context, explicitProject) {
|
|
66
71
|
const workspace = (await requireAuthenticatedAuthState(context)).workspace;
|
|
@@ -107,15 +112,84 @@ async function runProjectCreate(context, projectName) {
|
|
|
107
112
|
async function runProjectLink(context, projectRef) {
|
|
108
113
|
const workspace = (await requireAuthenticatedAuthState(context)).workspace;
|
|
109
114
|
if (!workspace) throw workspaceRequiredError();
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
let provider = null;
|
|
116
|
+
let projects;
|
|
117
|
+
if (isRealMode(context)) {
|
|
118
|
+
const client = await requireComputeAuth(context.runtime.env);
|
|
119
|
+
if (!client) throw authRequiredError();
|
|
120
|
+
provider = createPreviewAppProvider(client);
|
|
121
|
+
projects = await listRealWorkspaceProjects(client, workspace);
|
|
122
|
+
} else projects = listFixtureWorkspaceProjects(context, workspace);
|
|
123
|
+
let result;
|
|
124
|
+
if (projectRef?.trim()) result = await bindProjectToDirectory(context, workspace, toProjectSummary(resolveProjectForSetup(projectRef.trim(), projects, workspace)), "linked");
|
|
125
|
+
else if (canPrompt(context) && !context.flags.yes) result = await resolveInteractiveProjectLinkSetup(context, workspace, projects, provider);
|
|
126
|
+
else throw await projectLinkTargetRequiredError(context, projects);
|
|
112
127
|
return {
|
|
113
128
|
command: "project.link",
|
|
114
|
-
result
|
|
129
|
+
result,
|
|
115
130
|
warnings: [],
|
|
116
131
|
nextSteps: ["prisma-cli app deploy"]
|
|
117
132
|
};
|
|
118
133
|
}
|
|
134
|
+
async function resolveInteractiveProjectLinkSetup(context, workspace, projects, provider) {
|
|
135
|
+
const setup = await promptForProjectSetupChoice({
|
|
136
|
+
context,
|
|
137
|
+
projects,
|
|
138
|
+
createProject: (projectName) => {
|
|
139
|
+
if (!provider) throw featureUnavailableError("Project create is not available in fixture mode", "Creating Projects requires live platform integration.", "Rerun without fixture mode enabled to create a Project.", ["prisma-cli auth login"], "project");
|
|
140
|
+
return createProjectForLinkSetup(provider, projectName, workspace);
|
|
141
|
+
},
|
|
142
|
+
cancel: {
|
|
143
|
+
why: "Project link needs a Project before it can continue.",
|
|
144
|
+
fix: "Choose an existing Project or create a new one, then rerun project link.",
|
|
145
|
+
nextSteps: ["prisma-cli project link <id-or-name>", "prisma-cli project create <name>"]
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return bindProjectToDirectory(context, workspace, setup.project, setup.action);
|
|
149
|
+
}
|
|
150
|
+
async function createProjectForLinkSetup(provider, projectName, workspace) {
|
|
151
|
+
const created = await provider.createProject({ name: projectName }).catch((error) => {
|
|
152
|
+
throw projectCreateFailedError(error, projectName, workspace, {
|
|
153
|
+
nextSteps: [
|
|
154
|
+
"prisma-cli project list",
|
|
155
|
+
"prisma-cli project link <id-or-name>",
|
|
156
|
+
`prisma-cli project create ${formatCommandArgument(projectName)}`
|
|
157
|
+
],
|
|
158
|
+
permissionFix: "Grant the token permission to create Projects in this workspace, or link an existing Project.",
|
|
159
|
+
fallbackFix: "Retry the command, or choose an existing Project with prisma-cli project link <id-or-name>."
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
id: created.id,
|
|
164
|
+
name: created.name,
|
|
165
|
+
workspace
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async function projectLinkTargetRequiredError(context, projects) {
|
|
169
|
+
const suggestedName = await inferTargetName(context.runtime.cwd);
|
|
170
|
+
const createCommand = `prisma-cli project create ${formatCommandArgument(suggestedName.name)}`;
|
|
171
|
+
const recoveryCommands = ["prisma-cli project link <id-or-name>", createCommand];
|
|
172
|
+
return new CliError({
|
|
173
|
+
code: "PROJECT_LINK_TARGET_REQUIRED",
|
|
174
|
+
domain: "project",
|
|
175
|
+
summary: "Choose a Project to link this directory",
|
|
176
|
+
why: "This directory is not linked to a Prisma Project. Existing Projects are candidates until the user chooses one, and package or directory names are suggestions only.",
|
|
177
|
+
fix: "Run prisma-cli project link in a TTY to choose from the setup list, pass a Project id or name, or create a new Project.",
|
|
178
|
+
meta: {
|
|
179
|
+
suggestedProjectName: suggestedName.name,
|
|
180
|
+
suggestedProjectNameSource: suggestedName.source,
|
|
181
|
+
candidates: sortProjects(projects).map(toProjectSummary),
|
|
182
|
+
recoveryCommands
|
|
183
|
+
},
|
|
184
|
+
exitCode: 2,
|
|
185
|
+
nextSteps: ["prisma-cli project list", ...recoveryCommands],
|
|
186
|
+
nextActions: buildProjectSetupNextActions({
|
|
187
|
+
suggestedProjectName: suggestedName.name,
|
|
188
|
+
createCommand,
|
|
189
|
+
reason: "Project link needs the user to choose an existing Project or create a new one. Existing Projects, package names, and directory names are candidates only, not selections."
|
|
190
|
+
})
|
|
191
|
+
});
|
|
192
|
+
}
|
|
119
193
|
async function runGitConnect(context, gitUrl, options = {}) {
|
|
120
194
|
const workspace = (await requireAuthenticatedAuthState(context)).workspace;
|
|
121
195
|
if (!workspace) throw workspaceRequiredError();
|
|
@@ -242,11 +316,6 @@ async function resolveRequiredProjectInRealMode(context, workspace, explicitProj
|
|
|
242
316
|
commandName
|
|
243
317
|
});
|
|
244
318
|
}
|
|
245
|
-
async function listRealProjectsForLink(context, workspace) {
|
|
246
|
-
const client = await requireComputeAuth(context.runtime.env);
|
|
247
|
-
if (!client) throw authRequiredError();
|
|
248
|
-
return listRealWorkspaceProjects(client, workspace);
|
|
249
|
-
}
|
|
250
319
|
async function resolveProjectShowInFixtureMode(context, workspace, explicitProject) {
|
|
251
320
|
return inspectProjectBinding({
|
|
252
321
|
context,
|
|
@@ -2,6 +2,7 @@ import { padDisplay } from "../../shell/ui.js";
|
|
|
2
2
|
//#region src/lib/app/deploy-output.ts
|
|
3
3
|
const DEPLOY_OUTPUT_MIN_LABEL_WIDTH = 9;
|
|
4
4
|
const DEPLOY_OUTPUT_MIN_VALUE_WIDTH = 9;
|
|
5
|
+
const DEPLOY_SETTINGS_MIN_KEY_WIDTH = 10;
|
|
5
6
|
function renderDeployOutputRows(ui, rows) {
|
|
6
7
|
if (rows.length === 0) return [];
|
|
7
8
|
const labelWidth = Math.max(DEPLOY_OUTPUT_MIN_LABEL_WIDTH, ...rows.map((row) => row.label.length));
|
|
@@ -11,5 +12,13 @@ function renderDeployOutputRows(ui, rows) {
|
|
|
11
12
|
return ` ${padDisplay(row.label, labelWidth)} ${padDisplay(ui.strong(row.value), valueWidth)}${row.origin ? ` ${ui.dim(`· ${row.origin}`)}` : ""}`.trimEnd();
|
|
12
13
|
});
|
|
13
14
|
}
|
|
15
|
+
function renderDeploySettingsPreview(ui, rows) {
|
|
16
|
+
if (rows.length === 0) return [];
|
|
17
|
+
const keyWidth = Math.max(DEPLOY_SETTINGS_MIN_KEY_WIDTH, ...rows.map((row) => `${row.key}:`.length));
|
|
18
|
+
const rail = ui.dim("│");
|
|
19
|
+
return rows.map((row) => {
|
|
20
|
+
return `${rail} ${ui.accent(padDisplay(`${row.key}:`, keyWidth))} ${ui.strong(row.value)}`;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
14
23
|
//#endregion
|
|
15
|
-
export { renderDeployOutputRows };
|
|
24
|
+
export { renderDeployOutputRows, renderDeploySettingsPreview };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { usageError } from "../../shell/errors.js";
|
|
2
|
+
import { selectPrompt, textPrompt } from "../../shell/prompt.js";
|
|
3
|
+
import { inferTargetName, sortProjects } from "./resolution.js";
|
|
4
|
+
import { toProjectSummary, validateProjectSetupNameText } from "./setup.js";
|
|
5
|
+
//#region src/lib/project/interactive-setup.ts
|
|
6
|
+
async function promptForProjectSetupChoice(options) {
|
|
7
|
+
const sortedProjects = sortProjects(options.projects);
|
|
8
|
+
const projectNames = sortedProjects.map((project) => project.name);
|
|
9
|
+
const duplicateNames = new Set(projectNames.filter((name, index) => projectNames.indexOf(name) !== index));
|
|
10
|
+
const choice = await selectPrompt({
|
|
11
|
+
input: options.context.runtime.stdin,
|
|
12
|
+
output: options.context.runtime.stderr,
|
|
13
|
+
message: "Which Project should this directory use?",
|
|
14
|
+
choices: [
|
|
15
|
+
...sortedProjects.map((project) => ({
|
|
16
|
+
label: duplicateNames.has(project.name) ? `${project.name} (${project.id})` : project.name,
|
|
17
|
+
value: {
|
|
18
|
+
kind: "project",
|
|
19
|
+
project
|
|
20
|
+
}
|
|
21
|
+
})),
|
|
22
|
+
{
|
|
23
|
+
label: "Create a new Project",
|
|
24
|
+
value: { kind: "create" }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "Cancel",
|
|
28
|
+
value: { kind: "cancel" }
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
if (choice.kind === "cancel") throw usageError("Project setup canceled", options.cancel.why, options.cancel.fix, options.cancel.nextSteps, "project");
|
|
33
|
+
if (choice.kind === "project") return {
|
|
34
|
+
project: toProjectSummary(choice.project),
|
|
35
|
+
action: "linked",
|
|
36
|
+
targetName: choice.project.name,
|
|
37
|
+
targetNameSource: "prompt"
|
|
38
|
+
};
|
|
39
|
+
const suggestedName = await inferTargetName(options.context.runtime.cwd);
|
|
40
|
+
const rawName = await textPrompt({
|
|
41
|
+
input: options.context.runtime.stdin,
|
|
42
|
+
output: options.context.runtime.stderr,
|
|
43
|
+
message: "Project name",
|
|
44
|
+
placeholder: suggestedName.name,
|
|
45
|
+
validate: (value) => validateProjectSetupNameText(value, suggestedName.name)
|
|
46
|
+
});
|
|
47
|
+
const projectName = rawName.trim() || suggestedName.name;
|
|
48
|
+
return {
|
|
49
|
+
project: toProjectSummary(await options.createProject(projectName)),
|
|
50
|
+
action: "created",
|
|
51
|
+
targetName: projectName,
|
|
52
|
+
targetNameSource: rawName.trim() ? "prompt" : suggestedName.source
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { promptForProjectSetupChoice };
|
|
@@ -105,7 +105,7 @@ function buildProjectSetupNextActions(options = {}) {
|
|
|
105
105
|
const actions = [{
|
|
106
106
|
kind: "user-choice",
|
|
107
107
|
journey: "project-setup",
|
|
108
|
-
label: "Ask the user
|
|
108
|
+
label: "Ask the user whether to link an existing Project or create a new one",
|
|
109
109
|
commands: ["prisma-cli project list", ...recoveryCommands],
|
|
110
110
|
reason: options.reason ?? "This directory is not linked to a Prisma Project. Package and directory names are suggestions only, not a safe Project selection."
|
|
111
111
|
}, {
|
|
@@ -6,6 +6,10 @@ import { projectAmbiguousError, projectNotFoundError } from "./resolution.js";
|
|
|
6
6
|
function isValidProjectSetupName(projectName) {
|
|
7
7
|
return projectName.trim().length > 0;
|
|
8
8
|
}
|
|
9
|
+
function validateProjectSetupNameText(value, fallback) {
|
|
10
|
+
if ((value?.trim() || fallback).trim().length > 0) return;
|
|
11
|
+
return "Enter a Project name.";
|
|
12
|
+
}
|
|
9
13
|
function resolveProjectForSetup(projectRef, projects, workspace) {
|
|
10
14
|
const matches = projects.filter((project) => project.id === projectRef || project.name === projectRef);
|
|
11
15
|
if (matches.length === 1) return matches[0];
|
|
@@ -81,4 +85,4 @@ function formatDebugDetails(error) {
|
|
|
81
85
|
return typeof error === "string" ? error : null;
|
|
82
86
|
}
|
|
83
87
|
//#endregion
|
|
84
|
-
export { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary };
|
|
88
|
+
export { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary, validateProjectSetupNameText };
|
|
@@ -18,7 +18,7 @@ function renderProjectList(context, descriptor, result) {
|
|
|
18
18
|
})),
|
|
19
19
|
emptyMessage: "No projects found."
|
|
20
20
|
}, context.ui);
|
|
21
|
-
if (result.localBinding?.status === "not-linked" || result.localBinding?.status === "invalid") lines.push(...renderNextSteps(["Link
|
|
21
|
+
if (result.localBinding?.status === "not-linked" || result.localBinding?.status === "invalid") lines.push(...renderNextSteps(["Link an existing Project you choose: prisma-cli project link <id-or-name>", "Create a new Project: prisma-cli project create <name>"]));
|
|
22
22
|
return lines;
|
|
23
23
|
}
|
|
24
24
|
function serializeProjectList(result) {
|
|
@@ -49,7 +49,7 @@ function renderProjectShow(context, descriptor, result) {
|
|
|
49
49
|
tone: "warning"
|
|
50
50
|
}]
|
|
51
51
|
}, context.ui);
|
|
52
|
-
lines.push(...renderNextSteps(["Link an existing Project: prisma-cli project link <id-or-name>", `Create a new Project: prisma-cli project create ${formatCommandArgument(result.suggestedProjectName)}`]));
|
|
52
|
+
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)}`]));
|
|
53
53
|
return lines;
|
|
54
54
|
}
|
|
55
55
|
return renderShow({
|
|
@@ -115,8 +115,12 @@ const DESCRIPTORS = [
|
|
|
115
115
|
"project",
|
|
116
116
|
"link"
|
|
117
117
|
],
|
|
118
|
-
description: "Link this directory to
|
|
119
|
-
examples: [
|
|
118
|
+
description: "Link this directory to a Project",
|
|
119
|
+
examples: [
|
|
120
|
+
"prisma-cli project link",
|
|
121
|
+
"prisma-cli project link proj_123",
|
|
122
|
+
"prisma-cli project link \"Acme Dashboard\" --json"
|
|
123
|
+
]
|
|
120
124
|
},
|
|
121
125
|
{
|
|
122
126
|
id: "git.connect",
|