@prisma/cli 3.0.0-dev.56.1 → 3.0.0-dev.58.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/README.md +3 -2
- package/dist/commands/branch/index.js +2 -27
- package/dist/controllers/app-env.js +152 -21
- package/dist/controllers/app.js +1 -36
- package/dist/controllers/branch.js +73 -47
- package/dist/lib/git/local-branch.js +41 -0
- package/dist/presenters/app-env.js +14 -3
- package/dist/presenters/branch.js +29 -101
- package/dist/shell/command-meta.js +5 -24
- package/dist/shell/ui.js +4 -1
- package/dist/use-cases/branch.js +20 -68
- package/dist/use-cases/create-cli-gateways.js +2 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ Useful next commands:
|
|
|
57
57
|
npx prisma-cli app logs
|
|
58
58
|
npx prisma-cli app open
|
|
59
59
|
npx prisma-cli project env add DATABASE_URL=postgresql://example --role preview
|
|
60
|
+
npx prisma-cli project env list
|
|
60
61
|
npx prisma-cli project env list --role preview
|
|
61
62
|
```
|
|
62
63
|
|
|
@@ -73,7 +74,7 @@ The beta package exposes `prisma-cli` so it can coexist with the existing
|
|
|
73
74
|
| `auth` | Log in, log out, and inspect the active Prisma account. |
|
|
74
75
|
| `project` | List projects, show the resolved project, and manage project environment variables. |
|
|
75
76
|
| `git` | Connect or disconnect a project from a GitHub repository. |
|
|
76
|
-
| `branch` |
|
|
77
|
+
| `branch` | List Prisma branches for the resolved project. |
|
|
77
78
|
| `app` | Build, run, deploy, inspect, open, stream logs, promote, roll back, and remove apps. |
|
|
78
79
|
|
|
79
80
|
Common examples:
|
|
@@ -82,7 +83,7 @@ Common examples:
|
|
|
82
83
|
npx prisma-cli version
|
|
83
84
|
npx prisma-cli auth whoami
|
|
84
85
|
npx prisma-cli project show
|
|
85
|
-
npx prisma-cli branch
|
|
86
|
+
npx prisma-cli branch list
|
|
86
87
|
npx prisma-cli app deploy --branch feat-login --framework nextjs
|
|
87
88
|
npx prisma-cli app promote <deployment-id>
|
|
88
89
|
```
|
|
@@ -2,16 +2,14 @@ import { attachCommandDescriptor } from "../../shell/command-meta.js";
|
|
|
2
2
|
import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
|
|
3
3
|
import { configureRuntimeCommand } from "../../shell/runtime.js";
|
|
4
4
|
import { runCommand } from "../../shell/command-runner.js";
|
|
5
|
-
import { runBranchList
|
|
6
|
-
import { renderBranchList,
|
|
5
|
+
import { runBranchList } from "../../controllers/branch.js";
|
|
6
|
+
import { renderBranchList, serializeBranchList } from "../../presenters/branch.js";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
//#region src/commands/branch/index.ts
|
|
9
9
|
function createBranchCommand(runtime) {
|
|
10
10
|
const branch = attachCommandDescriptor(configureRuntimeCommand(new Command("branch"), runtime), "branch");
|
|
11
11
|
addCompactGlobalFlags(branch);
|
|
12
12
|
branch.addCommand(createBranchListCommand(runtime));
|
|
13
|
-
branch.addCommand(createBranchShowCommand(runtime));
|
|
14
|
-
branch.addCommand(createBranchUseCommand(runtime));
|
|
15
13
|
return branch;
|
|
16
14
|
}
|
|
17
15
|
function createBranchListCommand(runtime) {
|
|
@@ -25,28 +23,5 @@ function createBranchListCommand(runtime) {
|
|
|
25
23
|
});
|
|
26
24
|
return command;
|
|
27
25
|
}
|
|
28
|
-
function createBranchShowCommand(runtime) {
|
|
29
|
-
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "branch.show");
|
|
30
|
-
addGlobalFlags(command);
|
|
31
|
-
command.action(async (options) => {
|
|
32
|
-
await runCommand(runtime, "branch.show", options, (context) => runBranchShow(context), {
|
|
33
|
-
renderHuman: (context, descriptor, result) => renderBranchShow(context, descriptor, result),
|
|
34
|
-
renderJson: (result) => serializeBranchShow(result)
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
return command;
|
|
38
|
-
}
|
|
39
|
-
function createBranchUseCommand(runtime) {
|
|
40
|
-
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("use"), runtime), "branch.use");
|
|
41
|
-
command.argument("[name]", "Branch name");
|
|
42
|
-
addGlobalFlags(command);
|
|
43
|
-
command.action(async (branchName, options) => {
|
|
44
|
-
await runCommand(runtime, "branch.use", options, (context) => runBranchUse(context, branchName), {
|
|
45
|
-
renderHuman: (context, descriptor, result) => renderBranchUse(context, descriptor, result),
|
|
46
|
-
renderJson: (result) => serializeBranchShow(result)
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
return command;
|
|
50
|
-
}
|
|
51
26
|
//#endregion
|
|
52
27
|
export { createBranchCommand };
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
2
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
3
|
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
4
|
+
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
4
5
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
5
6
|
import { listRealWorkspaceProjects } from "./project.js";
|
|
6
7
|
import { formatScopeLabel, parseKeyValuePositional, resolveEnvScope } from "../lib/app/env-config.js";
|
|
7
8
|
//#region src/controllers/app-env.ts
|
|
8
|
-
function defaultRoleScope() {
|
|
9
|
-
return {
|
|
10
|
-
kind: "role",
|
|
11
|
-
role: "production"
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
9
|
async function runEnvAdd(context, rawAssignment, flags) {
|
|
15
10
|
const { key, value } = parseKeyValuePositional(rawAssignment, "add", context.runtime.env);
|
|
16
11
|
const scope = resolveEnvScope(flags, {
|
|
@@ -108,25 +103,30 @@ async function runEnvUpdate(context, rawAssignment, flags) {
|
|
|
108
103
|
};
|
|
109
104
|
}
|
|
110
105
|
async function runEnvList(context, flags) {
|
|
111
|
-
const
|
|
106
|
+
const explicit = resolveEnvScope(flags, {
|
|
112
107
|
requireExplicit: false,
|
|
113
108
|
command: "list"
|
|
114
|
-
})
|
|
109
|
+
});
|
|
115
110
|
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env list");
|
|
116
|
-
const resolved = await
|
|
117
|
-
|
|
111
|
+
const resolved = await resolveListScopeToApi(client, projectId, explicit, {
|
|
112
|
+
cwd: context.runtime.cwd,
|
|
118
113
|
signal: context.runtime.signal
|
|
119
114
|
});
|
|
120
|
-
const variables = await listVariables(client, projectId,
|
|
115
|
+
const variables = resolved.kind === "scoped" ? await listVariables(client, projectId, {
|
|
116
|
+
scope: resolved.addScope,
|
|
117
|
+
descriptor: resolved.descriptor,
|
|
118
|
+
apiTarget: resolved.apiTarget
|
|
119
|
+
}, context.runtime.signal) : await listOverviewVariables(client, projectId, context.runtime.signal);
|
|
121
120
|
return {
|
|
122
121
|
command: "project.env.list",
|
|
123
122
|
result: {
|
|
124
123
|
projectId,
|
|
125
124
|
scope: resolved.descriptor,
|
|
125
|
+
target: resolved.target,
|
|
126
126
|
variables: variables.map((row) => toMetadata(row, resolved.descriptor))
|
|
127
127
|
},
|
|
128
128
|
warnings: [],
|
|
129
|
-
nextSteps: variables.length === 0 ? [`prisma-cli project env add KEY=value ${formatScopeFlag(
|
|
129
|
+
nextSteps: variables.length === 0 ? [`prisma-cli project env add KEY=value ${formatScopeFlag(resolved.addScope)}`] : []
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
132
|
async function runEnvRemove(context, key, flags) {
|
|
@@ -196,12 +196,12 @@ async function resolveScopeToApi(client, projectId, scope, options) {
|
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
198
|
const branch = options.createBranchIfMissing ? await resolveOrCreateBranch(client, projectId, scope.branchName, options.signal) : await resolveExistingBranch(client, projectId, scope.branchName, options.signal);
|
|
199
|
-
if (branch.
|
|
199
|
+
if (branch.role === "production") throw new CliError({
|
|
200
200
|
code: "ENV_BRANCH_SCOPE_IS_PRODUCTION",
|
|
201
201
|
domain: "app",
|
|
202
|
-
summary: `Branch "${scope.branchName}" is the
|
|
202
|
+
summary: `Branch "${scope.branchName}" is the production branch`,
|
|
203
203
|
why: "Production variables are project-level only; branch overrides apply to preview branches.",
|
|
204
|
-
fix: "Use --role production for the
|
|
204
|
+
fix: "Use --role production for the production branch.",
|
|
205
205
|
exitCode: 1,
|
|
206
206
|
nextSteps: ["prisma-cli project env list --role production"]
|
|
207
207
|
});
|
|
@@ -218,6 +218,123 @@ async function resolveScopeToApi(client, projectId, scope, options) {
|
|
|
218
218
|
}
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
|
+
async function resolveListScopeToApi(client, projectId, explicit, options) {
|
|
222
|
+
if (explicit) {
|
|
223
|
+
const resolved = await resolveScopeToApi(client, projectId, explicit, {
|
|
224
|
+
createBranchIfMissing: false,
|
|
225
|
+
signal: options.signal
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
kind: "scoped",
|
|
229
|
+
descriptor: resolved.descriptor,
|
|
230
|
+
target: targetFromExplicitScope(resolved.descriptor),
|
|
231
|
+
apiTarget: resolved.apiTarget,
|
|
232
|
+
addScope: resolved.scope
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const gitBranch = await readLocalGitBranch(options.cwd, options.signal);
|
|
236
|
+
if (gitBranch) {
|
|
237
|
+
const branch = (await listBranchesByName(client, projectId, gitBranch, options.signal))[0];
|
|
238
|
+
if (!branch) return {
|
|
239
|
+
kind: "scoped",
|
|
240
|
+
descriptor: {
|
|
241
|
+
kind: "role",
|
|
242
|
+
role: "preview"
|
|
243
|
+
},
|
|
244
|
+
target: {
|
|
245
|
+
source: "local-git",
|
|
246
|
+
branchName: gitBranch,
|
|
247
|
+
branchExists: false,
|
|
248
|
+
envMap: "preview"
|
|
249
|
+
},
|
|
250
|
+
apiTarget: {
|
|
251
|
+
class: "preview",
|
|
252
|
+
branchId: null
|
|
253
|
+
},
|
|
254
|
+
addScope: {
|
|
255
|
+
kind: "branch",
|
|
256
|
+
branchName: gitBranch
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
if (branch.role === "production") return {
|
|
260
|
+
kind: "scoped",
|
|
261
|
+
descriptor: {
|
|
262
|
+
kind: "role",
|
|
263
|
+
role: "production"
|
|
264
|
+
},
|
|
265
|
+
target: {
|
|
266
|
+
source: "local-git",
|
|
267
|
+
branchName: branch.gitName,
|
|
268
|
+
branchId: branch.id,
|
|
269
|
+
branchRole: branch.role,
|
|
270
|
+
branchExists: true,
|
|
271
|
+
envMap: "production"
|
|
272
|
+
},
|
|
273
|
+
apiTarget: {
|
|
274
|
+
class: "production",
|
|
275
|
+
branchId: null
|
|
276
|
+
},
|
|
277
|
+
addScope: {
|
|
278
|
+
kind: "role",
|
|
279
|
+
role: "production"
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
return {
|
|
283
|
+
kind: "scoped",
|
|
284
|
+
descriptor: {
|
|
285
|
+
kind: "branch",
|
|
286
|
+
branchName: branch.gitName,
|
|
287
|
+
branchId: branch.id
|
|
288
|
+
},
|
|
289
|
+
target: {
|
|
290
|
+
source: "local-git",
|
|
291
|
+
branchName: branch.gitName,
|
|
292
|
+
branchId: branch.id,
|
|
293
|
+
branchRole: branch.role,
|
|
294
|
+
branchExists: true,
|
|
295
|
+
envMap: "preview"
|
|
296
|
+
},
|
|
297
|
+
apiTarget: {
|
|
298
|
+
class: "preview",
|
|
299
|
+
branchId: branch.id
|
|
300
|
+
},
|
|
301
|
+
addScope: {
|
|
302
|
+
kind: "branch",
|
|
303
|
+
branchName: branch.gitName
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
kind: "overview",
|
|
309
|
+
descriptor: { kind: "overview" },
|
|
310
|
+
target: {
|
|
311
|
+
source: "overview",
|
|
312
|
+
envMap: "overview"
|
|
313
|
+
},
|
|
314
|
+
addScope: {
|
|
315
|
+
kind: "role",
|
|
316
|
+
role: "preview"
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function targetFromExplicitScope(scope) {
|
|
321
|
+
if (scope.kind === "branch") return {
|
|
322
|
+
source: "explicit",
|
|
323
|
+
branchName: scope.branchName,
|
|
324
|
+
branchId: scope.branchId,
|
|
325
|
+
branchRole: "preview",
|
|
326
|
+
branchExists: true,
|
|
327
|
+
envMap: "preview"
|
|
328
|
+
};
|
|
329
|
+
if (scope.kind === "role") return {
|
|
330
|
+
source: "explicit",
|
|
331
|
+
envMap: scope.role
|
|
332
|
+
};
|
|
333
|
+
return {
|
|
334
|
+
source: "overview",
|
|
335
|
+
envMap: "overview"
|
|
336
|
+
};
|
|
337
|
+
}
|
|
221
338
|
function formatScopeFlag(scope) {
|
|
222
339
|
if (scope.kind === "role") return `--role ${scope.role}`;
|
|
223
340
|
return `--branch ${scope.branchName}`;
|
|
@@ -306,25 +423,38 @@ async function findVariableByNaturalKey(client, projectId, key, resolved, signal
|
|
|
306
423
|
return data.data.filter((row) => rowMatchesExactScope(row, resolved))[0] ?? null;
|
|
307
424
|
}
|
|
308
425
|
async function listVariables(client, projectId, resolved, signal) {
|
|
426
|
+
return materializeEffectiveRows(await collectEnvironmentVariables(client, projectId, signal, {
|
|
427
|
+
className: resolved.apiTarget.class,
|
|
428
|
+
filter: (row) => rowMatchesScope(row, resolved)
|
|
429
|
+
}), resolved);
|
|
430
|
+
}
|
|
431
|
+
async function listOverviewVariables(client, projectId, signal) {
|
|
432
|
+
return (await collectEnvironmentVariables(client, projectId, signal, { filter: (row) => row.branchId === null && (row.class === "production" || row.class === "preview") })).sort((left, right) => {
|
|
433
|
+
const roleOrder = roleSortOrder(left.class) - roleSortOrder(right.class);
|
|
434
|
+
return roleOrder !== 0 ? roleOrder : left.key.localeCompare(right.key);
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
async function collectEnvironmentVariables(client, projectId, signal, options) {
|
|
309
438
|
const collected = [];
|
|
310
439
|
let cursor;
|
|
311
440
|
while (true) {
|
|
312
|
-
const query = {
|
|
313
|
-
|
|
314
|
-
class: resolved.apiTarget.class
|
|
315
|
-
};
|
|
441
|
+
const query = { projectId };
|
|
442
|
+
if (options.className !== void 0) query.class = options.className;
|
|
316
443
|
if (cursor !== void 0) query.cursor = cursor;
|
|
317
444
|
const result = await client.GET("/v1/environment-variables", {
|
|
318
445
|
params: { query },
|
|
319
446
|
signal
|
|
320
447
|
});
|
|
321
448
|
if (result.error || !result.data) throw apiCallError(`Failed to list environment variables`, result.response, result.error);
|
|
322
|
-
const page = result.data.data.filter(
|
|
449
|
+
const page = result.data.data.filter(options.filter);
|
|
323
450
|
collected.push(...page);
|
|
324
451
|
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
325
452
|
cursor = result.data.pagination.nextCursor;
|
|
326
453
|
}
|
|
327
|
-
return
|
|
454
|
+
return collected;
|
|
455
|
+
}
|
|
456
|
+
function roleSortOrder(role) {
|
|
457
|
+
return role === "production" ? 0 : 1;
|
|
328
458
|
}
|
|
329
459
|
function rowMatchesScope(row, resolved) {
|
|
330
460
|
if (row.class !== resolved.apiTarget.class) return false;
|
|
@@ -357,6 +487,7 @@ function toMetadata(row, requestedScope) {
|
|
|
357
487
|
}
|
|
358
488
|
function formatDescriptorLabel(scope) {
|
|
359
489
|
if (scope.kind === "role") return scope.role ?? "unknown";
|
|
490
|
+
if (scope.kind === "overview") return "overview";
|
|
360
491
|
return `branch:${scope.branchName ?? scope.branchId ?? "unknown"}`;
|
|
361
492
|
}
|
|
362
493
|
function apiCallError(summary, response, error) {
|
package/dist/controllers/app.js
CHANGED
|
@@ -16,6 +16,7 @@ import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../l
|
|
|
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
18
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
19
|
+
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
19
20
|
import { PREVIEW_BUILD_TYPES, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild } from "../lib/app/preview-build.js";
|
|
20
21
|
import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction.js";
|
|
21
22
|
import { createPreviewDeployProgress, createPreviewDeployProgressState, createPreviewPromoteProgress } from "../lib/app/preview-progress.js";
|
|
@@ -1481,42 +1482,6 @@ async function resolveDeployBranch(context, explicitBranchName) {
|
|
|
1481
1482
|
annotation: "default"
|
|
1482
1483
|
};
|
|
1483
1484
|
}
|
|
1484
|
-
async function readLocalGitBranch(cwd, signal) {
|
|
1485
|
-
const headPath = await resolveGitHeadPath(path.join(cwd, ".git"), signal);
|
|
1486
|
-
if (!headPath) return null;
|
|
1487
|
-
try {
|
|
1488
|
-
const head = (await readFile(headPath, {
|
|
1489
|
-
encoding: "utf8",
|
|
1490
|
-
signal
|
|
1491
|
-
})).trim();
|
|
1492
|
-
if (head.startsWith("ref: refs/heads/")) return head.slice(16);
|
|
1493
|
-
} catch (error) {
|
|
1494
|
-
if (signal.aborted) throw error;
|
|
1495
|
-
return null;
|
|
1496
|
-
}
|
|
1497
|
-
return null;
|
|
1498
|
-
}
|
|
1499
|
-
async function resolveGitHeadPath(gitPath, signal) {
|
|
1500
|
-
signal.throwIfAborted();
|
|
1501
|
-
try {
|
|
1502
|
-
const raw = await readFile(gitPath, {
|
|
1503
|
-
encoding: "utf8",
|
|
1504
|
-
signal
|
|
1505
|
-
});
|
|
1506
|
-
if (raw.startsWith("gitdir:")) return path.join(path.resolve(path.dirname(gitPath), raw.slice(7).trim()), "HEAD");
|
|
1507
|
-
} catch (error) {
|
|
1508
|
-
if (signal.aborted) throw error;
|
|
1509
|
-
}
|
|
1510
|
-
signal.throwIfAborted();
|
|
1511
|
-
try {
|
|
1512
|
-
await access(path.join(gitPath, "HEAD"));
|
|
1513
|
-
signal.throwIfAborted();
|
|
1514
|
-
return path.join(gitPath, "HEAD");
|
|
1515
|
-
} catch (error) {
|
|
1516
|
-
if (signal.aborted) throw error;
|
|
1517
|
-
return null;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
1485
|
async function resolveDeployFramework(context, options) {
|
|
1521
1486
|
if (options.requestedFramework) return frameworkFromUserFacingValue(options.requestedFramework, "set by --framework");
|
|
1522
1487
|
if (options.entrypoint) return {
|
|
@@ -1,73 +1,99 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { CliError, authRequiredError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
|
+
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
|
+
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
3
4
|
import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
|
|
4
5
|
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
6
|
+
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
7
|
+
import { listRealWorkspaceProjects } from "./project.js";
|
|
5
8
|
import { createBranchUseCases } from "../use-cases/branch.js";
|
|
6
9
|
//#region src/controllers/branch.ts
|
|
7
|
-
const PREVIEW_BRANCH_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
8
10
|
function isRealMode(context) {
|
|
9
11
|
return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
|
|
10
12
|
}
|
|
11
13
|
async function runBranchList(context) {
|
|
12
|
-
if (isRealMode(context))
|
|
13
|
-
return {
|
|
14
|
+
if (isRealMode(context)) return {
|
|
14
15
|
command: "branch.list",
|
|
15
|
-
result: await
|
|
16
|
+
result: await listRealBranches(context),
|
|
16
17
|
warnings: [],
|
|
17
18
|
nextSteps: []
|
|
18
19
|
};
|
|
19
|
-
}
|
|
20
|
-
async function runBranchShow(context) {
|
|
21
|
-
if (isRealMode(context)) throw branchCommandsUnavailableError();
|
|
22
|
-
const result = await createBranchUseCases(createCliUseCaseGateways(context)).show();
|
|
23
20
|
return {
|
|
24
|
-
command: "branch.
|
|
25
|
-
result,
|
|
21
|
+
command: "branch.list",
|
|
22
|
+
result: await createBranchUseCases(createCliUseCaseGateways(context)).list(),
|
|
26
23
|
warnings: [],
|
|
27
|
-
nextSteps:
|
|
24
|
+
nextSteps: []
|
|
28
25
|
};
|
|
29
26
|
}
|
|
30
|
-
async function
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
async function listRealBranches(context) {
|
|
28
|
+
const authState = await requireAuthenticatedAuthState(context);
|
|
29
|
+
const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
|
|
30
|
+
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
31
|
+
const workspace = authState.workspace;
|
|
32
|
+
if (!workspace) throw workspaceRequiredError();
|
|
33
|
+
const target = await resolveProjectTarget({
|
|
34
|
+
context,
|
|
35
|
+
workspace,
|
|
36
|
+
listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
|
|
37
|
+
prompt: createSelectPromptPort(context),
|
|
38
|
+
remember: true
|
|
39
|
+
});
|
|
40
|
+
const branches = await listBranches(client, target.project.id, context.runtime.signal);
|
|
36
41
|
return {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
nextSteps: result.branch.kind === "preview" && !result.branch.remoteState ? ["prisma-cli branch show", "prisma-cli app deploy"] : ["prisma-cli branch show"]
|
|
42
|
+
projectId: target.project.id,
|
|
43
|
+
projectName: target.project.name,
|
|
44
|
+
branches: sortBranches(branches.map(toBranchSummary))
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
choices: result.branches.map((branch) => ({
|
|
50
|
-
label: renderBranchChoiceLabel(branch),
|
|
51
|
-
value: branch.name
|
|
52
|
-
}))
|
|
47
|
+
function sortBranches(branches) {
|
|
48
|
+
return branches.slice().sort((left, right) => {
|
|
49
|
+
const leftRank = branchOrder(left);
|
|
50
|
+
const rightRank = branchOrder(right);
|
|
51
|
+
if (leftRank !== rightRank) return leftRank - rightRank;
|
|
52
|
+
return left.name.localeCompare(right.name);
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
if (branch.active) markers.push("active");
|
|
58
|
-
if (!branch.remoteState) markers.push("not created yet");
|
|
59
|
-
return markers.length > 0 ? `${branch.name} (${markers.join(", ")})` : branch.name;
|
|
55
|
+
function branchOrder(branch) {
|
|
56
|
+
return branch.role === "production" ? 0 : 1;
|
|
60
57
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
async function listBranches(client, projectId, signal) {
|
|
59
|
+
const collected = [];
|
|
60
|
+
let cursor;
|
|
61
|
+
while (true) {
|
|
62
|
+
const query = {};
|
|
63
|
+
if (cursor !== void 0) query.cursor = cursor;
|
|
64
|
+
const { data, error, response } = await client.GET("/v1/projects/{projectId}/branches", {
|
|
65
|
+
params: {
|
|
66
|
+
path: { projectId },
|
|
67
|
+
query
|
|
68
|
+
},
|
|
69
|
+
signal
|
|
70
|
+
});
|
|
71
|
+
if (error || !data) throw branchApiError("Failed to list branches", response, error);
|
|
72
|
+
collected.push(...data.data);
|
|
73
|
+
if (!data.pagination.hasMore || !data.pagination.nextCursor) break;
|
|
74
|
+
cursor = data.pagination.nextCursor;
|
|
75
|
+
}
|
|
76
|
+
return collected;
|
|
65
77
|
}
|
|
66
|
-
function
|
|
67
|
-
return
|
|
78
|
+
function toBranchSummary(branch) {
|
|
79
|
+
return {
|
|
80
|
+
id: branch.id,
|
|
81
|
+
name: branch.gitName,
|
|
82
|
+
role: branch.role,
|
|
83
|
+
envMap: branch.role
|
|
84
|
+
};
|
|
68
85
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
86
|
+
function branchApiError(summary, response, error) {
|
|
87
|
+
const status = response?.status ?? 0;
|
|
88
|
+
return new CliError({
|
|
89
|
+
code: error?.error?.code ?? "BRANCH_API_ERROR",
|
|
90
|
+
domain: "branch",
|
|
91
|
+
summary,
|
|
92
|
+
why: error?.error?.message ?? `The Management API returned status ${status || "unknown"}.`,
|
|
93
|
+
fix: error?.error?.hint ?? "Re-run with --trace for the underlying API response details.",
|
|
94
|
+
exitCode: 1,
|
|
95
|
+
nextSteps: []
|
|
96
|
+
});
|
|
71
97
|
}
|
|
72
98
|
//#endregion
|
|
73
|
-
export { runBranchList
|
|
99
|
+
export { runBranchList };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/lib/git/local-branch.ts
|
|
4
|
+
async function readLocalGitBranch(cwd, signal) {
|
|
5
|
+
const headPath = await resolveGitHeadPath(path.join(cwd, ".git"), signal);
|
|
6
|
+
if (!headPath) return null;
|
|
7
|
+
try {
|
|
8
|
+
const head = (await readFile(headPath, {
|
|
9
|
+
encoding: "utf8",
|
|
10
|
+
signal
|
|
11
|
+
})).trim();
|
|
12
|
+
if (head.startsWith("ref: refs/heads/")) return head.slice(16);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
if (signal.aborted) throw error;
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
async function resolveGitHeadPath(gitPath, signal) {
|
|
20
|
+
signal.throwIfAborted();
|
|
21
|
+
try {
|
|
22
|
+
const raw = await readFile(gitPath, {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
signal
|
|
25
|
+
});
|
|
26
|
+
if (raw.startsWith("gitdir:")) return path.join(path.resolve(path.dirname(gitPath), raw.slice(7).trim()), "HEAD");
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (signal.aborted) throw error;
|
|
29
|
+
}
|
|
30
|
+
signal.throwIfAborted();
|
|
31
|
+
try {
|
|
32
|
+
await access(path.join(gitPath, "HEAD"));
|
|
33
|
+
signal.throwIfAborted();
|
|
34
|
+
return path.join(gitPath, "HEAD");
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (signal.aborted) throw error;
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { readLocalGitBranch };
|
|
@@ -2,8 +2,18 @@ import { renderList, renderShow, serializeList } from "../output/patterns.js";
|
|
|
2
2
|
//#region src/presenters/app-env.ts
|
|
3
3
|
function scopeLabel(scope) {
|
|
4
4
|
if (scope.kind === "role") return scope.role ?? "unknown";
|
|
5
|
+
if (scope.kind === "overview") return "overview";
|
|
5
6
|
return `branch:${scope.branchName ?? scope.branchId ?? "unknown"}`;
|
|
6
7
|
}
|
|
8
|
+
function listTargetLabel(result) {
|
|
9
|
+
const target = result.target;
|
|
10
|
+
if (target.source === "overview") return "overview";
|
|
11
|
+
if (target.branchName) {
|
|
12
|
+
const suffix = target.branchExists === false ? " (not created yet)" : "";
|
|
13
|
+
return `branch:${target.branchName} -> ${target.envMap}${suffix}`;
|
|
14
|
+
}
|
|
15
|
+
return scopeLabel(result.scope);
|
|
16
|
+
}
|
|
7
17
|
function renderEnvAdd(context, descriptor, result) {
|
|
8
18
|
return renderShow({
|
|
9
19
|
title: "Setting a new environment variable.",
|
|
@@ -75,8 +85,8 @@ function renderEnvList(context, descriptor, result) {
|
|
|
75
85
|
title: "Listing environment variables for the selected scope.",
|
|
76
86
|
descriptor,
|
|
77
87
|
parentContext: {
|
|
78
|
-
key: "
|
|
79
|
-
value:
|
|
88
|
+
key: "target",
|
|
89
|
+
value: listTargetLabel(result)
|
|
80
90
|
},
|
|
81
91
|
items: result.variables.map((variable) => ({
|
|
82
92
|
noun: "variable",
|
|
@@ -91,8 +101,9 @@ function serializeEnvList(result) {
|
|
|
91
101
|
return {
|
|
92
102
|
projectId: result.projectId,
|
|
93
103
|
scope: result.scope,
|
|
104
|
+
target: result.target,
|
|
94
105
|
...serializeList({
|
|
95
|
-
context: {
|
|
106
|
+
context: { target: listTargetLabel(result) },
|
|
96
107
|
items: result.variables.map((variable) => ({
|
|
97
108
|
noun: "variable",
|
|
98
109
|
label: `${variable.key} (${variable.source})`,
|
|
@@ -1,111 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatColumns } from "../shell/ui.js";
|
|
2
|
+
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
2
3
|
//#region src/presenters/branch.ts
|
|
3
4
|
function renderBranchList(context, descriptor, result) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
5
|
+
const ui = context.ui;
|
|
6
|
+
const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing branches for the resolved project.")}`, ""];
|
|
7
|
+
const rail = ui.dim("│");
|
|
8
|
+
lines.push(`${rail} ${ui.accent("project:")} ${result.projectName}`);
|
|
9
|
+
lines.push(rail);
|
|
10
|
+
if (result.branches.length === 0) {
|
|
11
|
+
lines.push(`${rail} ${ui.dim("No branches found.")}`);
|
|
12
|
+
return lines;
|
|
13
|
+
}
|
|
14
|
+
const widths = [
|
|
15
|
+
Math.max(4, ...result.branches.map((branch) => branch.name.length)),
|
|
16
|
+
Math.max(4, ...result.branches.map((branch) => branch.role.length)),
|
|
17
|
+
Math.max(7, ...result.branches.map((branch) => branch.envMap.length))
|
|
18
|
+
];
|
|
19
|
+
lines.push(`${rail} ${ui.accent(formatColumns([
|
|
20
|
+
"Name",
|
|
21
|
+
"Role",
|
|
22
|
+
"Env map"
|
|
23
|
+
], widths))}`);
|
|
24
|
+
for (const branch of result.branches) lines.push(`${rail} ${formatColumns([
|
|
25
|
+
branch.name,
|
|
26
|
+
branch.role,
|
|
27
|
+
branch.envMap
|
|
28
|
+
], widths)}`);
|
|
29
|
+
return lines;
|
|
19
30
|
}
|
|
20
31
|
function serializeBranchList(result) {
|
|
21
|
-
return serializeList({
|
|
22
|
-
context: { project: result.projectName ?? "not resolved" },
|
|
23
|
-
items: result.branches.map((branch) => ({
|
|
24
|
-
noun: "branch",
|
|
25
|
-
label: branch.name,
|
|
26
|
-
id: branch.id,
|
|
27
|
-
status: branch.active ? "active" : null
|
|
28
|
-
}))
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
function serializeBranchShow(result) {
|
|
32
32
|
return {
|
|
33
33
|
projectId: result.projectId,
|
|
34
34
|
projectName: result.projectName,
|
|
35
|
-
|
|
36
|
-
name: result.branch.name,
|
|
37
|
-
kind: result.branch.kind,
|
|
38
|
-
active: result.branch.active,
|
|
39
|
-
remoteState: result.branch.remoteState,
|
|
40
|
-
liveDeployment: result.branch.liveDeployment
|
|
41
|
-
}
|
|
35
|
+
branches: result.branches
|
|
42
36
|
};
|
|
43
37
|
}
|
|
44
|
-
function renderBranchShow(context, descriptor, result) {
|
|
45
|
-
const fields = [
|
|
46
|
-
{
|
|
47
|
-
key: "project",
|
|
48
|
-
value: result.projectName ?? "not resolved",
|
|
49
|
-
tone: result.projectName ? "default" : "dim"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
key: "branch",
|
|
53
|
-
value: result.branch.name,
|
|
54
|
-
tone: result.branch.active ? "success" : "default"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
key: "kind",
|
|
58
|
-
value: result.branch.kind
|
|
59
|
-
}
|
|
60
|
-
];
|
|
61
|
-
if (result.branch.liveDeployment) {
|
|
62
|
-
fields.push({
|
|
63
|
-
key: "status",
|
|
64
|
-
value: result.branch.liveDeployment.status,
|
|
65
|
-
tone: toneForDeploymentStatus(result.branch.liveDeployment.status)
|
|
66
|
-
});
|
|
67
|
-
if (result.branch.liveDeployment.url) fields.push({
|
|
68
|
-
key: "url",
|
|
69
|
-
value: result.branch.liveDeployment.url,
|
|
70
|
-
tone: "link"
|
|
71
|
-
});
|
|
72
|
-
} else if (!result.branch.remoteState) fields.push({
|
|
73
|
-
key: "remote state",
|
|
74
|
-
value: "not created yet",
|
|
75
|
-
tone: "dim"
|
|
76
|
-
});
|
|
77
|
-
return renderShow({
|
|
78
|
-
title: "Showing the current active branch context.",
|
|
79
|
-
descriptor,
|
|
80
|
-
fields
|
|
81
|
-
}, context.ui);
|
|
82
|
-
}
|
|
83
|
-
function toneForDeploymentStatus(status) {
|
|
84
|
-
if (status === "ready" || status === "active" || status === "healthy") return "success";
|
|
85
|
-
if (status === "pending" || status === "building" || status === "starting") return "warning";
|
|
86
|
-
if (status === "failed" || status === "error") return "error";
|
|
87
|
-
return "default";
|
|
88
|
-
}
|
|
89
|
-
function renderBranchUse(context, descriptor, result) {
|
|
90
|
-
return renderMutate({
|
|
91
|
-
title: "Changing the local default branch context.",
|
|
92
|
-
descriptor,
|
|
93
|
-
context: [{
|
|
94
|
-
key: "project",
|
|
95
|
-
value: result.projectName ?? "not resolved",
|
|
96
|
-
tone: result.projectName ? "default" : "dim"
|
|
97
|
-
}, {
|
|
98
|
-
key: "branch",
|
|
99
|
-
value: result.branch.name
|
|
100
|
-
}],
|
|
101
|
-
operationDescription: "Applying active branch change",
|
|
102
|
-
operationCount: 1,
|
|
103
|
-
details: ["Active branch updated in local CLI state for this repo."],
|
|
104
|
-
alerts: result.branch.kind === "production" ? [{
|
|
105
|
-
tone: "warning",
|
|
106
|
-
text: "Production is protected and durable. Use with care"
|
|
107
|
-
}] : void 0
|
|
108
|
-
}, context.ui);
|
|
109
|
-
}
|
|
110
38
|
//#endregion
|
|
111
|
-
export { renderBranchList,
|
|
39
|
+
export { renderBranchList, serializeBranchList };
|
|
@@ -69,8 +69,8 @@ const DESCRIPTORS = [
|
|
|
69
69
|
{
|
|
70
70
|
id: "branch",
|
|
71
71
|
path: ["prisma", "branch"],
|
|
72
|
-
description: "View your
|
|
73
|
-
examples: ["prisma-cli branch list"
|
|
72
|
+
description: "View your Platform branches",
|
|
73
|
+
examples: ["prisma-cli branch list"]
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
id: "git",
|
|
@@ -153,29 +153,9 @@ const DESCRIPTORS = [
|
|
|
153
153
|
"branch",
|
|
154
154
|
"list"
|
|
155
155
|
],
|
|
156
|
-
description: "List
|
|
156
|
+
description: "List Platform branches for the resolved project",
|
|
157
157
|
examples: ["prisma-cli branch list", "prisma-cli branch list --json"]
|
|
158
158
|
},
|
|
159
|
-
{
|
|
160
|
-
id: "branch.show",
|
|
161
|
-
path: [
|
|
162
|
-
"prisma",
|
|
163
|
-
"branch",
|
|
164
|
-
"show"
|
|
165
|
-
],
|
|
166
|
-
description: "Show the Platform branch matching your current Git branch",
|
|
167
|
-
examples: ["prisma-cli branch show", "prisma-cli branch show --json"]
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
id: "branch.use",
|
|
171
|
-
path: [
|
|
172
|
-
"prisma",
|
|
173
|
-
"branch",
|
|
174
|
-
"use"
|
|
175
|
-
],
|
|
176
|
-
description: "Change the local default branch context.",
|
|
177
|
-
examples: ["prisma-cli branch use", "prisma-cli branch use production"]
|
|
178
|
-
},
|
|
179
159
|
{
|
|
180
160
|
id: "app.build",
|
|
181
161
|
path: [
|
|
@@ -379,7 +359,7 @@ const DESCRIPTORS = [
|
|
|
379
359
|
],
|
|
380
360
|
description: "Manage environment variables for the active project",
|
|
381
361
|
examples: [
|
|
382
|
-
"prisma-cli project env list
|
|
362
|
+
"prisma-cli project env list",
|
|
383
363
|
"prisma-cli project env add STRIPE_KEY=sk_test_xxx --role production",
|
|
384
364
|
"prisma-cli project env add DATABASE_URL=postgresql://branch --branch feature/foo",
|
|
385
365
|
"prisma-cli project env remove STRIPE_KEY --role preview"
|
|
@@ -426,6 +406,7 @@ const DESCRIPTORS = [
|
|
|
426
406
|
],
|
|
427
407
|
description: "List environment variable metadata for a scope (no values).",
|
|
428
408
|
examples: [
|
|
409
|
+
"prisma-cli project env list",
|
|
429
410
|
"prisma-cli project env list --role production",
|
|
430
411
|
"prisma-cli project env list --role preview",
|
|
431
412
|
"prisma-cli project env list --branch feature/foo"
|
package/dist/shell/ui.js
CHANGED
|
@@ -48,6 +48,9 @@ function renderNextSteps(steps) {
|
|
|
48
48
|
...steps.map((step) => `- ${step}`)
|
|
49
49
|
];
|
|
50
50
|
}
|
|
51
|
+
function formatColumns(columns, widths) {
|
|
52
|
+
return columns.map((value, index) => padDisplay(value, widths[index])).join(" ").trimEnd();
|
|
53
|
+
}
|
|
51
54
|
function wrapText(text, width, indent = "") {
|
|
52
55
|
return wrapAnsi(text, width, {
|
|
53
56
|
hard: false,
|
|
@@ -74,4 +77,4 @@ function formatHeaderValue(ui, row) {
|
|
|
74
77
|
return value;
|
|
75
78
|
}
|
|
76
79
|
//#endregion
|
|
77
|
-
export { createShellUi, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, wrapText };
|
|
80
|
+
export { createShellUi, formatColumns, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, wrapText };
|
package/dist/use-cases/branch.js
CHANGED
|
@@ -1,34 +1,19 @@
|
|
|
1
1
|
//#region src/use-cases/branch.ts
|
|
2
2
|
function createBranchUseCases(dependencies) {
|
|
3
|
-
return {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
projectId,
|
|
18
|
-
projectName: resolveProjectName(dependencies.projectGateway, projectId),
|
|
19
|
-
branch: buildBranchDetail(dependencies.branchGateway, projectId, activeBranch)
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
use: async (branchName) => {
|
|
23
|
-
await dependencies.branchStateGateway.writeActiveBranch(branchName);
|
|
24
|
-
const projectId = await dependencies.projectStateGateway.readRememberedProjectId();
|
|
25
|
-
return {
|
|
26
|
-
projectId,
|
|
27
|
-
projectName: resolveProjectName(dependencies.projectGateway, projectId),
|
|
28
|
-
branch: buildBranchDetail(dependencies.branchGateway, projectId, branchName)
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
};
|
|
3
|
+
return { list: async () => {
|
|
4
|
+
const projectId = await dependencies.projectStateGateway.readRememberedProjectId();
|
|
5
|
+
if (!projectId) return {
|
|
6
|
+
projectId: "",
|
|
7
|
+
projectName: "not resolved",
|
|
8
|
+
branches: []
|
|
9
|
+
};
|
|
10
|
+
const remoteBranches = await listRemoteBranches(dependencies.branchGateway, projectId);
|
|
11
|
+
return {
|
|
12
|
+
projectId,
|
|
13
|
+
projectName: resolveProjectName(dependencies.projectGateway, projectId) ?? "not resolved",
|
|
14
|
+
branches: buildBranchSummaries(remoteBranches)
|
|
15
|
+
};
|
|
16
|
+
} };
|
|
32
17
|
}
|
|
33
18
|
function resolveProjectName(projectGateway, projectId) {
|
|
34
19
|
if (!projectId) return null;
|
|
@@ -38,38 +23,13 @@ async function listRemoteBranches(branchGateway, projectId) {
|
|
|
38
23
|
if (!projectId) return [];
|
|
39
24
|
return branchGateway.listBranchesForProject(projectId);
|
|
40
25
|
}
|
|
41
|
-
function buildBranchSummaries(
|
|
42
|
-
|
|
43
|
-
for (const branch of remoteBranches) byName.set(branch.name, {
|
|
26
|
+
function buildBranchSummaries(remoteBranches) {
|
|
27
|
+
return sortBranches(remoteBranches.map((branch) => ({
|
|
44
28
|
id: branch.id,
|
|
45
29
|
name: branch.name,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
50
|
-
if (!byName.has(activeBranch)) byName.set(activeBranch, {
|
|
51
|
-
id: activeBranch,
|
|
52
|
-
name: activeBranch,
|
|
53
|
-
kind: toBranchKind(activeBranch),
|
|
54
|
-
active: true,
|
|
55
|
-
remoteState: false
|
|
56
|
-
});
|
|
57
|
-
return sortBranches([...byName.values()]);
|
|
58
|
-
}
|
|
59
|
-
function buildBranchDetail(branchGateway, projectId, branchName) {
|
|
60
|
-
const kind = toBranchKind(branchName);
|
|
61
|
-
const remoteBranch = projectId ? branchGateway.getBranchForProject(projectId, branchName) : void 0;
|
|
62
|
-
return {
|
|
63
|
-
name: branchName,
|
|
64
|
-
kind,
|
|
65
|
-
active: true,
|
|
66
|
-
remoteState: Boolean(remoteBranch),
|
|
67
|
-
liveDeployment: remoteBranch && remoteBranch.currentDeploymentId ? toLiveDeployment(branchGateway.getDeployment(remoteBranch.currentDeploymentId)) : null
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function toBranchKind(name) {
|
|
71
|
-
if (name === "production") return "production";
|
|
72
|
-
return "preview";
|
|
30
|
+
role: branch.role,
|
|
31
|
+
envMap: branch.role
|
|
32
|
+
})));
|
|
73
33
|
}
|
|
74
34
|
function sortBranches(branches) {
|
|
75
35
|
return branches.slice().sort((left, right) => {
|
|
@@ -80,16 +40,8 @@ function sortBranches(branches) {
|
|
|
80
40
|
});
|
|
81
41
|
}
|
|
82
42
|
function branchOrder(branch) {
|
|
83
|
-
if (branch.
|
|
43
|
+
if (branch.role === "production") return 0;
|
|
84
44
|
return 1;
|
|
85
45
|
}
|
|
86
|
-
function toLiveDeployment(deployment) {
|
|
87
|
-
if (!deployment) return null;
|
|
88
|
-
return {
|
|
89
|
-
id: deployment.id,
|
|
90
|
-
status: deployment.status,
|
|
91
|
-
url: deployment.url
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
46
|
//#endregion
|
|
95
47
|
export { createBranchUseCases };
|
|
@@ -29,16 +29,9 @@ function createCliUseCaseGateways(context) {
|
|
|
29
29
|
getProjectForWorkspace: (workspaceId, projectId) => context.api.getProjectForWorkspace(workspaceId, projectId)
|
|
30
30
|
},
|
|
31
31
|
branchGateway: {
|
|
32
|
-
listBranchesForProject: (projectId) => context.api.listBranchesForProject(projectId)
|
|
33
|
-
...branch,
|
|
34
|
-
kind: branch.name === "production" ? "production" : "preview"
|
|
35
|
-
})),
|
|
32
|
+
listBranchesForProject: (projectId) => context.api.listBranchesForProject(projectId),
|
|
36
33
|
getBranchForProject: (projectId, name) => {
|
|
37
|
-
|
|
38
|
-
return branch ? {
|
|
39
|
-
...branch,
|
|
40
|
-
kind: branch.name === "production" ? "production" : "preview"
|
|
41
|
-
} : void 0;
|
|
34
|
+
return context.api.getBranchForProject(projectId, name);
|
|
42
35
|
},
|
|
43
36
|
getDeployment: (deploymentId) => context.api.getDeployment(deploymentId)
|
|
44
37
|
},
|
|
@@ -55,14 +48,6 @@ function createCliUseCaseGateways(context) {
|
|
|
55
48
|
clearAuthSession: async () => {
|
|
56
49
|
await context.stateStore.clearAuthSession();
|
|
57
50
|
}
|
|
58
|
-
},
|
|
59
|
-
branchStateGateway: {
|
|
60
|
-
readActiveBranch: async () => {
|
|
61
|
-
return (await context.stateStore.read()).branch.active;
|
|
62
|
-
},
|
|
63
|
-
writeActiveBranch: async (branchName) => {
|
|
64
|
-
await context.stateStore.setActiveBranch(branchName);
|
|
65
|
-
}
|
|
66
51
|
}
|
|
67
52
|
};
|
|
68
53
|
}
|