@prisma/cli 3.0.0-alpha.3 → 3.0.0-alpha.5

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.
@@ -8,6 +8,12 @@ const DESCRIPTORS = [
8
8
  examples: ["prisma-cli auth login", "prisma-cli app deploy"],
9
9
  longDescription: "Deploy your app with isolated infrastructure for every branch"
10
10
  },
11
+ {
12
+ id: "version",
13
+ path: ["prisma", "version"],
14
+ description: "Show CLI build and environment",
15
+ examples: ["prisma-cli version", "prisma-cli version --json"]
16
+ },
11
17
  {
12
18
  id: "auth",
13
19
  path: ["prisma", "auth"],
@@ -47,7 +53,7 @@ const DESCRIPTORS = [
47
53
  {
48
54
  id: "project",
49
55
  path: ["prisma", "project"],
50
- description: "Manage the link between this directory and a Prisma project",
56
+ description: "Manage and inspect your Prisma projects",
51
57
  examples: ["prisma-cli project list", "prisma-cli project show"]
52
58
  },
53
59
  {
@@ -62,6 +68,12 @@ const DESCRIPTORS = [
62
68
  description: "View your active Platform branches",
63
69
  examples: ["prisma-cli branch list", "prisma-cli branch show"]
64
70
  },
71
+ {
72
+ id: "git",
73
+ path: ["prisma", "git"],
74
+ description: "Manage Git repository connections for a project",
75
+ examples: ["prisma-cli git connect", "prisma-cli git disconnect"]
76
+ },
65
77
  {
66
78
  id: "project.list",
67
79
  path: [
@@ -79,18 +91,32 @@ const DESCRIPTORS = [
79
91
  "project",
80
92
  "show"
81
93
  ],
82
- description: "Show the Prisma project linked to this directory",
83
- examples: ["prisma-cli project show", "prisma-cli project show --json"]
94
+ description: "Show which project is active for this directory",
95
+ examples: ["prisma-cli project show", "prisma-cli project show --project proj_123 --json"]
84
96
  },
85
97
  {
86
- id: "project.link",
98
+ id: "git.connect",
87
99
  path: [
88
100
  "prisma",
89
- "project",
90
- "link"
101
+ "git",
102
+ "connect"
91
103
  ],
92
- description: "Link this directory to a Prisma project",
93
- examples: ["prisma-cli project link", "prisma-cli project link proj_123"]
104
+ description: "Connect the resolved project to a GitHub repository",
105
+ examples: [
106
+ "prisma-cli git connect",
107
+ "prisma-cli git connect git@github.com:prisma/prisma-cli.git",
108
+ "prisma-cli git connect --project proj_123"
109
+ ]
110
+ },
111
+ {
112
+ id: "git.disconnect",
113
+ path: [
114
+ "prisma",
115
+ "git",
116
+ "disconnect"
117
+ ],
118
+ description: "Disconnect the GitHub repository from the resolved project",
119
+ examples: ["prisma-cli git disconnect", "prisma-cli git disconnect --project proj_123"]
94
120
  },
95
121
  {
96
122
  id: "branch.list",
@@ -99,7 +125,7 @@ const DESCRIPTORS = [
99
125
  "branch",
100
126
  "list"
101
127
  ],
102
- description: "List active Platform branches linked to this project",
128
+ description: "List active Platform branches for the resolved project",
103
129
  examples: ["prisma-cli branch list", "prisma-cli branch list --json"]
104
130
  },
105
131
  {
@@ -268,7 +294,7 @@ const DESCRIPTORS = [
268
294
  "project",
269
295
  "env"
270
296
  ],
271
- description: "Manage environment variables for the linked project.",
297
+ description: "Manage environment variables for the active project",
272
298
  examples: [
273
299
  "prisma-cli project env list --role production",
274
300
  "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role production",
@@ -284,7 +310,11 @@ const DESCRIPTORS = [
284
310
  "add"
285
311
  ],
286
312
  description: "Create a new environment variable.",
287
- examples: ["prisma-cli project env add STRIPE_KEY=sk_test_xxx --role production", "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role preview"]
313
+ examples: [
314
+ "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role production",
315
+ "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role preview",
316
+ "API_URL=https://api.example prisma-cli project env add API_URL --project proj_123 --role preview"
317
+ ]
288
318
  },
289
319
  {
290
320
  id: "project.env.update",
@@ -51,6 +51,9 @@ function authRequiredError(nextSteps = ["prisma-cli auth login"]) {
51
51
  nextSteps
52
52
  });
53
53
  }
54
+ function workspaceRequiredError() {
55
+ return usageError("Workspace required", "This command needs an active workspace, but the authenticated session does not have one.", "Run prisma-cli auth login and choose a workspace.", ["prisma-cli auth login"], "auth");
56
+ }
54
57
  function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cli") {
55
58
  return new CliError({
56
59
  code: "FEATURE_UNAVAILABLE",
@@ -63,4 +66,4 @@ function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cl
63
66
  });
64
67
  }
65
68
  //#endregion
66
- export { CliError, authRequiredError, featureUnavailableError, usageError };
69
+ export { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError };
@@ -6,7 +6,8 @@ const COMPACT_GLOBAL_OPTION_FLAGS = [
6
6
  "-v, --verbose",
7
7
  "--trace",
8
8
  "--no-interactive",
9
- "-y, --yes"
9
+ "-y, --yes",
10
+ "--version"
10
11
  ];
11
12
  function addGlobalFlags(command) {
12
13
  return command.option("--json", "Emit structured JSON output.").option("-q, --quiet", "Reduce human-oriented output.").option("-v, --verbose", "Increase human-oriented output detail.").option("--trace", "Show deeper diagnostics for failures.").option("-y, --yes", "Accept supported confirmation prompts.").addOption(new Option("--interactive", "Force interactive behavior when prompts are supported.")).addOption(new Option("--no-interactive", "Disable interactive behavior and prompts.")).addOption(new Option("--color", "Force color output in supported terminals.")).addOption(new Option("--no-color", "Disable color output."));
@@ -40,13 +40,12 @@ function createAuthUseCases(dependencies) {
40
40
  };
41
41
  }
42
42
  async function resolveCurrentAuthState(dependencies) {
43
- const [session, linkedProjectId] = await Promise.all([dependencies.sessionGateway.readAuthSession(), dependencies.projectConfigGateway.readLinkedProjectId()]);
43
+ const session = await dependencies.sessionGateway.readAuthSession();
44
44
  if (!session) return {
45
45
  authenticated: false,
46
46
  provider: null,
47
47
  user: null,
48
- workspace: null,
49
- linkedProjectId
48
+ workspace: null
50
49
  };
51
50
  const provider = dependencies.identityGateway.getProvider(session.provider);
52
51
  const user = dependencies.identityGateway.getUser(session.userId);
@@ -55,15 +54,13 @@ async function resolveCurrentAuthState(dependencies) {
55
54
  authenticated: false,
56
55
  provider: null,
57
56
  user: null,
58
- workspace: null,
59
- linkedProjectId
57
+ workspace: null
60
58
  };
61
59
  return {
62
60
  authenticated: true,
63
61
  provider: provider.id,
64
62
  user: { email: user.email },
65
- workspace,
66
- linkedProjectId
63
+ workspace
67
64
  };
68
65
  }
69
66
  //#endregion
@@ -2,41 +2,41 @@
2
2
  function createBranchUseCases(dependencies) {
3
3
  return {
4
4
  list: async () => {
5
- const [linkedProjectId, activeBranch] = await Promise.all([dependencies.projectConfigGateway.readLinkedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
6
- const remoteBranches = await listRemoteBranches(dependencies.branchGateway, linkedProjectId);
5
+ const [projectId, activeBranch] = await Promise.all([dependencies.projectStateGateway.readRememberedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
6
+ const remoteBranches = await listRemoteBranches(dependencies.branchGateway, projectId);
7
7
  return {
8
- linkedProjectId,
9
- projectName: resolveProjectName(dependencies.projectGateway, linkedProjectId),
8
+ projectId,
9
+ projectName: resolveProjectName(dependencies.projectGateway, projectId),
10
10
  activeBranch,
11
11
  branches: buildBranchSummaries(activeBranch, remoteBranches)
12
12
  };
13
13
  },
14
14
  show: async () => {
15
- const [linkedProjectId, activeBranch] = await Promise.all([dependencies.projectConfigGateway.readLinkedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
15
+ const [projectId, activeBranch] = await Promise.all([dependencies.projectStateGateway.readRememberedProjectId(), dependencies.branchStateGateway.readActiveBranch()]);
16
16
  return {
17
- linkedProjectId,
18
- projectName: resolveProjectName(dependencies.projectGateway, linkedProjectId),
19
- branch: buildBranchDetail(dependencies.branchGateway, linkedProjectId, activeBranch)
17
+ projectId,
18
+ projectName: resolveProjectName(dependencies.projectGateway, projectId),
19
+ branch: buildBranchDetail(dependencies.branchGateway, projectId, activeBranch)
20
20
  };
21
21
  },
22
22
  use: async (branchName) => {
23
23
  await dependencies.branchStateGateway.writeActiveBranch(branchName);
24
- const linkedProjectId = await dependencies.projectConfigGateway.readLinkedProjectId();
24
+ const projectId = await dependencies.projectStateGateway.readRememberedProjectId();
25
25
  return {
26
- linkedProjectId,
27
- projectName: resolveProjectName(dependencies.projectGateway, linkedProjectId),
28
- branch: buildBranchDetail(dependencies.branchGateway, linkedProjectId, branchName)
26
+ projectId,
27
+ projectName: resolveProjectName(dependencies.projectGateway, projectId),
28
+ branch: buildBranchDetail(dependencies.branchGateway, projectId, branchName)
29
29
  };
30
30
  }
31
31
  };
32
32
  }
33
- function resolveProjectName(projectGateway, linkedProjectId) {
34
- if (!linkedProjectId) return null;
35
- return projectGateway.getProject(linkedProjectId)?.name ?? null;
33
+ function resolveProjectName(projectGateway, projectId) {
34
+ if (!projectId) return null;
35
+ return projectGateway.getProject(projectId)?.name ?? null;
36
36
  }
37
- async function listRemoteBranches(branchGateway, linkedProjectId) {
38
- if (!linkedProjectId) return [];
39
- return branchGateway.listBranchesForProject(linkedProjectId);
37
+ async function listRemoteBranches(branchGateway, projectId) {
38
+ if (!projectId) return [];
39
+ return branchGateway.listBranchesForProject(projectId);
40
40
  }
41
41
  function buildBranchSummaries(activeBranch, remoteBranches) {
42
42
  const byName = /* @__PURE__ */ new Map();
@@ -56,9 +56,9 @@ function buildBranchSummaries(activeBranch, remoteBranches) {
56
56
  });
57
57
  return sortBranches([...byName.values()]);
58
58
  }
59
- function buildBranchDetail(branchGateway, linkedProjectId, branchName) {
59
+ function buildBranchDetail(branchGateway, projectId, branchName) {
60
60
  const kind = toBranchKind(branchName);
61
- const remoteBranch = linkedProjectId ? branchGateway.getBranchForProject(linkedProjectId, branchName) : void 0;
61
+ const remoteBranch = projectId ? branchGateway.getBranchForProject(projectId, branchName) : void 0;
62
62
  return {
63
63
  name: branchName,
64
64
  kind,
@@ -1,5 +1,3 @@
1
- import { UnsafeConfigWriteError, readLinkedProjectId, writeLinkedProjectId } from "../adapters/config.js";
2
- import { usageError } from "../shell/errors.js";
3
1
  //#region src/use-cases/create-cli-gateways.ts
4
2
  function createCliUseCaseGateways(context) {
5
3
  return {
@@ -44,17 +42,9 @@ function createCliUseCaseGateways(context) {
44
42
  },
45
43
  getDeployment: (deploymentId) => context.api.getDeployment(deploymentId)
46
44
  },
47
- projectConfigGateway: {
48
- readLinkedProjectId: () => readLinkedProjectId(context.runtime.cwd),
49
- writeLinkedProjectId: async (projectId) => {
50
- try {
51
- await writeLinkedProjectId(context.runtime.cwd, projectId);
52
- } catch (error) {
53
- if (error instanceof UnsafeConfigWriteError) throw usageError("Project link requires a writable Prisma config", error.message, "Update prisma.config.ts to use a recognizable project field, or remove it and rerun prisma-cli project link.", ["prisma-cli project link proj_123"], "project");
54
- throw error;
55
- }
56
- }
57
- },
45
+ projectStateGateway: { readRememberedProjectId: async () => {
46
+ return (await context.stateStore.readLastResolvedProject())?.id ?? null;
47
+ } },
58
48
  sessionGateway: {
59
49
  readAuthSession: async () => {
60
50
  return (await context.stateStore.read()).auth;
@@ -1,4 +1,4 @@
1
- import { CliError, authRequiredError } from "../shell/errors.js";
1
+ import { authRequiredError } from "../shell/errors.js";
2
2
  //#region src/use-cases/project.ts
3
3
  function createProjectUseCases(dependencies) {
4
4
  return {
@@ -6,44 +6,9 @@ function createProjectUseCases(dependencies) {
6
6
  const workspace = requireWorkspace(authState);
7
7
  return {
8
8
  workspace,
9
- linkedProjectId: authState.linkedProjectId,
10
9
  projects: listSortedWorkspaceProjects(dependencies.projectGateway, workspace.id).map(toProjectSummary)
11
10
  };
12
11
  },
13
- show: async (authState) => {
14
- if (!authState.linkedProjectId) return {
15
- linkedProjectId: null,
16
- workspace: null,
17
- project: null
18
- };
19
- if (!authState.authenticated || !authState.workspace) return {
20
- linkedProjectId: authState.linkedProjectId,
21
- workspace: null,
22
- project: null
23
- };
24
- const project = dependencies.projectGateway.getProjectForWorkspace(authState.workspace.id, authState.linkedProjectId);
25
- if (!project) return {
26
- linkedProjectId: authState.linkedProjectId,
27
- workspace: null,
28
- project: null
29
- };
30
- return {
31
- linkedProjectId: authState.linkedProjectId,
32
- workspace: authState.workspace,
33
- project: toProjectSummary(project)
34
- };
35
- },
36
- link: async (authState, projectId) => {
37
- const workspace = requireWorkspace(authState);
38
- const project = dependencies.projectGateway.getProjectForWorkspace(workspace.id, projectId);
39
- if (!project) throw projectNotFoundError(`The project "${projectId}" does not exist in workspace "${workspace.name}".`, "Run prisma-cli project list and choose a project id from the active workspace.");
40
- await dependencies.projectConfigGateway.writeLinkedProjectId(project.id);
41
- return {
42
- linkedProjectId: project.id,
43
- workspace,
44
- project: toProjectSummary(project)
45
- };
46
- },
47
12
  listProjectsForWorkspace: async (workspaceId) => listSortedWorkspaceProjects(dependencies.projectGateway, workspaceId).map(toProjectSummary)
48
13
  };
49
14
  }
@@ -60,16 +25,5 @@ function toProjectSummary(project) {
60
25
  name: project.name
61
26
  };
62
27
  }
63
- function projectNotFoundError(why, fix, nextSteps = ["prisma-cli project list"]) {
64
- return new CliError({
65
- code: "PROJECT_NOT_FOUND",
66
- domain: "project",
67
- summary: "Project not found",
68
- why,
69
- fix,
70
- exitCode: 1,
71
- nextSteps
72
- });
73
- }
74
28
  //#endregion
75
- export { createProjectUseCases, projectNotFoundError };
29
+ export { createProjectUseCases };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.5",
4
4
  "description": "Preview of the unified Prisma CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,74 +0,0 @@
1
- import path from "node:path";
2
- import { copyFile, mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
3
- import os from "node:os";
4
- import { updateConfig } from "c12/update";
5
- //#region src/adapters/config.ts
6
- const PROJECT_FIELD_PATTERN = /project\s*:\s*["']([^"']+)["']/;
7
- async function readLinkedProjectId(cwd) {
8
- const configPath = path.join(cwd, "prisma.config.ts");
9
- try {
10
- return (await readFile(configPath, "utf8")).match(PROJECT_FIELD_PATTERN)?.[1] ?? null;
11
- } catch (error) {
12
- if (error.code === "ENOENT") return null;
13
- throw error;
14
- }
15
- }
16
- var UnsafeConfigWriteError = class extends Error {
17
- constructor(message) {
18
- super(message);
19
- this.name = "UnsafeConfigWriteError";
20
- }
21
- };
22
- async function assertLinkedProjectIdWritable(cwd) {
23
- const tempDir = await mkdtemp(path.join(os.tmpdir(), "prisma-cli-config-"));
24
- const sourceConfigPath = path.join(cwd, "prisma.config.ts");
25
- const tempConfigPath = path.join(tempDir, "prisma.config.ts");
26
- try {
27
- try {
28
- await copyFile(sourceConfigPath, tempConfigPath);
29
- } catch (error) {
30
- if (error.code !== "ENOENT") throw error;
31
- }
32
- await applyLinkedProjectIdUpdate(tempDir, "proj_preflight");
33
- } catch (error) {
34
- throw toUnsafeConfigWriteError(error);
35
- } finally {
36
- await rm(tempDir, {
37
- recursive: true,
38
- force: true
39
- });
40
- }
41
- }
42
- async function writeLinkedProjectId(cwd, projectId) {
43
- try {
44
- await applyLinkedProjectIdUpdate(cwd, projectId);
45
- } catch (error) {
46
- if (error.code === "ENOENT") {
47
- await mkdir(cwd, { recursive: true });
48
- await applyLinkedProjectIdUpdate(cwd, projectId);
49
- return;
50
- }
51
- throw toUnsafeConfigWriteError(error);
52
- }
53
- }
54
- async function applyLinkedProjectIdUpdate(cwd, projectId) {
55
- await updateConfig({
56
- cwd,
57
- configFile: "prisma.config",
58
- onUpdate(config) {
59
- config.project = projectId;
60
- },
61
- onCreate() {
62
- return renderProjectConfig(projectId);
63
- }
64
- });
65
- }
66
- function renderProjectConfig(projectId) {
67
- return `export default {\n project: "${projectId}",\n};\n`;
68
- }
69
- function toUnsafeConfigWriteError(error) {
70
- if (error instanceof UnsafeConfigWriteError) return error;
71
- return new UnsafeConfigWriteError("The existing prisma.config.ts file could not be updated safely.");
72
- }
73
- //#endregion
74
- export { UnsafeConfigWriteError, assertLinkedProjectIdWritable, readLinkedProjectId, writeLinkedProjectId };