Skip to content

Commit 90c4a6f

Browse files
committed
fix(ci): preserve frozen deadcode contracts
1 parent 7c72fef commit 90c4a6f

2 files changed

Lines changed: 114 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,12 +1597,30 @@ jobs:
15971597
fi
15981598
;;
15991599
dependencies)
1600-
if pnpm run --silent 2>/dev/null | grep -q '^ deadcode:dependencies$'; then
1600+
has_package_script() {
1601+
node -e '
1602+
const scripts = require("./package.json").scripts ?? {};
1603+
process.exit(Object.hasOwn(scripts, process.argv[1]) ? 0 : 1);
1604+
' "$1"
1605+
}
1606+
if has_package_script "deadcode:dependencies" &&
1607+
has_package_script "deadcode:unused-files" &&
1608+
has_package_script "deadcode:exports"; then
16011609
pnpm deadcode:dependencies
16021610
pnpm deadcode:unused-files
16031611
pnpm deadcode:exports
1604-
else
1612+
elif [[ "$HISTORICAL_TARGET" == "true" ]] &&
1613+
has_package_script "deadcode:dependencies" &&
1614+
has_package_script "deadcode:unused-files" &&
1615+
has_package_script "deadcode:report:ci:ts-unused"; then
1616+
pnpm deadcode:dependencies
1617+
pnpm deadcode:unused-files
1618+
pnpm deadcode:report:ci:ts-unused
1619+
elif [[ "$HISTORICAL_TARGET" == "true" ]] && has_package_script "deadcode:ci"; then
16051620
pnpm deadcode:ci
1621+
else
1622+
echo "Target does not provide a supported deadcode check." >&2
1623+
exit 1
16061624
fi
16071625
;;
16081626
test-types)

test/scripts/ci-workflow-guards.test.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,55 @@ function writeExecutable(filePath: string, lines: string[]): void {
385385
chmodSync(filePath, 0o755);
386386
}
387387

388+
function runDependencyCheckFixture(options: { historicalTarget: boolean; scripts: string[] }): {
389+
calls: string[];
390+
output: string;
391+
status: number | null;
392+
} {
393+
const root = mkdtempSync(path.join(tmpdir(), "openclaw-ci-deadcode-"));
394+
try {
395+
const fakeBin = path.join(root, "bin");
396+
const callsPath = path.join(root, "pnpm-calls.txt");
397+
mkdirSync(fakeBin);
398+
writeFileSync(
399+
path.join(root, "package.json"),
400+
`${JSON.stringify({
401+
scripts: Object.fromEntries(options.scripts.map((name) => [name, "true"])),
402+
})}\n`,
403+
);
404+
writeExecutable(path.join(fakeBin, "pnpm"), [
405+
"#!/usr/bin/env bash",
406+
"set -euo pipefail",
407+
'printf "%s\\n" "$*" >> "$PNPM_CALLS"',
408+
]);
409+
const checkShardRun = readCiWorkflow().jobs["check-shard"].steps.find(
410+
(step: WorkflowStep) => step.name === "Run check shard",
411+
).run;
412+
const run = spawnSync("bash", ["-c", checkShardRun], {
413+
cwd: root,
414+
encoding: "utf8",
415+
env: {
416+
...process.env,
417+
FORMAT_CHECK: "false",
418+
HISTORICAL_TARGET: options.historicalTarget ? "true" : "false",
419+
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
420+
PNPM_CALLS: callsPath,
421+
PR_BASE_SHA: "",
422+
TASK: "dependencies",
423+
},
424+
});
425+
return {
426+
calls: existsSync(callsPath)
427+
? readFileSync(callsPath, "utf8").trim().split("\n").filter(Boolean)
428+
: [],
429+
output: `${run.stdout}${run.stderr}`,
430+
status: run.status,
431+
};
432+
} finally {
433+
rmSync(root, { force: true, recursive: true });
434+
}
435+
}
436+
388437
function runGeneratedPublisherScenario(
389438
baseChangePath: "a" | "b" | null,
390439
options: {
@@ -1697,6 +1746,45 @@ describe("ci workflow guards", () => {
16971746
expect(preflightGuards).toContain("pnpm deps:patches:check");
16981747
});
16991748

1749+
it("uses the target-owned deadcode contract for current and frozen checkouts", () => {
1750+
const modern = runDependencyCheckFixture({
1751+
historicalTarget: false,
1752+
scripts: ["deadcode:dependencies", "deadcode:unused-files", "deadcode:exports"],
1753+
});
1754+
expect(modern.status, modern.output).toBe(0);
1755+
expect(modern.calls).toEqual([
1756+
"deadcode:dependencies",
1757+
"deadcode:unused-files",
1758+
"deadcode:exports",
1759+
]);
1760+
1761+
const frozen = runDependencyCheckFixture({
1762+
historicalTarget: true,
1763+
scripts: [
1764+
"deadcode:ci",
1765+
"deadcode:dependencies",
1766+
"deadcode:report:ci:ts-unused",
1767+
"deadcode:unused-files",
1768+
],
1769+
});
1770+
expect(frozen.status, frozen.output).toBe(0);
1771+
expect(frozen.calls).toEqual([
1772+
"deadcode:dependencies",
1773+
"deadcode:unused-files",
1774+
"deadcode:report:ci:ts-unused",
1775+
]);
1776+
1777+
const incompleteCurrent = runDependencyCheckFixture({
1778+
historicalTarget: false,
1779+
scripts: ["deadcode:dependencies", "deadcode:unused-files"],
1780+
});
1781+
expect(incompleteCurrent.status).toBe(1);
1782+
expect(incompleteCurrent.calls).toEqual([]);
1783+
expect(incompleteCurrent.output).toContain(
1784+
"Target does not provide a supported deadcode check.",
1785+
);
1786+
});
1787+
17001788
it("runs mobile protocol coverage for Node and native-only changes", () => {
17011789
const workflow = readCiWorkflow();
17021790
const coverageStep = workflow.jobs.preflight.steps.find(
@@ -1978,6 +2066,12 @@ describe("ci workflow guards", () => {
19782066
);
19792067
expect(checkShard.run).toContain("pnpm tsgo:scripts");
19802068
expect(checkShard.run).toContain('elif [[ "$HISTORICAL_TARGET" != "true" ]]');
2069+
expect(checkShard.run).toContain('has_package_script "deadcode:exports"');
2070+
expect(checkShard.run).toContain('has_package_script "deadcode:report:ci:ts-unused"');
2071+
expect(checkShard.run).toContain(
2072+
'elif [[ "$HISTORICAL_TARGET" == "true" ]] && has_package_script "deadcode:ci"',
2073+
);
2074+
expect(checkShard.run).toContain("Target does not provide a supported deadcode check.");
19812075

19822076
const uiInstall = workflow.jobs["checks-ui"].steps.find(
19832077
(step: { name?: string }) => step.name === "Install Playwright Chromium",

0 commit comments

Comments
 (0)