@prisma/cli 3.0.0-beta.9 → 3.0.0-dev.102.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -13
- package/dist/adapters/token-storage.js +311 -33
- package/dist/cli.js +7 -7
- package/dist/cli2.js +3 -3
- package/dist/commands/app/index.js +65 -52
- package/dist/commands/auth/index.js +55 -2
- package/dist/controllers/app-env.js +10 -7
- package/dist/controllers/app.js +539 -210
- package/dist/controllers/auth.js +211 -2
- package/dist/controllers/branch.js +5 -6
- package/dist/controllers/database.js +7 -5
- package/dist/controllers/project.js +33 -18
- package/dist/lib/app/app-interaction.js +5 -0
- package/dist/lib/app/{preview-provider.js → app-provider.js} +82 -78
- package/dist/lib/app/{preview-branch-database.js → branch-database-api.js} +1 -1
- package/dist/lib/app/branch-database-deploy.js +12 -60
- package/dist/lib/app/branch-database.js +1 -102
- package/dist/lib/app/build-settings.js +93 -0
- package/dist/lib/app/build.js +82 -0
- package/dist/lib/app/bun-project.js +2 -3
- package/dist/lib/app/compute-config.js +147 -0
- package/dist/lib/app/deploy-plan.js +58 -0
- package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
- package/dist/lib/app/local-dev.js +3 -60
- package/dist/lib/app/production-deploy-gate.js +3 -3
- package/dist/lib/app/read-branch.js +30 -0
- package/dist/lib/auth/auth-ops.js +10 -4
- package/dist/lib/auth/guard.js +4 -1
- package/dist/lib/auth/login.js +32 -25
- package/dist/lib/diagnostics.js +1 -1
- package/dist/lib/fs/home-path.js +24 -0
- package/dist/lib/git/local-branch.js +15 -3
- package/dist/lib/project/local-pin.js +106 -26
- package/dist/lib/project/resolution.js +162 -71
- package/dist/lib/project/setup.js +65 -19
- package/dist/output/patterns.js +1 -1
- package/dist/presenters/app.js +44 -39
- package/dist/presenters/auth.js +98 -1
- package/dist/presenters/branch.js +1 -1
- package/dist/presenters/database.js +2 -2
- package/dist/presenters/project.js +3 -9
- package/dist/shell/command-meta.js +52 -2
- package/dist/shell/command-runner.js +39 -28
- package/dist/shell/diagnostics-output.js +2 -8
- package/dist/shell/errors.js +50 -1
- package/dist/shell/help.js +30 -20
- package/dist/shell/runtime.js +8 -4
- package/dist/shell/ui.js +19 -2
- package/dist/use-cases/auth.js +68 -1
- package/package.json +18 -4
- package/dist/lib/app/preview-build-settings.js +0 -385
- package/dist/lib/app/preview-build.js +0 -475
- package/dist/lib/app/preview-interaction.js +0 -5
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
import { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable } from "./branch-database-api.js";
|
|
2
|
+
import { AppBuildStrategy } from "./build.js";
|
|
1
3
|
import { envVarNames } from "./env-vars.js";
|
|
2
|
-
import { PreviewBuildStrategy } from "./preview-build.js";
|
|
3
|
-
import { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable } from "./preview-branch-database.js";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { ApiError, CancelledError, ComputeClient, streamLogs } from "@prisma/compute-sdk";
|
|
6
|
-
//#region src/lib/app/
|
|
7
|
-
var
|
|
6
|
+
//#region src/lib/app/app-provider.ts
|
|
7
|
+
var DomainApiError = class extends Error {
|
|
8
8
|
status;
|
|
9
9
|
code;
|
|
10
10
|
hint;
|
|
11
11
|
constructor(options) {
|
|
12
12
|
super(`${options.summary}: ${options.message}${options.hint ? ` ${options.hint}` : ""}`);
|
|
13
|
-
this.name = "
|
|
13
|
+
this.name = "DomainApiError";
|
|
14
14
|
this.status = options.status;
|
|
15
15
|
this.code = options.code ?? null;
|
|
16
16
|
this.hint = options.hint ?? null;
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
-
function
|
|
19
|
+
function createAppProvider(client, options) {
|
|
20
20
|
const sdk = new ComputeClient(client);
|
|
21
21
|
return {
|
|
22
22
|
async createProject(options) {
|
|
@@ -68,14 +68,14 @@ function createPreviewAppProvider(client, options) {
|
|
|
68
68
|
return deleteEnvironmentVariable(client, options);
|
|
69
69
|
},
|
|
70
70
|
async removeApp(appId, options) {
|
|
71
|
-
const appResult = await sdk.
|
|
72
|
-
|
|
71
|
+
const appResult = await sdk.showApp({
|
|
72
|
+
appId,
|
|
73
73
|
signal: options?.signal
|
|
74
74
|
});
|
|
75
75
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
76
|
-
const destroyResult = await sdk.
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
const destroyResult = await sdk.destroyApp({
|
|
77
|
+
appId,
|
|
78
|
+
keepApp: false,
|
|
79
79
|
timeoutSeconds: 120,
|
|
80
80
|
pollIntervalMs: 2e3,
|
|
81
81
|
signal: options?.signal
|
|
@@ -90,8 +90,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
90
90
|
return listComputeServiceDomains(client, appId, options?.signal);
|
|
91
91
|
},
|
|
92
92
|
async addDomain(options) {
|
|
93
|
-
const result = await client.POST("/v1/
|
|
94
|
-
params: { path: {
|
|
93
|
+
const result = await client.POST("/v1/apps/{appId}/domains", {
|
|
94
|
+
params: { path: { appId: options.appId } },
|
|
95
95
|
body: { hostname: options.hostname },
|
|
96
96
|
signal: options.signal
|
|
97
97
|
});
|
|
@@ -135,8 +135,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
135
135
|
},
|
|
136
136
|
async promoteDeployment(options) {
|
|
137
137
|
const promoteResult = await sdk.promote({
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
appId: options.appId,
|
|
139
|
+
deploymentId: options.deploymentId,
|
|
140
140
|
timeoutSeconds: 120,
|
|
141
141
|
pollIntervalMs: 2e3,
|
|
142
142
|
signal: options.signal,
|
|
@@ -161,7 +161,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
161
161
|
region: options.region
|
|
162
162
|
};
|
|
163
163
|
const deployResult = await sdk.deploy({
|
|
164
|
-
strategy: new
|
|
164
|
+
strategy: new AppBuildStrategy({
|
|
165
165
|
appPath: path.resolve(options.cwd),
|
|
166
166
|
entrypoint: options.entrypoint,
|
|
167
167
|
buildType: options.buildType,
|
|
@@ -169,8 +169,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
169
169
|
buildSettings: options.buildSettings
|
|
170
170
|
}),
|
|
171
171
|
projectId: options.projectId,
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
appId: resolvedApp.appId,
|
|
173
|
+
appName: resolvedApp.appName,
|
|
174
174
|
region: resolvedApp.region,
|
|
175
175
|
portMapping: options.portMapping,
|
|
176
176
|
envVars: options.envVars,
|
|
@@ -185,22 +185,22 @@ function createPreviewAppProvider(client, options) {
|
|
|
185
185
|
return {
|
|
186
186
|
projectId: deployed.projectId,
|
|
187
187
|
app: {
|
|
188
|
-
id: deployed.
|
|
189
|
-
name: deployed.
|
|
188
|
+
id: deployed.appId,
|
|
189
|
+
name: deployed.appName,
|
|
190
190
|
region: deployed.region ?? null,
|
|
191
|
-
liveDeploymentId: deployed.
|
|
192
|
-
liveUrl: toAbsoluteUrl(deployed.
|
|
191
|
+
liveDeploymentId: deployed.deploymentId,
|
|
192
|
+
liveUrl: toAbsoluteUrl(deployed.appEndpointDomain ?? null)
|
|
193
193
|
},
|
|
194
194
|
deployment: {
|
|
195
|
-
id: deployed.
|
|
195
|
+
id: deployed.deploymentId,
|
|
196
196
|
status: "running",
|
|
197
|
-
url: toAbsoluteUrl(deployed.
|
|
197
|
+
url: toAbsoluteUrl(deployed.appEndpointDomain ?? deployed.deploymentEndpointDomain ?? null)
|
|
198
198
|
}
|
|
199
199
|
};
|
|
200
200
|
},
|
|
201
201
|
async updateAppEnv(options) {
|
|
202
202
|
const updateResult = await sdk.updateEnv({
|
|
203
|
-
|
|
203
|
+
appId: options.appId,
|
|
204
204
|
envVars: options.envVars,
|
|
205
205
|
timeoutSeconds: 120,
|
|
206
206
|
pollIntervalMs: 2e3,
|
|
@@ -209,19 +209,19 @@ function createPreviewAppProvider(client, options) {
|
|
|
209
209
|
});
|
|
210
210
|
if (updateResult.isErr()) throw new Error(updateResult.error.message);
|
|
211
211
|
const promoteResult = await sdk.promote({
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
appId: options.appId,
|
|
213
|
+
deploymentId: updateResult.value.deploymentId,
|
|
214
214
|
timeoutSeconds: 120,
|
|
215
215
|
pollIntervalMs: 2e3,
|
|
216
216
|
signal: options.signal,
|
|
217
217
|
progress: options.promoteProgress
|
|
218
218
|
});
|
|
219
219
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
220
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.
|
|
221
|
-
|
|
220
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
|
|
221
|
+
appId: options.appId,
|
|
222
222
|
signal: options.signal
|
|
223
|
-
}), sdk.
|
|
224
|
-
|
|
223
|
+
}), sdk.showDeployment({
|
|
224
|
+
deploymentId: updateResult.value.deploymentId,
|
|
225
225
|
signal: options.signal
|
|
226
226
|
})]);
|
|
227
227
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
@@ -232,25 +232,25 @@ function createPreviewAppProvider(client, options) {
|
|
|
232
232
|
id: serviceResult.value.id,
|
|
233
233
|
name: serviceResult.value.name,
|
|
234
234
|
region: serviceResult.value.region ?? null,
|
|
235
|
-
liveDeploymentId: serviceResult.value.
|
|
236
|
-
liveUrl: toAbsoluteUrl(serviceResult.value.
|
|
235
|
+
liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
|
|
236
|
+
liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
|
|
237
237
|
},
|
|
238
238
|
deployment: {
|
|
239
239
|
id: versionResult.value.id,
|
|
240
240
|
status: versionResult.value.status,
|
|
241
241
|
createdAt: versionResult.value.createdAt,
|
|
242
|
-
url: toAbsoluteUrl(serviceResult.value.
|
|
242
|
+
url: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? versionResult.value.previewDomain ?? null),
|
|
243
243
|
live: true
|
|
244
244
|
},
|
|
245
245
|
variables: envVarNames(versionResult.value.envVars)
|
|
246
246
|
};
|
|
247
247
|
},
|
|
248
248
|
async listAppEnvNames(options) {
|
|
249
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.
|
|
250
|
-
|
|
249
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
|
|
250
|
+
appId: options.appId,
|
|
251
251
|
signal: options.signal
|
|
252
|
-
}), sdk.
|
|
253
|
-
|
|
252
|
+
}), sdk.showDeployment({
|
|
253
|
+
deploymentId: options.deploymentId,
|
|
254
254
|
signal: options.signal
|
|
255
255
|
})]);
|
|
256
256
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
@@ -261,25 +261,25 @@ function createPreviewAppProvider(client, options) {
|
|
|
261
261
|
id: serviceResult.value.id,
|
|
262
262
|
name: serviceResult.value.name,
|
|
263
263
|
region: serviceResult.value.region ?? null,
|
|
264
|
-
liveDeploymentId: serviceResult.value.
|
|
265
|
-
liveUrl: toAbsoluteUrl(serviceResult.value.
|
|
264
|
+
liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
|
|
265
|
+
liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
|
|
266
266
|
},
|
|
267
267
|
deployment: {
|
|
268
268
|
id: versionResult.value.id,
|
|
269
269
|
status: versionResult.value.status,
|
|
270
270
|
createdAt: versionResult.value.createdAt,
|
|
271
271
|
url: toAbsoluteUrl(versionResult.value.previewDomain ?? null),
|
|
272
|
-
live: serviceResult.value.
|
|
272
|
+
live: serviceResult.value.latestDeploymentId === versionResult.value.id
|
|
273
273
|
},
|
|
274
274
|
variables: envVarNames(versionResult.value.envVars)
|
|
275
275
|
};
|
|
276
276
|
},
|
|
277
277
|
async listDeployments(appId, options) {
|
|
278
|
-
const [appResult, versionsResult] = await Promise.all([sdk.
|
|
279
|
-
|
|
278
|
+
const [appResult, versionsResult] = await Promise.all([sdk.showApp({
|
|
279
|
+
appId,
|
|
280
280
|
signal: options?.signal
|
|
281
|
-
}), sdk.
|
|
282
|
-
|
|
281
|
+
}), sdk.listDeployments({
|
|
282
|
+
appId,
|
|
283
283
|
signal: options?.signal
|
|
284
284
|
})]);
|
|
285
285
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
@@ -289,8 +289,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
289
289
|
id: appResult.value.id,
|
|
290
290
|
name: appResult.value.name,
|
|
291
291
|
region: appResult.value.region ?? null,
|
|
292
|
-
liveDeploymentId: appResult.value.
|
|
293
|
-
liveUrl: toAbsoluteUrl(appResult.value.
|
|
292
|
+
liveDeploymentId: appResult.value.latestDeploymentId ?? null,
|
|
293
|
+
liveUrl: toAbsoluteUrl(appResult.value.appEndpointDomain ?? null)
|
|
294
294
|
},
|
|
295
295
|
deployments: versionsResult.value.slice().sort((left, right) => {
|
|
296
296
|
const byDate = right.createdAt.localeCompare(left.createdAt);
|
|
@@ -305,8 +305,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
305
305
|
};
|
|
306
306
|
},
|
|
307
307
|
async showDeployment(deploymentId, options) {
|
|
308
|
-
const deploymentResult = await sdk.
|
|
309
|
-
|
|
308
|
+
const deploymentResult = await sdk.showDeployment({
|
|
309
|
+
deploymentId,
|
|
310
310
|
signal: options?.signal
|
|
311
311
|
});
|
|
312
312
|
if (deploymentResult.isErr()) {
|
|
@@ -329,7 +329,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
329
329
|
const result = await streamLogs({
|
|
330
330
|
baseUrl: options.baseUrl,
|
|
331
331
|
token: await options.getToken(),
|
|
332
|
-
|
|
332
|
+
deploymentId: streamOptions.deploymentId,
|
|
333
333
|
signal: streamOptions.signal
|
|
334
334
|
}, streamOptions.onRecord);
|
|
335
335
|
if (result.isErr()) {
|
|
@@ -382,7 +382,7 @@ async function listComputeServices(client, options) {
|
|
|
382
382
|
const services = [];
|
|
383
383
|
let cursor;
|
|
384
384
|
while (true) {
|
|
385
|
-
const result = await client.GET("/v1/
|
|
385
|
+
const result = await client.GET("/v1/apps", {
|
|
386
386
|
params: { query: {
|
|
387
387
|
projectId: options.projectId,
|
|
388
388
|
branchGitName: options.branchGitName,
|
|
@@ -400,13 +400,13 @@ async function listComputeServices(client, options) {
|
|
|
400
400
|
name: service.name,
|
|
401
401
|
region: service.region.id ?? null,
|
|
402
402
|
branchId: service.branchId,
|
|
403
|
-
liveDeploymentId: service.
|
|
404
|
-
liveUrl: toAbsoluteUrl(service.
|
|
403
|
+
liveDeploymentId: service.latestDeploymentId ?? null,
|
|
404
|
+
liveUrl: toAbsoluteUrl(service.appEndpointDomain ?? null)
|
|
405
405
|
}));
|
|
406
406
|
}
|
|
407
407
|
async function listComputeServiceDomains(client, computeServiceId, signal) {
|
|
408
|
-
const result = await client.GET("/v1/
|
|
409
|
-
params: { path: { computeServiceId } },
|
|
408
|
+
const result = await client.GET("/v1/apps/{appId}/domains", {
|
|
409
|
+
params: { path: { appId: computeServiceId } },
|
|
410
410
|
signal
|
|
411
411
|
});
|
|
412
412
|
if (result.error || !result.data) throw domainApiCallError("Failed to list custom domains", result.response, result.error);
|
|
@@ -453,7 +453,7 @@ async function createBranchApp(client, options) {
|
|
|
453
453
|
gitName: options.branchName,
|
|
454
454
|
signal: options.signal
|
|
455
455
|
});
|
|
456
|
-
const result = await client.POST("/v1/
|
|
456
|
+
const result = await client.POST("/v1/apps", {
|
|
457
457
|
body: {
|
|
458
458
|
projectId: options.projectId,
|
|
459
459
|
branchId: branch.id,
|
|
@@ -491,7 +491,7 @@ function apiCallError(summary, response, error) {
|
|
|
491
491
|
return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
|
|
492
492
|
}
|
|
493
493
|
function domainApiCallError(summary, response, error) {
|
|
494
|
-
return new
|
|
494
|
+
return new DomainApiError({
|
|
495
495
|
summary,
|
|
496
496
|
status: response.status,
|
|
497
497
|
code: error.error?.code ?? null,
|
|
@@ -503,38 +503,42 @@ async function findAppForDeployment(sdk, deploymentId, signal) {
|
|
|
503
503
|
const projectsResult = await sdk.listProjects({ signal });
|
|
504
504
|
if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
|
|
505
505
|
for (const project of projectsResult.value) {
|
|
506
|
-
const servicesResult = await sdk.
|
|
506
|
+
const servicesResult = await sdk.listApps({
|
|
507
507
|
projectId: project.id,
|
|
508
508
|
signal
|
|
509
509
|
});
|
|
510
510
|
if (servicesResult.isErr()) throw new Error(servicesResult.error.message);
|
|
511
511
|
for (const service of servicesResult.value) {
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
signal
|
|
515
|
-
});
|
|
516
|
-
if (detailResult.isErr()) throw new Error(detailResult.error.message);
|
|
517
|
-
const app = {
|
|
518
|
-
id: detailResult.value.id,
|
|
519
|
-
name: detailResult.value.name,
|
|
520
|
-
region: detailResult.value.region ?? null,
|
|
521
|
-
liveDeploymentId: detailResult.value.latestVersionId ?? null,
|
|
522
|
-
liveUrl: toAbsoluteUrl(detailResult.value.serviceEndpointDomain ?? null)
|
|
523
|
-
};
|
|
524
|
-
if (app.liveDeploymentId === deploymentId) return app;
|
|
525
|
-
const versionsResult = await sdk.listVersions({
|
|
526
|
-
serviceId: service.id,
|
|
527
|
-
signal
|
|
528
|
-
});
|
|
529
|
-
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
530
|
-
if (versionsResult.value.some((version) => version.id === deploymentId)) return app;
|
|
512
|
+
const app = await findServiceAppForDeployment(sdk, service.id, deploymentId, signal);
|
|
513
|
+
if (app) return app;
|
|
531
514
|
}
|
|
532
515
|
}
|
|
533
516
|
return null;
|
|
534
517
|
}
|
|
518
|
+
async function findServiceAppForDeployment(sdk, serviceId, deploymentId, signal) {
|
|
519
|
+
const detailResult = await sdk.showApp({
|
|
520
|
+
appId: serviceId,
|
|
521
|
+
signal
|
|
522
|
+
});
|
|
523
|
+
if (detailResult.isErr()) throw new Error(detailResult.error.message);
|
|
524
|
+
const app = {
|
|
525
|
+
id: detailResult.value.id,
|
|
526
|
+
name: detailResult.value.name,
|
|
527
|
+
region: detailResult.value.region ?? null,
|
|
528
|
+
liveDeploymentId: detailResult.value.latestDeploymentId ?? null,
|
|
529
|
+
liveUrl: toAbsoluteUrl(detailResult.value.appEndpointDomain ?? null)
|
|
530
|
+
};
|
|
531
|
+
if (app.liveDeploymentId === deploymentId) return app;
|
|
532
|
+
const versionsResult = await sdk.listDeployments({
|
|
533
|
+
appId: serviceId,
|
|
534
|
+
signal
|
|
535
|
+
});
|
|
536
|
+
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
537
|
+
return versionsResult.value.some((version) => version.id === deploymentId) ? app : null;
|
|
538
|
+
}
|
|
535
539
|
function toAbsoluteUrl(url) {
|
|
536
540
|
if (!url) return null;
|
|
537
541
|
return url.startsWith("https://") || url.startsWith("http://") ? url : `https://${url}`;
|
|
538
542
|
}
|
|
539
543
|
//#endregion
|
|
540
|
-
export {
|
|
544
|
+
export { DomainApiError, createAppProvider };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { CliError, usageError } from "../../shell/errors.js";
|
|
2
|
+
import { confirmPrompt } from "../../shell/prompt.js";
|
|
2
3
|
import { renderSummaryLine } from "../../shell/ui.js";
|
|
3
4
|
import { canPrompt } from "../../shell/runtime.js";
|
|
4
|
-
import { confirmPrompt } from "../../shell/prompt.js";
|
|
5
5
|
import { formatCommandArgument } from "../../shell/command-arguments.js";
|
|
6
6
|
import "../project/setup.js";
|
|
7
|
-
import { hasBranchDatabaseSignal, inspectBranchDatabaseSignal
|
|
7
|
+
import { hasBranchDatabaseSignal, inspectBranchDatabaseSignal } from "./branch-database.js";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
//#region src/lib/app/branch-database-deploy.ts
|
|
10
10
|
async function maybeSetupBranchDatabase(context, provider, projectId, branch, options) {
|
|
@@ -26,13 +26,12 @@ async function maybeSetupBranchDatabase(context, provider, projectId, branch, op
|
|
|
26
26
|
result: options.db === true ? {
|
|
27
27
|
status: "skipped",
|
|
28
28
|
reason: existingDatabaseEnvReason(branch),
|
|
29
|
-
envVars: targetEnvVars
|
|
30
|
-
schema: null
|
|
29
|
+
envVars: targetEnvVars
|
|
31
30
|
} : void 0,
|
|
32
31
|
warnings: warning ? [warning] : []
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
|
-
const localSignal = await inspectBranchDatabaseSignal(
|
|
34
|
+
const localSignal = await inspectBranchDatabaseSignal(options.projectDir, context.runtime.signal);
|
|
36
35
|
if (localSignal.unsupportedSchema) {
|
|
37
36
|
if (options.db === true) throw unsupportedBranchDatabaseSchemaError(localSignal.unsupportedSchema, branch, context);
|
|
38
37
|
return emptyBranchDatabaseSetupOutcome();
|
|
@@ -56,9 +55,9 @@ async function maybeSetupBranchDatabase(context, provider, projectId, branch, op
|
|
|
56
55
|
initialValue: false
|
|
57
56
|
})) return emptyBranchDatabaseSetupOutcome();
|
|
58
57
|
} else if (!canPrompt(context) && !context.flags.yes) throw nonInteractiveDatabaseSetupRequiresYesError(branch);
|
|
59
|
-
return setupBranchDatabase(context, provider, projectId, branch, localSignal, envState);
|
|
58
|
+
return setupBranchDatabase(context, provider, projectId, branch, localSignal, envState, options.projectDir);
|
|
60
59
|
}
|
|
61
|
-
async function setupBranchDatabase(context, provider, projectId, branch, signal, envState) {
|
|
60
|
+
async function setupBranchDatabase(context, provider, projectId, branch, signal, envState, projectDir) {
|
|
62
61
|
emitBranchDatabaseProgress(context, "pending", "Creating database");
|
|
63
62
|
const database = await provider.createBranchDatabase({
|
|
64
63
|
projectId,
|
|
@@ -70,27 +69,11 @@ async function setupBranchDatabase(context, provider, projectId, branch, signal,
|
|
|
70
69
|
});
|
|
71
70
|
emitBranchDatabaseProgress(context, "success", "Created database");
|
|
72
71
|
try {
|
|
73
|
-
let schemaSetup = null;
|
|
74
|
-
const warnings = [];
|
|
75
|
-
let skippedSchemaWarning = null;
|
|
76
|
-
if (signal.schema) {
|
|
77
|
-
emitBranchDatabaseProgress(context, "pending", `Applying database schema with ${formatSchemaSetupCommand(signal.schema.command)}`);
|
|
78
|
-
schemaSetup = await runBranchDatabaseSchemaSetup({
|
|
79
|
-
context,
|
|
80
|
-
schema: signal.schema,
|
|
81
|
-
databaseUrl: database.databaseUrl,
|
|
82
|
-
directUrl: database.directUrl
|
|
83
|
-
}).catch((error) => {
|
|
84
|
-
throw schemaSetupFailedError(error, signal.schema, branch, context.runtime.cwd);
|
|
85
|
-
});
|
|
86
|
-
emitBranchDatabaseProgress(context, "success", "Applied database schema");
|
|
87
|
-
} else skippedSchemaWarning = "No supported Prisma schema source was found. Database env vars were created, but schema setup was skipped.";
|
|
88
72
|
const envVars = await upsertBranchDatabaseEnvVars(context, provider, projectId, branch, database, envState);
|
|
89
|
-
emitBranchDatabaseProgress(context, "success", `Added ${envScopeLabel(branch)} env var${envVars.length === 1 ? "" : "s"} ${envVars.join(", ")}`);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
73
|
+
emitBranchDatabaseProgress(context, "success", `Added ${envScopeLabel(branch)} env var${envVars.length === 1 ? "" : "s"} ${envVars.join(", ")} — shared by every app on ${envScopeLabel(branch) === "production" ? "production" : `branch "${branch.name}"`}`);
|
|
74
|
+
const schemaCommand = signal.schema ? `DATABASE_URL=<url> npx ${formatSchemaSetupCommand(signal.schema.command)} (detected ${path.relative(projectDir, signal.schema.path) || signal.schema.path})` : "your own migration tooling";
|
|
75
|
+
const schemaSuggestion = `The new database is empty. Get a connection URL with \`prisma-cli database connection create ${database.id}\`, then apply your schema with ${schemaCommand}.`;
|
|
76
|
+
emitBranchDatabaseWarning(context, schemaSuggestion);
|
|
94
77
|
return {
|
|
95
78
|
result: {
|
|
96
79
|
status: "created",
|
|
@@ -98,14 +81,9 @@ async function setupBranchDatabase(context, provider, projectId, branch, signal,
|
|
|
98
81
|
id: database.id,
|
|
99
82
|
name: database.name
|
|
100
83
|
},
|
|
101
|
-
envVars
|
|
102
|
-
schema: schemaSetup ? {
|
|
103
|
-
command: schemaSetup.command,
|
|
104
|
-
source: schemaSetup.source,
|
|
105
|
-
path: schemaSetup.schemaPath
|
|
106
|
-
} : null
|
|
84
|
+
envVars
|
|
107
85
|
},
|
|
108
|
-
warnings
|
|
86
|
+
warnings: [schemaSuggestion]
|
|
109
87
|
};
|
|
110
88
|
} catch (error) {
|
|
111
89
|
throw await cleanupCreatedBranchDatabaseAfterFailure(context, provider, database, branch, error);
|
|
@@ -307,24 +285,6 @@ function branchDatabaseCleanupFailedError(setupError, cleanupError, database, br
|
|
|
307
285
|
nextSteps: []
|
|
308
286
|
});
|
|
309
287
|
}
|
|
310
|
-
function schemaSetupFailedError(error, schema, branch, cwd) {
|
|
311
|
-
return new CliError({
|
|
312
|
-
code: "SCHEMA_SETUP_FAILED",
|
|
313
|
-
domain: "app",
|
|
314
|
-
summary: "Database schema setup failed",
|
|
315
|
-
why: error instanceof Error ? error.message : String(error),
|
|
316
|
-
fix: "Fix the Prisma schema or migrations, then rerun deploy with --db.",
|
|
317
|
-
debug: formatDebugDetails(error),
|
|
318
|
-
meta: {
|
|
319
|
-
branch: branch.name,
|
|
320
|
-
schemaPath: schema.path,
|
|
321
|
-
source: schema.kind,
|
|
322
|
-
command: schema.command
|
|
323
|
-
},
|
|
324
|
-
exitCode: 1,
|
|
325
|
-
nextSteps: [...formatSchemaSetupNextSteps(schema, cwd), formatAppDeployWithDbNextStep(branch)]
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
288
|
function unsupportedBranchDatabaseSchemaError(schema, branch, context) {
|
|
329
289
|
return usageError("Database setup is not available for this Prisma schema", `${path.relative(context.runtime.cwd, schema.path) || defaultUnsupportedSchemaSourcePath(schema)} targets ${formatUnsupportedSchemaTarget(schema.target)}, but --db creates Prisma Postgres databases.`, "Use project env commands to provide a database URL, or switch the Prisma schema source to PostgreSQL before using --db.", [formatProjectEnvAddNextStep(branch), `prisma-cli app deploy --branch ${formatCommandArgument(branch.name)}`], "app");
|
|
330
290
|
}
|
|
@@ -337,14 +297,6 @@ function formatProjectEnvListNextStep(branch) {
|
|
|
337
297
|
function formatProjectEnvAddNextStep(branch) {
|
|
338
298
|
return branch.kind === "production" ? "prisma-cli project env add DATABASE_URL=<value> --role production" : `prisma-cli project env add DATABASE_URL=<value> --branch ${formatCommandArgument(branch.name)}`;
|
|
339
299
|
}
|
|
340
|
-
function formatSchemaSetupNextSteps(schema, cwd) {
|
|
341
|
-
const sourcePath = path.relative(cwd, schema.path) || defaultSchemaSourcePath(schema);
|
|
342
|
-
switch (schema.command) {
|
|
343
|
-
case "migrate-deploy": return [`npx --no-install prisma migrate deploy --schema ${formatCommandArgument(sourcePath)}`];
|
|
344
|
-
case "db-push": return [`npx --no-install prisma db push --schema ${formatCommandArgument(sourcePath)}`];
|
|
345
|
-
case "prisma-next-db-init": return [`npx --no-install prisma-next contract emit --config ${formatCommandArgument(sourcePath)}`, `npx --no-install prisma-next db init --config ${formatCommandArgument(sourcePath)} --db <DATABASE_URL>`];
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
300
|
function defaultSchemaSourcePath(schema) {
|
|
349
301
|
return schema.kind === "prisma-next" ? "prisma-next.config.ts" : "schema.prisma";
|
|
350
302
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { access, readFile, readdir, stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
3
|
//#region src/lib/app/branch-database.ts
|
|
5
4
|
const SKIPPED_DIRECTORIES = new Set([
|
|
6
5
|
".git",
|
|
@@ -67,23 +66,6 @@ function hasBranchDatabaseSignal(signal) {
|
|
|
67
66
|
if (signal.unsupportedSchema) return false;
|
|
68
67
|
return Boolean(signal.schema || signal.databaseUrlReferences.length > 0);
|
|
69
68
|
}
|
|
70
|
-
async function runBranchDatabaseSchemaSetup(options) {
|
|
71
|
-
const schemaPath = path.relative(options.context.runtime.cwd, options.schema.path) || defaultSchemaSourcePath(options.schema);
|
|
72
|
-
const commands = buildSchemaSetupCommands(options.schema, schemaPath, options.databaseUrl);
|
|
73
|
-
for (const command of commands) await runPrismaCommand({
|
|
74
|
-
context: options.context,
|
|
75
|
-
...command,
|
|
76
|
-
env: {
|
|
77
|
-
DATABASE_URL: options.databaseUrl,
|
|
78
|
-
...options.directUrl ? { DIRECT_URL: options.directUrl } : {}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
return {
|
|
82
|
-
command: options.schema.command,
|
|
83
|
-
source: options.schema.kind,
|
|
84
|
-
schemaPath
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
69
|
async function scanDirectory(cwd, directory, depth, state, signal) {
|
|
88
70
|
signal.throwIfAborted();
|
|
89
71
|
if (depth > MAX_SCAN_DEPTH || state.filesVisited >= MAX_SCAN_FILES) return;
|
|
@@ -229,88 +211,5 @@ async function readTextFileIfSmall(filePath, signal) {
|
|
|
229
211
|
signal
|
|
230
212
|
});
|
|
231
213
|
}
|
|
232
|
-
function buildSchemaSetupCommands(schema, schemaPath, databaseUrl) {
|
|
233
|
-
if (schema.command === "migrate-deploy") return [{
|
|
234
|
-
args: [
|
|
235
|
-
"--no-install",
|
|
236
|
-
"prisma",
|
|
237
|
-
"migrate",
|
|
238
|
-
"deploy",
|
|
239
|
-
"--schema",
|
|
240
|
-
schemaPath
|
|
241
|
-
],
|
|
242
|
-
displayCommand: "npx --no-install prisma migrate deploy"
|
|
243
|
-
}];
|
|
244
|
-
if (schema.command === "db-push") return [{
|
|
245
|
-
args: [
|
|
246
|
-
"--no-install",
|
|
247
|
-
"prisma",
|
|
248
|
-
"db",
|
|
249
|
-
"push",
|
|
250
|
-
"--schema",
|
|
251
|
-
schemaPath
|
|
252
|
-
],
|
|
253
|
-
displayCommand: "npx --no-install prisma db push"
|
|
254
|
-
}];
|
|
255
|
-
return [{
|
|
256
|
-
args: [
|
|
257
|
-
"--no-install",
|
|
258
|
-
"prisma-next",
|
|
259
|
-
"contract",
|
|
260
|
-
"emit",
|
|
261
|
-
"--config",
|
|
262
|
-
schemaPath
|
|
263
|
-
],
|
|
264
|
-
displayCommand: "npx --no-install prisma-next contract emit"
|
|
265
|
-
}, {
|
|
266
|
-
args: [
|
|
267
|
-
"--no-install",
|
|
268
|
-
"prisma-next",
|
|
269
|
-
"db",
|
|
270
|
-
"init",
|
|
271
|
-
"--config",
|
|
272
|
-
schemaPath,
|
|
273
|
-
"--db",
|
|
274
|
-
databaseUrl
|
|
275
|
-
],
|
|
276
|
-
displayCommand: "npx --no-install prisma-next db init"
|
|
277
|
-
}];
|
|
278
|
-
}
|
|
279
|
-
function defaultSchemaSourcePath(schema) {
|
|
280
|
-
return schema.kind === "prisma-next" ? "prisma-next.config.ts" : "schema.prisma";
|
|
281
|
-
}
|
|
282
|
-
async function runPrismaCommand(options) {
|
|
283
|
-
const shouldPipeOutput = !options.context.flags.json && !options.context.flags.quiet;
|
|
284
|
-
const child = spawn("npx", options.args, {
|
|
285
|
-
cwd: options.context.runtime.cwd,
|
|
286
|
-
env: {
|
|
287
|
-
...options.context.runtime.env,
|
|
288
|
-
...options.env
|
|
289
|
-
},
|
|
290
|
-
signal: options.context.runtime.signal,
|
|
291
|
-
stdio: shouldPipeOutput ? [
|
|
292
|
-
"ignore",
|
|
293
|
-
"pipe",
|
|
294
|
-
"pipe"
|
|
295
|
-
] : [
|
|
296
|
-
"ignore",
|
|
297
|
-
"ignore",
|
|
298
|
-
"ignore"
|
|
299
|
-
]
|
|
300
|
-
});
|
|
301
|
-
if (shouldPipeOutput) {
|
|
302
|
-
child.stdout?.pipe(options.context.output.stderr, { end: false });
|
|
303
|
-
child.stderr?.pipe(options.context.output.stderr, { end: false });
|
|
304
|
-
}
|
|
305
|
-
const exit = await new Promise((resolve, reject) => {
|
|
306
|
-
child.once("error", reject);
|
|
307
|
-
child.once("close", (code, signal) => resolve({
|
|
308
|
-
code,
|
|
309
|
-
signal
|
|
310
|
-
}));
|
|
311
|
-
});
|
|
312
|
-
if (exit.signal) throw new Error(`${options.displayCommand} was terminated by ${exit.signal}.`);
|
|
313
|
-
if (exit.code !== 0) throw new Error(`${options.displayCommand} exited with code ${exit.code ?? 1}.`);
|
|
314
|
-
}
|
|
315
214
|
//#endregion
|
|
316
|
-
export { hasBranchDatabaseSignal, inspectBranchDatabaseSignal
|
|
215
|
+
export { hasBranchDatabaseSignal, inspectBranchDatabaseSignal };
|