@prisma/cli 3.0.0-alpha.8 → 3.0.0-beta.0

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 CHANGED
@@ -1,27 +1,132 @@
1
- # Prisma CLI Preview
1
+ <p align="center">
2
+ <img src="https://i.imgur.com/h6UIYTu.png" alt="Prisma" width="360" />
3
+ </p>
2
4
 
3
- Preview npm package for the unified Prisma CLI.
5
+ # Prisma CLI
4
6
 
5
- Install:
7
+ [![npm version](https://img.shields.io/npm/v/@prisma/cli?label=npm)](https://www.npmjs.com/package/@prisma/cli)
8
+ [![license](https://img.shields.io/npm/l/@prisma/cli)](https://github.com/prisma/prisma-cli/blob/main/LICENSE)
9
+ [![Node.js](https://img.shields.io/node/v/@prisma/cli)](https://www.npmjs.com/package/@prisma/cli)
10
+
11
+ [Quickstart](#quickstart) • [Commands](#commands) • [Beta notes](#beta-notes) • [Documentation](#documentation) • [Support](#support)
12
+
13
+ ---
14
+
15
+ `@prisma/cli` is the public beta of the new CLI for the
16
+ Prisma Developer Platform.
17
+
18
+ It is the terminal surface managing your platform projects, branches, apps,
19
+ deployments, and environment variables.
20
+
21
+ The command model is under active development to include tooling for your
22
+ schema, database, migration, and broader platform workflows.
23
+
24
+ Looking for Prisma ORM commands such as `prisma generate`, `prisma migrate`, or
25
+ `prisma studio`? Use the [`prisma`](https://www.npmjs.com/package/prisma)
26
+ package.
27
+
28
+ ---
29
+
30
+ ## Quickstart
31
+
32
+ Install the beta package locally:
6
33
 
7
34
  ```bash
8
- pnpm add -D @prisma/cli@preview
35
+ npm install --save-dev @prisma/cli
9
36
  ```
10
37
 
11
- Run:
38
+ Run the binary exposed by this package:
12
39
 
13
40
  ```bash
14
- pnpm prisma-cli --help
41
+ npx prisma-cli --help
42
+ npx prisma-cli auth login
43
+ npx prisma-cli app deploy
44
+ ```
45
+
46
+ With `pnpm`:
47
+
48
+ ```bash
49
+ pnpm add -D @prisma/cli
15
50
  pnpm prisma-cli auth login
16
- pnpm prisma-cli app deploy --env DATABASE_URL=postgresql://example
17
- pnpm prisma-cli app list-env
51
+ pnpm prisma-cli app deploy
18
52
  ```
19
53
 
20
- The package exposes `prisma-cli` so it can coexist with the existing `prisma`
21
- executable.
54
+ Useful next commands:
55
+
56
+ ```bash
57
+ npx prisma-cli app logs
58
+ npx prisma-cli app open
59
+ npx prisma-cli project env add DATABASE_URL=postgresql://example --role preview
60
+ npx prisma-cli project env list --role preview
61
+ ```
62
+
63
+ The beta package exposes `prisma-cli` so it can coexist with the existing
64
+ `prisma` executable.
65
+
66
+ ---
67
+
68
+ ## Commands
69
+
70
+ | Group | What it does |
71
+ | --- | --- |
72
+ | `version` | Show the installed CLI build and host environment. |
73
+ | `auth` | Log in, log out, and inspect the active Prisma account. |
74
+ | `project` | List projects, show the resolved project, and manage project environment variables. |
75
+ | `git` | Connect or disconnect a project from a GitHub repository. |
76
+ | `branch` | Inspect the Prisma branch that maps to the current work context. |
77
+ | `app` | Build, run, deploy, inspect, open, stream logs, promote, roll back, and remove apps. |
78
+
79
+ Common examples:
80
+
81
+ ```bash
82
+ npx prisma-cli version
83
+ npx prisma-cli auth whoami
84
+ npx prisma-cli project show
85
+ npx prisma-cli branch show
86
+ npx prisma-cli app deploy --branch feat-login --framework nextjs
87
+ npx prisma-cli app promote <deployment-id>
88
+ ```
89
+
90
+ ### Built for humans, CI, and agents
91
+
92
+ - Human-readable output by default.
93
+ - `--json` for structured output.
94
+ - `--no-interactive` and `--yes` for automation.
95
+ - `PRISMA_SERVICE_TOKEN` for headless authenticated commands.
96
+ - Stable command groups, flags, and error codes for scripts and agents.
97
+ - Environment variable values are not printed back to the terminal.
98
+
99
+ ---
100
+
101
+ ## Beta notes
102
+
103
+ - Requires Node.js 20 or newer.
104
+ - This is a beta package and may change quickly.
105
+ - Official beta releases publish as `@prisma/cli`.
106
+ - The package binary is `prisma-cli`, not `prisma`, during beta.
107
+ - Local project context is cached in `.prisma/local.json`, which is gitignored and not a declarative repo config file.
108
+
109
+ ---
110
+
111
+ ## Documentation
112
+
113
+ - [CLI docs index](https://github.com/prisma/prisma-cli/blob/main/docs/README.md)
114
+ - [Resource model](https://github.com/prisma/prisma-cli/blob/main/docs/product/resource-model.md)
115
+ - [Command principles](https://github.com/prisma/prisma-cli/blob/main/docs/product/command-principles.md)
116
+ - [Command spec](https://github.com/prisma/prisma-cli/blob/main/docs/product/command-spec.md)
117
+ - [Output conventions](https://github.com/prisma/prisma-cli/blob/main/docs/product/output-conventions.md)
118
+ - [Error conventions](https://github.com/prisma/prisma-cli/blob/main/docs/product/error-conventions.md)
119
+
120
+ ## Support
121
+
122
+ Issues and feedback are welcome while the CLI is in public beta. Please use
123
+ [GitHub issues](https://github.com/prisma/prisma-cli/issues) for bug reports and
124
+ feature requests.
125
+
126
+ Security reports should follow Prisma's
127
+ [security policy](https://github.com/prisma/prisma-cli/blob/main/SECURITY.md)
128
+ and should not be filed as public issues.
22
129
 
23
- Notes:
130
+ ## License
24
131
 
25
- - This is a preview package and may change quickly.
26
- - `prisma.config.ts` stores linked project context for this CLI.
27
- - Environment variable values passed with `--env` are not printed back to the terminal.
132
+ Apache-2.0
@@ -1,5 +1,8 @@
1
1
  import { getAuthFilePath } from "../lib/auth/client.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
2
4
  import { CredentialsStore } from "@prisma/credentials-store";
5
+ import { randomUUID } from "node:crypto";
3
6
  //#region src/adapters/token-storage.ts
4
7
  function findLatestValidTokens(allCredentials) {
5
8
  for (let i = allCredentials.length - 1; i >= 0; i -= 1) {
@@ -14,10 +17,19 @@ function findLatestValidTokens(allCredentials) {
14
17
  }
15
18
  return null;
16
19
  }
20
+ function tokensEqual(a, b) {
21
+ return a?.workspaceId === b?.workspaceId && a?.accessToken === b?.accessToken && a?.refreshToken === b?.refreshToken;
22
+ }
23
+ function sleep(ms) {
24
+ return new Promise((resolve) => setTimeout(resolve, ms));
25
+ }
17
26
  var FileTokenStorage = class {
18
27
  credentialsStore;
28
+ lockFilePath;
19
29
  constructor(env = process.env) {
20
- this.credentialsStore = new CredentialsStore(getAuthFilePath(env));
30
+ const authFilePath = getAuthFilePath(env);
31
+ this.credentialsStore = new CredentialsStore(authFilePath);
32
+ this.lockFilePath = `${authFilePath}.lock`;
21
33
  }
22
34
  async getTokens() {
23
35
  try {
@@ -38,6 +50,50 @@ var FileTokenStorage = class {
38
50
  if (!tokens) return;
39
51
  await this.credentialsStore.deleteCredentials(tokens.workspaceId);
40
52
  }
53
+ async clearTokensIfCurrent(tokens) {
54
+ if (!tokensEqual(await this.getTokens(), tokens)) return;
55
+ await this.clearTokens();
56
+ }
57
+ async withRefreshLock(fn) {
58
+ const lockId = await this.acquireRefreshLock();
59
+ try {
60
+ return await fn();
61
+ } finally {
62
+ await this.releaseRefreshLock(lockId);
63
+ }
64
+ }
65
+ async acquireRefreshLock() {
66
+ const lockId = randomUUID();
67
+ await fs.mkdir(path.dirname(this.lockFilePath), { recursive: true });
68
+ while (true) try {
69
+ const handle = await fs.open(this.lockFilePath, "wx");
70
+ try {
71
+ await handle.writeFile(lockId, "utf8");
72
+ } finally {
73
+ await handle.close();
74
+ }
75
+ return lockId;
76
+ } catch (error) {
77
+ if (error.code !== "EEXIST") throw error;
78
+ const staleLockId = await this.getStaleRefreshLockId();
79
+ if (staleLockId) {
80
+ await this.releaseRefreshLock(staleLockId);
81
+ continue;
82
+ }
83
+ await sleep(100);
84
+ }
85
+ }
86
+ async getStaleRefreshLockId() {
87
+ const lockId = await fs.readFile(this.lockFilePath, "utf8").catch(() => null);
88
+ if (lockId === null) return null;
89
+ const stats = await fs.stat(this.lockFilePath).catch(() => null);
90
+ if (!stats) return null;
91
+ return Date.now() - stats.mtimeMs > 3e4 ? lockId : null;
92
+ }
93
+ async releaseRefreshLock(lockId) {
94
+ if (await fs.readFile(this.lockFilePath, "utf8").catch(() => null) !== lockId) return;
95
+ await fs.unlink(this.lockFilePath).catch(() => {});
96
+ }
41
97
  };
42
98
  //#endregion
43
99
  export { FileTokenStorage };
@@ -2,8 +2,8 @@ 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 { PREVIEW_BUILD_TYPES } from "../../lib/app/preview-build.js";
5
- import { runAppBuild, runAppDeploy, runAppListDeploys, runAppListEnv, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy, runAppUpdateEnv } from "../../controllers/app.js";
6
- import { renderAppBuild, renderAppDeploy, renderAppListDeploys, renderAppListEnv, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, renderAppUpdateEnv, serializeAppBuild, serializeAppDeploy, serializeAppListDeploys, serializeAppListEnv, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy, serializeAppUpdateEnv } from "../../presenters/app.js";
5
+ import { runAppBuild, runAppDeploy, runAppDomainAdd, runAppDomainRemove, runAppDomainRetry, runAppDomainShow, runAppDomainWait, runAppListDeploys, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy } from "../../controllers/app.js";
6
+ import { renderAppBuild, renderAppDeploy, renderAppDomainAdd, renderAppDomainRemove, renderAppDomainRetry, renderAppDomainShow, renderAppListDeploys, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, serializeAppBuild, serializeAppDeploy, serializeAppDomainAdd, serializeAppDomainRemove, serializeAppDomainRetry, serializeAppDomainShow, serializeAppListDeploys, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy } from "../../presenters/app.js";
7
7
  import { runCommand, runStreamingCommand } from "../../shell/command-runner.js";
8
8
  import { Command, Option } from "commander";
9
9
  //#region src/commands/app/index.ts
@@ -13,10 +13,9 @@ function createAppCommand(runtime) {
13
13
  app.addCommand(createBuildCommand(runtime));
14
14
  app.addCommand(createRunCommand(runtime));
15
15
  app.addCommand(createDeployCommand(runtime));
16
- app.addCommand(createUpdateEnvCommand(runtime));
17
- app.addCommand(createListEnvCommand(runtime));
18
16
  app.addCommand(createShowCommand(runtime));
19
17
  app.addCommand(createOpenCommand(runtime));
18
+ app.addCommand(createDomainCommand(runtime));
20
19
  app.addCommand(createLogsCommand(runtime));
21
20
  app.addCommand(createListDeploysCommand(runtime));
22
21
  app.addCommand(createShowDeployCommand(runtime));
@@ -90,63 +89,147 @@ function createDeployCommand(runtime) {
90
89
  });
91
90
  return command;
92
91
  }
93
- function createUpdateEnvCommand(runtime) {
94
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update-env"), runtime), "app.update-env");
95
- 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));
92
+ function createShowCommand(runtime) {
93
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.show");
94
+ command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
96
95
  addGlobalFlags(command);
97
96
  command.action(async (options) => {
98
97
  const appName = options.app;
99
- const envAssignments = options.env;
100
98
  const projectRef = options.project;
101
- await runCommand(runtime, "app.update-env", options, (context) => runAppUpdateEnv(context, appName, envAssignments, projectRef), {
102
- renderHuman: (context, descriptor, result) => renderAppUpdateEnv(context, descriptor, result),
103
- renderJson: (result) => serializeAppUpdateEnv(result)
99
+ await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName, projectRef), {
100
+ renderHuman: (context, descriptor, result) => renderAppShow(context, descriptor, result),
101
+ renderJson: (result) => serializeAppShow(result)
104
102
  });
105
103
  });
106
104
  return command;
107
105
  }
108
- function createListEnvCommand(runtime) {
109
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list-env"), runtime), "app.list-env");
106
+ function createOpenCommand(runtime) {
107
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("open"), runtime), "app.open");
110
108
  command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
111
109
  addGlobalFlags(command);
112
110
  command.action(async (options) => {
113
111
  const appName = options.app;
114
112
  const projectRef = options.project;
115
- await runCommand(runtime, "app.list-env", options, (context) => runAppListEnv(context, appName, projectRef), {
116
- renderHuman: (context, descriptor, result) => renderAppListEnv(context, descriptor, result),
117
- renderJson: (result) => serializeAppListEnv(result)
113
+ await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName, projectRef), {
114
+ renderHuman: (context, descriptor, result) => renderAppOpen(context, descriptor, result),
115
+ renderJson: (result) => serializeAppOpen(result)
118
116
  });
119
117
  });
120
118
  return command;
121
119
  }
122
- function createShowCommand(runtime) {
123
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.show");
124
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
120
+ function createDomainCommand(runtime) {
121
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("domain"), runtime), "app.domain");
122
+ addCompactGlobalFlags(command);
123
+ command.addCommand(createDomainAddCommand(runtime));
124
+ command.addCommand(createDomainShowCommand(runtime));
125
+ command.addCommand(createDomainRemoveCommand(runtime));
126
+ command.addCommand(createDomainRetryCommand(runtime));
127
+ command.addCommand(createDomainWaitCommand(runtime));
128
+ return command;
129
+ }
130
+ function addDomainTargetOptions(command) {
131
+ return command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--branch <name>", "Branch name"));
132
+ }
133
+ function createDomainAddCommand(runtime) {
134
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("add"), runtime), "app.domain.add");
135
+ command.argument("<hostname>", "Custom domain hostname");
136
+ addDomainTargetOptions(command);
125
137
  addGlobalFlags(command);
126
- command.action(async (options) => {
138
+ command.action(async (hostname, options) => {
127
139
  const appName = options.app;
128
140
  const projectRef = options.project;
129
- await runCommand(runtime, "app.show", options, (context) => runAppShow(context, appName, projectRef), {
130
- renderHuman: (context, descriptor, result) => renderAppShow(context, descriptor, result),
131
- renderJson: (result) => serializeAppShow(result)
141
+ const branchName = options.branch;
142
+ await runCommand(runtime, "app.domain.add", options, (context) => runAppDomainAdd(context, hostname, {
143
+ appName,
144
+ projectRef,
145
+ branchName
146
+ }), {
147
+ renderHuman: (context, descriptor, result) => renderAppDomainAdd(context, descriptor, result),
148
+ renderJson: (result) => serializeAppDomainAdd(result)
132
149
  });
133
150
  });
134
151
  return command;
135
152
  }
136
- function createOpenCommand(runtime) {
137
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("open"), runtime), "app.open");
138
- command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
153
+ function createDomainShowCommand(runtime) {
154
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.domain.show");
155
+ command.argument("<hostname>", "Custom domain hostname");
156
+ addDomainTargetOptions(command);
139
157
  addGlobalFlags(command);
140
- command.action(async (options) => {
158
+ command.action(async (hostname, options) => {
141
159
  const appName = options.app;
142
160
  const projectRef = options.project;
143
- await runCommand(runtime, "app.open", options, (context) => runAppOpen(context, appName, projectRef), {
144
- renderHuman: (context, descriptor, result) => renderAppOpen(context, descriptor, result),
145
- renderJson: (result) => serializeAppOpen(result)
161
+ const branchName = options.branch;
162
+ await runCommand(runtime, "app.domain.show", options, (context) => runAppDomainShow(context, hostname, {
163
+ appName,
164
+ projectRef,
165
+ branchName
166
+ }), {
167
+ renderHuman: (context, descriptor, result) => renderAppDomainShow(context, descriptor, result),
168
+ renderJson: (result) => serializeAppDomainShow(result)
169
+ });
170
+ });
171
+ return command;
172
+ }
173
+ function createDomainRemoveCommand(runtime) {
174
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "app.domain.remove");
175
+ command.argument("<hostname>", "Custom domain hostname");
176
+ addDomainTargetOptions(command);
177
+ addGlobalFlags(command);
178
+ command.action(async (hostname, options) => {
179
+ const appName = options.app;
180
+ const projectRef = options.project;
181
+ const branchName = options.branch;
182
+ await runCommand(runtime, "app.domain.remove", options, (context) => runAppDomainRemove(context, hostname, {
183
+ appName,
184
+ projectRef,
185
+ branchName
186
+ }), {
187
+ renderHuman: (context, descriptor, result) => renderAppDomainRemove(context, descriptor, result),
188
+ renderJson: (result) => serializeAppDomainRemove(result)
189
+ });
190
+ });
191
+ return command;
192
+ }
193
+ function createDomainRetryCommand(runtime) {
194
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("retry"), runtime), "app.domain.retry");
195
+ command.argument("<hostname>", "Custom domain hostname");
196
+ addDomainTargetOptions(command);
197
+ addGlobalFlags(command);
198
+ command.action(async (hostname, options) => {
199
+ const appName = options.app;
200
+ const projectRef = options.project;
201
+ const branchName = options.branch;
202
+ await runCommand(runtime, "app.domain.retry", options, (context) => runAppDomainRetry(context, hostname, {
203
+ appName,
204
+ projectRef,
205
+ branchName
206
+ }), {
207
+ renderHuman: (context, descriptor, result) => renderAppDomainRetry(context, descriptor, result),
208
+ renderJson: (result) => serializeAppDomainRetry(result)
146
209
  });
147
210
  });
148
211
  return command;
149
212
  }
213
+ function createDomainWaitCommand(runtime) {
214
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("wait"), runtime), "app.domain.wait");
215
+ command.argument("<hostname>", "Custom domain hostname");
216
+ addDomainTargetOptions(command);
217
+ command.addOption(new Option("--timeout <duration>", "Maximum time to wait").default("15m"));
218
+ addGlobalFlags(command);
219
+ command.action(async (hostname, options) => {
220
+ const appName = options.app;
221
+ const projectRef = options.project;
222
+ const branchName = options.branch;
223
+ const timeout = options.timeout;
224
+ await runStreamingCommand(runtime, "app.domain.wait", options, (context) => runAppDomainWait(context, hostname, {
225
+ appName,
226
+ projectRef,
227
+ branchName,
228
+ timeout
229
+ }));
230
+ });
231
+ return command;
232
+ }
150
233
  function createLogsCommand(runtime) {
151
234
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("logs"), runtime), "app.logs");
152
235
  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"));
@@ -2,7 +2,7 @@ import { attachCommandDescriptor } from "../shell/command-meta.js";
2
2
  import { 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 { runEnvAdd, runEnvList, runEnvRm, runEnvUpdate } from "../controllers/app-env.js";
5
+ import { runEnvAdd, runEnvList, runEnvRemove, runEnvUpdate } from "../controllers/app-env.js";
6
6
  import { renderEnvAdd, renderEnvList, renderEnvRm, renderEnvUpdate, serializeEnvAdd, serializeEnvList, serializeEnvRm, serializeEnvUpdate } from "../presenters/app-env.js";
7
7
  import { Command, Option } from "commander";
8
8
  //#region src/commands/env.ts
@@ -12,18 +12,20 @@ function createEnvCommand(runtime) {
12
12
  env.addCommand(createEnvAddCommand(runtime));
13
13
  env.addCommand(createEnvUpdateCommand(runtime));
14
14
  env.addCommand(createEnvListCommand(runtime));
15
- env.addCommand(createEnvRmCommand(runtime));
15
+ env.addCommand(createEnvRemoveCommand(runtime));
16
16
  return env;
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 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"));
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("--branch <git-name>", "Preview branch override scope")).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
+ const branchName = options.branch;
24
25
  const projectRef = options.project;
25
26
  await runCommand(runtime, "project.env.add", options, (context) => runEnvAdd(context, assignment, {
26
27
  roleName,
28
+ branchName,
27
29
  projectRef
28
30
  }), {
29
31
  renderHuman: (context, descriptor, result) => renderEnvAdd(context, descriptor, result),
@@ -34,13 +36,15 @@ function createEnvAddCommand(runtime) {
34
36
  }
35
37
  function createEnvUpdateCommand(runtime) {
36
38
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update"), runtime), "project.env.update");
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"));
39
+ 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("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
38
40
  addGlobalFlags(command);
39
41
  command.action(async (assignment, options) => {
40
42
  const roleName = options.role;
43
+ const branchName = options.branch;
41
44
  const projectRef = options.project;
42
45
  await runCommand(runtime, "project.env.update", options, (context) => runEnvUpdate(context, assignment, {
43
46
  roleName,
47
+ branchName,
44
48
  projectRef
45
49
  }), {
46
50
  renderHuman: (context, descriptor, result) => renderEnvUpdate(context, descriptor, result),
@@ -51,13 +55,15 @@ function createEnvUpdateCommand(runtime) {
51
55
  }
52
56
  function createEnvListCommand(runtime) {
53
57
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "project.env.list");
54
- command.addOption(new Option("--role <role>", "Project template scope").choices(["production", "preview"])).addOption(new Option("--project <id-or-name>", "Project id or name"));
58
+ command.addOption(new Option("--role <role>", "Project template scope").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch resolved scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
55
59
  addGlobalFlags(command);
56
60
  command.action(async (options) => {
57
61
  const roleName = options.role;
62
+ const branchName = options.branch;
58
63
  const projectRef = options.project;
59
64
  await runCommand(runtime, "project.env.list", options, (context) => runEnvList(context, {
60
65
  roleName,
66
+ branchName,
61
67
  projectRef
62
68
  }), {
63
69
  renderHuman: (context, descriptor, result) => renderEnvList(context, descriptor, result),
@@ -66,15 +72,17 @@ function createEnvListCommand(runtime) {
66
72
  });
67
73
  return command;
68
74
  }
69
- function createEnvRmCommand(runtime) {
70
- const command = attachCommandDescriptor(configureRuntimeCommand(new Command("rm"), runtime), "project.env.rm");
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"));
75
+ function createEnvRemoveCommand(runtime) {
76
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "project.env.remove");
77
+ command.alias("rm").argument("<key>", "Variable key to remove").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
72
78
  addGlobalFlags(command);
73
79
  command.action(async (key, options) => {
74
80
  const roleName = options.role;
81
+ const branchName = options.branch;
75
82
  const projectRef = options.project;
76
- await runCommand(runtime, "project.env.rm", options, (context) => runEnvRm(context, key, {
83
+ await runCommand(runtime, "project.env.remove", options, (context) => runEnvRemove(context, key, {
77
84
  roleName,
85
+ branchName,
78
86
  projectRef
79
87
  }), {
80
88
  renderHuman: (context, descriptor, result) => renderEnvRm(context, descriptor, result),