Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

75 lines · 3.6 KBRaw History
1import path from "node:path";
2import { errMsg, failure } from "../job.js";
3import { maxSatisfying, satisfies, truthyInput } from "../util.js";
4import type { Builtin } from "./index.js";
5import { fetchJson, installTarball, isCached, packageCache, probe, readVersionFile, rootLockHash, toolArch, toolDir } from "./tools.js";
6
7interface GoRelease {
8 version: string; // "go1.22.3"
9 stable: boolean;
10 files: Array<{ filename: string; os: string; arch: string; kind: string }>;
11}
12
13export const setupGo: Builtin = async (c) => {
14 let spec = c.input("go-version");
15 const file = c.input("go-version-file");
16 if (!spec && file) spec = await readVersionFile(c, file, "go");
17 spec = spec.trim().replace(/^go/, "");
18 const installedRaw = await probe(c, "go", ["version"]);
19 const installed = /go(\d+\.\d+(?:\.\d+)?)/.exec(installedRaw ?? "")?.[1] ?? null;
20 let version = installed;
21
22 if (!spec && !installed) throw failure("No go-version specified and Go is not installed on this runner.");
23 const useInstalled = installed && (!spec || (!/^(stable|oldstable)$/.test(spec) && satisfies(installed, spec))) && !truthyInput(c.input("check-latest"), false);
24 if (useInstalled) {
25 c.log(`Using pre-installed Go ${installed}`);
26 } else {
27 let releases: GoRelease[];
28 try {
29 releases = await fetchJson<GoRelease[]>(process.env.DIFFINERY_GO_INDEX ?? "https://go.dev/dl/?mode=json&include=all");
30 } catch (e) {
31 throw failure(`Unable to fetch the Go versions index: ${errMsg(e)}`);
32 }
33 const arch = toolArch("go");
34 const stable = releases.filter((r) => r.stable && r.files.some((f) => f.os === "linux" && f.arch === arch && f.kind === "archive"));
35 let v: string | null;
36 if (spec === "stable") v = maxSatisfying(stable.map((r) => r.version.replace(/^go/, "")), "*");
37 else if (spec === "oldstable") {
38 const sorted = stable.map((r) => r.version.replace(/^go/, ""));
39 const latest = maxSatisfying(sorted, "*");
40 const latestMinor = latest ? latest.split(".").slice(0, 2).join(".") : "";
41 v = maxSatisfying(sorted.filter((x) => !x.startsWith(latestMinor + ".") && x !== latestMinor), "*");
42 } else v = maxSatisfying(stable.map((r) => r.version.replace(/^go/, "")), spec);
43 if (!v) throw failure(`Unable to find Go version '${spec}' for platform linux and architecture ${arch}.`);
44 const rel = stable.find((r) => r.version === `go${v}`)!;
45 const f = rel.files.find((x) => x.os === "linux" && x.arch === arch && x.kind === "archive")!;
46 const dir = toolDir(c, "go", v, arch);
47 if (!isCached(dir)) await installTarball(c, `https://go.dev/dl/${f.filename}`, dir);
48 else c.log(`Found in cache @ ${dir}`);
49 c.addPath(path.join(dir, "bin"));
50 version = v;
51 }
52 const gopath = await probe(c, "go", ["env", "GOPATH"], c.toolEnv());
53 if (gopath) c.addPath(path.join(gopath, "bin"));
54 if (version) c.setOutput("go-version", version);
55
56 if (truthyInput(c.input("cache"), true)) {
57 let hash: string;
58 try {
59 hash = rootLockHash(c, c.input("cache-dependency-path"), ["go.sum"]);
60 if (!hash) throw failure("Some specified paths were not resolved, unable to cache dependencies.");
61 } catch (e) {
62 c.warn(`Restore cache failed: ${errMsg(e)}`);
63 return;
64 }
65 const env = c.toolEnv();
66 const modcache = await probe(c, "go", ["env", "GOMODCACHE"], env);
67 const buildcache = await probe(c, "go", ["env", "GOCACHE"], env);
68 const imageOs = env.ImageOS ?? "ubuntu24";
69 await packageCache(c, {
70 key: `setup-go-Linux-${process.arch}-${imageOs}-go-${version}-${hash}`,
71 paths: [modcache ?? "", buildcache ?? ""].filter(Boolean),
72 what: "go",
73 });
74 }
75};