Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement wildcard resolution into the action #93

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
54abc74
feat: remove retry attempts
xhyrom Jul 28, 2024
99d7a7a
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 28, 2024
3ed283c
feat: get download url from github's api
xhyrom Jul 29, 2024
1cf9dea
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
8611d10
fix: add token property to action definition & fix satisfies params
xhyrom Jul 29, 2024
c3e2edf
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
528c470
fix: getPlatform, getArchitecture + eversion
xhyrom Jul 29, 2024
4d53c4d
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
0d021b0
fix: duplicate v
xhyrom Jul 29, 2024
019399b
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
e53a660
fix: check if valid semver and add bun-v
xhyrom Jul 29, 2024
d9c4697
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
2cadd94
refactor: wrap validation
xhyrom Jul 29, 2024
bba0526
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
6d50d76
ci(format): use bun
xhyrom Jul 29, 2024
26e8dad
ci(format): use bun
xhyrom Jul 29, 2024
f96af5b
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
35cdfa7
feat: bring back support for sha downloads
xhyrom Jul 29, 2024
d51557d
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
6c4630f
fix: add bearer prefix for token
xhyrom Jul 29, 2024
65bc9b0
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
bb58792
fix: proper error when artifact is not found
xhyrom Jul 29, 2024
f3a3a4d
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Install Dependencies
run: npm install
run: bun install
- name: Format
run: |
npm run format
npm run build
bun run format
bun run build
- name: Commit
uses: autofix-ci/action@d3e591514b99d0fca6779455ff8338516663f7cc
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
&& 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 \
&& sudo apt update \
&& sudo apt install gh -y

- run: |
gh cache delete --all || true
env:
Expand All @@ -51,6 +51,7 @@ jobs:
- "1"
- "> 1.0.0"
- "< 2"
- "dbd320ccfa909053f95be9e1643d80d73286751f"
# Disable <sha> support for now. This is because Github Artifacts
# expire after 90 days, and we don't have another source of truth yet.
# - "822a00c4d508b54f650933a73ca5f4a3af9a7983" # 1.0.0 commit
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ inputs:
type: boolean
default: false
description: "Disable caching of bun executable."
token:
required: false
default: ${{ github.token }}
description: "Personal access token (PAT) used to fetch tags from oven-sh/bun repository"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more to access api.github.com with the per token rate limit instead of the per IP one. The documentation should mention that is recommended for user using wildcard or range version.

outputs:
bun-version:
description: The version of Bun that was installed.
Expand Down
Binary file modified bun.lockb
Binary file not shown.
198 changes: 156 additions & 42 deletions dist/cache-save/index.js

Large diffs are not rendered by default.

257 changes: 214 additions & 43 deletions dist/setup/index.js

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"@actions/exec": "^1.1.1",
"@actions/glob": "^0.4.0",
"@actions/io": "^1.1.2",
"@actions/tool-cache": "^2.0.1"
"@actions/tool-cache": "^2.0.1",
"compare-versions": "^6.1.1"
},
"devDependencies": {
"@types/node": "^20.8.2",
Expand All @@ -37,5 +38,8 @@
},
"prettier": {
"quoteProps": "preserve"
},
"patchedDependencies": {
"[email protected]": "patches/[email protected]"
}
}
67 changes: 67 additions & 0 deletions patches/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
diff --git a/lib/esm/satisfies.js b/lib/esm/satisfies.js
index 7586b71657332f855431c4dd4f05e9394fd9aac3..a6ec29bfc98907c67ed4af71fca73bd8bff88798 100644
--- a/lib/esm/satisfies.js
+++ b/lib/esm/satisfies.js
@@ -40,8 +40,9 @@ export const satisfies = (version, range) => {
// else range of either "~" or "^" is assumed
const [v1, v2, v3, , vp] = validateAndParse(version);
const [r1, r2, r3, , rp] = validateAndParse(range);
- const v = [v1, v2, v3];
+ const v = [v1, v2 !== null && v2 !== void 0 ? v2 : 'x', v3 !== null && v3 !== void 0 ? v3 : 'x'];
const r = [r1, r2 !== null && r2 !== void 0 ? r2 : 'x', r3 !== null && r3 !== void 0 ? r3 : 'x'];
+
// validate pre-release
if (rp) {
if (!vp)
diff --git a/lib/esm/utils.js b/lib/esm/utils.js
index b5cc8b9927ab38fc67032c133b531e95ec4cec15..ec56105fd2d806aa922f1488a27b02c56aff1865 100644
--- a/lib/esm/utils.js
+++ b/lib/esm/utils.js
@@ -28,7 +28,7 @@ const compareStrings = (a, b) => {
};
export const compareSegments = (a, b) => {
for (let i = 0; i < Math.max(a.length, b.length); i++) {
- const r = compareStrings(a[i] || '0', b[i] || '0');
+ const r = compareStrings(a[i] || 'x', b[i] || 'x');
if (r !== 0)
return r;
}
diff --git a/lib/umd/index.js b/lib/umd/index.js
index 2cfef261bca520e21ed41fc14950732b8aa6339b..1059784db86635f3aaaba83b5a72c5015e1d8490 100644
--- a/lib/umd/index.js
+++ b/lib/umd/index.js
@@ -152,7 +152,7 @@
// else range of either "~" or "^" is assumed
const [v1, v2, v3, , vp] = validateAndParse(version);
const [r1, r2, r3, , rp] = validateAndParse(range);
- const v = [v1, v2, v3];
+ const v = [v1, v2 !== null && v2 !== void 0 ? v2 : 'x', v3 !== null && v3 !== void 0 ? v3 : 'x'];
const r = [r1, r2 !== null && r2 !== void 0 ? r2 : 'x', r3 !== null && r3 !== void 0 ? r3 : 'x'];
// validate pre-release
if (rp) {
diff --git a/package.json b/package.json
index b05b3daf706d7ba4e594233f8791fc3007a8e2cd..e51e76b86f95e9ebf0b5dba3b82aeb119628528d 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
"prepublishOnly": "npm run build",
"test": "c8 --reporter=lcov mocha"
},
- "main": "./lib/umd/index.js",
+ "main": "./lib/src/index.ts",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",
"sideEffects": false,
diff --git a/src/satisfies.ts b/src/satisfies.ts
index 66cb171d7f32e68fdda6929d2da223b97a053737..6b4973f037843f264338a01efdc4ace5dcf042cd 100644
--- a/src/satisfies.ts
+++ b/src/satisfies.ts
@@ -43,7 +43,7 @@ export const satisfies = (version: string, range: string): boolean => {
// else range of either "~" or "^" is assumed
const [v1, v2, v3, , vp] = validateAndParse(version);
const [r1, r2, r3, , rp] = validateAndParse(range);
- const v = [v1, v2, v3];
+ const v = [v1, v2 ?? 'x', v3 ?? 'x'];
const r = [r1, r2 ?? 'x', r3 ?? 'x'];

// validate pre-release
40 changes: 16 additions & 24 deletions src/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { downloadTool, extractZip } from "@actions/tool-cache";
import { getExecOutput } from "@actions/exec";
import { writeBunfig } from "./bunfig";
import { saveState } from "@actions/core";
import { addExtension, retry } from "./utils";
import { addExtension } from "./utils";
import { DownloadMeta, getDownloadMeta } from "./download-url";

export type Input = {
customUrl?: string;
Expand All @@ -25,6 +26,7 @@ export type Input = {
scope?: string;
registryUrl?: string;
noCache?: boolean;
token: string;
};

export type Output = {
Expand All @@ -46,7 +48,9 @@ export default async (options: Input): Promise<Output> => {
const bunfigPath = join(process.cwd(), "bunfig.toml");
writeBunfig(bunfigPath, options);

const url = getDownloadUrl(options);
const downloadMeta = await getDownloadMeta(options);
const url = downloadMeta.url;

const cacheEnabled = isCacheEnabled(options);

const binPath = join(homedir(), ".bun", "bin");
Expand Down Expand Up @@ -89,8 +93,7 @@ export default async (options: Input): Promise<Output> => {

if (!cacheHit) {
info(`Downloading a new version of Bun: ${url}`);
// TODO: remove this, temporary fix for https://github.com/oven-sh/setup-bun/issues/73
revision = await retry(async () => await downloadBun(url, bunPath), 3);
revision = await downloadBun(downloadMeta, bunPath);
}

if (!revision) {
Expand Down Expand Up @@ -120,11 +123,18 @@ export default async (options: Input): Promise<Output> => {
};

async function downloadBun(
url: string,
downloadMeta: DownloadMeta,
bunPath: string
): Promise<string | undefined> {
// Workaround for https://github.com/oven-sh/setup-bun/issues/79 and https://github.com/actions/toolkit/issues/1179
const zipPath = addExtension(await downloadTool(url), ".zip");
const zipPath = addExtension(
await downloadTool(
downloadMeta.url,
undefined,
downloadMeta.auth ?? undefined
),
".zip"
);
const extractedZipPath = await extractZip(zipPath);
const extractedBunPath = await extractBun(extractedZipPath);
try {
Expand Down Expand Up @@ -152,24 +162,6 @@ function isCacheEnabled(options: Input): boolean {
return isFeatureAvailable();
}

function getDownloadUrl(options: Input): string {
const { customUrl } = options;
if (customUrl) {
return customUrl;
}
const { version, os, arch, avx2, profile } = options;
const eversion = encodeURIComponent(version ?? "latest");
const eos = encodeURIComponent(os ?? process.platform);
const earch = encodeURIComponent(arch ?? process.arch);
const eavx2 = encodeURIComponent(avx2 ?? true);
const eprofile = encodeURIComponent(profile ?? false);
const { href } = new URL(
`${eversion}/${eos}/${earch}?avx2=${eavx2}&profile=${eprofile}`,
"https://bun.sh/download/"
);
return href;
}

async function extractBun(path: string): Promise<string> {
for (const entry of readdirSync(path, { withFileTypes: true })) {
const { name } = entry;
Expand Down
125 changes: 125 additions & 0 deletions src/download-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { compareVersions, satisfies, validate } from "compare-versions";
import { Input } from "./action";
import { getArchitecture, getPlatform, request } from "./utils";

export interface DownloadMeta {
url: string;
auth?: string;
}

export async function getDownloadMeta(options: Input): Promise<DownloadMeta> {
const { customUrl } = options;
if (customUrl) {
return {
url: customUrl,
};
}

if (options.version && /^[0-9a-f]{40}$/i.test(options.version)) {
return await getShaDownloadMeta(options);
}

return await getSemverDownloadMeta(options);
}

interface Run {
id: string;
head_sha: string;
}

interface Runs {
workflow_runs: Run[];
}

async function getShaDownloadMeta(options: Input): Promise<DownloadMeta> {
let res: Runs;
let page = 1;
let run: Run;
while (
(res = (await (
await request(
`https://api.github.com/repos/oven-sh/bun/actions/workflows/ci.yml/runs?per_page=100&page=${page}`,
{
headers: {
"Authorization": `Bearer ${options.token}`,
},
}
)
).json()) as Runs)
) {
run = res.workflow_runs.find((item) => item.head_sha === options.version);
if (run) break;

page++;
}

const artifacts = (await (
await request(
`https://api.github.com/repos/oven-sh/bun/actions/runs/${run.id}/artifacts`,
{
headers: {
"Authorization": `Bearer ${options.token}`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the token is not defined in the configuration? The headers field add could be make conditional

},
}
)
).json()) as { artifacts: { name: string; archive_download_url: string }[] };

const { os, arch, avx2, profile, token } = options;

const name = `bun-${os ?? getPlatform()}-${arch ?? getArchitecture()}${
avx2 ? "-baseline" : ""
}${profile ? "-profile" : ""}`;

const artifact = artifacts.artifacts.find((item) => item.name === name);
if (!artifact) {
throw new Error(`Failed to find artifact '${name}' in run '${run.id}'`);
}

return {
url: artifact.archive_download_url,
auth: `Bearer ${token}`,
};
}

async function getSemverDownloadMeta(options: Input): Promise<DownloadMeta> {
const res = (await (
await request("https://api.github.com/repos/oven-sh/bun/git/refs/tags", {
headers: {
"Authorization": `Bearer ${options.token}`,
},
})
).json()) as { ref: string }[];
let tags = res
.filter(
(tag) =>
tag.ref.startsWith("refs/tags/bun-v") || tag.ref === "refs/tags/canary"
)
.map((item) => item.ref.replace(/refs\/tags\/(bun-v)?/g, ""));

const { version, os, arch, avx2, profile } = options;

let tag = tags.find((t) => t === version);
if (!tag) {
tags = tags.filter((t) => validate(t)).sort(compareVersions);

if (version === "latest") tag = `bun-v${tags.at(-1)}`;
else tag = `bun-v${tags.filter((t) => satisfies(t, version)).at(-1)}`;
} else if (validate(tag)) {
tag = `bun-v${tag}`;
}

const eversion = encodeURIComponent(tag ?? version);
const eos = encodeURIComponent(os ?? getPlatform());
const earch = encodeURIComponent(arch ?? getArchitecture());
const eavx2 = encodeURIComponent(avx2 ? "-baseline" : "");
const eprofile = encodeURIComponent(profile ? "-profile" : "");

const { href } = new URL(
`${eversion}/bun-${eos}-${earch}${eavx2}${eprofile}.zip`,
"https://github.com/oven-sh/bun/releases/download/"
);

return {
url: href,
};
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ runAction({
registryUrl: getInput("registry-url") || undefined,
scope: getInput("scope") || undefined,
noCache: getBooleanInput("no-cache") || false,
token: getInput("token"),
})
.then(({ version, revision, bunPath, url, cacheHit }) => {
setOutput("bun-version", version);
Expand Down
Loading
Loading