fix: harden CI evidence and removal contracts

This commit is contained in:
DongHyeonka
2026-08-02 14:48:04 +09:00
parent 1bb2cc4a20
commit f49d147b01
20 changed files with 1175 additions and 767 deletions
+47 -30
View File
@@ -1,25 +1,30 @@
import { spawnSync } from "node:child_process";
import {
access,
cp,
mkdir,
mkdtemp,
readFile,
readdir,
rm,
symlink,
writeFile,
} from "node:fs/promises";
import path from "node:path";
import { isProductionModulePath } from "./lib/risk-coverage.ts";
import {
filesBelow,
prepareRemovalFixture,
pruneRemovalFixtureCiContract,
pruneScriptOrchestration,
regenerateRemovalFixtureWorkflow,
requireRemovalFixtureEnvironment,
runRemovalFixturePnpm,
} from "./lib/removal-fixture.ts";
const fixtureParent = path.resolve(".tmp");
await mkdir(fixtureParent, { recursive: true });
const fixtureRoot = await mkdtemp(
path.join(fixtureParent, "reference-feature-removal-"),
);
const pnpmCli = requireEnvironment("npm_execpath");
const pnpmCli = requireRemovalFixtureEnvironment("npm_execpath");
const featureSource = "src/features/reference-feature";
const featureTests = "tests/features/reference-feature";
const commonTestPaths = [
@@ -162,36 +167,20 @@ type GovernanceRegistry = Record<string, unknown> & {
};
type RemovalGovernance = { registries: GovernanceRegistry[] };
function requireEnvironment(name: string): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required for sample removal`);
return value;
}
async function filesBelow(directory: string): Promise<string[]> {
const entries = await readdir(directory, { withFileTypes: true });
const groups = await Promise.all(
entries.map((entry) => {
const target = path.join(directory, entry.name);
return entry.isDirectory() ? filesBelow(target) : [target];
}),
);
return groups.flat();
}
function runPnpm(script: string, extra: string[] = []): boolean {
const result = spawnSync(process.execPath, [pnpmCli, script, ...extra], {
cwd: fixtureRoot,
stdio: "inherit",
});
return result.status === 0;
return runRemovalFixturePnpm(fixtureRoot, pnpmCli, script, extra);
}
try {
for (const target of copyTargets) {
await cp(target, path.join(fixtureRoot, target), { recursive: true });
await prepareRemovalFixture(fixtureRoot, copyTargets);
for (const excludedFixtureTest of [
"tests/unit/ci-workflow-generation.test.ts",
"tests/unit/__snapshots__/ci-workflow-generation.test.ts.snap",
"tests/unit/removal-fixture.test.ts",
"tests/unit/http-scenario-evidence.test.ts",
]) {
await rm(path.join(fixtureRoot, excludedFixtureTest), { force: true });
}
await symlink(path.resolve("node_modules"), path.join(fixtureRoot, "node_modules"), "dir");
const coveragePolicyFile = path.join(
fixtureRoot,
@@ -329,6 +318,33 @@ try {
`${JSON.stringify(removalGovernance, null, 2)}\n`,
);
const removedCiScripts = new Set([
"check:types:fixture:feature-input",
"check:types:fixture:reference-operation",
"test:http-scenario-evidence",
"test:reference-feature",
]);
const fixturePackagePath = path.join(fixtureRoot, "package.json");
const fixturePackage = JSON.parse(await readFile(fixturePackagePath, "utf8")) as {
scripts: Record<string, string>;
};
pruneScriptOrchestration(fixturePackage.scripts, "test:all", removedCiScripts);
fixturePackage.scripts["test:coverage"] = fixturePackage.scripts["test:coverage"]
.replace(" tests/features/reference-feature", "");
delete fixturePackage.scripts["check:http-scenario-evidence"];
delete fixturePackage.scripts["check:http-scenario-evidence:fixture"];
await writeFile(fixturePackagePath, `${JSON.stringify(fixturePackage, null, 2)}\n`);
await pruneRemovalFixtureCiContract({
root: fixtureRoot,
removedScripts: removedCiScripts,
removedEvidencePathFragments: [
"reference-feature.xml",
"http-scenario-executions",
"http-scenario-evidence",
],
});
await regenerateRemovalFixtureWorkflow(fixtureRoot);
const residue: string[] = [];
for (const root of ["src", "tests"]) {
for (const file of await filesBelow(path.join(fixtureRoot, root))) {
@@ -366,6 +382,7 @@ try {
["unit-integration", runPnpm("test:all")],
["coverage", runPnpm("test:coverage")],
["test-evidence-source", runPnpm("check:test-evidence:source")],
["ci-contract", runPnpm("check:ci")],
[
"home-smoke",
runPnpm("exec", [