123 lines
5.5 KiB
JavaScript
123 lines
5.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { execFile } from "node:child_process";
|
|
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import { promisify } from "node:util";
|
|
|
|
import {
|
|
classifyGlobalChange,
|
|
componentModelsForServices,
|
|
createG14CiPlan,
|
|
matchingPaths
|
|
} from "./src/g14-ci-plan-lib.mjs";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
|
|
test("G14 CI planner maps bridge changes to cloud-api only", async () => {
|
|
const repo = await createFixtureRepo();
|
|
await writeFile(path.join(repo, "cmd/hwlab-deepseek-responses-bridge/main.mjs"), "console.log('bridge v2');\n");
|
|
await git(repo, ["add", "."]);
|
|
await git(repo, ["commit", "-m", "change bridge"]);
|
|
|
|
const plan = await createG14CiPlan({ repoRoot: repo, baseRef: "HEAD~1", targetRef: "HEAD" });
|
|
assert.deepEqual(plan.affectedServices, ["hwlab-cloud-api"]);
|
|
assert.equal(plan.reusedServices.includes("hwlab-cloud-web"), true);
|
|
const cloudApi = plan.services.find((service) => service.serviceId === "hwlab-cloud-api");
|
|
assert.equal(cloudApi.affected, true);
|
|
assert.deepEqual(cloudApi.reason, ["component-path-changed"]);
|
|
});
|
|
|
|
test("G14 CI planner treats docs-only changes as no image build", async () => {
|
|
const repo = await createFixtureRepo();
|
|
await mkdir(path.join(repo, "docs/reference"), { recursive: true });
|
|
await writeFile(path.join(repo, "docs/reference/g14-gitops-cicd.md"), "docs v2\n");
|
|
await git(repo, ["add", "."]);
|
|
await git(repo, ["commit", "-m", "change docs"]);
|
|
|
|
const plan = await createG14CiPlan({ repoRoot: repo, baseRef: "HEAD~1", targetRef: "HEAD" });
|
|
assert.deepEqual(plan.affectedServices, []);
|
|
assert.equal(plan.imageBuildRequired, false);
|
|
assert.equal(plan.changedPathSummary.docsOnly, true);
|
|
});
|
|
|
|
test("component model supports CI.json overrides without replacing deploy.json", () => {
|
|
const models = componentModelsForServices(["hwlab-cloud-api"], {
|
|
g14CiPlan: {
|
|
components: {
|
|
"hwlab-cloud-api": {
|
|
componentPaths: ["custom/api/"],
|
|
sharedPaths: ["shared/runtime.mjs"],
|
|
runtimeDeps: ["package.json"]
|
|
}
|
|
}
|
|
}
|
|
});
|
|
assert.deepEqual(models[0].componentPaths, ["custom/api/"]);
|
|
assert.deepEqual(matchingPaths(["custom/api/main.mjs"], models[0].componentPaths), ["custom/api/main.mjs"]);
|
|
});
|
|
|
|
test("planner remains compatible with deploy.k3s.serviceMappings shape", async () => {
|
|
const repo = await createFixtureRepo({ deployServices: false, k3sServiceMappings: true });
|
|
await writeFile(path.join(repo, "cmd/hwlab-deepseek-responses-bridge/main.mjs"), "console.log('bridge v2');\n");
|
|
await git(repo, ["add", "."]);
|
|
await git(repo, ["commit", "-m", "change bridge"]);
|
|
|
|
const plan = await createG14CiPlan({ repoRoot: repo, baseRef: "HEAD~1", targetRef: "HEAD" });
|
|
assert.equal(plan.compatibility.currentRenderCompatible, true);
|
|
assert.equal(plan.compatibility.serviceIdSource, "deploy.k3s.serviceMappings");
|
|
assert.deepEqual(plan.affectedServices, ["hwlab-cloud-api"]);
|
|
assert.equal(plan.inputs.serviceCount, 2);
|
|
});
|
|
|
|
test("global change classifier distinguishes gitops-only and test-only", () => {
|
|
assert.equal(classifyGlobalChange(["deploy/gitops/g14/runtime-dev/workloads.yaml"]).gitopsOnly, true);
|
|
assert.equal(classifyGlobalChange(["cmd/hwlab-cloud-api/main.test.mjs"]).testOnly, true);
|
|
});
|
|
|
|
async function createFixtureRepo(options = {}) {
|
|
const deployServices = options.deployServices !== false;
|
|
const k3sServiceMappings = options.k3sServiceMappings === true;
|
|
const repo = await mkdtemp(path.join(os.tmpdir(), "hwlab-g14-ci-plan-"));
|
|
await mkdir(path.join(repo, "cmd/hwlab-cloud-api"), { recursive: true });
|
|
await mkdir(path.join(repo, "cmd/hwlab-deepseek-responses-bridge"), { recursive: true });
|
|
await mkdir(path.join(repo, "web/hwlab-cloud-web"), { recursive: true });
|
|
await mkdir(path.join(repo, "deploy"), { recursive: true });
|
|
await writeFile(path.join(repo, "CI.json"), JSON.stringify({ version: 1, commands: [] }, null, 2));
|
|
await writeFile(path.join(repo, "deploy/deploy.json"), JSON.stringify(createDeployFixture({ deployServices, k3sServiceMappings }), null, 2));
|
|
await writeFile(path.join(repo, "package.json"), JSON.stringify({ type: "module" }, null, 2));
|
|
await writeFile(path.join(repo, "package-lock.json"), JSON.stringify({ lockfileVersion: 3 }, null, 2));
|
|
await writeFile(path.join(repo, "cmd/hwlab-cloud-api/main.mjs"), "console.log('api');\n");
|
|
await writeFile(path.join(repo, "cmd/hwlab-deepseek-responses-bridge/main.mjs"), "console.log('bridge');\n");
|
|
await writeFile(path.join(repo, "cmd/hwlab-deepseek-responses-bridge/main.test.mjs"), "console.log('test');\n");
|
|
await writeFile(path.join(repo, "web/hwlab-cloud-web/index.html"), "<html></html>\n");
|
|
await git(repo, ["init"]);
|
|
await git(repo, ["add", "."]);
|
|
await git(repo, ["commit", "-m", "initial"]);
|
|
return repo;
|
|
}
|
|
|
|
function createDeployFixture({ deployServices, k3sServiceMappings }) {
|
|
const deploy = {};
|
|
if (deployServices) {
|
|
deploy.services = [
|
|
{ serviceId: "hwlab-cloud-api" },
|
|
{ serviceId: "hwlab-cloud-web" }
|
|
];
|
|
}
|
|
if (k3sServiceMappings) {
|
|
deploy.k3s = {
|
|
serviceMappings: [
|
|
{ serviceId: "hwlab-cloud-api", name: "hwlab-cloud-api" },
|
|
{ serviceId: "hwlab-cloud-web", name: "hwlab-cloud-web" }
|
|
]
|
|
};
|
|
}
|
|
return deploy;
|
|
}
|
|
|
|
async function git(cwd, args) {
|
|
return execFileAsync("git", ["-c", "user.name=HWLAB Test", "-c", "user.email=hwlab-test@example.invalid", ...args], { cwd });
|
|
}
|