@prisma/cli 3.0.0-alpha.3 → 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 +30 -19
- package/dist/commands/auth/index.js +1 -1
- package/dist/commands/env.js +25 -9
- package/dist/commands/git/index.js +36 -0
- package/dist/commands/project/index.js +8 -13
- package/dist/controllers/app-env.js +23 -21
- package/dist/controllers/app.js +110 -92
- 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 +13 -2
- package/dist/lib/auth/auth-ops.js +2 -4
- package/dist/lib/auth/client.js +1 -1
- package/dist/lib/project/resolution.js +148 -0
- package/dist/output/patterns.js +0 -1
- package/dist/presenters/app.js +9 -1
- package/dist/presenters/branch.js +6 -6
- package/dist/presenters/project.js +84 -44
- package/dist/shell/command-meta.js +35 -11
- package/dist/shell/errors.js +4 -1
- package/dist/use-cases/auth.js +4 -7
- 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 +1 -1
- package/dist/adapters/config.js +0 -74
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
//#region src/adapters/git.ts
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
async function readGitOriginRemote(cwd) {
|
|
6
|
+
try {
|
|
7
|
+
const { stdout } = await execFileAsync("git", [
|
|
8
|
+
"config",
|
|
9
|
+
"--get",
|
|
10
|
+
"remote.origin.url"
|
|
11
|
+
], {
|
|
12
|
+
cwd,
|
|
13
|
+
timeout: 5e3
|
|
14
|
+
});
|
|
15
|
+
const remote = stdout.trim();
|
|
16
|
+
return remote.length > 0 ? remote : null;
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function parseGitHubRepositoryUrl(value) {
|
|
22
|
+
const input = value.trim();
|
|
23
|
+
const shorthand = input.match(/^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);
|
|
24
|
+
if (shorthand) return toGitHubRepositoryReference(shorthand[1], shorthand[2]);
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = new URL(input);
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if (parsed.hostname !== "github.com") return null;
|
|
32
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:" && parsed.protocol !== "ssh:") return null;
|
|
33
|
+
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
34
|
+
if (parts.length !== 2) return null;
|
|
35
|
+
const [owner, rawName] = parts;
|
|
36
|
+
return toGitHubRepositoryReference(owner, rawName.endsWith(".git") ? rawName.slice(0, -4) : rawName);
|
|
37
|
+
}
|
|
38
|
+
function toGitHubRepositoryReference(owner, name) {
|
|
39
|
+
if (!owner || !name || owner.includes("/") || name.includes("/")) return null;
|
|
40
|
+
return {
|
|
41
|
+
provider: "github",
|
|
42
|
+
owner,
|
|
43
|
+
name,
|
|
44
|
+
fullName: `${owner}/${name}`,
|
|
45
|
+
url: `https://github.com/${owner}/${name}`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { parseGitHubRepositoryUrl, readGitOriginRemote };
|
|
@@ -3,6 +3,11 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
3
3
|
//#region src/adapters/local-state.ts
|
|
4
4
|
const DEFAULT_STATE = {
|
|
5
5
|
auth: null,
|
|
6
|
+
project: {
|
|
7
|
+
rememberedByWorkspace: {},
|
|
8
|
+
lastResolved: null,
|
|
9
|
+
repositoryConnectionsByProject: {}
|
|
10
|
+
},
|
|
6
11
|
branch: { active: "preview" },
|
|
7
12
|
app: {
|
|
8
13
|
selectedByProject: {},
|
|
@@ -24,6 +29,11 @@ var LocalStateStore = class {
|
|
|
24
29
|
const parsed = JSON.parse(raw);
|
|
25
30
|
return {
|
|
26
31
|
auth: parsed.auth ?? structuredClone(DEFAULT_STATE.auth),
|
|
32
|
+
project: {
|
|
33
|
+
rememberedByWorkspace: parsed.project?.rememberedByWorkspace ?? {},
|
|
34
|
+
lastResolved: parsed.project?.lastResolved ?? null,
|
|
35
|
+
repositoryConnectionsByProject: parsed.project?.repositoryConnectionsByProject ?? {}
|
|
36
|
+
},
|
|
27
37
|
branch: { active: parsed.branch?.active ?? DEFAULT_STATE.branch.active },
|
|
28
38
|
app: {
|
|
29
39
|
selectedByProject: parsed.app?.selectedByProject ?? {},
|
|
@@ -57,6 +67,34 @@ var LocalStateStore = class {
|
|
|
57
67
|
await this.write(state);
|
|
58
68
|
return state;
|
|
59
69
|
}
|
|
70
|
+
async readRememberedProject(workspaceId) {
|
|
71
|
+
return (await this.read()).project.rememberedByWorkspace[workspaceId] ?? null;
|
|
72
|
+
}
|
|
73
|
+
async readLastResolvedProject() {
|
|
74
|
+
return (await this.read()).project.lastResolved;
|
|
75
|
+
}
|
|
76
|
+
async setRememberedProject(project) {
|
|
77
|
+
const state = await this.read();
|
|
78
|
+
state.project.rememberedByWorkspace[project.workspaceId] = project;
|
|
79
|
+
state.project.lastResolved = project;
|
|
80
|
+
await this.write(state);
|
|
81
|
+
return state;
|
|
82
|
+
}
|
|
83
|
+
async readRepositoryConnection(projectId) {
|
|
84
|
+
return (await this.read()).project.repositoryConnectionsByProject[projectId] ?? null;
|
|
85
|
+
}
|
|
86
|
+
async setRepositoryConnection(projectId, connection) {
|
|
87
|
+
const state = await this.read();
|
|
88
|
+
state.project.repositoryConnectionsByProject[projectId] = connection;
|
|
89
|
+
await this.write(state);
|
|
90
|
+
return state;
|
|
91
|
+
}
|
|
92
|
+
async clearRepositoryConnection(projectId) {
|
|
93
|
+
const state = await this.read();
|
|
94
|
+
delete state.project.repositoryConnectionsByProject[projectId];
|
|
95
|
+
await this.write(state);
|
|
96
|
+
return state;
|
|
97
|
+
}
|
|
60
98
|
async readSelectedApp(projectId) {
|
|
61
99
|
return (await this.read()).app.selectedByProject[projectId] ?? null;
|
|
62
100
|
}
|
package/dist/cli2.js
CHANGED
|
@@ -5,6 +5,7 @@ import "./shell/prompt.js";
|
|
|
5
5
|
import { createAppCommand } from "./commands/app/index.js";
|
|
6
6
|
import { createAuthCommand } from "./commands/auth/index.js";
|
|
7
7
|
import { createBranchCommand } from "./commands/branch/index.js";
|
|
8
|
+
import { createGitCommand } from "./commands/git/index.js";
|
|
8
9
|
import { createProjectCommand } from "./commands/project/index.js";
|
|
9
10
|
import process from "node:process";
|
|
10
11
|
import { Command, CommanderError } from "commander";
|
|
@@ -35,8 +36,9 @@ function createProgram(runtime) {
|
|
|
35
36
|
addCompactGlobalFlags(program);
|
|
36
37
|
program.name("prisma").showSuggestionAfterError();
|
|
37
38
|
program.addCommand(createAuthCommand(runtime));
|
|
38
|
-
program.addCommand(createBranchCommand(runtime));
|
|
39
39
|
program.addCommand(createProjectCommand(runtime));
|
|
40
|
+
program.addCommand(createGitCommand(runtime));
|
|
41
|
+
program.addCommand(createBranchCommand(runtime));
|
|
40
42
|
program.addCommand(createAppCommand(runtime));
|
|
41
43
|
return program;
|
|
42
44
|
}
|
|
@@ -60,7 +60,7 @@ function createRunCommand(runtime) {
|
|
|
60
60
|
}
|
|
61
61
|
function createDeployCommand(runtime) {
|
|
62
62
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("deploy"), runtime), "app.deploy");
|
|
63
|
-
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto deploys")).addOption(new Option("--build-type <type>", "Deploy build type").choices([...PREVIEW_BUILD_TYPES]).default("auto")).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
|
|
63
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--entry <path>", "Entrypoint path for Bun or auto deploys")).addOption(new Option("--build-type <type>", "Deploy build type").choices([...PREVIEW_BUILD_TYPES]).default("auto")).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
|
|
64
64
|
addGlobalFlags(command);
|
|
65
65
|
command.action(async (options) => {
|
|
66
66
|
const appName = options.app;
|
|
@@ -68,7 +68,9 @@ function createDeployCommand(runtime) {
|
|
|
68
68
|
const buildType = options.buildType;
|
|
69
69
|
const httpPort = options.httpPort;
|
|
70
70
|
const envAssignments = options.env;
|
|
71
|
+
const projectRef = options.project;
|
|
71
72
|
await runCommand(runtime, "app.deploy", options, (context) => runAppDeploy(context, appName, {
|
|
73
|
+
projectRef,
|
|
72
74
|
entrypoint: entry,
|
|
73
75
|
buildType,
|
|
74
76
|
httpPort,
|
|
@@ -82,12 +84,13 @@ function createDeployCommand(runtime) {
|
|
|
82
84
|
}
|
|
83
85
|
function createUpdateEnvCommand(runtime) {
|
|
84
86
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update-env"), runtime), "app.update-env");
|
|
85
|
-
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
|
|
87
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--env <name=value>", "Environment variable").argParser(collectRepeatableValues));
|
|
86
88
|
addGlobalFlags(command);
|
|
87
89
|
command.action(async (options) => {
|
|
88
90
|
const appName = options.app;
|
|
89
91
|
const envAssignments = options.env;
|
|
90
|
-
|
|
92
|
+
const projectRef = options.project;
|
|
93
|
+
await runCommand(runtime, "app.update-env", options, (context) => runAppUpdateEnv(context, appName, envAssignments, projectRef), {
|
|
91
94
|
renderHuman: (context, descriptor, result) => renderAppUpdateEnv(context, descriptor, result),
|
|
92
95
|
renderJson: (result) => serializeAppUpdateEnv(result)
|
|
93
96
|
});
|
|
@@ -96,11 +99,12 @@ function createUpdateEnvCommand(runtime) {
|
|
|
96
99
|
}
|
|
97
100
|
function createListEnvCommand(runtime) {
|
|
98
101
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list-env"), runtime), "app.list-env");
|
|
99
|
-
command.addOption(new Option("--app <name>", "App name"));
|
|
102
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
100
103
|
addGlobalFlags(command);
|
|
101
104
|
command.action(async (options) => {
|
|
102
105
|
const appName = options.app;
|
|
103
|
-
|
|
106
|
+
const projectRef = options.project;
|
|
107
|
+
await runCommand(runtime, "app.list-env", options, (context) => runAppListEnv(context, appName, projectRef), {
|
|
104
108
|
renderHuman: (context, descriptor, result) => renderAppListEnv(context, descriptor, result),
|
|
105
109
|
renderJson: (result) => serializeAppListEnv(result)
|
|
106
110
|
});
|
|
@@ -109,11 +113,12 @@ function createListEnvCommand(runtime) {
|
|
|
109
113
|
}
|
|
110
114
|
function createShowCommand(runtime) {
|
|
111
115
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.show");
|
|
112
|
-
command.addOption(new Option("--app <name>", "App name"));
|
|
116
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
113
117
|
addGlobalFlags(command);
|
|
114
118
|
command.action(async (options) => {
|
|
115
119
|
const appName = options.app;
|
|
116
|
-
|
|
120
|
+
const projectRef = options.project;
|
|
121
|
+
await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName, projectRef), {
|
|
117
122
|
renderHuman: (context, descriptor, result) => renderAppShow(context, descriptor, result),
|
|
118
123
|
renderJson: (result) => serializeAppShow(result)
|
|
119
124
|
});
|
|
@@ -122,11 +127,12 @@ function createShowCommand(runtime) {
|
|
|
122
127
|
}
|
|
123
128
|
function createOpenCommand(runtime) {
|
|
124
129
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("open"), runtime), "app.open");
|
|
125
|
-
command.addOption(new Option("--app <name>", "App name"));
|
|
130
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
126
131
|
addGlobalFlags(command);
|
|
127
132
|
command.action(async (options) => {
|
|
128
133
|
const appName = options.app;
|
|
129
|
-
|
|
134
|
+
const projectRef = options.project;
|
|
135
|
+
await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName, projectRef), {
|
|
130
136
|
renderHuman: (context, descriptor, result) => renderAppOpen(context, descriptor, result),
|
|
131
137
|
renderJson: (result) => serializeAppOpen(result)
|
|
132
138
|
});
|
|
@@ -135,12 +141,13 @@ function createOpenCommand(runtime) {
|
|
|
135
141
|
}
|
|
136
142
|
function createLogsCommand(runtime) {
|
|
137
143
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("logs"), runtime), "app.logs");
|
|
138
|
-
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--deployment <id>", "Deployment id"));
|
|
144
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--deployment <id>", "Deployment id"));
|
|
139
145
|
addGlobalFlags(command);
|
|
140
146
|
command.action(async (options) => {
|
|
141
147
|
const appName = options.app;
|
|
142
148
|
const deploymentId = options.deployment;
|
|
143
|
-
|
|
149
|
+
const projectRef = options.project;
|
|
150
|
+
await runStreamingCommand(runtime, "app.logs", options, (context) => runAppLogs(context, appName, deploymentId, projectRef));
|
|
144
151
|
});
|
|
145
152
|
return command;
|
|
146
153
|
}
|
|
@@ -149,11 +156,12 @@ function collectRepeatableValues(value, previous) {
|
|
|
149
156
|
}
|
|
150
157
|
function createListDeploysCommand(runtime) {
|
|
151
158
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list-deploys"), runtime), "app.list-deploys");
|
|
152
|
-
command.addOption(new Option("--app <name>", "App name"));
|
|
159
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
153
160
|
addGlobalFlags(command);
|
|
154
161
|
command.action(async (options) => {
|
|
155
162
|
const appName = options.app;
|
|
156
|
-
|
|
163
|
+
const projectRef = options.project;
|
|
164
|
+
await runCommand(runtime, "app.list-deploys", options, (context) => runAppListDeploys(context, appName, projectRef), {
|
|
157
165
|
renderHuman: (context, descriptor, result) => renderAppListDeploys(context, descriptor, result),
|
|
158
166
|
renderJson: (result) => serializeAppListDeploys(result)
|
|
159
167
|
});
|
|
@@ -175,11 +183,12 @@ function createShowDeployCommand(runtime) {
|
|
|
175
183
|
function createPromoteCommand(runtime) {
|
|
176
184
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("promote"), runtime), "app.promote");
|
|
177
185
|
command.argument("<deployment>", "Deployment id");
|
|
178
|
-
command.addOption(new Option("--app <name>", "App name"));
|
|
186
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
179
187
|
addGlobalFlags(command);
|
|
180
188
|
command.action(async (deploymentId, options) => {
|
|
181
189
|
const appName = options.app;
|
|
182
|
-
|
|
190
|
+
const projectRef = options.project;
|
|
191
|
+
await runCommand(runtime, "app.promote", options, (context) => runAppPromote(context, deploymentId, appName, projectRef), {
|
|
183
192
|
renderHuman: (context, descriptor, result) => renderAppPromote(context, descriptor, result),
|
|
184
193
|
renderJson: (result) => serializeAppPromote(result)
|
|
185
194
|
});
|
|
@@ -188,12 +197,13 @@ function createPromoteCommand(runtime) {
|
|
|
188
197
|
}
|
|
189
198
|
function createRollbackCommand(runtime) {
|
|
190
199
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("rollback"), runtime), "app.rollback");
|
|
191
|
-
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--to <deployment>", "Deployment id"));
|
|
200
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--to <deployment>", "Deployment id"));
|
|
192
201
|
addGlobalFlags(command);
|
|
193
202
|
command.action(async (options) => {
|
|
194
203
|
const appName = options.app;
|
|
195
204
|
const deploymentId = options.to;
|
|
196
|
-
|
|
205
|
+
const projectRef = options.project;
|
|
206
|
+
await runCommand(runtime, "app.rollback", options, (context) => runAppRollback(context, appName, deploymentId, projectRef), {
|
|
197
207
|
renderHuman: (context, descriptor, result) => renderAppRollback(context, descriptor, result),
|
|
198
208
|
renderJson: (result) => serializeAppRollback(result)
|
|
199
209
|
});
|
|
@@ -202,11 +212,12 @@ function createRollbackCommand(runtime) {
|
|
|
202
212
|
}
|
|
203
213
|
function createRemoveCommand(runtime) {
|
|
204
214
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "app.remove");
|
|
205
|
-
command.addOption(new Option("--app <name>", "App name"));
|
|
215
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
206
216
|
addGlobalFlags(command);
|
|
207
217
|
command.action(async (options) => {
|
|
208
218
|
const appName = options.app;
|
|
209
|
-
|
|
219
|
+
const projectRef = options.project;
|
|
220
|
+
await runCommand(runtime, "app.remove", options, (context) => runAppRemove(context, appName, projectRef), {
|
|
210
221
|
renderHuman: (context, descriptor, result) => renderAppRemove(context, descriptor, result),
|
|
211
222
|
renderJson: (result) => serializeAppRemove(result)
|
|
212
223
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
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
|
-
import { runCommand } from "../../shell/command-runner.js";
|
|
5
4
|
import { runAuthLogin, runAuthLogout, runAuthWhoAmI } from "../../controllers/auth.js";
|
|
5
|
+
import { runCommand } from "../../shell/command-runner.js";
|
|
6
6
|
import { renderAuthSuccess } from "../../presenters/auth.js";
|
|
7
7
|
import { Command, Option } from "commander";
|
|
8
8
|
//#region src/commands/auth/index.ts
|
package/dist/commands/env.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Command, Option } from "commander";
|
|
|
8
8
|
//#region src/commands/env.ts
|
|
9
9
|
function createEnvCommand(runtime) {
|
|
10
10
|
const env = attachCommandDescriptor(configureRuntimeCommand(new Command("env"), runtime), "project.env");
|
|
11
|
-
env.description("Manage environment variables for the
|
|
11
|
+
env.description("Manage environment variables for the active project");
|
|
12
12
|
env.addCommand(createEnvAddCommand(runtime));
|
|
13
13
|
env.addCommand(createEnvUpdateCommand(runtime));
|
|
14
14
|
env.addCommand(createEnvListCommand(runtime));
|
|
@@ -17,11 +17,15 @@ function createEnvCommand(runtime) {
|
|
|
17
17
|
}
|
|
18
18
|
function createEnvAddCommand(runtime) {
|
|
19
19
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("add"), runtime), "project.env.add");
|
|
20
|
-
command.argument("<assignment>", "Variable assignment
|
|
20
|
+
command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
21
21
|
addGlobalFlags(command);
|
|
22
22
|
command.action(async (assignment, options) => {
|
|
23
23
|
const roleName = options.role;
|
|
24
|
-
|
|
24
|
+
const projectRef = options.project;
|
|
25
|
+
await runCommand(runtime, "project.env.add", options, (context) => runEnvAdd(context, assignment, {
|
|
26
|
+
roleName,
|
|
27
|
+
projectRef
|
|
28
|
+
}), {
|
|
25
29
|
renderHuman: (context, descriptor, result) => renderEnvAdd(context, descriptor, result),
|
|
26
30
|
renderJson: (result) => serializeEnvAdd(result)
|
|
27
31
|
});
|
|
@@ -30,11 +34,15 @@ function createEnvAddCommand(runtime) {
|
|
|
30
34
|
}
|
|
31
35
|
function createEnvUpdateCommand(runtime) {
|
|
32
36
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update"), runtime), "project.env.update");
|
|
33
|
-
command.argument("<assignment>", "Variable assignment
|
|
37
|
+
command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
34
38
|
addGlobalFlags(command);
|
|
35
39
|
command.action(async (assignment, options) => {
|
|
36
40
|
const roleName = options.role;
|
|
37
|
-
|
|
41
|
+
const projectRef = options.project;
|
|
42
|
+
await runCommand(runtime, "project.env.update", options, (context) => runEnvUpdate(context, assignment, {
|
|
43
|
+
roleName,
|
|
44
|
+
projectRef
|
|
45
|
+
}), {
|
|
38
46
|
renderHuman: (context, descriptor, result) => renderEnvUpdate(context, descriptor, result),
|
|
39
47
|
renderJson: (result) => serializeEnvUpdate(result)
|
|
40
48
|
});
|
|
@@ -43,11 +51,15 @@ function createEnvUpdateCommand(runtime) {
|
|
|
43
51
|
}
|
|
44
52
|
function createEnvListCommand(runtime) {
|
|
45
53
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "project.env.list");
|
|
46
|
-
command.addOption(new Option("--role <role>", "Project template scope").choices(["production", "preview"]));
|
|
54
|
+
command.addOption(new Option("--role <role>", "Project template scope").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
47
55
|
addGlobalFlags(command);
|
|
48
56
|
command.action(async (options) => {
|
|
49
57
|
const roleName = options.role;
|
|
50
|
-
|
|
58
|
+
const projectRef = options.project;
|
|
59
|
+
await runCommand(runtime, "project.env.list", options, (context) => runEnvList(context, {
|
|
60
|
+
roleName,
|
|
61
|
+
projectRef
|
|
62
|
+
}), {
|
|
51
63
|
renderHuman: (context, descriptor, result) => renderEnvList(context, descriptor, result),
|
|
52
64
|
renderJson: (result) => serializeEnvList(result)
|
|
53
65
|
});
|
|
@@ -56,11 +68,15 @@ function createEnvListCommand(runtime) {
|
|
|
56
68
|
}
|
|
57
69
|
function createEnvRmCommand(runtime) {
|
|
58
70
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("rm"), runtime), "project.env.rm");
|
|
59
|
-
command.argument("<key>", "Variable key to remove").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"]));
|
|
71
|
+
command.argument("<key>", "Variable key to remove").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
60
72
|
addGlobalFlags(command);
|
|
61
73
|
command.action(async (key, options) => {
|
|
62
74
|
const roleName = options.role;
|
|
63
|
-
|
|
75
|
+
const projectRef = options.project;
|
|
76
|
+
await runCommand(runtime, "project.env.rm", options, (context) => runEnvRm(context, key, {
|
|
77
|
+
roleName,
|
|
78
|
+
projectRef
|
|
79
|
+
}), {
|
|
64
80
|
renderHuman: (context, descriptor, result) => renderEnvRm(context, descriptor, result),
|
|
65
81
|
renderJson: (result) => serializeEnvRm(result)
|
|
66
82
|
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { attachCommandDescriptor } from "../../shell/command-meta.js";
|
|
2
|
+
import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
|
|
3
|
+
import { configureRuntimeCommand } from "../../shell/runtime.js";
|
|
4
|
+
import { runGitConnect, runGitDisconnect } from "../../controllers/project.js";
|
|
5
|
+
import { runCommand } from "../../shell/command-runner.js";
|
|
6
|
+
import { renderGitConnect, renderGitDisconnect } from "../../presenters/project.js";
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
//#region src/commands/git/index.ts
|
|
9
|
+
function createGitCommand(runtime) {
|
|
10
|
+
const git = attachCommandDescriptor(configureRuntimeCommand(new Command("git"), runtime), "git");
|
|
11
|
+
addCompactGlobalFlags(git);
|
|
12
|
+
git.addCommand(createGitConnectCommand(runtime));
|
|
13
|
+
git.addCommand(createGitDisconnectCommand(runtime));
|
|
14
|
+
return git;
|
|
15
|
+
}
|
|
16
|
+
function createGitConnectCommand(runtime) {
|
|
17
|
+
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("connect"), runtime), "git.connect");
|
|
18
|
+
command.argument("[git-url]", "GitHub repository URL");
|
|
19
|
+
command.option("--project <id-or-name>", "Project id or name");
|
|
20
|
+
addGlobalFlags(command);
|
|
21
|
+
command.action(async (gitUrl, options) => {
|
|
22
|
+
await runCommand(runtime, "git.connect", options, (context) => runGitConnect(context, gitUrl, { project: typeof options.project === "string" ? options.project : void 0 }), { renderHuman: (context, descriptor, result) => renderGitConnect(context, descriptor, result) });
|
|
23
|
+
});
|
|
24
|
+
return command;
|
|
25
|
+
}
|
|
26
|
+
function createGitDisconnectCommand(runtime) {
|
|
27
|
+
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("disconnect"), runtime), "git.disconnect");
|
|
28
|
+
command.option("--project <id-or-name>", "Project id or name");
|
|
29
|
+
addGlobalFlags(command);
|
|
30
|
+
command.action(async (options) => {
|
|
31
|
+
await runCommand(runtime, "git.disconnect", options, (context) => runGitDisconnect(context, { project: typeof options.project === "string" ? options.project : void 0 }), { renderHuman: (context, descriptor, result) => renderGitDisconnect(context, descriptor, result) });
|
|
32
|
+
});
|
|
33
|
+
return command;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createGitCommand };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
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
|
+
import { runProjectList, runProjectShow } from "../../controllers/project.js";
|
|
4
5
|
import { runCommand } from "../../shell/command-runner.js";
|
|
5
|
-
import {
|
|
6
|
-
import { renderProjectLink, renderProjectList, renderProjectShow, serializeProjectList } from "../../presenters/project.js";
|
|
6
|
+
import { renderProjectList, renderProjectShow, serializeProjectList, serializeProjectShow } from "../../presenters/project.js";
|
|
7
7
|
import { createEnvCommand } from "../env.js";
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
//#region src/commands/project/index.ts
|
|
@@ -12,7 +12,6 @@ function createProjectCommand(runtime) {
|
|
|
12
12
|
addCompactGlobalFlags(project);
|
|
13
13
|
project.addCommand(createProjectListCommand(runtime));
|
|
14
14
|
project.addCommand(createProjectShowCommand(runtime));
|
|
15
|
-
project.addCommand(createProjectLinkCommand(runtime));
|
|
16
15
|
project.addCommand(createEnvCommand(runtime));
|
|
17
16
|
return project;
|
|
18
17
|
}
|
|
@@ -29,18 +28,14 @@ function createProjectListCommand(runtime) {
|
|
|
29
28
|
}
|
|
30
29
|
function createProjectShowCommand(runtime) {
|
|
31
30
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "project.show");
|
|
31
|
+
command.option("--project <id-or-name>", "Project id or name");
|
|
32
32
|
addGlobalFlags(command);
|
|
33
33
|
command.action(async (options) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("link"), runtime), "project.link");
|
|
40
|
-
command.argument("[project]", "Project id");
|
|
41
|
-
addGlobalFlags(command);
|
|
42
|
-
command.action(async (projectId, options) => {
|
|
43
|
-
await runCommand(runtime, "project.link", options, (context) => runProjectLink(context, projectId), { renderHuman: (context, descriptor, result) => renderProjectLink(context, descriptor, result) });
|
|
34
|
+
const projectRef = options.project;
|
|
35
|
+
await runCommand(runtime, "project.show", options, (context) => runProjectShow(context, projectRef), {
|
|
36
|
+
renderHuman: (context, descriptor, result) => renderProjectShow(context, descriptor, result),
|
|
37
|
+
renderJson: (result) => serializeProjectShow(result)
|
|
38
|
+
});
|
|
44
39
|
});
|
|
45
40
|
return command;
|
|
46
41
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CliError, authRequiredError, usageError } from "../shell/errors.js";
|
|
1
|
+
import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
3
2
|
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
|
+
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
4
|
+
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
5
|
+
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
6
|
+
import { listRealWorkspaceProjects } from "./project.js";
|
|
4
7
|
import { formatScopeLabel, parseKeyValuePositional, resolveEnvScope } from "../lib/app/env-config.js";
|
|
5
8
|
//#region src/controllers/app-env.ts
|
|
6
9
|
function defaultRoleScope() {
|
|
@@ -10,13 +13,13 @@ function defaultRoleScope() {
|
|
|
10
13
|
};
|
|
11
14
|
}
|
|
12
15
|
async function runEnvAdd(context, rawAssignment, flags) {
|
|
13
|
-
const { key, value } = parseKeyValuePositional(rawAssignment, "add");
|
|
16
|
+
const { key, value } = parseKeyValuePositional(rawAssignment, "add", context.runtime.env);
|
|
14
17
|
const scope = resolveEnvScope(flags, {
|
|
15
18
|
requireExplicit: true,
|
|
16
19
|
command: "add"
|
|
17
20
|
});
|
|
18
21
|
if (!scope) throw usageError(`prisma-cli project env add requires --role`, "Writing without an explicit scope is rejected.", "Pass --role production or --role preview.", [`prisma-cli project env add ${key}=${value} --role production`], "app");
|
|
19
|
-
const { client, projectId } = await requireClientAndProject(context);
|
|
22
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
20
23
|
const resolved = resolveScopeToApi(scope);
|
|
21
24
|
if (await findVariableByNaturalKey(client, projectId, key, resolved)) throw new CliError({
|
|
22
25
|
code: "ENV_VARIABLE_ALREADY_EXISTS",
|
|
@@ -46,13 +49,13 @@ async function runEnvAdd(context, rawAssignment, flags) {
|
|
|
46
49
|
};
|
|
47
50
|
}
|
|
48
51
|
async function runEnvUpdate(context, rawAssignment, flags) {
|
|
49
|
-
const { key, value } = parseKeyValuePositional(rawAssignment, "update");
|
|
52
|
+
const { key, value } = parseKeyValuePositional(rawAssignment, "update", context.runtime.env);
|
|
50
53
|
const scope = resolveEnvScope(flags, {
|
|
51
54
|
requireExplicit: true,
|
|
52
55
|
command: "update"
|
|
53
56
|
});
|
|
54
57
|
if (!scope) throw usageError(`prisma-cli project env update requires --role`, "Writing without an explicit scope is rejected.", "Pass --role production or --role preview.", [`prisma-cli project env update ${key}=${value} --role production`], "app");
|
|
55
|
-
const { client, projectId } = await requireClientAndProject(context);
|
|
58
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
56
59
|
const resolved = resolveScopeToApi(scope);
|
|
57
60
|
const existing = await findVariableByNaturalKey(client, projectId, key, resolved);
|
|
58
61
|
if (!existing) throw new CliError({
|
|
@@ -85,7 +88,7 @@ async function runEnvList(context, flags) {
|
|
|
85
88
|
requireExplicit: false,
|
|
86
89
|
command: "list"
|
|
87
90
|
}) ?? defaultRoleScope();
|
|
88
|
-
const { client, projectId } = await requireClientAndProject(context);
|
|
91
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
89
92
|
const resolved = resolveScopeToApi(scope);
|
|
90
93
|
const variables = await listVariables(client, projectId, resolved);
|
|
91
94
|
return {
|
|
@@ -106,7 +109,7 @@ async function runEnvRm(context, key, flags) {
|
|
|
106
109
|
command: "rm"
|
|
107
110
|
});
|
|
108
111
|
if (!scope) throw usageError("prisma-cli project env rm requires --role", "Writing without an explicit scope is rejected.", "Pass --role production or --role preview.", [`prisma-cli project env rm ${key} --role production`], "app");
|
|
109
|
-
const { client, projectId } = await requireClientAndProject(context);
|
|
112
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
110
113
|
const resolved = resolveScopeToApi(scope);
|
|
111
114
|
const existing = await findVariableByNaturalKey(client, projectId, key, resolved);
|
|
112
115
|
if (!existing) throw new CliError({
|
|
@@ -131,22 +134,21 @@ async function runEnvRm(context, key, flags) {
|
|
|
131
134
|
nextSteps: []
|
|
132
135
|
};
|
|
133
136
|
}
|
|
134
|
-
async function requireClientAndProject(context) {
|
|
135
|
-
const
|
|
136
|
-
if (!projectId) throw new CliError({
|
|
137
|
-
code: "PROJECT_NOT_LINKED",
|
|
138
|
-
domain: "project",
|
|
139
|
-
summary: "Project link required",
|
|
140
|
-
why: "prisma-cli project env needs a linked project for the current repo.",
|
|
141
|
-
fix: "Run prisma project link before managing environment variables.",
|
|
142
|
-
exitCode: 1,
|
|
143
|
-
nextSteps: ["prisma project link"]
|
|
144
|
-
});
|
|
137
|
+
async function requireClientAndProject(context, explicitProject) {
|
|
138
|
+
const authState = await requireAuthenticatedAuthState(context);
|
|
145
139
|
const client = await requireComputeAuth(context.runtime.env);
|
|
146
|
-
if (!client) throw authRequiredError(["prisma auth login"]);
|
|
140
|
+
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
141
|
+
if (!authState.workspace) throw workspaceRequiredError();
|
|
147
142
|
return {
|
|
148
143
|
client,
|
|
149
|
-
projectId
|
|
144
|
+
projectId: (await resolveProjectTarget({
|
|
145
|
+
context,
|
|
146
|
+
workspace: authState.workspace,
|
|
147
|
+
explicitProject,
|
|
148
|
+
listProjects: () => listRealWorkspaceProjects(client, authState.workspace),
|
|
149
|
+
prompt: createSelectPromptPort(context),
|
|
150
|
+
remember: true
|
|
151
|
+
})).project.id
|
|
150
152
|
};
|
|
151
153
|
}
|
|
152
154
|
function resolveScopeToApi(scope) {
|