Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/scripts/verify-workflow-node-runtime.test.mjs
T

131 lines
5.0 KiB
JavaScript

import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, it } from "vitest";
import { inspectWorkflowNodeRuntime, verifyWorkflowNodeRuntime } from "./verify-workflow-node-runtime.mjs";
const temporaryDirectories = [];
const setupNodeStep = [
" - name: Set up Node.js",
" uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4",
" with:",
" node-version-file: .nvmrc",
].join("\n");
const persistNodeStep = [" - name: Persist Node.js toolchain", " run: bash scripts/ci/persist-node-toolchain.sh"].join("\n");
const corepackSteps = [
" - name: Enable Corepack",
" run: corepack enable --install-directory /usr/local/bin",
" - name: Prepare pnpm 11.12.0",
" run: corepack prepare pnpm@11.12.0 --activate",
].join("\n");
afterEach(() => {
for (const directory of temporaryDirectories.splice(0)) {
fs.rmSync(directory, { recursive: true, force: true });
}
});
function validWorkflow(extraSteps = "") {
return [
"name: CI",
"jobs:",
" verify:",
" runs-on: ubuntu-latest",
" steps:",
setupNodeStep,
persistNodeStep,
corepackSteps,
extraSteps,
" - name: Install dependencies",
" run: pnpm install --frozen-lockfile",
]
.filter(Boolean)
.join("\n");
}
function createRepository(workflow = validWorkflow()) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "hivegrid-workflow-node-"));
temporaryDirectories.push(root);
fs.mkdirSync(path.join(root, ".gitea/workflows"), { recursive: true });
fs.mkdirSync(path.join(root, "apps/hocuspocus"), { recursive: true });
fs.mkdirSync(path.join(root, "scripts/ci"), { recursive: true });
fs.writeFileSync(path.join(root, ".nvmrc"), "v24.18.0\n");
fs.writeFileSync(path.join(root, "Dockerfile"), "FROM node:24.18.0-bookworm-slim@sha256:abc\n");
fs.writeFileSync(path.join(root, "apps/hocuspocus/Dockerfile"), "FROM node:24.18.0-bookworm-slim@sha256:def\n");
fs.writeFileSync(path.join(root, ".gitea/workflows/ci.yml"), workflow);
fs.writeFileSync(
path.join(root, "scripts/ci/persist-node-toolchain.sh"),
[
".nvmrc",
"RUNNER_TOOL_CACHE",
'ln -sfn "$node_binary" "$install_directory/node"',
'ln -sfn "$corepack_binary" "$install_directory/corepack"',
'actual_version="$("$install_directory/node" --version)"',
].join("\n")
);
return root;
}
describe("workflow Node.js runtime verification", () => {
it("accepts a persistent pinned setup-node runtime before pnpm", () => {
const result = inspectWorkflowNodeRuntime(validWorkflow(), ".gitea/workflows/ci.yml");
assert.deepEqual(result.failures, []);
assert.equal(result.passes.length, 2);
});
it("rejects a pnpm job without setup-node", () => {
const source = validWorkflow().replace(`${setupNodeStep}\n`, "");
const result = inspectWorkflowNodeRuntime(source, ".gitea/workflows/ci.yml");
assert.equal(result.failures.length, 1);
assert.match(result.failures[0], /must run before/);
});
it("rejects setup-node after the first pnpm command", () => {
const source = validWorkflow().replace(`${setupNodeStep}\n`, "") + `\n${setupNodeStep}`;
const result = inspectWorkflowNodeRuntime(source, ".gitea/workflows/ci.yml");
assert.ok(result.failures.some((failure) => failure.includes("must run before")));
});
it("rejects setup-node without the shared version file", () => {
const source = validWorkflow().replace("node-version-file: .nvmrc", 'node-version: "24"');
const result = inspectWorkflowNodeRuntime(source, ".gitea/workflows/ci.yml");
assert.equal(result.failures.length, 1);
assert.match(result.failures[0], /node-version-file/);
});
it("rejects a Gitea job that does not persist setup-node's toolchain", () => {
const source = validWorkflow().replace(`${persistNodeStep}\n`, "");
const result = inspectWorkflowNodeRuntime(source, ".gitea/workflows/ci.yml");
assert.ok(result.failures.some((failure) => failure.includes("persist its runtime")));
});
it("rejects a Gitea Corepack shim outside the persistent tool directory", () => {
const source = validWorkflow().replace("corepack enable --install-directory /usr/local/bin", "corepack enable");
const result = inspectWorkflowNodeRuntime(source, ".gitea/workflows/ci.yml");
assert.ok(result.failures.some((failure) => failure.includes("persistent /usr/local/bin")));
});
it("keeps local, CI, and production Node.js runtimes aligned", () => {
const root = createRepository();
const result = verifyWorkflowNodeRuntime(root);
assert.deepEqual(result.failures, []);
assert.equal(result.passes.length, 6);
});
it("rejects a runtime below pnpm's minimum", () => {
const root = createRepository();
fs.writeFileSync(path.join(root, ".nvmrc"), "v22.12.0\n");
const result = verifyWorkflowNodeRuntime(root);
assert.ok(result.failures.some((failure) => failure.includes("minimum 22.13.0")));
});
});