Skip to content

Commit 35cdfa7

Browse files
committed
feat: bring back support for sha downloads
1 parent f96af5b commit 35cdfa7

File tree

3 files changed

+130
-53
lines changed

3 files changed

+130
-53
lines changed

.github/workflows/test.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
2828
&& sudo apt update \
2929
&& sudo apt install gh -y
30-
30+
3131
- run: |
3232
gh cache delete --all || true
3333
env:
@@ -51,6 +51,7 @@ jobs:
5151
- "1"
5252
- "> 1.0.0"
5353
- "< 2"
54+
- "08a9b6a98b14d3c23b58080bea31513546246c50"
5455
# Disable <sha> support for now. This is because Github Artifacts
5556
# expire after 90 days, and we don't have another source of truth yet.
5657
# - "822a00c4d508b54f650933a73ca5f4a3af9a7983" # 1.0.0 commit

src/action.ts

+15-52
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { downloadTool, extractZip } from "@actions/tool-cache";
1313
import { getExecOutput } from "@actions/exec";
1414
import { writeBunfig } from "./bunfig";
1515
import { saveState } from "@actions/core";
16-
import { addExtension, getArchitecture, getPlatform, request } from "./utils";
17-
import { compareVersions, satisfies, validate } from "compare-versions";
16+
import { addExtension } from "./utils";
17+
import { DownloadMeta, getDownloadMeta } from "./download-url";
1818

1919
export type Input = {
2020
customUrl?: string;
@@ -48,7 +48,9 @@ export default async (options: Input): Promise<Output> => {
4848
const bunfigPath = join(process.cwd(), "bunfig.toml");
4949
writeBunfig(bunfigPath, options);
5050

51-
const url = await getDownloadUrl(options);
51+
const downloadMeta = await getDownloadMeta(options);
52+
const url = downloadMeta.url;
53+
5254
const cacheEnabled = isCacheEnabled(options);
5355

5456
const binPath = join(homedir(), ".bun", "bin");
@@ -91,7 +93,7 @@ export default async (options: Input): Promise<Output> => {
9193

9294
if (!cacheHit) {
9395
info(`Downloading a new version of Bun: ${url}`);
94-
revision = await downloadBun(url, bunPath);
96+
revision = await downloadBun(downloadMeta, bunPath);
9597
}
9698

9799
if (!revision) {
@@ -121,11 +123,18 @@ export default async (options: Input): Promise<Output> => {
121123
};
122124

123125
async function downloadBun(
124-
url: string,
126+
downloadMeta: DownloadMeta,
125127
bunPath: string
126128
): Promise<string | undefined> {
127129
// Workaround for https://github.com/oven-sh/setup-bun/issues/79 and https://github.com/actions/toolkit/issues/1179
128-
const zipPath = addExtension(await downloadTool(url), ".zip");
130+
const zipPath = addExtension(
131+
await downloadTool(
132+
downloadMeta.url,
133+
undefined,
134+
downloadMeta.auth ?? undefined
135+
),
136+
".zip"
137+
);
129138
const extractedZipPath = await extractZip(zipPath);
130139
const extractedBunPath = await extractBun(extractedZipPath);
131140
try {
@@ -153,52 +162,6 @@ function isCacheEnabled(options: Input): boolean {
153162
return isFeatureAvailable();
154163
}
155164

156-
async function getDownloadUrl(options: Input): Promise<string> {
157-
const { customUrl } = options;
158-
if (customUrl) {
159-
return customUrl;
160-
}
161-
162-
const res = (await (
163-
await request("https://api.github.com/repos/oven-sh/bun/git/refs/tags", {
164-
headers: {
165-
"Authorization": `Bearer ${options.token}`,
166-
},
167-
})
168-
).json()) as { ref: string }[];
169-
let tags = res
170-
.filter(
171-
(tag) =>
172-
tag.ref.startsWith("refs/tags/bun-v") || tag.ref === "refs/tags/canary"
173-
)
174-
.map((item) => item.ref.replace(/refs\/tags\/(bun-v)?/g, ""));
175-
176-
const { version, os, arch, avx2, profile } = options;
177-
178-
let tag = tags.find((t) => t === version);
179-
if (!tag) {
180-
tags = tags.filter((t) => validate(t)).sort(compareVersions);
181-
182-
if (version === "latest") tag = `bun-v${tags.at(-1)}`;
183-
else tag = `bun-v${tags.filter((t) => satisfies(t, version)).at(-1)}`;
184-
} else if (validate(tag)) {
185-
tag = `bun-v${tag}`;
186-
}
187-
188-
const eversion = encodeURIComponent(tag ?? version);
189-
const eos = encodeURIComponent(os ?? getPlatform());
190-
const earch = encodeURIComponent(arch ?? getArchitecture());
191-
const eavx2 = encodeURIComponent(avx2 ? "-baseline" : "");
192-
const eprofile = encodeURIComponent(profile ? "-profile" : "");
193-
194-
const { href } = new URL(
195-
`${eversion}/bun-${eos}-${earch}${eavx2}${eprofile}.zip`,
196-
"https://github.com/oven-sh/bun/releases/download/"
197-
);
198-
199-
return href;
200-
}
201-
202165
async function extractBun(path: string): Promise<string> {
203166
for (const entry of readdirSync(path, { withFileTypes: true })) {
204167
const { name } = entry;

src/download-url.ts

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { compareVersions, satisfies, validate } from "compare-versions";
2+
import { Input } from "./action";
3+
import { getArchitecture, getPlatform, request } from "./utils";
4+
5+
export interface DownloadMeta {
6+
url: string;
7+
auth?: string;
8+
}
9+
10+
export async function getDownloadMeta(options: Input): Promise<DownloadMeta> {
11+
const { customUrl } = options;
12+
if (customUrl) {
13+
return {
14+
url: customUrl,
15+
};
16+
}
17+
18+
if (options.version && /^[0-9a-f]{40}$/i.test(options.version)) {
19+
return await getShaDownloadMeta(options);
20+
}
21+
22+
return await getSemverDownloadMeta(options);
23+
}
24+
25+
interface Run {
26+
id: string;
27+
head_sha: string;
28+
}
29+
30+
interface Runs {
31+
workflow_runs: Run[];
32+
}
33+
34+
async function getShaDownloadMeta(options: Input): Promise<DownloadMeta> {
35+
let res: Runs;
36+
let page = 1;
37+
let run: Run;
38+
while (
39+
(res = (await (
40+
await request(
41+
`https://api.github.com/repos/oven-sh/bun/actions/workflows/ci.yml/runs?per_page=100&page=${page}`,
42+
{}
43+
)
44+
).json()) as Runs)
45+
) {
46+
run = res.workflow_runs.find((item) => item.head_sha === options.version);
47+
if (run) break;
48+
49+
page++;
50+
}
51+
52+
const artifacts = (await (
53+
await request(
54+
`https://api.github.com/repos/oven-sh/bun/actions/runs/${run.id}/artifacts`,
55+
{}
56+
)
57+
).json()) as { artifacts: { name: string; archive_download_url: string }[] };
58+
59+
const { os, arch, avx2, profile, token } = options;
60+
61+
const name = `bun-${os ?? getPlatform()}-${arch ?? getArchitecture()}${
62+
avx2 ? "-baseline" : ""
63+
}${profile ? "-profile" : ""}`;
64+
65+
return {
66+
url: artifacts.artifacts.find((item) => item.name === name)
67+
.archive_download_url,
68+
auth: token,
69+
};
70+
}
71+
72+
async function getSemverDownloadMeta(options: Input): Promise<DownloadMeta> {
73+
const res = (await (
74+
await request("https://api.github.com/repos/oven-sh/bun/git/refs/tags", {
75+
headers: {
76+
"Authorization": `Bearer ${options.token}`,
77+
},
78+
})
79+
).json()) as { ref: string }[];
80+
let tags = res
81+
.filter(
82+
(tag) =>
83+
tag.ref.startsWith("refs/tags/bun-v") || tag.ref === "refs/tags/canary"
84+
)
85+
.map((item) => item.ref.replace(/refs\/tags\/(bun-v)?/g, ""));
86+
87+
const { version, os, arch, avx2, profile } = options;
88+
89+
let tag = tags.find((t) => t === version);
90+
if (!tag) {
91+
tags = tags.filter((t) => validate(t)).sort(compareVersions);
92+
93+
if (version === "latest") tag = `bun-v${tags.at(-1)}`;
94+
else tag = `bun-v${tags.filter((t) => satisfies(t, version)).at(-1)}`;
95+
} else if (validate(tag)) {
96+
tag = `bun-v${tag}`;
97+
}
98+
99+
const eversion = encodeURIComponent(tag ?? version);
100+
const eos = encodeURIComponent(os ?? getPlatform());
101+
const earch = encodeURIComponent(arch ?? getArchitecture());
102+
const eavx2 = encodeURIComponent(avx2 ? "-baseline" : "");
103+
const eprofile = encodeURIComponent(profile ? "-profile" : "");
104+
105+
const { href } = new URL(
106+
`${eversion}/bun-${eos}-${earch}${eavx2}${eprofile}.zip`,
107+
"https://github.com/oven-sh/bun/releases/download/"
108+
);
109+
110+
return {
111+
url: href,
112+
};
113+
}

0 commit comments

Comments
 (0)