|
| 1 | +// Apply Prisma migrations to the RUN-OPS database — the second physical DB in the run-ops |
| 2 | +// split. The standard `db:migrate` only targets DATABASE_URL (the control-plane DB), so the |
| 3 | +// run-ops DB must be migrated explicitly or its schema drifts (e.g. cross-DB FKs that were |
| 4 | +// dropped on the control-plane DB linger on the run-ops DB and break inserts). |
| 5 | +// |
| 6 | +// The run-ops connection comes from TASK_RUN_DATABASE_URL / TASK_RUN_DATABASE_DIRECT_URL |
| 7 | +// (set directly in deploy environments; read from the local .env otherwise). We then run |
| 8 | +// `prisma migrate deploy` with DATABASE_URL/DIRECT_URL pointed at it. |
| 9 | +import { spawnSync } from "node:child_process"; |
| 10 | +import { readFileSync } from "node:fs"; |
| 11 | +import { dirname, resolve } from "node:path"; |
| 12 | +import { fileURLToPath } from "node:url"; |
| 13 | + |
| 14 | +const dbPackageRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); |
| 15 | + |
| 16 | +function readFromEnvFiles(key) { |
| 17 | + for (const file of [resolve(dbPackageRoot, ".env"), resolve(dbPackageRoot, "../../.env")]) { |
| 18 | + let contents; |
| 19 | + try { |
| 20 | + contents = readFileSync(file, "utf8"); |
| 21 | + } catch { |
| 22 | + continue; |
| 23 | + } |
| 24 | + for (const line of contents.split("\n")) { |
| 25 | + const match = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/); |
| 26 | + if (!match || match[1] !== key) continue; |
| 27 | + let value = match[2]; |
| 28 | + if ( |
| 29 | + (value.startsWith('"') && value.endsWith('"')) || |
| 30 | + (value.startsWith("'") && value.endsWith("'")) |
| 31 | + ) { |
| 32 | + value = value.slice(1, -1); |
| 33 | + } |
| 34 | + if (value) return value; |
| 35 | + } |
| 36 | + } |
| 37 | + return undefined; |
| 38 | +} |
| 39 | + |
| 40 | +const resolveVar = (key) => process.env[key] || readFromEnvFiles(key); |
| 41 | +const redact = (url) => url.replace(/:\/\/[^@]*@/, "://***@"); |
| 42 | + |
| 43 | +const databaseUrl = resolveVar("TASK_RUN_DATABASE_URL"); |
| 44 | +const directUrl = resolveVar("TASK_RUN_DATABASE_DIRECT_URL") || databaseUrl; |
| 45 | + |
| 46 | +if (!databaseUrl) { |
| 47 | + console.error( |
| 48 | + "db:migrate:run-ops: TASK_RUN_DATABASE_URL is not set (checked env and .env). " + |
| 49 | + "It is the run-ops database in the split — nothing to migrate without it." |
| 50 | + ); |
| 51 | + process.exit(1); |
| 52 | +} |
| 53 | + |
| 54 | +console.log(`Applying Prisma migrations to the run-ops database (${redact(databaseUrl)})`); |
| 55 | + |
| 56 | +const result = spawnSync("prisma", ["migrate", "deploy"], { |
| 57 | + cwd: dbPackageRoot, |
| 58 | + stdio: "inherit", |
| 59 | + env: { ...process.env, DATABASE_URL: databaseUrl, DIRECT_URL: directUrl }, |
| 60 | +}); |
| 61 | + |
| 62 | +process.exit(result.status ?? 1); |
0 commit comments