Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion docs/product/command-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ prisma-cli app run --build-type nextjs
prisma-cli app run --build-type bun --entry server.ts --port 3000
```

## `prisma-cli app deploy --project <id-or-name> --create-project <name> --app <name> --branch <name> --framework <nextjs|hono|tanstack-start|bun> --entry <path> --http-port <port> --env <name=value> --prod`
## `prisma-cli app deploy --project <id-or-name> --create-project <name> --app <name> --branch <name> --framework <nextjs|hono|tanstack-start|bun> --entry <path> --http-port <port> --env <name=value> --db --no-db --prod`

Purpose:

Expand Down Expand Up @@ -629,6 +629,19 @@ Behavior:
- deploy progress uses short stage copy (`Building locally...`, `Built <size>`, `Uploading...`, `Uploaded`, `Deploying...`, `Deployed`) and never prints `Status: running` or `Deployment is running at ...`
- success human output prints `Live in <duration>`, the URL on its own line, and `Logs prisma-cli app logs`
- accepts repeated `--env NAME=VALUE` flags
- supports `--db` for preview Branches to create a new empty Prisma Postgres database, apply the local Prisma schema when one exists, and write branch-scoped `DATABASE_URL` and `DIRECT_URL` overrides through the existing `project env` storage
- supports `--no-db` to suppress automatic database prompting for the deploy
- `--db` and `--no-db` are mutually exclusive; passing both is rejected
- `--yes` alone never creates a database; CI must pass `--db --yes` to create and wire one
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- branch database setup only runs for preview Branches; production database env vars are managed with `project env`
- branch database setup never overwrites an existing branch-scoped `DATABASE_URL`; when the branch already has `DATABASE_URL`, `--db` leaves branch database env vars unchanged and continues
- when only `DIRECT_URL` exists on the branch, explicit `--db` treats it as partial setup and repairs the pair by writing fresh branch database env values
- if schema setup or branch env-var wiring fails after database creation, the CLI deletes the newly created database before returning the error
- branch database setup does not clone or infer schema from another database; it only creates an empty database and optionally applies schema from local code
- when `prisma/migrations` exists next to `schema.prisma`, schema setup runs `prisma migrate deploy`; otherwise a found `schema.prisma` runs `prisma db push`
- when no `schema.prisma` is found, `--db` still creates the database and env overrides but skips schema setup
- if schema setup fails, deploy stops before the app build/deploy starts
- inline `--env DATABASE_URL=...` or `--env DIRECT_URL=...` suppresses automatic database prompting; combining those inline env vars with `--db` is rejected
- maps user-facing framework names to deploy build strategies
- uses `src/index.ts` as the Hono deploy entrypoint when the app has no `package.json#main` or `package.json#module` and that file exists
- supports vanilla Bun apps with `--framework bun` using `package.json#main` or `package.json#module`, or with `--entry <path>`
Expand All @@ -643,6 +656,9 @@ prisma-cli app deploy
prisma-cli app deploy --project proj_123
prisma-cli app deploy --create-project my-app --yes
prisma-cli app deploy --app my-app --env DATABASE_URL=postgresql://example
prisma-cli app deploy --db
prisma-cli app deploy --db --yes
prisma-cli app deploy --no-db
prisma-cli app deploy --framework nextjs --http-port 3000
prisma-cli app deploy --branch feat-login --framework hono --http-port 3000
prisma-cli app deploy --prod --yes
Expand Down
4 changes: 4 additions & 0 deletions docs/product/error-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ These codes are the minimum stable set for the MVP:
- `REPO_ALREADY_CONNECTED`
- `REPO_CONNECTION_FAILED`
- `BUILD_FAILED`
- `BRANCH_DATABASE_SETUP_FAILED`
- `SCHEMA_SETUP_FAILED`
- `RUN_FAILED`
- `DEPLOY_FAILED`
- `VERSION_UNAVAILABLE`
Expand Down Expand Up @@ -235,6 +237,8 @@ Recommended meanings:
- `REPO_ALREADY_CONNECTED`: a project already has a different GitHub repository connected
- `REPO_CONNECTION_FAILED`: the Management API repository connection operation failed
- `BUILD_FAILED`: build failed before a healthy deployment existed
- `BRANCH_DATABASE_SETUP_FAILED`: preview Branch database creation or branch env-var wiring failed before deployment started
- `SCHEMA_SETUP_FAILED`: local Prisma schema setup against a newly created Branch database failed before deployment started
- `RUN_FAILED`: local framework run command could not be started or exited unsuccessfully
- `DEPLOY_FAILED`: deployment or post-build health failed
- `VERSION_UNAVAILABLE`: CLI could not read its own bundled package metadata to report a version (defensive; not expected in normal installs)
Expand Down
20 changes: 14 additions & 6 deletions docs/product/resource-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,22 @@ top-level target-context group is `branch`, not `env`.

### Schema and Database

`schema` and `database` are out of scope for the current beta package, but
they remain part of the long-term hierarchy.
`schema` stays a local code artifact. `database` stays a branch-bound remote
resource.

- `schema` stays a local code artifact
- `database` stays a branch-bound resource
The beta package does not expose a standalone database command group yet. The
current database surface is limited to `app deploy --db`, which can create an
empty Prisma Postgres database for a preview Branch, apply the local
`schema.prisma` shape when available, and write normal branch-scoped
environment variable overrides.

The beta package must not redefine project or branch in a way that makes
future schema, database, and migration workflows awkward.
Rules:

- database wiring uses the existing environment-variable model
- `DATABASE_URL` is written as a preview Branch override, not a separate app binding
- branch database setup never overwrites an existing branch-scoped `DATABASE_URL`
- schema setup is sourced only from local code; the CLI does not clone or infer schema from another database
- production database configuration is managed through explicit environment-variable commands

## Relationships

Expand Down
45 changes: 35 additions & 10 deletions packages/cli/src/commands/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
serializeAppShowDeploy,
} from "../../presenters/app";
import { attachCommandDescriptor } from "../../shell/command-meta";
import { usageError } from "../../shell/errors";
import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags";
import { runCommand, runStreamingCommand } from "../../shell/command-runner";
import { configureRuntimeCommand, type CliRuntime } from "../../shell/runtime";
Expand Down Expand Up @@ -182,6 +183,8 @@ function createDeployCommand(runtime: CliRuntime): Command {
new Option("--env <name=value>", "Environment variable")
.argParser(collectRepeatableValues),
)
.addOption(new Option("--db", "Create and wire an isolated database for the preview Branch"))
.addOption(new Option("--no-db", "Skip branch database setup"))
.addOption(new Option("--prod", "Confirm intent to deploy to production"));
addGlobalFlags(command);

Expand All @@ -195,21 +198,39 @@ function createDeployCommand(runtime: CliRuntime): Command {
const projectRef = (options as { project?: string }).project;
const createProjectName = (options as { createProject?: string }).createProject;
const prod = (options as { prod?: boolean }).prod;
const db = (options as { db?: boolean }).db;
const hasDbConflict = hasFlag(runtime.argv, "--db") && hasFlag(runtime.argv, "--no-db");

await runCommand<AppDeployResult>(
runtime,
"app.deploy",
options as Record<string, unknown>,
(context) => runAppDeploy(context, appName, {
projectRef,
createProjectName,
branchName,
entrypoint: entry,
framework,
httpPort,
envAssignments,
prod: prod === true,
}),
(context) => {
if (hasDbConflict) {
throw usageError(
"app deploy accepts either --db or --no-db",
"--db requests branch database setup, while --no-db disables it.",
"Pass exactly one database setup flag.",
[
"prisma-cli app deploy --db",
"prisma-cli app deploy --no-db",
],
"app",
);
}

return runAppDeploy(context, appName, {
projectRef,
createProjectName,
branchName,
entrypoint: entry,
framework,
httpPort,
envAssignments,
prod: prod === true,
db,
});
},
{
renderHuman: (context, descriptor, result) => renderAppDeploy(context, descriptor, result),
renderJson: (result) => serializeAppDeploy(result),
Expand All @@ -220,6 +241,10 @@ function createDeployCommand(runtime: CliRuntime): Command {
return command;
}

function hasFlag(argv: string[], flag: string): boolean {
return argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
}

function createShowCommand(runtime: CliRuntime): Command {
const command = attachCommandDescriptor(
configureRuntimeCommand(new Command("show"), runtime),
Expand Down
36 changes: 33 additions & 3 deletions packages/cli/src/controllers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import {
type PreviewBuildType,
} from "../lib/app/preview-build";
import { PREVIEW_DEFAULT_REGION } from "../lib/app/preview-interaction";
import { maybeSetupBranchDatabase, type BranchDatabaseDeployBranch } from "../lib/app/branch-database-deploy";
import {
createPreviewDeployProgress,
createPreviewDeployProgressState,
Expand Down Expand Up @@ -224,6 +225,7 @@ export async function runAppDeploy(
httpPort?: string;
envAssignments?: string[];
prod?: boolean;
db?: boolean;
},
): Promise<CommandSuccess<AppDeployResult>> {
ensurePreviewAppMode(context);
Expand Down Expand Up @@ -320,6 +322,10 @@ export async function runAppDeploy(
assertSupportedEntrypoint(buildType, options?.entrypoint, "deploy");
const entrypoint = await resolveDeployEntrypoint(context.runtime.cwd, framework, options?.entrypoint, context.runtime.signal);
const portMapping = parseDeployPortMapping(String(runtime.port));
const branchDatabaseSetup = await maybeSetupBranchDatabase(context, provider, projectId, toBranchDatabaseDeployBranch(target.branch), {
db: options?.db,
inlineEnvVars: envVars,
});

const progressState = createPreviewDeployProgressState();
const deployStartedAt = Date.now();
Expand Down Expand Up @@ -353,8 +359,9 @@ export async function runAppDeploy(
result: {
workspace: target.workspace,
project: target.project,
branch: target.branch,
branch: toResultBranch(target.branch),
resolution: target.resolution,
branchDatabase: branchDatabaseSetup.result,
app: {
id: deployResult.app.id,
name: deployResult.app.name,
Expand All @@ -363,7 +370,7 @@ export async function runAppDeploy(
durationMs: deployDurationMs,
localPin: localPinResult,
},
warnings: [],
warnings: branchDatabaseSetup.warnings,
nextSteps: ["prisma-cli app list-deploys", `prisma-cli app show-deploy ${deployResult.deployment.id}`],
};
}
Expand Down Expand Up @@ -1264,7 +1271,7 @@ async function resolveAppDomainTarget(
resultTarget: {
workspace: target.workspace,
project: target.project,
branch: target.branch,
branch: toResultBranch(target.branch),
app: {
id: selectedApp.id,
name: selectedApp.name,
Expand Down Expand Up @@ -2199,6 +2206,7 @@ interface ResolvedAppProjectContext {
workspace: AuthWorkspace;
project: ProjectSummary;
branch: {
id: string | null;
name: string;
kind: BranchKind;
};
Expand Down Expand Up @@ -2262,6 +2270,7 @@ async function resolveProjectContext(
options?: {
branch?: ResolvedDeployBranch;
commandName?: string;
envProjectId?: string;
},
): Promise<ResolvedAppProjectContext> {
const authState = await requireAuthenticatedAuthState(context);
Expand All @@ -2282,6 +2291,7 @@ async function resolveProjectContext(
return {
...resolved,
branch: {
id: null,
name: branch.name,
kind: toBranchKind(branch.name),
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -2470,6 +2480,7 @@ async function withRemoteDeployBranch(
return {
...target,
branch: {
id: remoteBranch.id,
name: remoteBranch.name,
kind: remoteBranch.role,
},
Expand All @@ -2480,6 +2491,25 @@ function toBranchKind(name: string): BranchKind {
return name === "production" || name === "main" ? "production" : "preview";
}

function toResultBranch(branch: ResolvedAppProjectContext["branch"]): AppDeployResult["branch"] {
return {
name: branch.name,
kind: branch.kind,
};
}

function toBranchDatabaseDeployBranch(branch: ResolvedAppProjectContext["branch"]): BranchDatabaseDeployBranch {
if (!branch.id) {
throw new Error(`Deploy branch "${branch.name}" was not resolved remotely.`);
}

return {
id: branch.id,
name: branch.name,
kind: branch.kind,
};
}

function assertExclusiveDeployProjectInputs(options: {
projectRef: string | undefined;
createProjectName: string | undefined;
Expand Down
Loading
Loading