@prisma/cli 3.0.0-dev.75.1 → 3.0.0-dev.78.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/controllers/app-env.js +4 -2
- package/dist/controllers/app.js +9 -5
- package/dist/controllers/branch.js +5 -6
- package/dist/controllers/database.js +7 -5
- package/dist/controllers/project.js +27 -12
- package/dist/lib/project/local-pin.js +106 -26
- package/dist/lib/project/resolution.js +156 -68
- package/dist/lib/project/setup.js +58 -15
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { CliError, authRequiredError, usageError, workspaceRequiredError } from
|
|
|
2
2
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
3
|
import { formatScopeLabel, parseKeyValuePositional, resolveEnvScope } from "../lib/app/env-config.js";
|
|
4
4
|
import { readEnvFileAssignments } from "../lib/app/env-file.js";
|
|
5
|
-
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
5
|
+
import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
|
|
6
6
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
7
7
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
8
8
|
import { listRealWorkspaceProjects } from "./project.js";
|
|
@@ -205,13 +205,15 @@ 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
|
|
208
|
+
const targetResult = await resolveProjectTarget({
|
|
209
209
|
context,
|
|
210
210
|
workspace: authState.workspace,
|
|
211
211
|
explicitProject,
|
|
212
212
|
listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
|
|
213
213
|
commandName
|
|
214
214
|
});
|
|
215
|
+
if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
|
|
216
|
+
const target = targetResult.value;
|
|
215
217
|
return {
|
|
216
218
|
client,
|
|
217
219
|
projectId: target.project.id,
|
package/dist/controllers/app.js
CHANGED
|
@@ -13,8 +13,8 @@ import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-pro
|
|
|
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
|
-
import { buildProjectSetupNextActions, inferTargetName, projectNotFoundError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
17
|
-
import { bindProjectToDirectory, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
16
|
+
import { buildProjectSetupNextActions, inferTargetName, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
17
|
+
import { bindProjectToDirectory, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
18
18
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
19
19
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
20
20
|
import { resolveOrCreatePreviewBuildSettings } from "../lib/app/preview-build-settings.js";
|
|
@@ -131,8 +131,10 @@ async function runAppDeploy(context, appName, options) {
|
|
|
131
131
|
let localPinResult;
|
|
132
132
|
if (target.localPinAction) {
|
|
133
133
|
const setupResult = await bindProjectToDirectory(context, target.workspace, target.project, target.localPinAction);
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
if (setupResult.isErr()) throw projectDirectoryBindingErrorToCliError(setupResult.error);
|
|
135
|
+
const projectSetup = setupResult.value;
|
|
136
|
+
localPinResult = projectSetup.localPin;
|
|
137
|
+
maybeRenderProjectLinked(context, projectSetup.directory, projectSetup.project.name, projectSetup.localPin.path);
|
|
136
138
|
}
|
|
137
139
|
let framework = await resolveDeployFramework(context, {
|
|
138
140
|
requestedFramework: options?.framework,
|
|
@@ -1356,7 +1358,7 @@ async function requireProviderAndDeployProjectContext(context, explicitProject,
|
|
|
1356
1358
|
async function resolveProjectContext(context, client, explicitProject, options) {
|
|
1357
1359
|
const authState = await requireAuthenticatedAuthState(context);
|
|
1358
1360
|
if (!authState.workspace) throw workspaceRequiredError();
|
|
1359
|
-
const
|
|
1361
|
+
const resolvedResult = await resolveProjectTarget({
|
|
1360
1362
|
context,
|
|
1361
1363
|
workspace: authState.workspace,
|
|
1362
1364
|
explicitProject,
|
|
@@ -1364,6 +1366,8 @@ async function resolveProjectContext(context, client, explicitProject, options)
|
|
|
1364
1366
|
listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
|
|
1365
1367
|
commandName: options?.commandName
|
|
1366
1368
|
});
|
|
1369
|
+
if (resolvedResult.isErr()) throw projectResolutionErrorToCliError(resolvedResult.error);
|
|
1370
|
+
const resolved = resolvedResult.value;
|
|
1367
1371
|
const branch = options?.branch ?? await resolveDeployBranch(context, void 0);
|
|
1368
1372
|
return {
|
|
1369
1373
|
...resolved,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { CliError, authRequiredError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
2
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
|
-
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
3
|
+
import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
|
|
4
4
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
5
|
-
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
6
5
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
7
6
|
import { listRealWorkspaceProjects } from "./project.js";
|
|
8
7
|
import { createBranchUseCases } from "../use-cases/branch.js";
|
|
@@ -30,13 +29,13 @@ async function listRealBranches(context) {
|
|
|
30
29
|
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
31
30
|
const workspace = authState.workspace;
|
|
32
31
|
if (!workspace) throw workspaceRequiredError();
|
|
33
|
-
const
|
|
32
|
+
const targetResult = await resolveProjectTarget({
|
|
34
33
|
context,
|
|
35
34
|
workspace,
|
|
36
|
-
listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal)
|
|
37
|
-
prompt: createSelectPromptPort(context),
|
|
38
|
-
remember: true
|
|
35
|
+
listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal)
|
|
39
36
|
});
|
|
37
|
+
if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
|
|
38
|
+
const target = targetResult.value;
|
|
40
39
|
const branches = await listBranches(client, target.project.id, context.runtime.signal);
|
|
41
40
|
return {
|
|
42
41
|
projectId: target.project.id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
2
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
|
-
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
3
|
+
import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
|
|
4
4
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
5
5
|
import { listFixtureWorkspaceProjects, listRealWorkspaceProjects } from "./project.js";
|
|
6
6
|
import { createManagementDatabaseProvider, normalizeConnection, normalizeDatabase } from "../lib/database/provider.js";
|
|
@@ -155,28 +155,30 @@ async function requireDatabaseContext(context, flags, commandName) {
|
|
|
155
155
|
if (isRealMode(context)) {
|
|
156
156
|
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
157
157
|
if (!client) throw authRequiredError();
|
|
158
|
-
const
|
|
158
|
+
const targetResult = await resolveProjectTarget({
|
|
159
159
|
context,
|
|
160
160
|
workspace,
|
|
161
161
|
explicitProject: flags.projectRef,
|
|
162
162
|
listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
|
|
163
163
|
commandName
|
|
164
164
|
});
|
|
165
|
+
if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
|
|
165
166
|
return {
|
|
166
167
|
provider: createManagementDatabaseProvider(client),
|
|
167
|
-
target
|
|
168
|
+
target: targetResult.value
|
|
168
169
|
};
|
|
169
170
|
}
|
|
170
|
-
const
|
|
171
|
+
const targetResult = await resolveProjectTarget({
|
|
171
172
|
context,
|
|
172
173
|
workspace,
|
|
173
174
|
explicitProject: flags.projectRef,
|
|
174
175
|
listProjects: async () => listFixtureWorkspaceProjects(context, workspace),
|
|
175
176
|
commandName
|
|
176
177
|
});
|
|
178
|
+
if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
|
|
177
179
|
return {
|
|
178
180
|
provider: createFixtureDatabaseProvider(context),
|
|
179
|
-
target
|
|
181
|
+
target: targetResult.value
|
|
180
182
|
};
|
|
181
183
|
}
|
|
182
184
|
async function requireDatabaseProviderOnly(context) {
|
|
@@ -4,8 +4,8 @@ import { canPrompt } from "../shell/runtime.js";
|
|
|
4
4
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
5
5
|
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
6
6
|
import { readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
7
|
-
import { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
8
|
-
import { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
7
|
+
import { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, projectResolutionErrorToCliError, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
|
|
8
|
+
import { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
|
|
9
9
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
10
10
|
import { createPreviewAppProvider } from "../lib/app/preview-provider.js";
|
|
11
11
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
@@ -116,12 +116,14 @@ async function runProjectCreate(context, projectName) {
|
|
|
116
116
|
fallbackFix: "Retry the command, or choose an existing Project with prisma-cli project link <id-or-name>."
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
|
+
const bindResult = await bindProjectToDirectory(context, workspace, {
|
|
120
|
+
id: created.id,
|
|
121
|
+
name: created.name
|
|
122
|
+
}, "created");
|
|
123
|
+
if (bindResult.isErr()) throw projectDirectoryBindingErrorToCliError(bindResult.error);
|
|
119
124
|
return {
|
|
120
125
|
command: "project.create",
|
|
121
|
-
result:
|
|
122
|
-
id: created.id,
|
|
123
|
-
name: created.name
|
|
124
|
-
}, "created"),
|
|
126
|
+
result: bindResult.value,
|
|
125
127
|
warnings: [],
|
|
126
128
|
nextSteps: ["prisma-cli app deploy"]
|
|
127
129
|
};
|
|
@@ -138,7 +140,7 @@ async function runProjectLink(context, projectRef) {
|
|
|
138
140
|
projects = await listRealWorkspaceProjects(client, workspace, context.runtime.signal);
|
|
139
141
|
} else projects = listFixtureWorkspaceProjects(context, workspace);
|
|
140
142
|
let result;
|
|
141
|
-
if (projectRef?.trim()) result = await
|
|
143
|
+
if (projectRef?.trim()) result = await requireProjectDirectoryBinding(context, workspace, toProjectSummary(resolveProjectForSetup(projectRef.trim(), projects, workspace)), "linked");
|
|
142
144
|
else if (canPrompt(context) && !context.flags.yes) result = await resolveInteractiveProjectLinkSetup(context, workspace, projects, provider);
|
|
143
145
|
else throw await projectLinkTargetRequiredError(context, projects);
|
|
144
146
|
return {
|
|
@@ -162,7 +164,12 @@ async function resolveInteractiveProjectLinkSetup(context, workspace, projects,
|
|
|
162
164
|
nextSteps: ["prisma-cli project link <id-or-name>", "prisma-cli project create <name>"]
|
|
163
165
|
}
|
|
164
166
|
});
|
|
165
|
-
return
|
|
167
|
+
return requireProjectDirectoryBinding(context, workspace, setup.project, setup.action);
|
|
168
|
+
}
|
|
169
|
+
async function requireProjectDirectoryBinding(context, workspace, project, action) {
|
|
170
|
+
const bindResult = await bindProjectToDirectory(context, workspace, project, action);
|
|
171
|
+
if (bindResult.isErr()) throw projectDirectoryBindingErrorToCliError(bindResult.error);
|
|
172
|
+
return bindResult.value;
|
|
166
173
|
}
|
|
167
174
|
async function createProjectForLinkSetup(provider, projectName, workspace, signal) {
|
|
168
175
|
const created = await provider.createProject({
|
|
@@ -323,42 +330,50 @@ async function runGitDisconnect(context, options = {}) {
|
|
|
323
330
|
async function resolveProjectShowInRealMode(context, workspace, explicitProject) {
|
|
324
331
|
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
325
332
|
if (!client) throw authRequiredError();
|
|
326
|
-
|
|
333
|
+
const result = await inspectProjectBinding({
|
|
327
334
|
context,
|
|
328
335
|
workspace,
|
|
329
336
|
explicitProject,
|
|
330
337
|
listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
|
|
331
338
|
commandName: "project show"
|
|
332
339
|
});
|
|
340
|
+
if (result.isErr()) throw projectResolutionErrorToCliError(result.error);
|
|
341
|
+
return result.value;
|
|
333
342
|
}
|
|
334
343
|
async function resolveRequiredProjectInRealMode(context, workspace, explicitProject, commandName) {
|
|
335
344
|
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
336
345
|
if (!client) throw authRequiredError();
|
|
337
|
-
|
|
346
|
+
const result = await resolveProjectTarget({
|
|
338
347
|
context,
|
|
339
348
|
workspace,
|
|
340
349
|
explicitProject,
|
|
341
350
|
listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
|
|
342
351
|
commandName
|
|
343
352
|
});
|
|
353
|
+
if (result.isErr()) throw projectResolutionErrorToCliError(result.error);
|
|
354
|
+
return result.value;
|
|
344
355
|
}
|
|
345
356
|
async function resolveProjectShowInFixtureMode(context, workspace, explicitProject) {
|
|
346
|
-
|
|
357
|
+
const result = await inspectProjectBinding({
|
|
347
358
|
context,
|
|
348
359
|
workspace,
|
|
349
360
|
explicitProject,
|
|
350
361
|
listProjects: async () => listFixtureWorkspaceProjects(context, workspace),
|
|
351
362
|
commandName: "project show"
|
|
352
363
|
});
|
|
364
|
+
if (result.isErr()) throw projectResolutionErrorToCliError(result.error);
|
|
365
|
+
return result.value;
|
|
353
366
|
}
|
|
354
367
|
async function resolveRequiredProjectInFixtureMode(context, workspace, explicitProject, commandName) {
|
|
355
|
-
|
|
368
|
+
const result = await resolveProjectTarget({
|
|
356
369
|
context,
|
|
357
370
|
workspace,
|
|
358
371
|
explicitProject,
|
|
359
372
|
listProjects: async () => listFixtureWorkspaceProjects(context, workspace),
|
|
360
373
|
commandName
|
|
361
374
|
});
|
|
375
|
+
if (result.isErr()) throw projectResolutionErrorToCliError(result.error);
|
|
376
|
+
return result.value;
|
|
362
377
|
}
|
|
363
378
|
async function listRealWorkspaceProjects(client, workspace, signal) {
|
|
364
379
|
const { data } = await client.GET("/v1/projects", { signal });
|
|
@@ -29,6 +29,53 @@ var LocalResolutionPinReadAbortedError = class extends TaggedError("LocalResolut
|
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
+
var LocalResolutionPinSerializationError = class extends TaggedError("LocalResolutionPinSerializationError")() {
|
|
33
|
+
constructor(cause) {
|
|
34
|
+
super({
|
|
35
|
+
message: `Could not serialize ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}.`,
|
|
36
|
+
cause,
|
|
37
|
+
pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var LocalResolutionPinWriteAbortedError = class extends TaggedError("LocalResolutionPinWriteAbortedError")() {
|
|
42
|
+
constructor(cause) {
|
|
43
|
+
super({
|
|
44
|
+
message: `Writing ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} was aborted.`,
|
|
45
|
+
cause,
|
|
46
|
+
pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var LocalResolutionPinWriteFailedError = class extends TaggedError("LocalResolutionPinWriteFailedError")() {
|
|
51
|
+
constructor(operation, cause) {
|
|
52
|
+
super({
|
|
53
|
+
message: `Could not write ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}.`,
|
|
54
|
+
cause,
|
|
55
|
+
operation,
|
|
56
|
+
pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var LocalResolutionPinGitignoreUpdateAbortedError = class extends TaggedError("LocalResolutionPinGitignoreUpdateAbortedError")() {
|
|
61
|
+
constructor(cause) {
|
|
62
|
+
super({
|
|
63
|
+
message: "Updating .gitignore for the local Project binding was aborted.",
|
|
64
|
+
cause,
|
|
65
|
+
gitignorePath: ".gitignore"
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var LocalResolutionPinGitignoreUpdateFailedError = class extends TaggedError("LocalResolutionPinGitignoreUpdateFailedError")() {
|
|
70
|
+
constructor(operation, cause) {
|
|
71
|
+
super({
|
|
72
|
+
message: "Could not update .gitignore for the local Project binding.",
|
|
73
|
+
cause,
|
|
74
|
+
operation,
|
|
75
|
+
gitignorePath: ".gitignore"
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
32
79
|
async function readLocalResolutionPin(cwd, signal) {
|
|
33
80
|
return Result.gen(async function* () {
|
|
34
81
|
yield* ensureLocalResolutionPinReadNotAborted(signal);
|
|
@@ -72,41 +119,74 @@ function parseLocalResolutionPin(raw) {
|
|
|
72
119
|
});
|
|
73
120
|
}
|
|
74
121
|
async function writeLocalResolutionPin(cwd, pin, signal) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
122
|
+
return Result.gen(async function* () {
|
|
123
|
+
const prismaDir = path.join(cwd, ".prisma");
|
|
124
|
+
yield* ensureLocalResolutionPinWriteNotAborted(signal);
|
|
125
|
+
yield* Result.await(writeLocalResolutionPinBoundary(() => mkdir(prismaDir, { recursive: true }), "create-directory", signal));
|
|
126
|
+
const pinPath = path.join(cwd, LOCAL_RESOLUTION_PIN_RELATIVE_PATH);
|
|
127
|
+
const tmpPath = path.join(prismaDir, `local.${process.pid}.${Date.now()}.tmp`);
|
|
128
|
+
const serialized = yield* serializeLocalResolutionPin(pin);
|
|
129
|
+
yield* Result.await(writeLocalResolutionPinBoundary(() => writeFile(tmpPath, serialized, {
|
|
130
|
+
encoding: "utf8",
|
|
131
|
+
signal
|
|
132
|
+
}), "write-temp-file", signal));
|
|
133
|
+
yield* ensureLocalResolutionPinWriteNotAborted(signal);
|
|
134
|
+
yield* Result.await(writeLocalResolutionPinBoundary(() => rename(tmpPath, pinPath), "rename-temp-file", signal));
|
|
135
|
+
return Result.ok(void 0);
|
|
83
136
|
});
|
|
84
|
-
signal?.throwIfAborted();
|
|
85
|
-
await rename(tmpPath, pinPath);
|
|
86
137
|
}
|
|
87
138
|
async function ensureLocalResolutionPinGitignore(cwd, signal) {
|
|
88
139
|
const gitignorePath = path.join(cwd, ".gitignore");
|
|
89
140
|
let existing = null;
|
|
90
|
-
signal
|
|
91
|
-
|
|
92
|
-
|
|
141
|
+
const notAborted = ensureLocalResolutionPinGitignoreUpdateNotAborted(signal);
|
|
142
|
+
if (notAborted.isErr()) return Result.err(notAborted.error);
|
|
143
|
+
const existingResult = await Result.tryPromise({
|
|
144
|
+
try: () => readFile(gitignorePath, {
|
|
93
145
|
encoding: "utf8",
|
|
94
146
|
signal
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
147
|
+
}),
|
|
148
|
+
catch: (cause) => signal?.aborted ? new LocalResolutionPinGitignoreUpdateAbortedError(cause) : new LocalResolutionPinGitignoreUpdateFailedError("read", cause)
|
|
149
|
+
});
|
|
150
|
+
if (existingResult.isErr()) if (existingResult.error instanceof LocalResolutionPinGitignoreUpdateFailedError && existingResult.error.cause.code === "ENOENT") existing = null;
|
|
151
|
+
else return Result.err(existingResult.error);
|
|
152
|
+
else existing = existingResult.value;
|
|
153
|
+
if (existing === null) return writeLocalResolutionPinGitignore(gitignorePath, ".prisma/\n", signal);
|
|
154
|
+
if (existing.split(/\r?\n/).map((line) => line.trim()).some((line) => line === ".prisma/" || line === ".prisma/local.json")) return Result.ok(void 0);
|
|
155
|
+
return writeLocalResolutionPinGitignore(gitignorePath, existing.endsWith("\n") ? `${existing}.prisma/\n` : `${existing}\n.prisma/\n`, signal);
|
|
156
|
+
}
|
|
157
|
+
function ensureLocalResolutionPinWriteNotAborted(signal) {
|
|
158
|
+
return Result.try({
|
|
159
|
+
try: () => signal?.throwIfAborted(),
|
|
160
|
+
catch: (cause) => new LocalResolutionPinWriteAbortedError(cause)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function serializeLocalResolutionPin(pin) {
|
|
164
|
+
return Result.try({
|
|
165
|
+
try: () => `${JSON.stringify(pin, null, 2)}\n`,
|
|
166
|
+
catch: (cause) => new LocalResolutionPinSerializationError(cause)
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function writeLocalResolutionPinBoundary(run, operation, signal) {
|
|
170
|
+
return Result.tryPromise({
|
|
171
|
+
try: async () => {
|
|
172
|
+
await run();
|
|
173
|
+
},
|
|
174
|
+
catch: (cause) => signal?.aborted ? new LocalResolutionPinWriteAbortedError(cause) : new LocalResolutionPinWriteFailedError(operation, cause)
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function ensureLocalResolutionPinGitignoreUpdateNotAborted(signal) {
|
|
178
|
+
return Result.try({
|
|
179
|
+
try: () => signal?.throwIfAborted(),
|
|
180
|
+
catch: (cause) => new LocalResolutionPinGitignoreUpdateAbortedError(cause)
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function writeLocalResolutionPinGitignore(gitignorePath, contents, signal) {
|
|
184
|
+
return Result.tryPromise({
|
|
185
|
+
try: () => writeFile(gitignorePath, contents, {
|
|
101
186
|
encoding: "utf8",
|
|
102
187
|
signal
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
if (existing.split(/\r?\n/).map((line) => line.trim()).some((line) => line === ".prisma/" || line === ".prisma/local.json")) return;
|
|
107
|
-
await writeFile(gitignorePath, existing.endsWith("\n") ? `${existing}.prisma/\n` : `${existing}\n.prisma/\n`, {
|
|
108
|
-
encoding: "utf8",
|
|
109
|
-
signal
|
|
188
|
+
}),
|
|
189
|
+
catch: (cause) => signal?.aborted ? new LocalResolutionPinGitignoreUpdateAbortedError(cause) : new LocalResolutionPinGitignoreUpdateFailedError("write", cause)
|
|
110
190
|
});
|
|
111
191
|
}
|
|
112
192
|
function isLocalResolutionPin(value) {
|
|
@@ -3,45 +3,98 @@ import { formatCommandArgument } from "../../shell/command-arguments.js";
|
|
|
3
3
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "./local-pin.js";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { matchError } from "better-result";
|
|
6
|
+
import { Result, TaggedError, matchError } from "better-result";
|
|
7
7
|
//#region src/lib/project/resolution.ts
|
|
8
|
+
var ProjectNotFoundError = class extends TaggedError("ProjectNotFoundError")() {
|
|
9
|
+
constructor(projectRef, workspace) {
|
|
10
|
+
super({
|
|
11
|
+
message: `Project "${projectRef}" was not found in workspace "${workspace.name}".`,
|
|
12
|
+
projectRef,
|
|
13
|
+
workspace
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var ProjectAmbiguousError = class extends TaggedError("ProjectAmbiguousError")() {
|
|
18
|
+
constructor(projectRef, matches) {
|
|
19
|
+
super({
|
|
20
|
+
message: projectRef ? `Multiple projects matched "${projectRef}".` : "Multiple projects matched the current directory context.",
|
|
21
|
+
projectRef,
|
|
22
|
+
matches
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var LocalStateStaleError = class extends TaggedError("LocalStateStaleError")() {
|
|
27
|
+
constructor() {
|
|
28
|
+
super({
|
|
29
|
+
message: `The target recorded in ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} is no longer available in the selected workspace.`,
|
|
30
|
+
pinPath: LOCAL_RESOLUTION_PIN_RELATIVE_PATH
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var LocalProjectWorkspaceMismatchError = class extends TaggedError("LocalProjectWorkspaceMismatchError")() {
|
|
35
|
+
constructor(options) {
|
|
36
|
+
super({
|
|
37
|
+
message: `${LOCAL_RESOLUTION_PIN_RELATIVE_PATH} links this directory to project ${options.pinnedProjectId} in workspace ${options.pinnedWorkspaceId}, but the active workspace is "${options.activeWorkspace.name}" (${options.activeWorkspace.id}).`,
|
|
38
|
+
pinnedWorkspaceId: options.pinnedWorkspaceId,
|
|
39
|
+
pinnedProjectId: options.pinnedProjectId,
|
|
40
|
+
activeWorkspace: options.activeWorkspace
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var ProjectSetupRequiredError = class extends TaggedError("ProjectSetupRequiredError")() {
|
|
45
|
+
constructor(options) {
|
|
46
|
+
const commandLabel = options.commandName ? `prisma-cli ${options.commandName}` : "this command";
|
|
47
|
+
super({
|
|
48
|
+
message: `This directory is not linked to a Prisma Project, and ${commandLabel} will not choose one from package or directory names.`,
|
|
49
|
+
commandName: options.commandName,
|
|
50
|
+
suggestion: options.suggestion
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
8
54
|
async function resolveProjectTarget(options) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
55
|
+
return Result.gen(async function* () {
|
|
56
|
+
const localPin = yield* Result.await(readImplicitLocalPin(options, { allowEnvProjectId: true }));
|
|
57
|
+
const projects = await options.listProjects();
|
|
58
|
+
const target = yield* Result.await(resolveBoundProjectTarget(options, projects, {
|
|
59
|
+
allowEnvProjectId: true,
|
|
60
|
+
localPin
|
|
61
|
+
}));
|
|
62
|
+
if (target) return Result.ok(target);
|
|
63
|
+
return Result.err(await projectSetupRequiredError({
|
|
64
|
+
cwd: options.context.runtime.cwd,
|
|
65
|
+
projects,
|
|
66
|
+
commandName: options.commandName,
|
|
67
|
+
signal: options.context.runtime.signal
|
|
68
|
+
}));
|
|
21
69
|
});
|
|
22
70
|
}
|
|
23
71
|
async function inspectProjectBinding(options) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
72
|
+
return Result.gen(async function* () {
|
|
73
|
+
const localPin = yield* Result.await(readImplicitLocalPin(options, { allowEnvProjectId: false }));
|
|
74
|
+
const projects = await options.listProjects();
|
|
75
|
+
const target = yield* Result.await(resolveBoundProjectTarget(options, projects, {
|
|
76
|
+
allowEnvProjectId: false,
|
|
77
|
+
localPin
|
|
78
|
+
}));
|
|
79
|
+
if (target) return Result.ok(target);
|
|
80
|
+
return Result.ok({
|
|
81
|
+
workspace: options.workspace,
|
|
82
|
+
project: null,
|
|
83
|
+
localBinding: { status: "not-linked" },
|
|
84
|
+
resolution: { projectSource: "unbound" },
|
|
85
|
+
...await buildProjectSetupSuggestion({
|
|
86
|
+
cwd: options.context.runtime.cwd,
|
|
87
|
+
projects,
|
|
88
|
+
commandName: options.commandName ?? "project show",
|
|
89
|
+
signal: options.context.runtime.signal
|
|
90
|
+
})
|
|
91
|
+
});
|
|
29
92
|
});
|
|
30
|
-
if (target) return target;
|
|
31
|
-
return {
|
|
32
|
-
workspace: options.workspace,
|
|
33
|
-
project: null,
|
|
34
|
-
localBinding: { status: "not-linked" },
|
|
35
|
-
resolution: { projectSource: "unbound" },
|
|
36
|
-
...await buildProjectSetupSuggestion({
|
|
37
|
-
cwd: options.context.runtime.cwd,
|
|
38
|
-
projects,
|
|
39
|
-
commandName: options.commandName ?? "project show",
|
|
40
|
-
signal: options.context.runtime.signal
|
|
41
|
-
})
|
|
42
|
-
};
|
|
43
93
|
}
|
|
44
94
|
function projectNotFoundError(projectRef, workspace) {
|
|
95
|
+
return projectResolutionErrorToCliError(new ProjectNotFoundError(projectRef, workspace));
|
|
96
|
+
}
|
|
97
|
+
function projectNotFoundCliError(projectRef, workspace) {
|
|
45
98
|
return new CliError({
|
|
46
99
|
code: "PROJECT_NOT_FOUND",
|
|
47
100
|
domain: "project",
|
|
@@ -53,6 +106,9 @@ function projectNotFoundError(projectRef, workspace) {
|
|
|
53
106
|
});
|
|
54
107
|
}
|
|
55
108
|
function projectAmbiguousError(projectRef, matches) {
|
|
109
|
+
return projectResolutionErrorToCliError(new ProjectAmbiguousError(projectRef, matches));
|
|
110
|
+
}
|
|
111
|
+
function projectAmbiguousCliError(projectRef, matches) {
|
|
56
112
|
const firstMatch = matches[0];
|
|
57
113
|
const nextSteps = ["prisma-cli project list"];
|
|
58
114
|
if (firstMatch) nextSteps.push(`prisma-cli app deploy --project ${firstMatch.id}`);
|
|
@@ -70,7 +126,7 @@ function projectAmbiguousError(projectRef, matches) {
|
|
|
70
126
|
nextSteps
|
|
71
127
|
});
|
|
72
128
|
}
|
|
73
|
-
function
|
|
129
|
+
function localStateStaleCliError() {
|
|
74
130
|
return new CliError({
|
|
75
131
|
code: "LOCAL_STATE_STALE",
|
|
76
132
|
domain: "project",
|
|
@@ -82,7 +138,7 @@ function localStateStaleError() {
|
|
|
82
138
|
nextSteps: ["prisma-cli project list", "prisma-cli project link <id-or-name>"]
|
|
83
139
|
});
|
|
84
140
|
}
|
|
85
|
-
function
|
|
141
|
+
function localProjectWorkspaceMismatchCliError(options) {
|
|
86
142
|
return new CliError({
|
|
87
143
|
code: "LOCAL_PROJECT_WORKSPACE_MISMATCH",
|
|
88
144
|
domain: "project",
|
|
@@ -104,6 +160,31 @@ function localProjectWorkspaceMismatchError(options) {
|
|
|
104
160
|
]
|
|
105
161
|
});
|
|
106
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Converts expected project-resolution variants to command-boundary CliErrors.
|
|
165
|
+
* `LocalResolutionPinReadAbortedError` and `UnhandledException` intentionally
|
|
166
|
+
* propagate as exceptions; callers such as `resolveProjectShowInRealMode`
|
|
167
|
+
* throw this helper's result, so passthrough variants should keep bubbling.
|
|
168
|
+
*/
|
|
169
|
+
function projectResolutionErrorToCliError(error) {
|
|
170
|
+
return matchError(error, {
|
|
171
|
+
ProjectNotFoundError: (error) => projectNotFoundCliError(error.projectRef, error.workspace),
|
|
172
|
+
ProjectAmbiguousError: (error) => projectAmbiguousCliError(error.projectRef, error.matches),
|
|
173
|
+
ProjectSetupRequiredError: (error) => projectSetupRequiredCliError(error),
|
|
174
|
+
LocalStateStaleError: () => localStateStaleCliError(),
|
|
175
|
+
LocalProjectWorkspaceMismatchError: (error) => localProjectWorkspaceMismatchCliError({
|
|
176
|
+
pinnedWorkspaceId: error.pinnedWorkspaceId,
|
|
177
|
+
pinnedProjectId: error.pinnedProjectId,
|
|
178
|
+
activeWorkspace: error.activeWorkspace
|
|
179
|
+
}),
|
|
180
|
+
LocalResolutionPinReadAbortedError: (error) => {
|
|
181
|
+
throw error;
|
|
182
|
+
},
|
|
183
|
+
UnhandledException: (error) => {
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
107
188
|
async function buildProjectSetupSuggestion(options) {
|
|
108
189
|
const suggestedName = await inferTargetName(options.cwd, options.signal);
|
|
109
190
|
const candidates = sortProjects(options.projects.filter((project) => projectMatchesSuggestedName(project, suggestedName.name))).map(toProjectSummary);
|
|
@@ -116,17 +197,24 @@ async function buildProjectSetupSuggestion(options) {
|
|
|
116
197
|
}
|
|
117
198
|
async function projectSetupRequiredError(options) {
|
|
118
199
|
const suggestion = await buildProjectSetupSuggestion(options);
|
|
200
|
+
return new ProjectSetupRequiredError({
|
|
201
|
+
commandName: options.commandName,
|
|
202
|
+
suggestion
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function projectSetupRequiredCliError(error) {
|
|
206
|
+
const suggestion = error.suggestion;
|
|
119
207
|
return new CliError({
|
|
120
208
|
code: "PROJECT_SETUP_REQUIRED",
|
|
121
209
|
domain: "project",
|
|
122
210
|
summary: "Choose a Project before running this command",
|
|
123
|
-
why:
|
|
211
|
+
why: error.message,
|
|
124
212
|
fix: "Link the directory to an existing Project, or pass --project <id-or-name> for this command.",
|
|
125
213
|
meta: { ...suggestion },
|
|
126
214
|
exitCode: 1,
|
|
127
215
|
nextSteps: ["prisma-cli project list", ...suggestion.recoveryCommands],
|
|
128
216
|
nextActions: buildProjectSetupNextActions({
|
|
129
|
-
commandName:
|
|
217
|
+
commandName: error.commandName,
|
|
130
218
|
suggestedProjectName: suggestion.suggestedProjectName
|
|
131
219
|
})
|
|
132
220
|
});
|
|
@@ -200,9 +288,9 @@ function sortProjects(projects) {
|
|
|
200
288
|
}
|
|
201
289
|
function resolveExplicitProject(projectRef, projects, workspace) {
|
|
202
290
|
const matches = projects.filter((project) => project.id === projectRef || project.name === projectRef);
|
|
203
|
-
if (matches.length === 1) return matches[0];
|
|
204
|
-
if (matches.length > 1)
|
|
205
|
-
|
|
291
|
+
if (matches.length === 1) return Result.ok(matches[0]);
|
|
292
|
+
if (matches.length > 1) return Result.err(new ProjectAmbiguousError(projectRef, matches));
|
|
293
|
+
return Result.err(new ProjectNotFoundError(projectRef, workspace));
|
|
206
294
|
}
|
|
207
295
|
function projectMatchesSuggestedName(project, suggestedName) {
|
|
208
296
|
return project.id === suggestedName || project.name === suggestedName || project.slug === suggestedName;
|
|
@@ -211,62 +299,62 @@ async function resolveDurablePlatformMapping() {
|
|
|
211
299
|
return null;
|
|
212
300
|
}
|
|
213
301
|
async function resolveBoundProjectTarget(options, projects, settings) {
|
|
214
|
-
if (options.explicitProject)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
302
|
+
if (options.explicitProject) {
|
|
303
|
+
const projectResult = resolveExplicitProject(options.explicitProject, projects, options.workspace);
|
|
304
|
+
if (projectResult.isErr()) return Result.err(projectResult.error);
|
|
305
|
+
return Result.ok(resolvedTarget(options.workspace, projectResult.value, "explicit", {
|
|
306
|
+
targetName: options.explicitProject,
|
|
307
|
+
targetNameSource: "explicit"
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
218
310
|
if (settings.allowEnvProjectId && options.envProjectId) {
|
|
219
311
|
const project = projects.find((candidate) => candidate.id === options.envProjectId);
|
|
220
|
-
if (!project)
|
|
221
|
-
return resolvedTarget(options.workspace, project, "env", {
|
|
312
|
+
if (!project) return Result.err(new ProjectNotFoundError(options.envProjectId, options.workspace));
|
|
313
|
+
return Result.ok(resolvedTarget(options.workspace, project, "env", {
|
|
222
314
|
targetName: options.envProjectId,
|
|
223
315
|
targetNameSource: "env"
|
|
224
|
-
});
|
|
316
|
+
}));
|
|
225
317
|
}
|
|
226
318
|
const localPin = settings.localPin;
|
|
227
|
-
if (!localPin) return null;
|
|
319
|
+
if (!localPin) return Result.ok(null);
|
|
228
320
|
if (localPin.kind === "present") {
|
|
229
|
-
if (localPin.pin.workspaceId !== options.workspace.id)
|
|
321
|
+
if (localPin.pin.workspaceId !== options.workspace.id) return Result.err(new LocalProjectWorkspaceMismatchError({
|
|
230
322
|
pinnedWorkspaceId: localPin.pin.workspaceId,
|
|
231
323
|
pinnedProjectId: localPin.pin.projectId,
|
|
232
324
|
activeWorkspace: options.workspace
|
|
233
|
-
});
|
|
325
|
+
}));
|
|
234
326
|
const project = projects.find((candidate) => candidate.id === localPin.pin.projectId);
|
|
235
|
-
if (!project)
|
|
236
|
-
return resolvedTarget(options.workspace, project, "local-pin", {
|
|
327
|
+
if (!project) return Result.err(new LocalStateStaleError());
|
|
328
|
+
return Result.ok(resolvedTarget(options.workspace, project, "local-pin", {
|
|
237
329
|
targetName: project.name,
|
|
238
330
|
targetNameSource: "local-pin"
|
|
239
|
-
});
|
|
331
|
+
}));
|
|
240
332
|
}
|
|
241
333
|
const platformMapping = await resolveDurablePlatformMapping();
|
|
242
|
-
if (platformMapping && platformMapping.workspace.id === options.workspace.id) return resolvedTarget(options.workspace, platformMapping, "platform-mapping", {
|
|
334
|
+
if (platformMapping && platformMapping.workspace.id === options.workspace.id) return Result.ok(resolvedTarget(options.workspace, platformMapping, "platform-mapping", {
|
|
243
335
|
targetName: platformMapping.name,
|
|
244
336
|
targetNameSource: "platform-mapping"
|
|
245
|
-
});
|
|
246
|
-
return null;
|
|
337
|
+
}));
|
|
338
|
+
return Result.ok(null);
|
|
247
339
|
}
|
|
248
340
|
async function readImplicitLocalPin(options, settings) {
|
|
249
|
-
if (options.explicitProject || settings.allowEnvProjectId && options.envProjectId) return null;
|
|
341
|
+
if (options.explicitProject || settings.allowEnvProjectId && options.envProjectId) return Result.ok(null);
|
|
250
342
|
const localPinResult = await readLocalResolutionPin(options.context.runtime.cwd, options.context.runtime.signal);
|
|
251
|
-
if (localPinResult.isErr())
|
|
343
|
+
if (localPinResult.isErr()) return Result.err(localPinReadErrorToProjectError(localPinResult.error));
|
|
252
344
|
const localPin = localPinResult.value;
|
|
253
|
-
if (localPin.kind === "present" && localPin.pin.workspaceId !== options.workspace.id)
|
|
345
|
+
if (localPin.kind === "present" && localPin.pin.workspaceId !== options.workspace.id) return Result.err(new LocalProjectWorkspaceMismatchError({
|
|
254
346
|
pinnedWorkspaceId: localPin.pin.workspaceId,
|
|
255
347
|
pinnedProjectId: localPin.pin.projectId,
|
|
256
348
|
activeWorkspace: options.workspace
|
|
257
|
-
});
|
|
258
|
-
return localPin;
|
|
349
|
+
}));
|
|
350
|
+
return Result.ok(localPin);
|
|
259
351
|
}
|
|
260
352
|
function localPinReadErrorToProjectError(error) {
|
|
261
353
|
return matchError(error, {
|
|
262
|
-
LocalResolutionPinInvalidJsonError: () =>
|
|
263
|
-
LocalResolutionPinInvalidShapeError: () =>
|
|
264
|
-
LocalResolutionPinReadAbortedError: (error) =>
|
|
265
|
-
|
|
266
|
-
},
|
|
267
|
-
UnhandledException: (error) => {
|
|
268
|
-
throw error;
|
|
269
|
-
}
|
|
354
|
+
LocalResolutionPinInvalidJsonError: () => new LocalStateStaleError(),
|
|
355
|
+
LocalResolutionPinInvalidShapeError: () => new LocalStateStaleError(),
|
|
356
|
+
LocalResolutionPinReadAbortedError: (error) => error,
|
|
357
|
+
UnhandledException: (error) => error
|
|
270
358
|
});
|
|
271
359
|
}
|
|
272
360
|
function resolvedTarget(workspace, project, projectSource, resolutionDetails) {
|
|
@@ -292,4 +380,4 @@ function toProjectSummary(project) {
|
|
|
292
380
|
};
|
|
293
381
|
}
|
|
294
382
|
//#endregion
|
|
295
|
-
export { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, projectAmbiguousError, projectNotFoundError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects };
|
|
383
|
+
export { buildProjectSetupNextActions, inferTargetName, inspectProjectBinding, projectAmbiguousError, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects };
|
|
@@ -2,6 +2,7 @@ import { CliError, usageError } from "../../shell/errors.js";
|
|
|
2
2
|
import "../../shell/command-arguments.js";
|
|
3
3
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, ensureLocalResolutionPinGitignore, writeLocalResolutionPin } from "./local-pin.js";
|
|
4
4
|
import { projectAmbiguousError, projectNotFoundError } from "./resolution.js";
|
|
5
|
+
import { Result, matchError } from "better-result";
|
|
5
6
|
//#region src/lib/project/setup.ts
|
|
6
7
|
function isValidProjectSetupName(projectName) {
|
|
7
8
|
return projectName.trim().length > 0;
|
|
@@ -17,21 +18,63 @@ function resolveProjectForSetup(projectRef, projects, workspace) {
|
|
|
17
18
|
throw projectNotFoundError(projectRef, workspace);
|
|
18
19
|
}
|
|
19
20
|
async function bindProjectToDirectory(context, workspace, project, action) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
return Result.gen(async function* () {
|
|
22
|
+
yield* Result.await(writeLocalResolutionPin(context.runtime.cwd, {
|
|
23
|
+
workspaceId: workspace.id,
|
|
24
|
+
projectId: project.id
|
|
25
|
+
}, context.runtime.signal));
|
|
26
|
+
yield* Result.await(ensureLocalResolutionPinGitignore(context.runtime.cwd, context.runtime.signal));
|
|
27
|
+
return Result.ok({
|
|
28
|
+
workspace,
|
|
29
|
+
project,
|
|
30
|
+
directory: formatSetupDirectory(context.runtime.cwd),
|
|
31
|
+
localPin: {
|
|
32
|
+
path: LOCAL_RESOLUTION_PIN_RELATIVE_PATH,
|
|
33
|
+
written: true
|
|
34
|
+
},
|
|
35
|
+
action
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function projectDirectoryBindingErrorToCliError(error) {
|
|
40
|
+
return matchError(error, {
|
|
41
|
+
LocalResolutionPinSerializationError: (error) => {
|
|
42
|
+
throw error;
|
|
32
43
|
},
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
LocalResolutionPinWriteAbortedError: (error) => {
|
|
45
|
+
throw error;
|
|
46
|
+
},
|
|
47
|
+
LocalResolutionPinWriteFailedError: (error) => localStateWriteFailedError(error, {
|
|
48
|
+
why: `The CLI could not write ${LOCAL_RESOLUTION_PIN_RELATIVE_PATH}.`,
|
|
49
|
+
meta: {
|
|
50
|
+
pinPath: error.pinPath,
|
|
51
|
+
operation: error.operation
|
|
52
|
+
}
|
|
53
|
+
}),
|
|
54
|
+
LocalResolutionPinGitignoreUpdateAbortedError: (error) => {
|
|
55
|
+
throw error;
|
|
56
|
+
},
|
|
57
|
+
LocalResolutionPinGitignoreUpdateFailedError: (error) => localStateWriteFailedError(error, {
|
|
58
|
+
why: "The CLI could not update .gitignore to keep local Project binding state out of git.",
|
|
59
|
+
meta: {
|
|
60
|
+
gitignorePath: error.gitignorePath,
|
|
61
|
+
operation: error.operation
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function localStateWriteFailedError(error, options) {
|
|
67
|
+
return new CliError({
|
|
68
|
+
code: "LOCAL_STATE_WRITE_FAILED",
|
|
69
|
+
domain: "project",
|
|
70
|
+
summary: "Could not save local Project binding",
|
|
71
|
+
why: options.why,
|
|
72
|
+
fix: "Check that this directory is writable and that .prisma/local.json and .gitignore are not blocked by directories or permissions, then retry.",
|
|
73
|
+
debug: formatDebugDetails(error.cause),
|
|
74
|
+
meta: options.meta,
|
|
75
|
+
exitCode: 1,
|
|
76
|
+
nextSteps: ["prisma-cli project link <id-or-name>", "prisma-cli app deploy --project <id-or-name>"]
|
|
77
|
+
});
|
|
35
78
|
}
|
|
36
79
|
function toProjectSummary(project) {
|
|
37
80
|
return {
|
|
@@ -86,4 +129,4 @@ function formatDebugDetails(error) {
|
|
|
86
129
|
return typeof error === "string" ? error : null;
|
|
87
130
|
}
|
|
88
131
|
//#endregion
|
|
89
|
-
export { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary, validateProjectSetupNameText };
|
|
132
|
+
export { bindProjectToDirectory, isValidProjectSetupName, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary, validateProjectSetupNameText };
|