mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
* perf(ci): run the deadcode Knip scans concurrently check-dependencies spent ~194s running seven Knip child processes strictly serially (three package scripts, each iterating its scans). The scans are independent processes over separate configs: both deadcode scripts now Promise.all their scans, the CI task launches the three package scripts concurrently with buffered logs, and the lane moves to the 16 vCPU class for core/memory headroom. The missing-exports-script contract violation now fails fast before launching scans. Local: unused-files 218% CPU, 37s wall. * test(ci): align prerelease plan with the 16 vCPU dependencies lane
137 lines
3.8 KiB
JavaScript
137 lines
3.8 KiB
JavaScript
#!/usr/bin/env node
|
|
// Enforces a hard-zero policy for Knip's unused files.
|
|
import { fileURLToPath } from "node:url";
|
|
import {
|
|
isLikelyRepoFilePath,
|
|
KNIP_MAX_BUFFER_BYTES,
|
|
runKnip,
|
|
uniqueSorted,
|
|
} from "./deadcode-knip-runner.mjs";
|
|
|
|
export { KNIP_MAX_BUFFER_BYTES };
|
|
|
|
const KNIP_COMMON_ARGS = ["--no-progress", "--reporter", "compact", "--files", "--no-config-hints"];
|
|
|
|
const KNIP_SCANS = [
|
|
{
|
|
name: "production unused-file scan",
|
|
args: ["--config", "config/knip.config.ts", "--production"],
|
|
},
|
|
{
|
|
name: "full-tree unused-file scan",
|
|
args: ["--config", "config/knip.all-exports.config.ts"],
|
|
},
|
|
];
|
|
|
|
/** Parses compact Knip output into unused file paths. */
|
|
export function parseKnipCompactUnusedFiles(output) {
|
|
const files = [];
|
|
let inUnusedFilesSection = false;
|
|
let sawUnusedFilesSection = false;
|
|
|
|
for (const line of output.split(/\r?\n/u)) {
|
|
if (/^Unused files \(\d+\)$/u.test(line)) {
|
|
inUnusedFilesSection = true;
|
|
sawUnusedFilesSection = true;
|
|
continue;
|
|
}
|
|
if (inUnusedFilesSection && line.trim() === "") {
|
|
break;
|
|
}
|
|
|
|
const separatorIndex = line.lastIndexOf(": ");
|
|
if (separatorIndex === -1 || (sawUnusedFilesSection && !inUnusedFilesSection)) {
|
|
continue;
|
|
}
|
|
const file = line.slice(separatorIndex + 2).trim();
|
|
if (isLikelyRepoFilePath(file)) {
|
|
files.push(file);
|
|
}
|
|
}
|
|
|
|
return uniqueSorted(files);
|
|
}
|
|
|
|
/** Runs Knip and returns parsed unused-file results. */
|
|
export async function runKnipUnusedFiles(params = {}) {
|
|
return await runKnip([...KNIP_SCANS[0].args, ...KNIP_COMMON_ARGS], {
|
|
...params,
|
|
scanName: KNIP_SCANS[0].name,
|
|
});
|
|
}
|
|
|
|
/** Rejects every unused file reported by Knip. */
|
|
export function checkUnusedFiles(output) {
|
|
const files = parseKnipCompactUnusedFiles(output);
|
|
return {
|
|
ok: files.length === 0,
|
|
files,
|
|
message:
|
|
files.length === 0
|
|
? ""
|
|
: [
|
|
"Unused files are not allowed:",
|
|
...files.map((file) => ` ${file}`),
|
|
"Delete the files or model their real entrypoints in Knip.",
|
|
].join("\n"),
|
|
};
|
|
}
|
|
|
|
/** Validates both Knip process completion and the unused-file report. */
|
|
export function checkKnipUnusedFileScanResult(result) {
|
|
if (result.errorCode || result.status === null || result.status !== 0) {
|
|
return {
|
|
ok: false,
|
|
failureReason: result.errorCode ?? result.signal ?? `exit status ${String(result.status)}`,
|
|
message: "",
|
|
};
|
|
}
|
|
const check = checkUnusedFiles(result.output);
|
|
return { ok: check.ok, failureReason: "", message: check.message };
|
|
}
|
|
|
|
async function main() {
|
|
// The scans are independent Knip child processes over separate configs;
|
|
// running them concurrently halves the lane's serial wall clock.
|
|
const results = await Promise.all(
|
|
KNIP_SCANS.map(async (scan) => ({
|
|
scan,
|
|
result: await runKnip([...scan.args, ...KNIP_COMMON_ARGS], { scanName: scan.name }),
|
|
})),
|
|
);
|
|
for (const { scan, result } of results) {
|
|
if (!reportUnusedFileScan(scan, result)) {
|
|
process.exitCode = 1;
|
|
return;
|
|
}
|
|
}
|
|
console.log("[deadcode] Knip production and full-tree unused-file checks passed with 0 entries.");
|
|
}
|
|
|
|
function reportUnusedFileScan(scan, result) {
|
|
const validation = checkKnipUnusedFileScanResult(result);
|
|
if (validation.failureReason) {
|
|
console.error(
|
|
`deadcode ${scan.name} failed: ${validation.failureReason}${
|
|
result.errorMessage ? `: ${result.errorMessage}` : ""
|
|
}`,
|
|
);
|
|
if (result.output) {
|
|
console.error(result.output);
|
|
}
|
|
return false;
|
|
}
|
|
if (!validation.ok) {
|
|
if (validation.message) {
|
|
console.error(`${scan.name}:\n${validation.message}`);
|
|
}
|
|
return false;
|
|
}
|
|
console.log(`[deadcode] Knip ${scan.name} passed with 0 entries.`);
|
|
return true;
|
|
}
|
|
|
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
await main();
|
|
}
|