feat(platform): checkpoint current implementation state

This commit is contained in:
2026-04-01 07:42:03 +02:00
parent 3e53471f05
commit 8c5be51251
125 changed files with 10269 additions and 17808 deletions
+68 -8
View File
@@ -1,4 +1,5 @@
import { spawn } from "node:child_process";
import { randomBytes } from "node:crypto";
import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
import { createServer } from "node:net";
import { dirname, resolve } from "node:path";
@@ -7,12 +8,16 @@ import { fileURLToPath } from "node:url";
const currentDir = dirname(fileURLToPath(import.meta.url));
const workspaceRoot = resolve(currentDir, "../../..");
const webRoot = resolve(currentDir, "..");
const runtimeEnvPath = resolve(currentDir, ".playwright-runtime.json");
const webEnvLocal = resolve(webRoot, ".env.local");
const webEnvBackup = resolve(webRoot, ".env.local.e2e-backup");
const webDistDir = ".next-e2e";
const webDistDirPath = resolve(webRoot, webDistDir);
const managedEnvBanner = "# Managed by apps/web/e2e/test-server.mjs";
const e2ePort = process.env.PLAYWRIGHT_TEST_PORT ?? "3110";
const e2eBaseUrl = process.env.PLAYWRIGHT_TEST_BASE_URL ?? `http://localhost:${e2ePort}`;
const e2eAuthSecret = process.env.PLAYWRIGHT_AUTH_SECRET ?? `capakraken-e2e-${randomBytes(24).toString("hex")}`;
const manageWebEnvFile = process.env.PLAYWRIGHT_MANAGE_WEB_ENV_FILE === "true";
const composeProjectName = `capakraken-e2e-${process.pid}`;
const managedEnvKeys = [
"DATABASE_URL",
@@ -68,12 +73,24 @@ function applyEnv(env) {
}
function writeManagedWebEnv(rootEnv) {
if (existsSync(webEnvBackup)) {
if (!manageWebEnvFile) {
restoreWebEnv();
return;
}
if (existsSync(webEnvBackup) && isManagedEnvFile(webEnvBackup)) {
rmSync(webEnvBackup, { force: true });
}
if (existsSync(webEnvLocal)) {
renameSync(webEnvLocal, webEnvBackup);
if (isManagedEnvFile(webEnvLocal)) {
rmSync(webEnvLocal, { force: true });
} else {
if (existsSync(webEnvBackup)) {
rmSync(webEnvBackup, { force: true });
}
renameSync(webEnvLocal, webEnvBackup);
}
}
const contents = managedEnvKeys
@@ -84,16 +101,41 @@ function writeManagedWebEnv(rootEnv) {
.filter(Boolean)
.join("\n");
writeFileSync(webEnvLocal, `${contents}\n`, "utf8");
writeFileSync(webEnvLocal, `${managedEnvBanner}\n${contents}\n`, "utf8");
}
function restoreWebEnv() {
if (existsSync(webEnvLocal)) {
if (existsSync(webEnvLocal) && isManagedEnvFile(webEnvLocal)) {
rmSync(webEnvLocal, { force: true });
}
if (existsSync(webEnvBackup)) {
renameSync(webEnvBackup, webEnvLocal);
if (isManagedEnvFile(webEnvBackup)) {
rmSync(webEnvBackup, { force: true });
} else {
renameSync(webEnvBackup, webEnvLocal);
}
}
}
let restoredManagedEnv = false;
function restoreWebEnvOnce() {
if (restoredManagedEnv) {
return;
}
restoredManagedEnv = true;
restoreWebEnv();
rmSync(runtimeEnvPath, { force: true });
}
function isManagedEnvFile(filePath) {
try {
const contents = readFileSync(filePath, "utf8");
return contents.includes(managedEnvBanner) || contents.includes("E2E_TEST_MODE=true");
} catch {
return false;
}
}
@@ -307,15 +349,33 @@ if (!/(^|_)(test|e2e|ci)$/u.test(playwrightDatabaseName)) {
process.env.DATABASE_URL = playwrightDatabaseUrl;
process.env.PLAYWRIGHT_DATABASE_URL = playwrightDatabaseUrl;
process.env.POSTGRES_TEST_PORT = String(selectedTestDbPort);
process.env.CAPAKRAKEN_EXPECTED_DB_NAME = playwrightDatabaseName;
process.env.ALLOW_DESTRUCTIVE_DB_TOOLS = "true";
process.env.CONFIRM_DESTRUCTIVE_DB_NAME = playwrightDatabaseName;
process.env.NODE_ENV = process.env.NODE_ENV ?? "development";
process.env.PORT = e2ePort;
process.env.NEXTAUTH_URL = e2eBaseUrl;
process.env.AUTH_URL = e2eBaseUrl;
process.env.NEXTAUTH_SECRET = e2eAuthSecret;
process.env.AUTH_SECRET = e2eAuthSecret;
process.env.NEXT_DIST_DIR = webDistDir;
process.env.E2E_TEST_MODE = "true";
writeFileSync(
runtimeEnvPath,
JSON.stringify(
{
DATABASE_URL: process.env.DATABASE_URL,
PLAYWRIGHT_DATABASE_URL: process.env.PLAYWRIGHT_DATABASE_URL,
POSTGRES_TEST_PORT: process.env.POSTGRES_TEST_PORT,
BASE_URL: e2eBaseUrl,
},
null,
2,
),
"utf8",
);
writeManagedWebEnv(rootEnv);
process.on("exit", restoreWebEnvOnce);
try {
await cleanupStaleE2eArtifacts();
@@ -333,19 +393,19 @@ try {
for (const signal of ["SIGINT", "SIGTERM"]) {
process.on(signal, () => {
restoreWebEnv();
restoreWebEnvOnce();
void cleanupComposeProject();
server.kill(signal);
});
}
server.on("exit", async (code) => {
restoreWebEnv();
restoreWebEnvOnce();
await cleanupComposeProject();
process.exit(code ?? 0);
});
} catch (error) {
restoreWebEnv();
restoreWebEnvOnce();
await cleanupComposeProject();
throw error;
}