Files
oh-my-pi/scripts/bazel-natives.test.ts
T
can1357 8facd237d5 feat(build): migrated native pipeline to bazel with remote caching
- Replaced the napi-cli/cargo-zigbuild/cargo-xwin/sccache build path with
  Bazel: rules_rust + crate_universe over Cargo.lock, hermetic zig cc
  toolchains (linux-gnu pinned to glibc 2.17, linux-musl), host Xcode for
  darwin, and a repo-local hermetic clang-cl + llvm-ml + xwin toolchain for
  windows-msvc (bazel/toolchains/msvc).
- All eight shipped addons build as //:natives-<target> via the release
  transition in bazel/defs.bzl (opt, thin LTO, cgu=16, stripped, canonical
  .node naming); scripts/bazel-natives.ts is the single driver for local
  dev and CI.
- Rust validation moved to bazel test + clippy aspects (strict workspace
  policy for opted-in crates, default lints elsewhere, mirroring cargo
  semantics) and the rustfmt aspect; cargo stays as the dev-iteration
  surface, with brush-core/brush-builtins promoted to workspace members
  and excluded from cargo dev tasks to keep their historical scope.
- CI caches through an in-cluster bazel-remote action cache (TLS + basic
  auth, cluster-internal only); GitHub-hosted runners never touch the
  infrastructure and use an actions/cache-backed disk cache instead.
- Deleted the hand-rolled caching machinery: ci-target-cache,
  ci-native-artifact-cache, ci-build-native, native-source-hash,
  find-native-artifacts, restore-linux-native, native-prewarm workflow,
  ensure-* toolchain actions, and all sccache/Swatinem wiring.
- Warm native rebuilds drop from ~20 minutes to seconds; a cold client
  with a warm remote cache rebuilds the linux x64 pair in ~2.5 minutes.
2026-07-27 12:22:19 +02:00

116 lines
4.7 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import {
conventionOutputPaths,
type HostInfo,
hostTargetName,
parseBazelFilesOutput,
parseCliArgs,
resolveTargetLabels,
} from "./bazel-natives";
const linuxModern: HostInfo = { platform: "linux", arch: "x64", avx2: true };
const linuxBaseline: HostInfo = { platform: "linux", arch: "x64", avx2: false };
const macArm: HostInfo = { platform: "darwin", arch: "arm64", avx2: false };
describe("hostTargetName", () => {
test("picks the x64 variant from AVX2 support", () => {
expect(hostTargetName(linuxModern)).toBe("linux-x64-modern");
expect(hostTargetName(linuxBaseline)).toBe("linux-x64-baseline");
// darwin x64 ships baseline only; AVX2 must not invent a modern target.
expect(hostTargetName({ platform: "darwin", arch: "x64", avx2: true })).toBe("darwin-x64-baseline");
});
test("maps non-x64 and windows hosts", () => {
expect(hostTargetName(macArm)).toBe("darwin-arm64");
expect(hostTargetName({ platform: "linux", arch: "arm64", avx2: false })).toBe("linux-arm64");
expect(hostTargetName({ platform: "win32", arch: "x64", avx2: true })).toBe("win32-x64-baseline");
});
test("rejects hosts without an addon target", () => {
expect(() => hostTargetName({ platform: "freebsd", arch: "x64", avx2: false })).toThrow(
/No pi_natives addon target/,
);
expect(() => hostTargetName({ platform: "win32", arch: "arm64", avx2: false })).toThrow(
/No pi_natives addon target/,
);
});
});
describe("resolveTargetLabels", () => {
test("maps explicit names, pseudo-targets, and aggregates to labels", () => {
expect(resolveTargetLabels(["linux-x64-baseline", "linux-x64-modern"], macArm)).toEqual([
"//:natives-linux-x64-baseline",
"//:natives-linux-x64-modern",
]);
expect(resolveTargetLabels(["host"], linuxModern)).toEqual(["//:natives-linux-x64-modern"]);
expect(resolveTargetLabels(["linux-all", "darwin-all"], macArm)).toEqual([
"//:natives-linux-all",
"//:natives-darwin-all",
]);
});
test("deduplicates and rejects unknown targets", () => {
expect(resolveTargetLabels(["host", "darwin-arm64"], macArm)).toEqual(["//:natives-darwin-arm64"]);
expect(() => resolveTargetLabels(["linux-x64"], macArm)).toThrow(/Unknown native target "linux-x64"/);
});
});
describe("conventionOutputPaths", () => {
test("builds bazel-bin paths with canonical filenames (musl reuses linux names)", () => {
expect(conventionOutputPaths(["linux-musl-x64-baseline", "win32-x64-baseline"], macArm)).toEqual([
"bazel-bin/natives-linux-musl-x64-baseline/pi_natives.linux-x64-baseline.node",
"bazel-bin/natives-win32-x64-baseline/pi_natives.win32-x64-baseline.node",
]);
});
test("expands aggregates and the host pseudo-target", () => {
expect(conventionOutputPaths(["darwin-all"], macArm)).toEqual([
"bazel-bin/natives-darwin-arm64/pi_natives.darwin-arm64.node",
"bazel-bin/natives-darwin-x64-baseline/pi_natives.darwin-x64-baseline.node",
]);
expect(conventionOutputPaths(["host"], linuxBaseline)).toEqual([
"bazel-bin/natives-linux-x64-baseline/pi_natives.linux-x64-baseline.node",
]);
});
});
describe("parseBazelFilesOutput", () => {
test("keeps only .node paths, trimmed and deduplicated", () => {
const output = [
"bazel-bin/natives-linux-x64-baseline/pi_natives.linux-x64-baseline.node",
" bazel-bin/natives-linux-x64-modern/pi_natives.linux-x64-modern.node ",
"bazel-bin/natives-linux-x64-baseline/pi_natives.linux-x64-baseline.node",
"INFO: Analyzed 2 targets (0 packages loaded, 0 targets configured).",
"",
].join("\n");
expect(parseBazelFilesOutput(output)).toEqual([
"bazel-bin/natives-linux-x64-baseline/pi_natives.linux-x64-baseline.node",
"bazel-bin/natives-linux-x64-modern/pi_natives.linux-x64-modern.node",
]);
});
test("returns empty for output without addon files", () => {
expect(parseBazelFilesOutput("INFO: Build completed successfully\n")).toEqual([]);
});
});
describe("parseCliArgs", () => {
test("splits targets, --dest, and passthrough bazel args", () => {
expect(
parseCliArgs(["linux-x64-baseline", "linux-x64-modern", "--dest", "out", "--", "--config=ci", "--dest"]),
).toEqual({
targets: ["linux-x64-baseline", "linux-x64-modern"],
dest: "out",
bazelArgs: ["--config=ci", "--dest"],
});
expect(parseCliArgs(["host"])).toEqual({ targets: ["host"], dest: null, bazelArgs: [] });
});
test("rejects missing targets, stray flags, and a valueless --dest", () => {
expect(() => parseCliArgs([])).toThrow(/Usage:/);
expect(() => parseCliArgs(["--", "--config=ci"])).toThrow(/Usage:/);
expect(() => parseCliArgs(["host", "--config=ci"])).toThrow(/Unknown flag --config=ci/);
expect(() => parseCliArgs(["host", "--dest"])).toThrow(/--dest requires/);
});
});