Skip to content

Commit 4200cae

Browse files
committed
feat(dashboard-agent-db): add a pending-migration status check
migrate-status.mjs reports whether the trigger_dashboard_agent schema has unapplied migrations (exit 0 = up to date, 1 = pending), so a deploy pipeline can check before gating and running migrate.mjs. Sibling of migrate.mjs: same connection handling, queries the journal table directly, exposed as db:migrate:status.
1 parent 82bdd1f commit 4200cae

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Pending-status check for the `trigger_dashboard_agent` schema (sibling of
2+
// migrate.mjs). Exit 0 = up to date, 1 = pending, 2 = error.
3+
import { readFileSync } from "node:fs";
4+
import { dirname, join } from "node:path";
5+
import { fileURLToPath } from "node:url";
6+
import postgres from "postgres";
7+
8+
const MIGRATIONS_SCHEMA = "drizzle";
9+
const MIGRATIONS_TABLE = "__dashboard_agent_migrations";
10+
11+
const connectionString = process.env.DASHBOARD_AGENT_DATABASE_URL ?? process.env.DATABASE_URL;
12+
13+
if (!connectionString) {
14+
console.error(
15+
"[dashboard-agent-db] DASHBOARD_AGENT_DATABASE_URL / DATABASE_URL not set; cannot check status."
16+
);
17+
process.exit(2);
18+
}
19+
20+
// Match migrate.mjs: drop the Prisma-style `?schema=` param postgres.js forwards.
21+
function normalizeConnectionString(value) {
22+
try {
23+
const url = new URL(value);
24+
url.searchParams.delete("schema");
25+
return url.toString();
26+
} catch {
27+
return value;
28+
}
29+
}
30+
31+
const journalPath = join(
32+
dirname(fileURLToPath(import.meta.url)),
33+
"drizzle/meta/_journal.json"
34+
);
35+
const sql = postgres(normalizeConnectionString(connectionString), {
36+
max: 1,
37+
prepare: false,
38+
onnotice: () => {},
39+
});
40+
41+
async function main() {
42+
const journal = JSON.parse(readFileSync(journalPath, "utf-8"));
43+
const entries = [...journal.entries].sort((a, b) => a.when - b.when);
44+
45+
let lastAppliedAt = -1;
46+
try {
47+
const rows = await sql`SELECT MAX(created_at)::bigint AS last FROM ${sql(
48+
MIGRATIONS_SCHEMA
49+
)}.${sql(MIGRATIONS_TABLE)}`;
50+
lastAppliedAt = rows[0].last === null ? -1 : Number(rows[0].last);
51+
} catch (err) {
52+
// 42P01: journal table absent (fresh database), so nothing is applied.
53+
if (err.code !== "42P01") throw err;
54+
}
55+
56+
const pending = entries.filter((e) => e.when > lastAppliedAt);
57+
console.log(
58+
`${entries.length} migration(s) found, ${entries.length - pending.length} applied`
59+
);
60+
61+
if (pending.length > 0) {
62+
console.log(`${pending.length} pending migration(s):`);
63+
for (const e of pending) console.log(` - ${e.tag}`);
64+
return 1;
65+
}
66+
67+
console.log("Dashboard agent schema is up to date");
68+
return 0;
69+
}
70+
71+
main()
72+
.then((code) => sql.end({ timeout: 5 }).then(() => process.exit(code)))
73+
.catch((err) => {
74+
console.error(err);
75+
sql.end({ timeout: 5 }).finally(() => process.exit(2));
76+
});

internal-packages/dashboard-agent-db/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"db:generate": "drizzle-kit generate",
1818
"db:migrate": "drizzle-kit migrate",
1919
"db:migrate:deploy": "node migrate.mjs",
20+
"db:migrate:status": "node migrate-status.mjs",
2021
"db:studio": "drizzle-kit studio"
2122
}
2223
}

0 commit comments

Comments
 (0)