test: complete WP4-07 visual and performance budgets
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 2m34s
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 2m34s
This commit is contained in:
+43
-21
@@ -2,12 +2,19 @@ import { createHash } from "node:crypto";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
|
||||
import { WP4_07_RED_RESOURCE_VERSION, WP4_07_SOURCE_HASHES, assertWp407Fixture } from "../../tests/visual-performance/wp4-07-fixture.mjs";
|
||||
import {
|
||||
WP4_07_REAL_RESOURCE_VERSIONS,
|
||||
WP4_07_RED_RESOURCE_VERSION,
|
||||
WP4_07_SOURCE_HASHES,
|
||||
assertWp407Fixture,
|
||||
} from "../../tests/visual-performance/wp4-07-fixture.mjs";
|
||||
|
||||
export const WP4_07_REQUIRED_WP5_TASKS = Object.freeze(
|
||||
Array.from({ length: 7 }, (_, index) => `TASK-WP5-0${index + 1}`),
|
||||
);
|
||||
export const WP4_07_FINAL_WP5_BRANCH = "codex/wp5-07";
|
||||
export const WP4_07_REQUIRED_WP5_BRANCHES = Object.freeze(
|
||||
Array.from({ length: 5 }, (_, index) => `codex/wp5-0${index + 3}`),
|
||||
);
|
||||
|
||||
export function validateWp407FrozenInputs() {
|
||||
const mismatches = [];
|
||||
@@ -27,25 +34,40 @@ export function validateWp407FrozenInputs() {
|
||||
return assertWp407Fixture();
|
||||
}
|
||||
|
||||
export function inspectWp5TaskLineage(heads, commits) {
|
||||
function subjectMatchesTask(subject, taskId) {
|
||||
const shortId = taskId.replace("TASK-", "");
|
||||
return subject.includes(taskId) || subject.includes(shortId);
|
||||
}
|
||||
|
||||
export function inspectWp5TaskLineage(heads, histories) {
|
||||
const candidate_branch = [...WP4_07_REQUIRED_WP5_TASKS]
|
||||
.reverse()
|
||||
.map((taskId) => taskId.replace("TASK-WP5-", "codex/wp5-"))
|
||||
.find((branch) => /^[0-9a-f]{40}$/.test(heads[branch] ?? "")) ?? null;
|
||||
const allCommits = Object.values(histories).flat();
|
||||
const task_shas = Object.fromEntries(WP4_07_REQUIRED_WP5_TASKS.flatMap((taskId) => {
|
||||
const commit = commits.find((entry) => entry.subject.includes(taskId));
|
||||
const commit = allCommits.find((entry) => subjectMatchesTask(entry.subject, taskId));
|
||||
return commit && /^[0-9a-f]{40}$/.test(commit.sha) ? [[taskId, commit.sha]] : [];
|
||||
}));
|
||||
const missing_tasks = WP4_07_REQUIRED_WP5_TASKS.filter((taskId) => !task_shas[taskId]);
|
||||
const missing_tasks = WP4_07_REQUIRED_WP5_TASKS.filter((taskId) => {
|
||||
const taskNumber = Number(taskId.slice(-2));
|
||||
if (taskNumber <= 2) return !task_shas[taskId];
|
||||
const branch = taskId.replace("TASK-WP5-", "codex/wp5-");
|
||||
return !/^[0-9a-f]{40}$/.test(heads[branch] ?? "")
|
||||
|| !(histories[branch] ?? []).some((entry) => subjectMatchesTask(entry.subject, taskId));
|
||||
});
|
||||
const terminal_branch_shas = Object.fromEntries(WP4_07_REQUIRED_WP5_BRANCHES.flatMap((branch) => (
|
||||
/^[0-9a-f]{40}$/.test(heads[branch] ?? "") ? [[branch, heads[branch]]] : []
|
||||
)));
|
||||
return {
|
||||
candidate_baseline_branch: candidate_branch,
|
||||
candidate_baseline_sha: candidate_branch ? heads[candidate_branch] : null,
|
||||
complete: candidate_branch === WP4_07_FINAL_WP5_BRANCH && missing_tasks.length === 0,
|
||||
final_branch_sha: heads[WP4_07_FINAL_WP5_BRANCH] ?? null,
|
||||
complete: missing_tasks.length === 0 && Object.keys(terminal_branch_shas).length === WP4_07_REQUIRED_WP5_BRANCHES.length,
|
||||
missing_tasks,
|
||||
required_final_branch: WP4_07_FINAL_WP5_BRANCH,
|
||||
required_final_branches: WP4_07_REQUIRED_WP5_BRANCHES,
|
||||
required_tasks: WP4_07_REQUIRED_WP5_TASKS,
|
||||
task_shas,
|
||||
terminal_branch_shas,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,32 +82,28 @@ export function readWp5RemoteGate() {
|
||||
const [sha, reference] = line.split(/\s+/);
|
||||
return [reference.replace("refs/heads/", ""), sha];
|
||||
}));
|
||||
const candidateBranch = [...WP4_07_REQUIRED_WP5_TASKS]
|
||||
.reverse()
|
||||
.map((taskId) => taskId.replace("TASK-WP5-", "codex/wp5-"))
|
||||
.find((branch) => /^[0-9a-f]{40}$/.test(heads[branch] ?? ""));
|
||||
let commits = [];
|
||||
if (candidateBranch) {
|
||||
const fetch = spawnSync("git", ["fetch", "--quiet", "--no-tags", "origin", `refs/heads/${candidateBranch}`], { encoding: "utf8", timeout: 60_000 });
|
||||
const histories = {};
|
||||
for (const branch of WP4_07_REQUIRED_WP5_BRANCHES.filter((name) => /^[0-9a-f]{40}$/.test(heads[name] ?? ""))) {
|
||||
const fetch = spawnSync("git", ["fetch", "--quiet", "--no-tags", "origin", `refs/heads/${branch}`], { encoding: "utf8", timeout: 60_000 });
|
||||
if ((fetch.status ?? 1) !== 0) {
|
||||
const error = new Error("WP4_07_GITEA_BASELINE_FETCH_FAILED");
|
||||
error.details = { branch: candidateBranch, exit_code: fetch.status ?? 1 };
|
||||
error.details = { branch, exit_code: fetch.status ?? 1 };
|
||||
throw error;
|
||||
}
|
||||
const log = spawnSync("git", ["log", "--format=%H%x09%s", heads[candidateBranch]], { encoding: "utf8", timeout: 30_000 });
|
||||
const log = spawnSync("git", ["log", "--format=%H%x09%s", heads[branch]], { encoding: "utf8", timeout: 30_000 });
|
||||
if ((log.status ?? 1) !== 0) {
|
||||
const error = new Error("WP4_07_GITEA_BASELINE_HISTORY_UNREADABLE");
|
||||
error.details = { branch: candidateBranch, exit_code: log.status ?? 1 };
|
||||
error.details = { branch, exit_code: log.status ?? 1 };
|
||||
throw error;
|
||||
}
|
||||
commits = log.stdout.trim().split(/\r?\n/).filter(Boolean).map((line) => {
|
||||
histories[branch] = log.stdout.trim().split(/\r?\n/).filter(Boolean).map((line) => {
|
||||
const separator = line.indexOf("\t");
|
||||
return { sha: line.slice(0, separator), subject: line.slice(separator + 1) };
|
||||
});
|
||||
}
|
||||
return {
|
||||
heads,
|
||||
...inspectWp5TaskLineage(heads, commits),
|
||||
...inspectWp5TaskLineage(heads, histories),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -94,10 +112,14 @@ export function validateWp5FinalManifest(path) {
|
||||
const raw = readFileSync(path, "utf8");
|
||||
if (raw.includes(WP4_07_RED_RESOURCE_VERSION) || raw.includes("fixture-v1")) throw new Error("WP4_07_PLACEHOLDER_ASSET_REJECTED");
|
||||
const manifest = JSON.parse(raw);
|
||||
const expectedCounts = { color_cards: 4, dynamic_stickers: 10, static_parts: 25, static_stickers: 1_407, text_templates: 32 };
|
||||
const expectedCounts = { color_cards: 4, dynamic_stickers: 10, font_panel_items: 11, static_parts: 25, static_stickers: 1_407, text_templates: 32 };
|
||||
for (const [key, expected] of Object.entries(expectedCounts)) {
|
||||
if (manifest.counts?.[key] !== expected) throw new Error(`WP4_07_FINAL_MANIFEST_COUNT_MISMATCH:${key}`);
|
||||
}
|
||||
if (!manifest.release_version || String(manifest.release_version).includes("fixture")) throw new Error("WP4_07_FINAL_RELEASE_VERSION_REQUIRED");
|
||||
if (manifest.source_versions?.complex !== WP4_07_REAL_RESOURCE_VERSIONS.complex
|
||||
|| manifest.source_versions?.static_stickers !== WP4_07_REAL_RESOURCE_VERSIONS.static) {
|
||||
throw new Error("WP4_07_FINAL_MANIFEST_VERSION_MISMATCH");
|
||||
}
|
||||
return { release_version: manifest.release_version, sha256: createHash("sha256").update(raw).digest("hex").toUpperCase() };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user