mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-27 23:27:09 +09:00
## Outcome Builder development, backend, E2E, and CI tooling now share one ownership model: Builder defines named commands and backend modes, while CI only schedules those commands. ## Technical choices - Group shared Compose files, PostgreSQL initialization, and backend helpers under `apps/builder/backend`. - Resolve `compose.<mode>.yaml` by convention instead of maintaining Compose filename lists in scripts and workflows. - Keep persistent development and disposable test Compose projects separate by default, while allowing the standard `COMPOSE_PROJECT_NAME` override. - Make schema snapshots invalidate from discovered migration sources and backend files. - Move E2E behavior recipes into named Builder commands; retain concise root proxies for developer entry points. - Let Vitest allocate available browser ports instead of maintaining a cross-package port registry. - Keep test-suite scheduling explicit in `main.yml`, but move executable test commands to root package scripts. - Move fixture-size enforcement from inline GitHub JavaScript into a locally runnable repository script. ## Todo - [x] Consolidate Builder backend and Compose ownership. - [x] Add named development, E2E, schema-cache, Supabase, and CI-shard commands. - [x] Remove Compose topology and behavior flags from CI. - [x] Remove the static Vitest browser-port registry. - [x] Extract fixture-size checking from the workflow. - [x] Verify migration bootstrap, snapshot-backed E2E, tests, builds, types, formatting, lint, generated contracts, and workflow syntax. - [x] Review documentation impact: updated the E2E developer guide; no user-facing `docs/` content is affected. ## Verification - Full package, CLI, Builder core, and Builder app test suites - Full workspace typecheck - Builder production build - Schema-cache generation through the complete migration history - Supabase migration compatibility - Snapshot-backed Playwright animation workflow - Backend regression tests, including demonstrated fail/pass coverage - All four Compose mode configurations - `oxfmt`, `oxlint`, package boundaries, generated API, and generated docs checks - `actionlint` and Bash syntax checks The fixture-size checker preserves the existing Linux `du` thresholds. Its three inputs build locally; macOS allocation sizes are not directly comparable to the Linux CI thresholds, so CI remains the authoritative size result.
121 lines
3.2 KiB
TypeScript
121 lines
3.2 KiB
TypeScript
import { execFile } from "node:child_process";
|
|
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { afterEach, expect, test } from "vitest";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
const backendLibrary = join(import.meta.dirname, "lib.sh");
|
|
const temporaryDirectories: string[] = [];
|
|
|
|
const createRepositoryFixture = async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "webstudio-builder-backend-"));
|
|
temporaryDirectories.push(root);
|
|
await mkdir(join(root, "packages/prisma-client/prisma/migrations/initial"), {
|
|
recursive: true,
|
|
});
|
|
await mkdir(join(root, "apps/builder/backend"), { recursive: true });
|
|
await writeFile(
|
|
join(
|
|
root,
|
|
"packages/prisma-client/prisma/migrations/initial/migration.sql"
|
|
),
|
|
"SELECT 1;"
|
|
);
|
|
await writeFile(join(root, "apps/builder/backend/compose.yaml"), "services:");
|
|
await writeFile(
|
|
join(root, "apps/builder/backend/compose.development.yaml"),
|
|
"services:"
|
|
);
|
|
await writeFile(
|
|
join(root, "apps/builder/backend/compose.test.yaml"),
|
|
"services:"
|
|
);
|
|
return root;
|
|
};
|
|
|
|
const readSchemaFingerprint = async (root: string) => {
|
|
const { stdout } = await execFileAsync(
|
|
"bash",
|
|
[
|
|
"-c",
|
|
'source "$1"; ROOT_DIR="$2"; builder_backend_schema_fingerprint',
|
|
"bash",
|
|
backendLibrary,
|
|
root,
|
|
],
|
|
{ cwd: root }
|
|
);
|
|
return stdout.trim();
|
|
};
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
temporaryDirectories
|
|
.splice(0)
|
|
.map((directory) => rm(directory, { recursive: true, force: true }))
|
|
);
|
|
});
|
|
|
|
test("schema fingerprint includes new backend files", async () => {
|
|
const root = await createRepositoryFixture();
|
|
const before = await readSchemaFingerprint(root);
|
|
|
|
await writeFile(join(root, "apps/builder/backend/init.sql"), "SELECT 2;");
|
|
|
|
expect(await readSchemaFingerprint(root)).not.toBe(before);
|
|
});
|
|
|
|
test("backend modes select safe Compose projects", async () => {
|
|
const root = await createRepositoryFixture();
|
|
const readProjectName = async (mode: "development" | "test") => {
|
|
const { stdout } = await execFileAsync(
|
|
"bash",
|
|
[
|
|
"-c",
|
|
[
|
|
"unset COMPOSE_PROJECT_NAME",
|
|
'source "$1"',
|
|
'ROOT_DIR="$2"',
|
|
'builder_backend_init "$3"',
|
|
'printf "%s" "$COMPOSE_PROJECT_NAME"',
|
|
].join("; "),
|
|
"bash",
|
|
backendLibrary,
|
|
root,
|
|
mode,
|
|
],
|
|
{ cwd: root }
|
|
);
|
|
return stdout;
|
|
};
|
|
|
|
expect(await readProjectName("development")).toBe("builder");
|
|
expect(await readProjectName("test")).toBe("builder-e2e");
|
|
});
|
|
|
|
test("migration bootstrap requires the Builder schema", async () => {
|
|
const root = await createRepositoryFixture();
|
|
|
|
await expect(
|
|
execFileAsync(
|
|
"bash",
|
|
[
|
|
"-c",
|
|
[
|
|
'source "$1"',
|
|
'ROOT_DIR="$2"',
|
|
"pnpm() { :; }",
|
|
"builder_backend_schema_exists() { return 1; }",
|
|
"builder_backend_migrate",
|
|
].join("; "),
|
|
"bash",
|
|
backendLibrary,
|
|
root,
|
|
],
|
|
{ cwd: root }
|
|
)
|
|
).rejects.toThrow("Migrations completed without creating the Builder schema");
|
|
});
|