Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
81 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'worktree-agent-a63425cb2d4935c5f'1import { test } from "node:test";
2import assert from "node:assert/strict";
3import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4import { tmpdir } from "node:os";
5import { join } from "node:path";
Release tags' runs no longer save to the cache what only their own tag could read, and the CLI's release builds in a pinned image from a cache kept on main. scripts/sccache.sh sets SCCACHE_GHA_RW_MODE=READ_ONLY when GITHUB_REF_TYPE is tag, for the server and the steps after it: against a stand-in for the cache service, sccache 0.18.0 on a branch's run made a CreateCacheEntry call and on a tag's run made none, and looked its compile up in both. The CLI's release ran in ghcr.io/rust-cross/cargo-zigbuild:latest; it now runs in that image pinned by digest (sha256:d8313491ec57…, Rust 1.93.0, zig 0.16.0), reads the crates entry CI saves from the job's ~/.cargo/registry instead of an empty Docker volume, hands what it wrote as root back to the job's user, and restores target/zig from cli-release-<os>-<image digest>-<deps>, which the Caches workflow builds whole when the key is new (ci-cache.mjs keys gives the digest as zigbuild). Built in that image on an 8-core machine, the five platforms took 162 s from nothing and 103 s from the cache, with only the g1t crate compiled again for each; the entry is 1.3 GB, 463 MB compressed. Tests hold the tag rule in sccache.sh, the CLI's entry to the image's digest and to being built whole, and the builder's flags; CONTRIBUTING.md and the Actions guide say both.6import { depsHash, externalPackages, imageDigest, rustVersion, stale, unitHash, usedHashes } from "./ci-cache.mjs";
7import { BUILDER } from "../cli-release.mjs";
Merge branch 'worktree-agent-a63425cb2d4935c5f'8
9const LOCK = (runner, serde) => `# This file is automatically @generated by Cargo.
10version = 4
11
12[[package]]
13name = "g1t-runner"
14version = "${runner}"
15dependencies = [
16 "serde",
17]
18
19[[package]]
20name = "serde"
21version = "${serde}"
22source = "registry+https://github.com/rust-lang/crates.io-index"
23checksum = "abc"
24`;
25
26test("a release's version bump keeps the Rust caches' key, a new dependency changes it", () => {
27 assert.deepEqual(externalPackages(LOCK("0.3.3", "1.0.200")).length, 1);
28 assert.equal(depsHash(LOCK("0.3.3", "1.0.200")), depsHash(LOCK("0.3.4", "1.0.200")));
29 assert.notEqual(depsHash(LOCK("0.3.3", "1.0.200")), depsHash(LOCK("0.3.3", "1.0.201")));
30 assert.match(depsHash(LOCK("0.3.3", "1.0.200")), /^[0-9a-f]{16}$/);
31});
32
33test("the toolchain is read from rustc -V", () => {
34 assert.equal(rustVersion("rustc 1.99.0 (90b35a623 2026-09-30)\n"), "1.99.0");
35 assert.equal(rustVersion("rustc 1.100.0-nightly (abc 2026-10-01)"), "1.100.0-nightly");
36 assert.equal(rustVersion(""), null);
37});
38
Release tags' runs no longer save to the cache what only their own tag could read, and the CLI's release builds in a pinned image from a cache kept on main. scripts/sccache.sh sets SCCACHE_GHA_RW_MODE=READ_ONLY when GITHUB_REF_TYPE is tag, for the server and the steps after it: against a stand-in for the cache service, sccache 0.18.0 on a branch's run made a CreateCacheEntry call and on a tag's run made none, and looked its compile up in both. The CLI's release ran in ghcr.io/rust-cross/cargo-zigbuild:latest; it now runs in that image pinned by digest (sha256:d8313491ec57…, Rust 1.93.0, zig 0.16.0), reads the crates entry CI saves from the job's ~/.cargo/registry instead of an empty Docker volume, hands what it wrote as root back to the job's user, and restores target/zig from cli-release-<os>-<image digest>-<deps>, which the Caches workflow builds whole when the key is new (ci-cache.mjs keys gives the digest as zigbuild). Built in that image on an 8-core machine, the five platforms took 162 s from nothing and 103 s from the cache, with only the g1t crate compiled again for each; the entry is 1.3 GB, 463 MB compressed. Tests hold the tag rule in sccache.sh, the CLI's entry to the image's digest and to being built whole, and the builder's flags; CONTRIBUTING.md and the Actions guide say both.39test("the CLI's builder image is pinned, and keys its cache by its digest", () => {
40 assert.match(imageDigest(BUILDER), /^[0-9a-f]{12}$/);
41 assert.equal(imageDigest(`ghcr.io/rust-cross/cargo-zigbuild@sha256:${"ab".repeat(32)}`), "abababababab");
42 assert.equal(imageDigest("ghcr.io/rust-cross/cargo-zigbuild:latest"), null);
43});
44
Merge branch 'worktree-agent-a63425cb2d4935c5f'45test("a unit's hash is read from its files and folders", () => {
46 assert.equal(unitHash("libserde-0123456789abcdef.rlib"), "0123456789abcdef");
47 assert.equal(unitHash("serde-0123456789abcdef"), "0123456789abcdef");
48 assert.equal(unitHash("g1t_actions-0123456789abcdef.d"), "0123456789abcdef");
49 assert.equal(unitHash("repository_workflows-0123456789abcdef"), "0123456789abcdef");
50 assert.equal(unitHash("g1t"), null);
51 assert.equal(unitHash("libg1t.rlib"), null);
52});
53
54test("only the units the build did not use are pruned", () => {
55 const dir = mkdtempSync(join(tmpdir(), "ci-cache-"));
56 try {
57 const [used, old, script, run] = ["1111111111111111", "2222222222222222", "3333333333333333", "4444444444444444"];
58 for (const sub of ["deps", "build", ".fingerprint"]) mkdirSync(join(dir, sub), { recursive: true });
59 for (const f of [`libserde-${used}.rlib`, `libserde-${used}.rmeta`, `serde-${used}.d`, `libserde-${old}.rlib`, `serde-${old}.d`, `tests-${used}`]) {
60 writeFileSync(join(dir, "deps", f), "x");
61 }
62 for (const d of [`serde-${script}`, `serde-${run}`, `serde-${old}`]) mkdirSync(join(dir, "build", d));
63 for (const d of [`serde-${used}`, `serde-${script}`, `serde-${run}`, `serde-${old}`]) mkdirSync(join(dir, ".fingerprint", d));
64 const messages = [
65 " Compiling serde",
66 JSON.stringify({ reason: "compiler-artifact", filenames: [join(dir, "build", `serde-${script}`, "build-script-build")], executable: null }),
67 JSON.stringify({ reason: "build-script-executed", out_dir: join(dir, "build", `serde-${run}`, "out") }),
68 JSON.stringify({ reason: "compiler-artifact", filenames: [join(dir, "deps", `libserde-${used}.rlib`), join(dir, "deps", `libserde-${used}.rmeta`)] }),
69 JSON.stringify({ reason: "compiler-artifact", filenames: [], executable: join(dir, "deps", `tests-${used}`) }),
70 JSON.stringify({ reason: "build-finished", success: true }),
71 ].join("\n");
72 const hashes = usedHashes(messages);
73 assert.deepEqual([...hashes].sort(), [used, script, run].sort());
74 const gone = stale(dir, hashes).map((p) => p.slice(dir.length + 1).replaceAll("\\", "/")).sort();
75 assert.deepEqual(gone, [`.fingerprint/serde-${old}`, `build/serde-${old}`, `deps/libserde-${old}.rlib`, `deps/serde-${old}.d`]);
76 // Nothing listed: nothing would be kept, so the caller prunes nothing.
77 assert.equal(usedHashes("error: could not compile").size, 0);
78 } finally {
79 rmSync(dir, { recursive: true, force: true });
80 }
81});

This file's history is long; its oldest lines are credited to the oldest commit read.