ci: skip no-op changed-scope fanout

This commit is contained in:
Peter Steinberger
2026-04-23 00:15:40 +01:00
parent 44965bf63c
commit da9700903c
2 changed files with 70 additions and 18 deletions

View File

@@ -3,6 +3,26 @@ import { appendFileSync } from "node:fs";
/** @typedef {{ runNode: boolean; runMacos: boolean; runAndroid: boolean; runWindows: boolean; runSkillsPython: boolean; runChangedSmoke: boolean; runControlUiI18n: boolean }} ChangedScope */
const FULL_SCOPE = {
runNode: true,
runMacos: true,
runAndroid: true,
runWindows: true,
runSkillsPython: true,
runChangedSmoke: true,
runControlUiI18n: true,
};
const EMPTY_SCOPE = {
runNode: false,
runMacos: false,
runAndroid: false,
runWindows: false,
runSkillsPython: false,
runChangedSmoke: false,
runControlUiI18n: false,
};
const DOCS_PATH_RE = /^(docs\/|.*\.mdx?$)/;
const SKILLS_PYTHON_SCOPE_RE = /^(skills\/|pyproject\.toml$)/;
const INSTALL_SMOKE_WORKFLOW_SCOPE_RE = /^\.github\/workflows\/install-smoke\.yml$/;
@@ -183,27 +203,11 @@ if (isDirectRun()) {
try {
const changedPaths = listChangedPaths(args.base, args.head);
if (changedPaths.length === 0) {
writeGitHubOutput({
runNode: true,
runMacos: true,
runAndroid: true,
runWindows: true,
runSkillsPython: true,
runChangedSmoke: true,
runControlUiI18n: true,
});
writeGitHubOutput(EMPTY_SCOPE);
process.exit(0);
}
writeGitHubOutput(detectChangedScope(changedPaths));
} catch {
writeGitHubOutput({
runNode: true,
runMacos: true,
runAndroid: true,
runWindows: true,
runSkillsPython: true,
runChangedSmoke: true,
runControlUiI18n: true,
});
writeGitHubOutput(FULL_SCOPE);
}
}

View File

@@ -1,3 +1,4 @@
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
@@ -19,6 +20,7 @@ const { detectChangedScope, listChangedPaths } =
};
const markerPaths: string[] = [];
const tempDirs: string[] = [];
afterEach(() => {
for (const markerPath of markerPaths) {
@@ -27,8 +29,25 @@ afterEach(() => {
} catch {}
}
markerPaths.length = 0;
for (const tempDir of tempDirs) {
fs.rmSync(tempDir, { force: true, recursive: true });
}
tempDirs.length = 0;
});
function parseGitHubOutput(output: string): Record<string, string> {
return Object.fromEntries(
output
.trim()
.split("\n")
.filter(Boolean)
.map((line) => {
const separator = line.indexOf("=");
return [line.slice(0, separator), line.slice(separator + 1)];
}),
);
}
describe("detectChangedScope", () => {
it("fails safe when no paths are provided", () => {
expect(detectChangedScope([])).toEqual({
@@ -333,4 +352,33 @@ describe("detectChangedScope", () => {
expect(() => listChangedPaths(injectedBase, "HEAD")).toThrow();
expect(fs.existsSync(markerPath)).toBe(false);
});
it("keeps direct CLI preflight empty diffs as no-op scope", () => {
const repoDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-ci-scope-empty-"));
tempDirs.push(repoDir);
const outputPath = path.join(repoDir, "github-output.txt");
const scriptPath = path.resolve("scripts/ci-changed-scope.mjs");
execFileSync("git", ["init", "-b", "main"], { cwd: repoDir });
execFileSync("git", ["config", "user.email", "ci@example.invalid"], { cwd: repoDir });
execFileSync("git", ["config", "user.name", "CI"], { cwd: repoDir });
fs.writeFileSync(path.join(repoDir, "README.md"), "test\n", "utf8");
execFileSync("git", ["add", "README.md"], { cwd: repoDir });
execFileSync("git", ["commit", "-m", "test"], { cwd: repoDir });
execFileSync(process.execPath, [scriptPath, "--base", "HEAD", "--head", "HEAD"], {
cwd: repoDir,
env: { ...process.env, GITHUB_OUTPUT: outputPath },
});
expect(parseGitHubOutput(fs.readFileSync(outputPath, "utf8"))).toEqual({
run_node: "false",
run_macos: "false",
run_android: "false",
run_windows: "false",
run_skills_python: "false",
run_changed_smoke: "false",
run_control_ui_i18n: "false",
});
});
});