Files
openclaw/test/scripts/write-build-info.test.ts
Peter Steinberger 7fe004d852 feat: show build identity in About screens (#103595)
* feat: show build identity in About screens

* chore: leave root changelog to release automation

* fix: translate Control UI About build details
2026-07-10 10:42:36 +01:00

157 lines
5.0 KiB
TypeScript

// Build info tests cover canonical package provenance generation.
import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
normalizeBuildCommit,
normalizeBuildTimestamp,
resolveBuildInfo,
writeBuildInfo,
} from "../../scripts/write-build-info.ts";
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";
describe("write-build-info", () => {
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
function createPackage(version = "2026.7.10"): string {
const rootDir = tempDirs.make("openclaw-build-info-");
fs.writeFileSync(path.join(rootDir, "package.json"), `${JSON.stringify({ version })}\n`);
return rootDir;
}
it("normalizes explicit release provenance and writes the shared manifest", () => {
const rootDir = createPackage();
const execFileSync = vi.fn(() => {
throw new Error("Git fallback should not run");
});
const outputPath = writeBuildInfo({
rootDir,
env: {
GIT_COMMIT: "ABCDEF0123456789ABCDEF0123456789ABCDEF01",
OPENCLAW_BUILD_TIMESTAMP: "2026-07-10T12:34:56Z",
},
execFileSync,
});
expect(execFileSync).not.toHaveBeenCalled();
expect(path.relative(rootDir, outputPath)).toBe("dist/build-info.json");
expect(JSON.parse(fs.readFileSync(outputPath, "utf8"))).toEqual({
version: "2026.7.10",
commit: "abcdef0123456789abcdef0123456789abcdef01",
builtAt: "2026-07-10T12:34:56.000Z",
});
});
it("falls back to build-time Git and one current UTC timestamp for local builds", () => {
const rootDir = createPackage("2026.7.10-beta.1");
const execFileSync = vi.fn(() => "1234567890ABCDEF1234567890ABCDEF12345678\n");
expect(
resolveBuildInfo({
rootDir,
env: {},
execFileSync,
now: () => new Date("2026-07-10T01:02:03.456Z"),
}),
).toEqual({
version: "2026.7.10-beta.1",
commit: "1234567890abcdef1234567890abcdef12345678",
builtAt: "2026-07-10T01:02:03.456Z",
});
expect(execFileSync).toHaveBeenCalledWith("git", ["rev-parse", "HEAD"], {
cwd: rootDir,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
});
});
it("uses null when Git metadata is unavailable", () => {
const rootDir = createPackage();
expect(
resolveBuildInfo({
rootDir,
env: {},
execFileSync: () => {
throw new Error("git unavailable");
},
now: () => new Date("2026-07-10T01:02:03.000Z"),
}).commit,
).toBeNull();
});
it("preserves GIT_COMMIT then GIT_SHA explicit input precedence", () => {
const rootDir = createPackage();
const fallbackSha = "1234567890abcdef1234567890abcdef12345678";
expect(
resolveBuildInfo({
rootDir,
env: { GIT_SHA: fallbackSha },
now: () => new Date("2026-07-10T01:02:03.000Z"),
}).commit,
).toBe(fallbackSha);
expect(() =>
resolveBuildInfo({
rootDir,
env: { GIT_COMMIT: "bad", GIT_SHA: fallbackSha },
}),
).toThrow("GIT_COMMIT must be a full 40-character Git commit SHA.");
});
it("uses checked-out Git instead of unverified GitHub workflow context", () => {
const rootDir = createPackage();
const checkedOutCommit = "b".repeat(40);
const execFileSync = vi.fn(() => checkedOutCommit);
expect(
resolveBuildInfo({
rootDir,
env: { GITHUB_SHA: "a".repeat(40) },
execFileSync,
now: () => new Date("2026-07-10T01:02:03.000Z"),
}).commit,
).toBe(checkedOutCommit);
expect(execFileSync).toHaveBeenCalledOnce();
expect(
resolveBuildInfo({
rootDir,
env: { GITHUB_SHA: "a".repeat(40) },
execFileSync: () => {
throw new Error("git unavailable");
},
now: () => new Date("2026-07-10T01:02:03.000Z"),
}).commit,
).toBe("a".repeat(40));
expect(() =>
resolveBuildInfo({
rootDir,
env: { GITHUB_SHA: "bad" },
execFileSync: () => {
throw new Error("git unavailable");
},
}),
).toThrow("GITHUB_SHA must be a full 40-character Git commit SHA.");
});
it("rejects abbreviated or malformed explicit commits", () => {
expect(() => normalizeBuildCommit("abc1234")).toThrow(
"GIT_COMMIT must be a full 40-character Git commit SHA.",
);
expect(() => normalizeBuildCommit("g".repeat(40))).toThrow(
"GIT_COMMIT must be a full 40-character Git commit SHA.",
);
});
it("normalizes valid UTC timestamps and rejects offsets or impossible dates", () => {
expect(normalizeBuildTimestamp("2026-07-10T12:34:56.7Z")).toBe("2026-07-10T12:34:56.700Z");
expect(() => normalizeBuildTimestamp("2026-07-10T12:34:56+00:00")).toThrow(
"OPENCLAW_BUILD_TIMESTAMP must be an ISO-8601 UTC timestamp ending in Z.",
);
expect(() => normalizeBuildTimestamp("2026-02-30T12:34:56Z")).toThrow(
"OPENCLAW_BUILD_TIMESTAMP must be a valid ISO-8601 UTC timestamp.",
);
});
});