@prisma/cli 3.0.0-alpha.2 → 3.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/git.js +49 -0
- package/dist/adapters/local-state.js +38 -0
- package/dist/cli2.js +3 -1
- package/dist/commands/app/index.js +31 -20
- package/dist/commands/auth/index.js +1 -1
- package/dist/commands/env.js +87 -0
- package/dist/commands/git/index.js +36 -0
- package/dist/commands/project/index.js +10 -13
- package/dist/controllers/app-env.js +223 -0
- package/dist/controllers/app.js +260 -86
- package/dist/controllers/auth.js +2 -2
- package/dist/controllers/branch.js +1 -1
- package/dist/controllers/project.js +451 -161
- package/dist/lib/app/env-config.js +57 -0
- package/dist/lib/app/preview-provider.js +15 -2
- package/dist/lib/auth/auth-ops.js +8 -10
- package/dist/lib/auth/client.js +1 -1
- package/dist/lib/project/resolution.js +148 -0
- package/dist/output/patterns.js +1 -2
- package/dist/presenters/app-env.js +129 -0
- package/dist/presenters/app.js +9 -1
- package/dist/presenters/auth.js +2 -2
- package/dist/presenters/branch.js +6 -6
- package/dist/presenters/project.js +84 -44
- package/dist/shell/command-meta.js +91 -9
- package/dist/shell/command-runner.js +32 -2
- package/dist/shell/errors.js +4 -1
- package/dist/shell/help.js +1 -1
- package/dist/shell/output.js +18 -12
- package/dist/shell/runtime.js +1 -1
- package/dist/shell/ui.js +19 -1
- package/dist/use-cases/auth.js +5 -8
- package/dist/use-cases/branch.js +20 -20
- package/dist/use-cases/create-cli-gateways.js +3 -13
- package/dist/use-cases/project.js +2 -48
- package/package.json +2 -2
- package/dist/adapters/config.js +0 -74
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { usageError } from "../../shell/errors.js";
|
|
2
|
+
//#region src/lib/app/env-config.ts
|
|
3
|
+
const VALID_ROLES = new Set(["production", "preview"]);
|
|
4
|
+
function positionalHint(command) {
|
|
5
|
+
if (command === "add" || command === "update") return "KEY=value ";
|
|
6
|
+
if (command === "rm") return "KEY ";
|
|
7
|
+
return "";
|
|
8
|
+
}
|
|
9
|
+
function resolveEnvScope(flags, options) {
|
|
10
|
+
if (flags.roleName) {
|
|
11
|
+
if (!VALID_ROLES.has(flags.roleName)) throw usageError(`Unknown role "${flags.roleName}"`, "--role accepts production or preview.", "Pass --role production or --role preview.", [`prisma-cli project env ${options.command} --role production`, `prisma-cli project env ${options.command} --role preview`], "app");
|
|
12
|
+
return {
|
|
13
|
+
kind: "role",
|
|
14
|
+
role: flags.roleName
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (options.requireExplicit) {
|
|
18
|
+
const positional = positionalHint(options.command);
|
|
19
|
+
throw usageError(`prisma-cli project env ${options.command} requires --role`, "Writing without an explicit scope is rejected so the command never silently targets production.", "Pass --role production or --role preview.", [`prisma-cli project env ${options.command} ${positional}--role production`, `prisma-cli project env ${options.command} ${positional}--role preview`], "app");
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
function parseKeyValuePositional(raw, command, env = process.env) {
|
|
24
|
+
if (!raw) throw usageError(`prisma-cli project env ${command} requires KEY=VALUE`, "No KEY=VALUE positional argument was supplied.", "Pass the variable as KEY=VALUE, e.g. STRIPE_KEY=sk_test_xxx.", [`prisma-cli project env ${command} STRIPE_KEY=sk_test_xxx --role production`], "app");
|
|
25
|
+
const separatorIndex = raw.indexOf("=");
|
|
26
|
+
if (separatorIndex === -1) {
|
|
27
|
+
if (KEY_SHAPE.test(raw)) {
|
|
28
|
+
validateKey(raw, command);
|
|
29
|
+
const value = env[raw];
|
|
30
|
+
if (typeof value === "string" && value.length > 0) return {
|
|
31
|
+
key: raw,
|
|
32
|
+
value
|
|
33
|
+
};
|
|
34
|
+
throw usageError(`Value for "${raw}" was not provided`, `No KEY=VALUE assignment was supplied, and ${raw} is not set in the current environment.`, "Pass KEY=VALUE or export the variable before running the command.", [`prisma-cli project env ${command} ${raw}=value --role production`, `${raw}=value prisma-cli project env ${command} ${raw} --role production`], "app");
|
|
35
|
+
}
|
|
36
|
+
throw usageError(`KEY=VALUE argument is missing the = separator`, `"${raw}" does not contain an = character.`, "Pass the variable as KEY=VALUE, e.g. STRIPE_KEY=sk_test_xxx.", [`prisma-cli project env ${command} STRIPE_KEY=sk_test_xxx --role production`], "app");
|
|
37
|
+
}
|
|
38
|
+
const key = raw.slice(0, separatorIndex);
|
|
39
|
+
const value = raw.slice(separatorIndex + 1);
|
|
40
|
+
validateKey(key, command);
|
|
41
|
+
if (value.length === 0) throw usageError(`KEY=VALUE argument has an empty value`, `"${raw}" has an empty value after the = separator.`, `Pass a non-empty value, or use prisma-cli project env rm to remove a variable.`, [`prisma-cli project env ${command} ${key}=value --role production`], "app");
|
|
42
|
+
return {
|
|
43
|
+
key,
|
|
44
|
+
value
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const KEY_SHAPE = /^[A-Z_][A-Z0-9_]*$/;
|
|
48
|
+
function validateKey(key, command) {
|
|
49
|
+
if (key.length === 0) throw usageError(`Variable key cannot be empty`, "An empty key was passed.", "Pass an env-var key, e.g. STRIPE_KEY.", [`prisma-cli project env ${command} STRIPE_KEY${command === "rm" ? "" : "=value"} --role production`], "app");
|
|
50
|
+
if (key.length > 256) throw usageError(`Variable key "${key}" exceeds the 256-character limit`, "Env-var keys are capped at 256 characters by the platform.", "Use a shorter key.", [], "app");
|
|
51
|
+
if (!KEY_SHAPE.test(key)) throw usageError(`Variable key "${key}" must match the POSIX env-var shape`, "Keys must start with an uppercase letter or underscore and contain only uppercase letters, digits, and underscores.", "Rename the key to match [A-Z_][A-Z0-9_]*.", [`prisma-cli project env ${command} STRIPE_KEY${command === "rm" ? "" : "=value"} --role production`], "app");
|
|
52
|
+
}
|
|
53
|
+
function formatScopeLabel(scope) {
|
|
54
|
+
return scope.role;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { formatScopeLabel, parseKeyValuePositional, resolveEnvScope };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { envVarNames } from "./env-vars.js";
|
|
2
2
|
import { PreviewBuildStrategy } from "./preview-build.js";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { ApiError, ComputeClient } from "@prisma/compute-sdk";
|
|
4
|
+
import { ApiError, CancelledError, ComputeClient, streamLogs } from "@prisma/compute-sdk";
|
|
5
5
|
//#region src/lib/app/preview-provider.ts
|
|
6
|
-
function createPreviewAppProvider(client) {
|
|
6
|
+
function createPreviewAppProvider(client, options) {
|
|
7
7
|
const sdk = new ComputeClient(client);
|
|
8
8
|
return {
|
|
9
9
|
async createProject(options) {
|
|
@@ -197,6 +197,19 @@ function createPreviewAppProvider(client) {
|
|
|
197
197
|
live: null
|
|
198
198
|
}
|
|
199
199
|
};
|
|
200
|
+
},
|
|
201
|
+
async streamDeploymentLogs(streamOptions) {
|
|
202
|
+
if (!options?.baseUrl || !options.getToken) throw new Error("Log streaming requires an authenticated API base URL and token.");
|
|
203
|
+
const result = await streamLogs({
|
|
204
|
+
baseUrl: options.baseUrl,
|
|
205
|
+
token: await options.getToken(),
|
|
206
|
+
versionId: streamOptions.deploymentId,
|
|
207
|
+
signal: streamOptions.signal
|
|
208
|
+
}, streamOptions.onRecord);
|
|
209
|
+
if (result.isErr()) {
|
|
210
|
+
if (CancelledError.is(result.error)) return;
|
|
211
|
+
throw result.error;
|
|
212
|
+
}
|
|
200
213
|
}
|
|
201
214
|
};
|
|
202
215
|
}
|
|
@@ -11,6 +11,10 @@ function decodeJwtPayload(token) {
|
|
|
11
11
|
return {};
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
function emailFromClaims(claims) {
|
|
15
|
+
const email = claims.email;
|
|
16
|
+
return typeof email === "string" && email.trim().length > 0 ? email.trim() : null;
|
|
17
|
+
}
|
|
14
18
|
async function performLogin(env) {
|
|
15
19
|
await login({
|
|
16
20
|
tokenStorage: new FileTokenStorage(env),
|
|
@@ -23,10 +27,9 @@ async function readAuthState(env) {
|
|
|
23
27
|
authenticated: false,
|
|
24
28
|
provider: null,
|
|
25
29
|
user: null,
|
|
26
|
-
workspace: null
|
|
27
|
-
linkedProjectId: null
|
|
30
|
+
workspace: null
|
|
28
31
|
};
|
|
29
|
-
const
|
|
32
|
+
const email = emailFromClaims(decodeJwtPayload(tokens.accessToken));
|
|
30
33
|
const client = await requireComputeAuth(env);
|
|
31
34
|
let workspaceId = tokens.workspaceId;
|
|
32
35
|
let workspaceName = tokens.workspaceId;
|
|
@@ -38,16 +41,11 @@ async function readAuthState(env) {
|
|
|
38
41
|
return {
|
|
39
42
|
authenticated: true,
|
|
40
43
|
provider: null,
|
|
41
|
-
user: {
|
|
42
|
-
id: claims.sub ?? "",
|
|
43
|
-
name: claims.name ?? "",
|
|
44
|
-
email: claims.email ?? ""
|
|
45
|
-
},
|
|
44
|
+
user: email ? { email } : null,
|
|
46
45
|
workspace: {
|
|
47
46
|
id: workspaceId,
|
|
48
47
|
name: workspaceName
|
|
49
|
-
}
|
|
50
|
-
linkedProjectId: null
|
|
48
|
+
}
|
|
51
49
|
};
|
|
52
50
|
}
|
|
53
51
|
async function performLogout(env) {
|
package/dist/lib/auth/client.js
CHANGED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { CliError } from "../../shell/errors.js";
|
|
2
|
+
import { canPrompt } from "../../shell/runtime.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
//#region src/lib/project/resolution.ts
|
|
6
|
+
async function resolveProjectTarget(options) {
|
|
7
|
+
const projects = await options.listProjects();
|
|
8
|
+
if (options.explicitProject) return rememberIfRequested(options, resolveExplicitProject(options.explicitProject, projects, options.workspace), "explicit");
|
|
9
|
+
const platformMapping = await resolveDurablePlatformMapping();
|
|
10
|
+
if (platformMapping) return rememberIfRequested(options, platformMapping, "platform-mapping");
|
|
11
|
+
const remembered = await options.context.stateStore.readRememberedProject(options.workspace.id);
|
|
12
|
+
let staleRemembered = false;
|
|
13
|
+
if (remembered) {
|
|
14
|
+
const matched = projects.find((project) => project.id === remembered.id);
|
|
15
|
+
if (matched) return rememberIfRequested(options, matched, "remembered-local");
|
|
16
|
+
staleRemembered = true;
|
|
17
|
+
}
|
|
18
|
+
const packageName = await readPackageName(options.context.runtime.cwd);
|
|
19
|
+
if (packageName) {
|
|
20
|
+
const matches = projects.filter((project) => projectMatchesPackageName(project, packageName));
|
|
21
|
+
if (matches.length === 1) return rememberIfRequested(options, matches[0], "package-name");
|
|
22
|
+
if (matches.length > 1) return resolveAmbiguousProject(options, matches, "package-name");
|
|
23
|
+
}
|
|
24
|
+
if (options.allowCreate && options.createProject) {
|
|
25
|
+
const inferredName = packageName ?? path.basename(options.context.runtime.cwd);
|
|
26
|
+
if (inferredName) {
|
|
27
|
+
const existing = projects.filter((project) => projectMatchesPackageName(project, inferredName));
|
|
28
|
+
if (existing.length === 1) return rememberIfRequested(options, existing[0], "package-name");
|
|
29
|
+
if (existing.length > 1) return resolveAmbiguousProject(options, existing, "package-name");
|
|
30
|
+
return rememberIfRequested(options, await options.createProject(inferredName), "created");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (options.prompt && canPrompt(options.context) && projects.length > 0) return rememberIfRequested(options, await options.prompt.select({
|
|
34
|
+
message: "Select a project",
|
|
35
|
+
choices: sortProjects(projects).map((project) => ({
|
|
36
|
+
label: `${project.name} (${project.id})`,
|
|
37
|
+
value: project
|
|
38
|
+
}))
|
|
39
|
+
}), "prompt");
|
|
40
|
+
if (staleRemembered && projects.length > 1) throw localStateStaleError();
|
|
41
|
+
throw projectUnresolvedError();
|
|
42
|
+
}
|
|
43
|
+
function projectNotFoundError(projectRef, workspace) {
|
|
44
|
+
return new CliError({
|
|
45
|
+
code: "PROJECT_NOT_FOUND",
|
|
46
|
+
domain: "project",
|
|
47
|
+
summary: "Project not found",
|
|
48
|
+
why: `The project "${projectRef}" does not exist in workspace "${workspace.name}" or is not accessible.`,
|
|
49
|
+
fix: "Pass a project id or name from prisma-cli project list.",
|
|
50
|
+
exitCode: 1,
|
|
51
|
+
nextSteps: ["prisma-cli project list"]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function projectAmbiguousError(projectRef, matches) {
|
|
55
|
+
return new CliError({
|
|
56
|
+
code: "PROJECT_AMBIGUOUS",
|
|
57
|
+
domain: "project",
|
|
58
|
+
summary: "Project resolution is ambiguous",
|
|
59
|
+
why: projectRef ? `Multiple projects matched "${projectRef}".` : "Multiple projects matched the current directory context.",
|
|
60
|
+
fix: "Pass --project <id-or-name> to choose the project explicitly.",
|
|
61
|
+
meta: { matches: matches.map((project) => ({
|
|
62
|
+
id: project.id,
|
|
63
|
+
name: project.name
|
|
64
|
+
})) },
|
|
65
|
+
exitCode: 1,
|
|
66
|
+
nextSteps: ["prisma-cli project list"]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function projectUnresolvedError() {
|
|
70
|
+
return new CliError({
|
|
71
|
+
code: "PROJECT_UNRESOLVED",
|
|
72
|
+
domain: "project",
|
|
73
|
+
summary: "No project is resolved for this directory",
|
|
74
|
+
why: "No project could be resolved from explicit input, platform mappings, remembered local context, or package metadata.",
|
|
75
|
+
fix: "Pass --project <id-or-name> on the command that needs a project, or add a package.json name that matches an accessible project.",
|
|
76
|
+
exitCode: 1,
|
|
77
|
+
nextSteps: ["prisma-cli project list", "prisma-cli project show --project <id-or-name>"]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function localStateStaleError() {
|
|
81
|
+
return new CliError({
|
|
82
|
+
code: "LOCAL_STATE_STALE",
|
|
83
|
+
domain: "project",
|
|
84
|
+
summary: "Remembered project context is stale",
|
|
85
|
+
why: "The remembered project is no longer available in the selected workspace, and automatic resolution would be ambiguous.",
|
|
86
|
+
fix: "Pass --project <id-or-name> to choose the project explicitly.",
|
|
87
|
+
exitCode: 1,
|
|
88
|
+
nextSteps: ["prisma-cli project list"]
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async function readPackageName(cwd) {
|
|
92
|
+
try {
|
|
93
|
+
const raw = await readFile(path.join(cwd, "package.json"), "utf8");
|
|
94
|
+
const parsed = JSON.parse(raw);
|
|
95
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
96
|
+
const packageName = "name" in parsed ? parsed.name : null;
|
|
97
|
+
return typeof packageName === "string" && packageName.trim().length > 0 ? packageName.trim() : null;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error.code === "ENOENT") return null;
|
|
100
|
+
if (error instanceof SyntaxError) return null;
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function sortProjects(projects) {
|
|
105
|
+
return projects.slice().sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id));
|
|
106
|
+
}
|
|
107
|
+
function resolveExplicitProject(projectRef, projects, workspace) {
|
|
108
|
+
const matches = projects.filter((project) => project.id === projectRef || project.name === projectRef);
|
|
109
|
+
if (matches.length === 1) return matches[0];
|
|
110
|
+
if (matches.length > 1) throw projectAmbiguousError(projectRef, matches);
|
|
111
|
+
throw projectNotFoundError(projectRef, workspace);
|
|
112
|
+
}
|
|
113
|
+
function resolveAmbiguousProject(options, matches, projectRef) {
|
|
114
|
+
if (options.prompt && canPrompt(options.context)) return options.prompt.select({
|
|
115
|
+
message: "Select a project",
|
|
116
|
+
choices: sortProjects(matches).map((project) => ({
|
|
117
|
+
label: `${project.name} (${project.id})`,
|
|
118
|
+
value: project
|
|
119
|
+
}))
|
|
120
|
+
}).then((selected) => rememberIfRequested(options, selected, "prompt"));
|
|
121
|
+
throw projectAmbiguousError(projectRef, matches);
|
|
122
|
+
}
|
|
123
|
+
function projectMatchesPackageName(project, packageName) {
|
|
124
|
+
return project.id === packageName || project.name === packageName || project.slug === packageName;
|
|
125
|
+
}
|
|
126
|
+
async function resolveDurablePlatformMapping() {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
async function rememberIfRequested(options, project, projectSource) {
|
|
130
|
+
if (options.remember) await options.context.stateStore.setRememberedProject({
|
|
131
|
+
id: project.id,
|
|
132
|
+
name: project.name,
|
|
133
|
+
workspaceId: options.workspace.id
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
workspace: options.workspace,
|
|
137
|
+
project: toProjectSummary(project),
|
|
138
|
+
resolution: { projectSource }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function toProjectSummary(project) {
|
|
142
|
+
return {
|
|
143
|
+
id: project.id,
|
|
144
|
+
name: project.name
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
export { resolveProjectTarget, sortProjects };
|
package/dist/output/patterns.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
2
1
|
import { maskValue, padDisplay, renderSummaryLine } from "../shell/ui.js";
|
|
2
|
+
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
3
3
|
import stringWidth from "string-width";
|
|
4
4
|
//#region src/output/patterns.ts
|
|
5
5
|
function renderList(input, ui) {
|
|
@@ -74,7 +74,6 @@ function formatListItemValue(ui, item) {
|
|
|
74
74
|
}
|
|
75
75
|
function renderAnnotation(ui, status) {
|
|
76
76
|
if (status === "active") return ui.success("(active)");
|
|
77
|
-
if (status === "linked") return ui.accent("(linked)");
|
|
78
77
|
if (status === "default") return ui.dim("(default)");
|
|
79
78
|
return "";
|
|
80
79
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { renderList, renderShow, serializeList } from "../output/patterns.js";
|
|
2
|
+
//#region src/presenters/app-env.ts
|
|
3
|
+
function scopeLabel(scope) {
|
|
4
|
+
return scope.role;
|
|
5
|
+
}
|
|
6
|
+
function renderEnvAdd(context, descriptor, result) {
|
|
7
|
+
return renderShow({
|
|
8
|
+
title: "Setting a new environment variable.",
|
|
9
|
+
descriptor,
|
|
10
|
+
fields: [
|
|
11
|
+
{
|
|
12
|
+
key: "project",
|
|
13
|
+
value: result.projectId
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
key: "scope",
|
|
17
|
+
value: scopeLabel(result.scope)
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: "key",
|
|
21
|
+
value: result.variable.key
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
key: "id",
|
|
25
|
+
value: result.variable.id,
|
|
26
|
+
tone: "dim"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: "last updated",
|
|
30
|
+
value: result.variable.updatedAt,
|
|
31
|
+
tone: "dim"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}, context.ui);
|
|
35
|
+
}
|
|
36
|
+
function serializeEnvAdd(result) {
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
function renderEnvUpdate(context, descriptor, result) {
|
|
40
|
+
return renderShow({
|
|
41
|
+
title: "Replacing the environment variable's value.",
|
|
42
|
+
descriptor,
|
|
43
|
+
fields: [
|
|
44
|
+
{
|
|
45
|
+
key: "project",
|
|
46
|
+
value: result.projectId
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "scope",
|
|
50
|
+
value: scopeLabel(result.scope)
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: "key",
|
|
54
|
+
value: result.variable.key
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: "id",
|
|
58
|
+
value: result.variable.id,
|
|
59
|
+
tone: "dim"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: "last updated",
|
|
63
|
+
value: result.variable.updatedAt,
|
|
64
|
+
tone: "dim"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}, context.ui);
|
|
68
|
+
}
|
|
69
|
+
function serializeEnvUpdate(result) {
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
function renderEnvList(context, descriptor, result) {
|
|
73
|
+
return renderList({
|
|
74
|
+
title: "Listing environment variables for the selected scope.",
|
|
75
|
+
descriptor,
|
|
76
|
+
parentContext: {
|
|
77
|
+
key: "scope",
|
|
78
|
+
value: scopeLabel(result.scope)
|
|
79
|
+
},
|
|
80
|
+
items: result.variables.map((variable) => ({
|
|
81
|
+
noun: "variable",
|
|
82
|
+
label: variable.key,
|
|
83
|
+
id: variable.id,
|
|
84
|
+
status: variable.isManagedBySystem ? "default" : null
|
|
85
|
+
})),
|
|
86
|
+
emptyMessage: "No environment variables defined in this scope."
|
|
87
|
+
}, context.ui);
|
|
88
|
+
}
|
|
89
|
+
function serializeEnvList(result) {
|
|
90
|
+
return {
|
|
91
|
+
projectId: result.projectId,
|
|
92
|
+
scope: result.scope,
|
|
93
|
+
...serializeList({
|
|
94
|
+
context: { scope: scopeLabel(result.scope) },
|
|
95
|
+
items: result.variables.map((variable) => ({
|
|
96
|
+
noun: "variable",
|
|
97
|
+
label: variable.key,
|
|
98
|
+
id: variable.id,
|
|
99
|
+
status: variable.isManagedBySystem ? "default" : null
|
|
100
|
+
}))
|
|
101
|
+
}),
|
|
102
|
+
variables: result.variables
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function renderEnvRm(context, descriptor, result) {
|
|
106
|
+
return renderShow({
|
|
107
|
+
title: "Removing the environment variable from the scope.",
|
|
108
|
+
descriptor,
|
|
109
|
+
fields: [
|
|
110
|
+
{
|
|
111
|
+
key: "project",
|
|
112
|
+
value: result.projectId
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
key: "scope",
|
|
116
|
+
value: scopeLabel(result.scope)
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
key: "key",
|
|
120
|
+
value: result.key
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}, context.ui);
|
|
124
|
+
}
|
|
125
|
+
function serializeEnvRm(result) {
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
export { renderEnvAdd, renderEnvList, renderEnvRm, renderEnvUpdate, serializeEnvAdd, serializeEnvList, serializeEnvRm, serializeEnvUpdate };
|
package/dist/presenters/app.js
CHANGED
|
@@ -29,9 +29,17 @@ function renderAppDeploy(context, descriptor, result) {
|
|
|
29
29
|
title: "Deploying the selected app.",
|
|
30
30
|
descriptor,
|
|
31
31
|
fields: [
|
|
32
|
+
{
|
|
33
|
+
key: "workspace",
|
|
34
|
+
value: result.workspace.name
|
|
35
|
+
},
|
|
32
36
|
{
|
|
33
37
|
key: "project",
|
|
34
|
-
value: result.
|
|
38
|
+
value: result.project.name
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: "branch",
|
|
42
|
+
value: result.branch.name
|
|
35
43
|
},
|
|
36
44
|
{
|
|
37
45
|
key: "app",
|
package/dist/presenters/auth.js
CHANGED
|
@@ -9,7 +9,7 @@ function renderAuthSuccess(context, descriptor, command, result) {
|
|
|
9
9
|
});
|
|
10
10
|
if (result.user) rows.push({
|
|
11
11
|
key: "user",
|
|
12
|
-
value:
|
|
12
|
+
value: result.user.email
|
|
13
13
|
});
|
|
14
14
|
if (result.workspace?.name) rows.push({
|
|
15
15
|
key: "workspace",
|
|
@@ -47,7 +47,7 @@ function renderAuthSuccess(context, descriptor, command, result) {
|
|
|
47
47
|
},
|
|
48
48
|
...result.user ? [{
|
|
49
49
|
key: "user",
|
|
50
|
-
value:
|
|
50
|
+
value: result.user.email
|
|
51
51
|
}] : [],
|
|
52
52
|
...result.provider ? [{
|
|
53
53
|
key: "provider",
|
|
@@ -2,11 +2,11 @@ import { renderList, renderMutate, renderShow, serializeList } from "../output/p
|
|
|
2
2
|
//#region src/presenters/branch.ts
|
|
3
3
|
function renderBranchList(context, descriptor, result) {
|
|
4
4
|
return renderList({
|
|
5
|
-
title: "Listing branches for the
|
|
5
|
+
title: "Listing branches for the resolved project.",
|
|
6
6
|
descriptor,
|
|
7
7
|
parentContext: {
|
|
8
8
|
key: "project",
|
|
9
|
-
value: result.projectName ?? "not
|
|
9
|
+
value: result.projectName ?? "not resolved"
|
|
10
10
|
},
|
|
11
11
|
items: result.branches.map((branch) => ({
|
|
12
12
|
noun: "branch",
|
|
@@ -19,7 +19,7 @@ function renderBranchList(context, descriptor, result) {
|
|
|
19
19
|
}
|
|
20
20
|
function serializeBranchList(result) {
|
|
21
21
|
return serializeList({
|
|
22
|
-
context: { project: result.projectName ?? "not
|
|
22
|
+
context: { project: result.projectName ?? "not resolved" },
|
|
23
23
|
items: result.branches.map((branch) => ({
|
|
24
24
|
noun: "branch",
|
|
25
25
|
label: branch.name,
|
|
@@ -30,7 +30,7 @@ function serializeBranchList(result) {
|
|
|
30
30
|
}
|
|
31
31
|
function serializeBranchShow(result) {
|
|
32
32
|
return {
|
|
33
|
-
|
|
33
|
+
projectId: result.projectId,
|
|
34
34
|
projectName: result.projectName,
|
|
35
35
|
branch: {
|
|
36
36
|
name: result.branch.name,
|
|
@@ -45,7 +45,7 @@ function renderBranchShow(context, descriptor, result) {
|
|
|
45
45
|
const fields = [
|
|
46
46
|
{
|
|
47
47
|
key: "project",
|
|
48
|
-
value: result.projectName ?? "not
|
|
48
|
+
value: result.projectName ?? "not resolved",
|
|
49
49
|
tone: result.projectName ? "default" : "dim"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
@@ -92,7 +92,7 @@ function renderBranchUse(context, descriptor, result) {
|
|
|
92
92
|
descriptor,
|
|
93
93
|
context: [{
|
|
94
94
|
key: "project",
|
|
95
|
-
value: result.projectName ?? "not
|
|
95
|
+
value: result.projectName ?? "not resolved",
|
|
96
96
|
tone: result.projectName ? "default" : "dim"
|
|
97
97
|
}, {
|
|
98
98
|
key: "branch",
|
|
@@ -12,7 +12,7 @@ function renderProjectList(context, descriptor, result) {
|
|
|
12
12
|
noun: "project",
|
|
13
13
|
label: project.name,
|
|
14
14
|
id: project.id,
|
|
15
|
-
status:
|
|
15
|
+
status: null
|
|
16
16
|
})),
|
|
17
17
|
emptyMessage: "No projects found."
|
|
18
18
|
}, context.ui);
|
|
@@ -24,61 +24,101 @@ function serializeProjectList(result) {
|
|
|
24
24
|
noun: "project",
|
|
25
25
|
label: project.name,
|
|
26
26
|
id: project.id,
|
|
27
|
-
status:
|
|
27
|
+
status: null
|
|
28
28
|
}))
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
function renderProjectShow(context, descriptor, result) {
|
|
32
|
-
|
|
33
|
-
title: "Showing the
|
|
34
|
-
descriptor,
|
|
35
|
-
fields: [{
|
|
36
|
-
key: "project",
|
|
37
|
-
value: "not linked",
|
|
38
|
-
tone: "dim"
|
|
39
|
-
}]
|
|
40
|
-
}, context.ui);
|
|
41
|
-
if (!result.project || !result.workspace) return renderShow({
|
|
42
|
-
title: "Showing the linked project for the current repo.",
|
|
32
|
+
return renderShow({
|
|
33
|
+
title: "Showing the project Prisma resolves for this directory.",
|
|
43
34
|
descriptor,
|
|
44
|
-
fields: [
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
fields: [
|
|
36
|
+
{
|
|
37
|
+
key: "workspace",
|
|
38
|
+
value: result.workspace.name
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: "project",
|
|
42
|
+
value: result.project.name
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: "resolution",
|
|
46
|
+
value: formatProjectSource(result.resolution.projectSource)
|
|
47
|
+
}
|
|
48
|
+
]
|
|
53
49
|
}, context.ui);
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
}
|
|
51
|
+
function serializeProjectShow(result) {
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function renderGitConnect(context, descriptor, result) {
|
|
55
|
+
const connection = result.repositoryConnection;
|
|
56
|
+
return renderMutate({
|
|
57
|
+
title: "Connecting Git to the resolved project.",
|
|
56
58
|
descriptor,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
context: [
|
|
60
|
+
{
|
|
61
|
+
key: "project",
|
|
62
|
+
value: result.project.name
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
key: "workspace",
|
|
66
|
+
value: result.workspace.name
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: "repository",
|
|
70
|
+
value: connection.repository.fullName
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: "status",
|
|
74
|
+
value: connection.status
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
operationDescription: "Applying repository connection",
|
|
78
|
+
operationCount: 1,
|
|
79
|
+
details: [formatGitConnectionDetail(connection.status)]
|
|
64
80
|
}, context.ui);
|
|
65
81
|
}
|
|
66
|
-
function
|
|
67
|
-
if (!result.project || !result.workspace) throw new Error("Linked project result must be enriched for human output.");
|
|
82
|
+
function renderGitDisconnect(context, descriptor, result) {
|
|
68
83
|
return renderMutate({
|
|
69
|
-
title: "
|
|
84
|
+
title: "Disconnecting Git from the resolved project.",
|
|
70
85
|
descriptor,
|
|
71
|
-
context: [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
context: [
|
|
87
|
+
{
|
|
88
|
+
key: "project",
|
|
89
|
+
value: result.project.name
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: "workspace",
|
|
93
|
+
value: result.workspace.name
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
key: "repository",
|
|
97
|
+
value: result.repositoryConnection.repository.fullName
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
operationDescription: "Applying repository disconnection",
|
|
79
101
|
operationCount: 1,
|
|
80
|
-
details: ["
|
|
102
|
+
details: ["GitHub branch automation is no longer active for this project."]
|
|
81
103
|
}, context.ui);
|
|
82
104
|
}
|
|
105
|
+
function formatProjectSource(source) {
|
|
106
|
+
switch (source) {
|
|
107
|
+
case "explicit": return "explicit";
|
|
108
|
+
case "platform-mapping": return "platform mapping";
|
|
109
|
+
case "remembered-local": return "remembered local context";
|
|
110
|
+
case "package-name": return "package name";
|
|
111
|
+
case "created": return "created";
|
|
112
|
+
case "prompt": return "prompt";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function formatGitConnectionDetail(status) {
|
|
116
|
+
switch (status) {
|
|
117
|
+
case "active": return "GitHub branch automation is active for this project.";
|
|
118
|
+
case "pending": return "GitHub branch automation is pending GitHub App installation.";
|
|
119
|
+
case "archived": return "GitHub branch automation has been archived for this project.";
|
|
120
|
+
default: return "GitHub repository is connected, but branch automation is not active.";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
83
123
|
//#endregion
|
|
84
|
-
export {
|
|
124
|
+
export { renderGitConnect, renderGitDisconnect, renderProjectList, renderProjectShow, serializeProjectList, serializeProjectShow };
|