mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 01:29:56 +00:00
ci: honor the pinned Node version on hosted runners
Resolve hosted 24.x requests through the workflow's existing same-major Node pin, preserving explicit compatibility inputs and self-hosted selection. This keeps runner moves from silently changing the tested runtime patch. No version value changes. Linux owning-config and setup guards, changed checks, boundary lint, and P2 review passed. The repository pin remains 24.21.0.
This commit is contained in:
parent
11c32c4313
commit
84bf30fecf
4 changed files with 54 additions and 9 deletions
2
.github/actions/setup-node-env/action.yml
vendored
2
.github/actions/setup-node-env/action.yml
vendored
|
|
@ -149,7 +149,7 @@ runs:
|
|||
id: setup-node
|
||||
shell: bash
|
||||
env:
|
||||
REQUESTED_NODE_VERSION: ${{ inputs.node-version }}
|
||||
REQUESTED_NODE_VERSION: ${{ runner.environment == 'github-hosted' && inputs.node-version == '24.x' && startsWith(env.NODE_VERSION, '24.') && env.NODE_VERSION || inputs.node-version }}
|
||||
OPENCLAW_NODE_TOOLCHAIN_ROOT: ${{ inputs.cache-mode != 'off' && runner.os != 'Windows' && format('{0}/openclaw-node-toolchain/node', runner.temp) || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@ read_when:
|
|||
|
||||
## Runners
|
||||
|
||||
Hosted Node 24 setup honors the workflow's existing `NODE_VERSION` pin when the
|
||||
setup input is `24.x`. This prevents runner-image refreshes from silently choosing
|
||||
a different patch version. Explicit compatibility versions retain their own
|
||||
selection, and self-hosted setup retains its existing range and toolchain-cache
|
||||
policy. A restored cache key is not runtime proof: record the selected binary and
|
||||
`node -v` when comparing runner backends.
|
||||
|
||||
Runner choice follows contributor trust, not whether a pull request came from a fork. Every `runs-on` expression admits Blacksmith only when `github.event.pull_request.author_association` is `OWNER`, `MEMBER`, `COLLABORATOR`, or `CONTRIBUTOR`, so a fork pull request from someone who has already landed a commit is routed exactly like a maintainer pull request. `FIRST_TIME_CONTRIBUTOR`, `FIRST_TIMER`, `NONE`, and `MANNEQUIN` stay on GitHub-hosted runners, which are free for public repositories, so an unreviewed author cannot spend Blacksmith capacity. Maintainers report `CONTRIBUTOR` here because org membership is concealed; keep `CONTRIBUTOR` in that list or maintainer pull requests lose Blacksmith. Pushes and manual dispatches are unaffected. Cache trust is a separate, stricter boundary: exact dependency restores require a pull request from `openclaw/openclaw`, and ordinary CI never publishes the shared archives. The separate trusted warmer owns publication.
|
||||
|
||||
| Runner | Jobs |
|
||||
|
|
|
|||
|
|
@ -4883,6 +4883,40 @@ setImmediate(() => {
|
|||
}
|
||||
});
|
||||
|
||||
it("uses the workflow Node 24 pin for hosted default requests", () => {
|
||||
const action = parse(readFileSync(".github/actions/setup-node-env/action.yml", "utf8"));
|
||||
const setup: WorkflowStep = expectDefined(
|
||||
action.runs.steps.find((step: WorkflowStep) => step.id === "setup-node"),
|
||||
"Node setup",
|
||||
);
|
||||
const expression = String(
|
||||
expectDefined(setup.env?.REQUESTED_NODE_VERSION, "requested Node version"),
|
||||
)
|
||||
.replace(/^\$\{\{\s*|\s*\}\}$/gu, "")
|
||||
.replaceAll("inputs.node-version", 'inputs["node-version"]');
|
||||
for (const [environment, requested, pin, expected] of [
|
||||
["github-hosted", "24.x", "24.21.0", "24.21.0"],
|
||||
["github-hosted", "24.x", undefined, "24.x"],
|
||||
["github-hosted", "24.x", "", "24.x"],
|
||||
["github-hosted", "24.x", "26.1.0", "24.x"],
|
||||
["github-hosted", "24.16.0", "24.21.0", "24.16.0"],
|
||||
["github-hosted", "26.x", "24.21.0", "26.x"],
|
||||
["self-hosted", "24.x", "24.21.0", "24.x"],
|
||||
["", "24.x", "24.21.0", "24.x"],
|
||||
] as const) {
|
||||
expect(
|
||||
runInNewContext(expression, {
|
||||
runner: { environment },
|
||||
inputs: { "node-version": requested },
|
||||
env: pin === undefined ? {} : { NODE_VERSION: pin },
|
||||
startsWith: (value: unknown, prefix: string) =>
|
||||
typeof value === "string" && value.startsWith(prefix),
|
||||
}),
|
||||
`${environment}/${requested}/${pin ?? "unset"}`,
|
||||
).toBe(expected);
|
||||
}
|
||||
});
|
||||
|
||||
it("owns one exact immutable semantic dependency cache", () => {
|
||||
const actionSource = readFileSync(".github/actions/setup-node-env/action.yml", "utf8");
|
||||
const ciSource = readFileSync(".github/workflows/ci.yml", "utf8");
|
||||
|
|
|
|||
|
|
@ -177,25 +177,29 @@ describe("setup-pnpm-store-cache ensure-node", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("repairs PATH from the toolcache when setup-node leaves an old node active", () => {
|
||||
it.each([
|
||||
{ active: "20.20.0", requested: "24.16.0" },
|
||||
{ active: "24.22.0", requested: "24.21.0" },
|
||||
])("repairs PATH from active Node $active to requested $requested", ({ active, requested }) => {
|
||||
const root = mkdtempSync(join(tmpdir(), "openclaw-ensure-node-"));
|
||||
try {
|
||||
const activeBin = join(root, "active", "bin");
|
||||
writeFakeNode(activeBin, "20.20.0");
|
||||
const toolcacheBin = join(root, "toolcache", "node", "24.16.0", "x64", "bin");
|
||||
const toolcacheNode = writeFakeNode(toolcacheBin, "24.16.0");
|
||||
writeFakeNode(activeBin, active);
|
||||
const toolcacheBin = join(root, "toolcache", "node", requested, "x64", "bin");
|
||||
const toolcacheNode = writeFakeNode(toolcacheBin, requested);
|
||||
writeFakeNode(
|
||||
join(root, "toolcache", "node", "26.1.0", "x64", "lib", "node_modules", "bundled", "bin"),
|
||||
"24.16.0",
|
||||
requested,
|
||||
);
|
||||
const result = runEnsureNode(root, "24.16.0", {
|
||||
const result = runEnsureNode(root, requested, {
|
||||
PATH: `${activeBin}:${process.env.PATH ?? ""}`,
|
||||
OPENCLAW_NODE_TOOLCHAIN_ROOT: join(root, "missing-owned-toolchain"),
|
||||
RUNNER_TOOL_CACHE: join(root, "toolcache"),
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stdout).toContain(`Using Node 24.16.0 from ${toolcacheNode}`);
|
||||
expect(result.stdout).toContain(`${toolcacheNode}\n24.16.0`);
|
||||
expect(result.stdout).toContain(`Using Node ${requested} from ${toolcacheNode}`);
|
||||
expect(result.stdout).toContain(`${toolcacheNode}\n${requested}`);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue