fix(ci): migrate on tag release and wire drizzle schema generate
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
20b85381fe
commit
67656a9aad
5 files changed
+91
No files matched your search
@@ -301,8 +301,27 @@ jobs:
|
||||
export NODE_ENV=production
|
||||
export SKIP_ENV_VALIDATION=1
|
||||
pnpm install --frozen-lockfile
|
||||
# prisma generate only needs a resolvable URL — no live DB connection.
|
||||
export DATABASE_URL="mysql://placeholder:please@localhost/placeholder"
|
||||
pnpm prisma:generate
|
||||
unset DATABASE_URL
|
||||
# Tag releases must apply CMS SQL migrations against the live DB
|
||||
# (same path as push-to-main deploy), using the production .env.
|
||||
LIVE="/var/www/atom-nexst"
|
||||
ln -sfn "${LIVE}/.env" "${WORK}/.env"
|
||||
MIGRATE_OK=0
|
||||
for i in $(seq 1 10); do
|
||||
if pnpm db:migrate; then
|
||||
MIGRATE_OK=1
|
||||
break
|
||||
fi
|
||||
echo "migrate attempt ${i}/10 failed (likely DB connections), retrying..."
|
||||
sleep 5
|
||||
done
|
||||
if [ "${MIGRATE_OK}" != "1" ]; then
|
||||
echo "ERROR: db:migrate failed after retries" >&2
|
||||
exit 1
|
||||
fi
|
||||
pnpm build
|
||||
pm2 restart next --update-env
|
||||
pm2 save
|
||||
|
||||
@@ -164,6 +164,7 @@ The CMS runs behind an nginx reverse proxy on the default port 3000. Static asse
|
||||
| `pnpm test` | Run all tests (Vitest) |
|
||||
| `pnpm db:migrate` | Apply pending SQL migrations |
|
||||
| `pnpm db:migrate:status` | Show migration status |
|
||||
| `pnpm db:schema:generate` | Regen `src/db/schema.ts` from Prisma + live DB (needs `DATABASE_URL`) |
|
||||
| `pnpm prisma:generate` | Regenerate Prisma type stubs (dev only, not prod) |
|
||||
| `pnpm analyze` | Build + open bundle analyzer |
|
||||
| `pnpm jobs:worker` | Start background task worker (systemd / PM2) |
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"test": "vitest run",
|
||||
"db:migrate": "tsx scripts/apply-migrations.ts",
|
||||
"db:migrate:status": "tsx scripts/apply-migrations.ts --status",
|
||||
"db:schema:generate": "node scripts/generate-drizzle-schema.mjs",
|
||||
"jobs:worker": "tsx scripts/jobs-worker.ts",
|
||||
"prepare": "husky"
|
||||
},
|
||||
|
||||
@@ -31,4 +31,14 @@ describe("CI workflow", () => {
|
||||
expect(workflow).toContain("Creating release for");
|
||||
expect(workflow).toContain("startsWith(gitea.ref_name, 'v')");
|
||||
});
|
||||
|
||||
it("applies CMS migrations on tag release before build", () => {
|
||||
const release = workflow.slice(workflow.indexOf("\n release:"));
|
||||
expect(release).toContain("pnpm db:migrate");
|
||||
expect(release).toContain("unset DATABASE_URL");
|
||||
const migrateAt = release.indexOf("pnpm db:migrate");
|
||||
const buildAt = release.indexOf("pnpm build");
|
||||
expect(migrateAt).toBeGreaterThan(-1);
|
||||
expect(buildAt).toBeGreaterThan(migrateAt);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
describe("prisma-facade include contract", () => {
|
||||
const src = readFileSync(
|
||||
resolve(process.cwd(), "src/lib/prisma-facade.ts"),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
it("groups many-relations as arrays (polls/tickets/events)", () => {
|
||||
expect(src).toContain('mode: "one" | "many"');
|
||||
expect(src).toContain('mode === "many"');
|
||||
expect(src).toContain("list.push(cleaned)");
|
||||
expect(src).toContain('"many"');
|
||||
expect(src).toMatch(/queryRelationRows\([\s\S]*?"many"/);
|
||||
});
|
||||
|
||||
it("recurses nested include on related rows", () => {
|
||||
expect(src).toContain("opts.include && related.length > 0");
|
||||
expect(src).toContain(
|
||||
"await attachIncludes(client, rel.referencedTable, related, opts.include)",
|
||||
);
|
||||
});
|
||||
|
||||
it("applies relation where filters when present", () => {
|
||||
expect(src).toContain("buildCondition(rel.referencedTable, opts.where)");
|
||||
});
|
||||
|
||||
it("ships poll/ticket/event drizzle relations used by admin includes", () => {
|
||||
const relations = readFileSync(
|
||||
resolve(process.cwd(), "src/db/relations.ts"),
|
||||
"utf8",
|
||||
);
|
||||
expect(relations).toContain("questions: many(WebsitePollQuestion)");
|
||||
expect(relations).toContain("votes: many(WebsitePollVote)");
|
||||
expect(relations).toContain("messages: many(WebsiteTicketMessage)");
|
||||
expect(relations).toContain("prizes: many(WebsiteEventPrize)");
|
||||
expect(relations).toContain(
|
||||
"registrations: many(WebsiteEventRegistration)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("drizzle schema generate script", () => {
|
||||
it("is wired as pnpm db:schema:generate", () => {
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(resolve(process.cwd(), "package.json"), "utf8"),
|
||||
) as { scripts: Record<string, string> };
|
||||
expect(pkg.scripts["db:schema:generate"]).toContain(
|
||||
"generate-drizzle-schema.mjs",
|
||||
);
|
||||
expect(
|
||||
readFileSync(
|
||||
resolve(process.cwd(), "scripts/generate-drizzle-schema.mjs"),
|
||||
"utf8",
|
||||
),
|
||||
).toContain("Usage: pnpm db:schema:generate");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user