@prisma/cli 8.0.0-rc.1 → 8.0.0-rc.10-dev.80
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/README.md +25 -29
- package/dist/cli.js +14551 -16
- package/dist/{v8/sender.js → sender.js} +1 -1
- package/package.json +17 -18
- package/dist/adapters/git.js +0 -54
- package/dist/adapters/local-state.js +0 -155
- package/dist/auth/client.js +0 -30
- package/dist/auth/errors.js +0 -50
- package/dist/auth/guard.js +0 -39
- package/dist/auth/login.js +0 -471
- package/dist/auth/operations.js +0 -208
- package/dist/auth/recipient.js +0 -42
- package/dist/auth/token-storage.js +0 -439
- package/dist/auth/workspaces.js +0 -171
- package/dist/cli-command.js +0 -14
- package/dist/cli-name.js +0 -12
- package/dist/cli2.js +0 -136
- package/dist/command-arguments.js +0 -12
- package/dist/commands/agent/index.js +0 -60
- package/dist/commands/app/index.js +0 -350
- package/dist/commands/auth/index.js +0 -95
- package/dist/commands/branch/index.js +0 -27
- package/dist/commands/bucket/index.js +0 -123
- package/dist/commands/build/index.js +0 -29
- package/dist/commands/database/index.js +0 -249
- package/dist/commands/env.js +0 -99
- package/dist/commands/feedback/index.js +0 -20
- package/dist/commands/git/index.js +0 -36
- package/dist/commands/init/index.js +0 -33
- package/dist/commands/project/index.js +0 -118
- package/dist/commands/version/index.js +0 -18
- package/dist/controllers/agent-setup.js +0 -52
- package/dist/controllers/agent.js +0 -228
- package/dist/controllers/app-env-api.js +0 -55
- package/dist/controllers/app-env-file.js +0 -181
- package/dist/controllers/app-env.js +0 -502
- package/dist/controllers/app.js +0 -2508
- package/dist/controllers/auth.js +0 -124
- package/dist/controllers/branch.js +0 -92
- package/dist/controllers/bucket.js +0 -184
- package/dist/controllers/build.js +0 -88
- package/dist/controllers/database.js +0 -463
- package/dist/controllers/feedback.js +0 -90
- package/dist/controllers/init.js +0 -814
- package/dist/controllers/project.js +0 -892
- package/dist/controllers/select-prompt-port.js +0 -13
- package/dist/controllers/version.js +0 -12
- package/dist/errors.js +0 -102
- package/dist/lib/agent/cli-command.js +0 -20
- package/dist/lib/agent/constants.js +0 -12
- package/dist/lib/agent/package-manager.js +0 -99
- package/dist/lib/agent/setup-status.js +0 -83
- package/dist/lib/app/app-provider.js +0 -617
- package/dist/lib/app/branch-database-api.js +0 -102
- package/dist/lib/app/branch-database-deploy.js +0 -353
- package/dist/lib/app/branch-database.js +0 -234
- package/dist/lib/app/build-settings.js +0 -98
- package/dist/lib/app/build.js +0 -82
- package/dist/lib/app/bun-project.js +0 -45
- package/dist/lib/app/compute-config.js +0 -145
- package/dist/lib/app/deploy-output.js +0 -24
- package/dist/lib/app/deploy-plan.js +0 -59
- package/dist/lib/app/deploy-progress.js +0 -100
- package/dist/lib/app/domain-guidance.js +0 -14
- package/dist/lib/app/env-config.js +0 -67
- package/dist/lib/app/env-file.js +0 -82
- package/dist/lib/app/env-vars.js +0 -50
- package/dist/lib/app/local-dev.js +0 -109
- package/dist/lib/app/production-deploy-gate.js +0 -162
- package/dist/lib/app/read-branch.js +0 -30
- package/dist/lib/bucket/provider.js +0 -139
- package/dist/lib/database/provider.js +0 -385
- package/dist/lib/diagnostics.js +0 -16
- package/dist/lib/feedback.js +0 -15
- package/dist/lib/fs/home-path.js +0 -24
- package/dist/lib/git/local-branch.js +0 -53
- package/dist/lib/git/local-status.js +0 -57
- package/dist/lib/project/interactive-setup.js +0 -57
- package/dist/lib/project/local-pin.js +0 -200
- package/dist/lib/project/provider.js +0 -93
- package/dist/lib/project/resolution.js +0 -389
- package/dist/lib/project/setup.js +0 -138
- package/dist/lib/version.js +0 -56
- package/dist/lib/workspace-id.js +0 -18
- package/dist/output/patterns.js +0 -90
- package/dist/presenters/agent.js +0 -74
- package/dist/presenters/app-env.js +0 -265
- package/dist/presenters/app.js +0 -672
- package/dist/presenters/auth.js +0 -184
- package/dist/presenters/branch.js +0 -46
- package/dist/presenters/bucket.js +0 -174
- package/dist/presenters/database.js +0 -462
- package/dist/presenters/feedback.js +0 -26
- package/dist/presenters/init.js +0 -30
- package/dist/presenters/project.js +0 -268
- package/dist/presenters/verbose-context.js +0 -64
- package/dist/presenters/version.js +0 -29
- package/dist/shell/cli-command.js +0 -2
- package/dist/shell/command-meta.js +0 -923
- package/dist/shell/command-runner.js +0 -119
- package/dist/shell/diagnostics-output.js +0 -57
- package/dist/shell/global-flags.js +0 -37
- package/dist/shell/help.js +0 -90
- package/dist/shell/output.js +0 -144
- package/dist/shell/prompt.js +0 -48
- package/dist/shell/runtime.js +0 -38
- package/dist/shell/ui.js +0 -116
- package/dist/state-dir.js +0 -12
- package/dist/update-check.js +0 -248
- package/dist/v8/cli.js +0 -14699
|
@@ -1,502 +0,0 @@
|
|
|
1
|
-
import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../errors.js";
|
|
2
|
-
import { authenticatedManagementApiClient } from "../auth/guard.js";
|
|
3
|
-
import { formatScopeLabel, parseKeyValuePositional, resolveEnvScope } from "../lib/app/env-config.js";
|
|
4
|
-
import { readEnvFileAssignments } from "../lib/app/env-file.js";
|
|
5
|
-
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
6
|
-
import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
|
|
7
|
-
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
8
|
-
import { listRealWorkspaceProjects } from "./project.js";
|
|
9
|
-
import { apiCallError, findVariableByNaturalKey, toMetadata } from "./app-env-api.js";
|
|
10
|
-
import { runEnvAddFile, runEnvUpdateFile } from "./app-env-file.js";
|
|
11
|
-
//#region src/controllers/app-env.ts
|
|
12
|
-
async function runEnvAdd(context, rawAssignment, flags) {
|
|
13
|
-
const source = resolveEnvWriteSource(rawAssignment, flags.filePath, "add");
|
|
14
|
-
const scope = resolveEnvScope(flags, {
|
|
15
|
-
requireExplicit: true,
|
|
16
|
-
command: "add"
|
|
17
|
-
});
|
|
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
|
-
const input = await resolveEnvWriteInput(context, source, "add");
|
|
20
|
-
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env add");
|
|
21
|
-
const resolved = await resolveScopeToApi(client, projectId, scope, {
|
|
22
|
-
createBranchIfMissing: true,
|
|
23
|
-
signal: context.runtime.signal
|
|
24
|
-
});
|
|
25
|
-
if (input.kind === "file") return runEnvAddFile(context, client, projectId, resolved, input.filePath, input.assignments, verboseContext);
|
|
26
|
-
if (await findVariableByNaturalKey(client, projectId, input.key, resolved, context.runtime.signal)) throw new CliError({
|
|
27
|
-
code: "ENV_VARIABLE_ALREADY_EXISTS",
|
|
28
|
-
domain: "app",
|
|
29
|
-
summary: `Variable "${input.key}" already exists in ${formatScopeLabel(scope)}`,
|
|
30
|
-
why: "A variable with this key already exists in the targeted scope.",
|
|
31
|
-
fix: "Use `prisma-cli project env update` to change an existing variable's value.",
|
|
32
|
-
exitCode: 1,
|
|
33
|
-
nextSteps: [`prisma-cli project env update ${input.key}=<new-value> ${formatScopeFlag(scope)}`]
|
|
34
|
-
});
|
|
35
|
-
const warnings = scope.kind === "branch" && !await findVariableByNaturalKey(client, projectId, input.key, {
|
|
36
|
-
descriptor: {
|
|
37
|
-
kind: "role",
|
|
38
|
-
role: "preview"
|
|
39
|
-
},
|
|
40
|
-
apiTarget: {
|
|
41
|
-
class: "preview",
|
|
42
|
-
branchId: null
|
|
43
|
-
}
|
|
44
|
-
}, context.runtime.signal) ? [`Variable "${input.key}" does not exist in preview. It will only exist on ${formatScopeLabel(scope)}.`] : [];
|
|
45
|
-
const { data, error, response } = await client.POST("/v1/environment-variables", {
|
|
46
|
-
body: {
|
|
47
|
-
projectId,
|
|
48
|
-
class: resolved.apiTarget.class,
|
|
49
|
-
...resolved.apiTarget.branchId !== null ? { branchId: resolved.apiTarget.branchId } : {},
|
|
50
|
-
key: input.key,
|
|
51
|
-
value: input.value
|
|
52
|
-
},
|
|
53
|
-
signal: context.runtime.signal
|
|
54
|
-
});
|
|
55
|
-
if (error || !data) throw apiCallError(`Failed to add ${input.key}`, response, error);
|
|
56
|
-
return {
|
|
57
|
-
command: "project.env.add",
|
|
58
|
-
result: {
|
|
59
|
-
projectId,
|
|
60
|
-
verboseContext,
|
|
61
|
-
scope: resolved.descriptor,
|
|
62
|
-
variable: toMetadata(data.data, resolved.descriptor)
|
|
63
|
-
},
|
|
64
|
-
warnings,
|
|
65
|
-
nextSteps: []
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
async function runEnvUpdate(context, rawAssignment, flags) {
|
|
69
|
-
const source = resolveEnvWriteSource(rawAssignment, flags.filePath, "update");
|
|
70
|
-
const scope = resolveEnvScope(flags, {
|
|
71
|
-
requireExplicit: true,
|
|
72
|
-
command: "update"
|
|
73
|
-
});
|
|
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");
|
|
75
|
-
const input = await resolveEnvWriteInput(context, source, "update");
|
|
76
|
-
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env update");
|
|
77
|
-
const resolved = await resolveScopeToApi(client, projectId, scope, {
|
|
78
|
-
createBranchIfMissing: false,
|
|
79
|
-
signal: context.runtime.signal
|
|
80
|
-
});
|
|
81
|
-
if (input.kind === "file") return runEnvUpdateFile(context, client, projectId, resolved, input.filePath, input.assignments, verboseContext);
|
|
82
|
-
const existing = await findVariableByNaturalKey(client, projectId, input.key, resolved, context.runtime.signal);
|
|
83
|
-
if (!existing) throw new CliError({
|
|
84
|
-
code: "ENV_VARIABLE_NOT_FOUND",
|
|
85
|
-
domain: "app",
|
|
86
|
-
summary: `Variable "${input.key}" not found in ${formatScopeLabel(scope)}`,
|
|
87
|
-
why: "No variable with this key exists in the targeted scope.",
|
|
88
|
-
fix: "Use `prisma-cli project env add` to create a new variable.",
|
|
89
|
-
exitCode: 1,
|
|
90
|
-
nextSteps: [`prisma-cli project env add ${input.key}=<value> ${formatScopeFlag(scope)}`]
|
|
91
|
-
});
|
|
92
|
-
const { data, error, response } = await client.PATCH("/v1/environment-variables/{envVarId}", {
|
|
93
|
-
params: { path: { envVarId: existing.id } },
|
|
94
|
-
body: { value: input.value },
|
|
95
|
-
signal: context.runtime.signal
|
|
96
|
-
});
|
|
97
|
-
if (error || !data) throw apiCallError(`Failed to update value for ${input.key}`, response, error);
|
|
98
|
-
return {
|
|
99
|
-
command: "project.env.update",
|
|
100
|
-
result: {
|
|
101
|
-
projectId,
|
|
102
|
-
verboseContext,
|
|
103
|
-
scope: resolved.descriptor,
|
|
104
|
-
variable: toMetadata(data.data, resolved.descriptor)
|
|
105
|
-
},
|
|
106
|
-
warnings: [],
|
|
107
|
-
nextSteps: []
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function resolveEnvWriteSource(rawAssignment, filePath, command) {
|
|
111
|
-
if (filePath !== void 0 && rawAssignment !== void 0) throw usageError(`prisma-cli project env ${command} accepts either KEY=VALUE or --file`, "The command received both a positional assignment and a dotenv file path.", "Pass one input source.", [`prisma-cli project env ${command} KEY=value --role preview`, `prisma-cli project env ${command} --file .env --role preview`], "app");
|
|
112
|
-
if (filePath !== void 0) {
|
|
113
|
-
if (filePath.length === 0) throw usageError(`prisma-cli project env ${command} --file requires a path`, "The --file flag was passed without a file path.", "Pass a readable dotenv file path.", [`prisma-cli project env ${command} --file .env --role preview`], "app");
|
|
114
|
-
return {
|
|
115
|
-
kind: "file",
|
|
116
|
-
filePath
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
if (rawAssignment === void 0) throw usageError(`prisma-cli project env ${command} requires KEY=VALUE or --file`, "No environment variable input was supplied.", "Pass a single KEY=VALUE assignment or a dotenv file path.", [`prisma-cli project env ${command} KEY=value --role preview`, `prisma-cli project env ${command} --file .env --role preview`], "app");
|
|
120
|
-
return {
|
|
121
|
-
kind: "single",
|
|
122
|
-
rawAssignment
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
async function resolveEnvWriteInput(context, source, command) {
|
|
126
|
-
if (source.kind === "file") return {
|
|
127
|
-
kind: "file",
|
|
128
|
-
filePath: source.filePath,
|
|
129
|
-
assignments: await readEnvFileAssignments(context.runtime.cwd, source.filePath, command)
|
|
130
|
-
};
|
|
131
|
-
return {
|
|
132
|
-
kind: "single",
|
|
133
|
-
...parseKeyValuePositional(source.rawAssignment, command, context.runtime.env)
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
async function runEnvList(context, flags) {
|
|
137
|
-
const explicit = resolveEnvScope(flags, {
|
|
138
|
-
requireExplicit: false,
|
|
139
|
-
command: "list"
|
|
140
|
-
});
|
|
141
|
-
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env list");
|
|
142
|
-
const resolved = await resolveListScopeToApi(client, projectId, explicit ?? void 0, {
|
|
143
|
-
cwd: context.runtime.cwd,
|
|
144
|
-
signal: context.runtime.signal
|
|
145
|
-
});
|
|
146
|
-
const variables = resolved.kind === "scoped" ? await listVariables(client, projectId, {
|
|
147
|
-
scope: resolved.addScope,
|
|
148
|
-
descriptor: resolved.descriptor,
|
|
149
|
-
apiTarget: resolved.apiTarget
|
|
150
|
-
}, context.runtime.signal) : await listOverviewVariables(client, projectId, context.runtime.signal);
|
|
151
|
-
return {
|
|
152
|
-
command: "project.env.list",
|
|
153
|
-
result: {
|
|
154
|
-
projectId,
|
|
155
|
-
verboseContext,
|
|
156
|
-
scope: resolved.descriptor,
|
|
157
|
-
target: resolved.target,
|
|
158
|
-
variables: variables.map((row) => toMetadata(row, resolved.descriptor))
|
|
159
|
-
},
|
|
160
|
-
warnings: [],
|
|
161
|
-
nextSteps: variables.length === 0 ? [`prisma-cli project env add KEY=value ${formatScopeFlag(resolved.addScope)}`] : []
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
async function runEnvRemove(context, key, flags) {
|
|
165
|
-
if (!key) throw usageError("prisma-cli project env remove requires KEY", "No KEY positional argument was supplied.", "Pass the variable name to remove, e.g. STRIPE_KEY.", ["prisma-cli project env remove STRIPE_KEY --role production"], "app");
|
|
166
|
-
const scope = resolveEnvScope(flags, {
|
|
167
|
-
requireExplicit: true,
|
|
168
|
-
command: "remove"
|
|
169
|
-
});
|
|
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");
|
|
171
|
-
const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env remove");
|
|
172
|
-
const resolved = await resolveScopeToApi(client, projectId, scope, {
|
|
173
|
-
createBranchIfMissing: false,
|
|
174
|
-
signal: context.runtime.signal
|
|
175
|
-
});
|
|
176
|
-
const existing = await findVariableByNaturalKey(client, projectId, key, resolved, context.runtime.signal);
|
|
177
|
-
if (!existing) throw new CliError({
|
|
178
|
-
code: "ENV_VARIABLE_NOT_FOUND",
|
|
179
|
-
domain: "app",
|
|
180
|
-
summary: `Variable "${key}" not found in ${formatScopeLabel(scope)}`,
|
|
181
|
-
why: "No variable with this key exists in the targeted scope, so there is nothing to remove.",
|
|
182
|
-
fix: "Run prisma-cli project env list with the same scope to see the available variables.",
|
|
183
|
-
exitCode: 1,
|
|
184
|
-
nextSteps: [`prisma-cli project env list ${formatScopeFlag(scope)}`]
|
|
185
|
-
});
|
|
186
|
-
const { error, response } = await client.DELETE("/v1/environment-variables/{envVarId}", {
|
|
187
|
-
params: { path: { envVarId: existing.id } },
|
|
188
|
-
signal: context.runtime.signal
|
|
189
|
-
});
|
|
190
|
-
if (error) throw apiCallError(`Failed to remove ${key}`, response, error);
|
|
191
|
-
return {
|
|
192
|
-
command: "project.env.remove",
|
|
193
|
-
result: {
|
|
194
|
-
projectId,
|
|
195
|
-
verboseContext,
|
|
196
|
-
scope: resolved.descriptor,
|
|
197
|
-
key
|
|
198
|
-
},
|
|
199
|
-
warnings: [],
|
|
200
|
-
nextSteps: []
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
async function requireClientAndProject(context, explicitProject, commandName) {
|
|
204
|
-
const authState = await requireAuthenticatedAuthState(context);
|
|
205
|
-
const client = await authenticatedManagementApiClient(context.runtime.env, context.runtime.signal);
|
|
206
|
-
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
207
|
-
const workspace = authState.workspace;
|
|
208
|
-
if (!workspace) throw workspaceRequiredError();
|
|
209
|
-
const targetResult = await resolveProjectTarget({
|
|
210
|
-
context,
|
|
211
|
-
workspace,
|
|
212
|
-
explicitProject,
|
|
213
|
-
listProjects: () => listRealWorkspaceProjects(client, context.runtime.signal),
|
|
214
|
-
commandName
|
|
215
|
-
});
|
|
216
|
-
if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
|
|
217
|
-
const target = targetResult.value;
|
|
218
|
-
return {
|
|
219
|
-
client,
|
|
220
|
-
projectId: target.project.id,
|
|
221
|
-
verboseContext: {
|
|
222
|
-
workspace,
|
|
223
|
-
project: target.project,
|
|
224
|
-
resolution: target.resolution
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
async function resolveScopeToApi(client, projectId, scope, options) {
|
|
229
|
-
if (scope.kind === "role") return {
|
|
230
|
-
scope,
|
|
231
|
-
descriptor: {
|
|
232
|
-
kind: "role",
|
|
233
|
-
role: scope.role
|
|
234
|
-
},
|
|
235
|
-
apiTarget: {
|
|
236
|
-
class: scope.role,
|
|
237
|
-
branchId: null
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
const branch = options.createBranchIfMissing ? await resolveOrCreateBranch(client, projectId, scope.branchName, options.signal) : await resolveExistingBranch(client, projectId, scope.branchName, options.signal);
|
|
241
|
-
if (branch.role === "production") throw new CliError({
|
|
242
|
-
code: "ENV_BRANCH_SCOPE_IS_PRODUCTION",
|
|
243
|
-
domain: "app",
|
|
244
|
-
summary: `Branch "${scope.branchName}" is the production branch`,
|
|
245
|
-
why: "Production variables are project-level only; branch overrides apply to preview branches.",
|
|
246
|
-
fix: "Use --role production for the production branch.",
|
|
247
|
-
exitCode: 1,
|
|
248
|
-
nextSteps: ["prisma-cli project env list --role production"]
|
|
249
|
-
});
|
|
250
|
-
return {
|
|
251
|
-
scope,
|
|
252
|
-
descriptor: {
|
|
253
|
-
kind: "branch",
|
|
254
|
-
branchName: branch.gitName,
|
|
255
|
-
branchId: branch.id
|
|
256
|
-
},
|
|
257
|
-
apiTarget: {
|
|
258
|
-
class: "preview",
|
|
259
|
-
branchId: branch.id
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
async function resolveListScopeToApi(client, projectId, explicit, options) {
|
|
264
|
-
if (explicit) {
|
|
265
|
-
const resolved = await resolveScopeToApi(client, projectId, explicit, {
|
|
266
|
-
createBranchIfMissing: false,
|
|
267
|
-
signal: options.signal
|
|
268
|
-
});
|
|
269
|
-
return {
|
|
270
|
-
kind: "scoped",
|
|
271
|
-
descriptor: resolved.descriptor,
|
|
272
|
-
target: targetFromExplicitScope(resolved.descriptor),
|
|
273
|
-
apiTarget: resolved.apiTarget,
|
|
274
|
-
addScope: resolved.scope
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
const gitBranch = await readLocalGitBranch(options.cwd, options.signal);
|
|
278
|
-
if (gitBranch) {
|
|
279
|
-
const branch = (await listBranchesByName(client, projectId, gitBranch, options.signal))[0];
|
|
280
|
-
if (!branch) return {
|
|
281
|
-
kind: "scoped",
|
|
282
|
-
descriptor: {
|
|
283
|
-
kind: "role",
|
|
284
|
-
role: "preview"
|
|
285
|
-
},
|
|
286
|
-
target: {
|
|
287
|
-
source: "local-git",
|
|
288
|
-
branchName: gitBranch,
|
|
289
|
-
branchExists: false,
|
|
290
|
-
envMap: "preview"
|
|
291
|
-
},
|
|
292
|
-
apiTarget: {
|
|
293
|
-
class: "preview",
|
|
294
|
-
branchId: null
|
|
295
|
-
},
|
|
296
|
-
addScope: {
|
|
297
|
-
kind: "branch",
|
|
298
|
-
branchName: gitBranch
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
if (branch.role === "production") return {
|
|
302
|
-
kind: "scoped",
|
|
303
|
-
descriptor: {
|
|
304
|
-
kind: "role",
|
|
305
|
-
role: "production"
|
|
306
|
-
},
|
|
307
|
-
target: {
|
|
308
|
-
source: "local-git",
|
|
309
|
-
branchName: branch.gitName,
|
|
310
|
-
branchId: branch.id,
|
|
311
|
-
branchRole: branch.role,
|
|
312
|
-
branchExists: true,
|
|
313
|
-
envMap: "production"
|
|
314
|
-
},
|
|
315
|
-
apiTarget: {
|
|
316
|
-
class: "production",
|
|
317
|
-
branchId: null
|
|
318
|
-
},
|
|
319
|
-
addScope: {
|
|
320
|
-
kind: "role",
|
|
321
|
-
role: "production"
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
return {
|
|
325
|
-
kind: "scoped",
|
|
326
|
-
descriptor: {
|
|
327
|
-
kind: "branch",
|
|
328
|
-
branchName: branch.gitName,
|
|
329
|
-
branchId: branch.id
|
|
330
|
-
},
|
|
331
|
-
target: {
|
|
332
|
-
source: "local-git",
|
|
333
|
-
branchName: branch.gitName,
|
|
334
|
-
branchId: branch.id,
|
|
335
|
-
branchRole: branch.role,
|
|
336
|
-
branchExists: true,
|
|
337
|
-
envMap: "preview"
|
|
338
|
-
},
|
|
339
|
-
apiTarget: {
|
|
340
|
-
class: "preview",
|
|
341
|
-
branchId: branch.id
|
|
342
|
-
},
|
|
343
|
-
addScope: {
|
|
344
|
-
kind: "branch",
|
|
345
|
-
branchName: branch.gitName
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
return {
|
|
350
|
-
kind: "overview",
|
|
351
|
-
descriptor: { kind: "overview" },
|
|
352
|
-
target: {
|
|
353
|
-
source: "overview",
|
|
354
|
-
envMap: "overview"
|
|
355
|
-
},
|
|
356
|
-
addScope: {
|
|
357
|
-
kind: "role",
|
|
358
|
-
role: "preview"
|
|
359
|
-
}
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
function targetFromExplicitScope(scope) {
|
|
363
|
-
if (scope.kind === "branch") return {
|
|
364
|
-
source: "explicit",
|
|
365
|
-
branchName: scope.branchName,
|
|
366
|
-
branchId: scope.branchId,
|
|
367
|
-
branchRole: "preview",
|
|
368
|
-
branchExists: true,
|
|
369
|
-
envMap: "preview"
|
|
370
|
-
};
|
|
371
|
-
if (scope.kind === "role") return {
|
|
372
|
-
source: "explicit",
|
|
373
|
-
envMap: scope.role
|
|
374
|
-
};
|
|
375
|
-
return {
|
|
376
|
-
source: "overview",
|
|
377
|
-
envMap: "overview"
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
function formatScopeFlag(scope) {
|
|
381
|
-
if (scope.kind === "role") return `--role ${scope.role}`;
|
|
382
|
-
return `--branch ${scope.branchName}`;
|
|
383
|
-
}
|
|
384
|
-
async function listBranchesByName(client, projectId, branchName, signal) {
|
|
385
|
-
const { data, error, response } = await client.GET("/v1/projects/{projectId}/branches", {
|
|
386
|
-
params: {
|
|
387
|
-
path: { projectId },
|
|
388
|
-
query: { gitName: branchName }
|
|
389
|
-
},
|
|
390
|
-
signal
|
|
391
|
-
});
|
|
392
|
-
if (error || !data) throw apiCallError(`Failed to resolve branch "${branchName}"`, response, error);
|
|
393
|
-
return data.data;
|
|
394
|
-
}
|
|
395
|
-
async function resolveExistingBranch(client, projectId, branchName, signal) {
|
|
396
|
-
const branch = (await listBranchesByName(client, projectId, branchName, signal))[0];
|
|
397
|
-
if (!branch) throw new CliError({
|
|
398
|
-
code: "ENV_BRANCH_NOT_FOUND",
|
|
399
|
-
domain: "app",
|
|
400
|
-
summary: `Branch "${branchName}" not found`,
|
|
401
|
-
why: "Branch update, list, and remove commands only target existing preview branches.",
|
|
402
|
-
fix: "Create the branch by deploying it, or use `project env add --branch` to create its first override.",
|
|
403
|
-
exitCode: 1,
|
|
404
|
-
nextSteps: [`prisma-cli project env add KEY=value --branch ${branchName}`]
|
|
405
|
-
});
|
|
406
|
-
return branch;
|
|
407
|
-
}
|
|
408
|
-
async function resolveOrCreateBranch(client, projectId, branchName, signal) {
|
|
409
|
-
const existing = (await listBranchesByName(client, projectId, branchName, signal))[0];
|
|
410
|
-
if (existing) return existing;
|
|
411
|
-
if (!await projectHasDefaultBranch(client, projectId, signal)) throw new CliError({
|
|
412
|
-
code: "ENV_BRANCH_CREATE_REQUIRES_DEFAULT_BRANCH",
|
|
413
|
-
domain: "app",
|
|
414
|
-
summary: `Cannot create branch "${branchName}" from project env`,
|
|
415
|
-
why: "Creating the first branch would make it the project default, but branch overrides are preview-only.",
|
|
416
|
-
fix: "Create or deploy the default branch first, then add the branch override.",
|
|
417
|
-
exitCode: 1,
|
|
418
|
-
nextSteps: ["prisma-cli app deploy --branch main"]
|
|
419
|
-
});
|
|
420
|
-
const { data, error, response } = await client.POST("/v1/projects/{projectId}/branches", {
|
|
421
|
-
params: { path: { projectId } },
|
|
422
|
-
body: {
|
|
423
|
-
gitName: branchName,
|
|
424
|
-
isDefault: false
|
|
425
|
-
},
|
|
426
|
-
signal
|
|
427
|
-
});
|
|
428
|
-
if (error || !data) {
|
|
429
|
-
if (response?.status === 409) {
|
|
430
|
-
const raced = (await listBranchesByName(client, projectId, branchName, signal))[0];
|
|
431
|
-
if (raced) return raced;
|
|
432
|
-
}
|
|
433
|
-
throw apiCallError(`Failed to create branch "${branchName}"`, response, error);
|
|
434
|
-
}
|
|
435
|
-
return data.data;
|
|
436
|
-
}
|
|
437
|
-
async function projectHasDefaultBranch(client, projectId, signal) {
|
|
438
|
-
let cursor;
|
|
439
|
-
while (true) {
|
|
440
|
-
const query = {};
|
|
441
|
-
if (cursor !== void 0) query.cursor = cursor;
|
|
442
|
-
const result = await client.GET("/v1/projects/{projectId}/branches", {
|
|
443
|
-
params: {
|
|
444
|
-
path: { projectId },
|
|
445
|
-
query
|
|
446
|
-
},
|
|
447
|
-
signal
|
|
448
|
-
});
|
|
449
|
-
if (result.error || !result.data) throw apiCallError("Failed to check project default branch", result.response, result.error);
|
|
450
|
-
if (result.data.data.some((branch) => branch.isDefault)) return true;
|
|
451
|
-
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) return false;
|
|
452
|
-
cursor = result.data.pagination.nextCursor;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
async function listVariables(client, projectId, resolved, signal) {
|
|
456
|
-
return materializeEffectiveRows(await collectEnvironmentVariables(client, projectId, signal, {
|
|
457
|
-
className: resolved.apiTarget.class,
|
|
458
|
-
filter: (row) => rowMatchesScope(row, resolved)
|
|
459
|
-
}), resolved);
|
|
460
|
-
}
|
|
461
|
-
async function listOverviewVariables(client, projectId, signal) {
|
|
462
|
-
return (await collectEnvironmentVariables(client, projectId, signal, { filter: (row) => row.branchId === null && (row.class === "production" || row.class === "preview") })).sort((left, right) => {
|
|
463
|
-
const roleOrder = roleSortOrder(left.class) - roleSortOrder(right.class);
|
|
464
|
-
return roleOrder !== 0 ? roleOrder : left.key.localeCompare(right.key);
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
async function collectEnvironmentVariables(client, projectId, signal, options) {
|
|
468
|
-
const collected = [];
|
|
469
|
-
let cursor;
|
|
470
|
-
while (true) {
|
|
471
|
-
const query = { projectId };
|
|
472
|
-
if (options.className !== void 0) query.class = options.className;
|
|
473
|
-
if (cursor !== void 0) query.cursor = cursor;
|
|
474
|
-
const result = await client.GET("/v1/environment-variables", {
|
|
475
|
-
params: { query },
|
|
476
|
-
signal
|
|
477
|
-
});
|
|
478
|
-
if (result.error || !result.data) throw apiCallError(`Failed to list environment variables`, result.response, result.error);
|
|
479
|
-
const page = result.data.data.filter(options.filter);
|
|
480
|
-
collected.push(...page);
|
|
481
|
-
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
482
|
-
cursor = result.data.pagination.nextCursor;
|
|
483
|
-
}
|
|
484
|
-
return collected;
|
|
485
|
-
}
|
|
486
|
-
function roleSortOrder(role) {
|
|
487
|
-
return role === "production" ? 0 : 1;
|
|
488
|
-
}
|
|
489
|
-
function rowMatchesScope(row, resolved) {
|
|
490
|
-
if (row.class !== resolved.apiTarget.class) return false;
|
|
491
|
-
if (resolved.apiTarget.branchId === null) return row.branchId === null;
|
|
492
|
-
return row.branchId === null || row.branchId === resolved.apiTarget.branchId;
|
|
493
|
-
}
|
|
494
|
-
function materializeEffectiveRows(rows, resolved) {
|
|
495
|
-
if (resolved.apiTarget.branchId === null) return rows;
|
|
496
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
497
|
-
for (const row of rows) if (row.branchId === null && !byKey.has(row.key)) byKey.set(row.key, row);
|
|
498
|
-
for (const row of rows) if (row.branchId === resolved.apiTarget.branchId) byKey.set(row.key, row);
|
|
499
|
-
return [...byKey.values()].sort((left, right) => left.key.localeCompare(right.key));
|
|
500
|
-
}
|
|
501
|
-
//#endregion
|
|
502
|
-
export { runEnvAdd, runEnvList, runEnvRemove, runEnvUpdate };
|