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.

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