2 Commits
v2.1.2 ... main

Author SHA1 Message Date
Max Schwenk
ab8cb4e8f8 feat: add bun- prefix to cache keys (#160)
Some checks failed
autofix.ci / format (push) Successful in 47s
🧪 Test / remove-cache (push) Successful in 5s
🧪 Test / Tests (push) Successful in 21m39s
🧪 Test / setup-bun (1, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (1, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (1, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (1, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun (1.1.0, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (1.1.0, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (1.1.0, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (1.1.0, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun (1.x, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (1.x, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (1.x, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (1.x, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun (< 2, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (< 2, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (< 2, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (< 2, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun (> 1.0.0, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (> 1.0.0, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (> 1.0.0, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (> 1.0.0, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun (canary, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (canary, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (canary, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (canary, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun (latest, macos-latest) (push) Has been cancelled
🧪 Test / setup-bun (latest, ubuntu-latest) (push) Has been cancelled
🧪 Test / setup-bun (latest, windows-11-arm) (push) Has been cancelled
🧪 Test / setup-bun (latest, windows-latest) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, .bumrc (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, .bumrc (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, .bumrc (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, .bumrc (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, .bun-version (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, .bun-version (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, .bun-version (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, .bun-version (1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, .tool-versions (bun 1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, .tool-versions (bun1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, .tool-versions (bun1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, .tool-versions (bun1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, .tool-versions (bun1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, foo/package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, foo/package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, foo/package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, foo/package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, package.json (engines bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, package.json (engines bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, package.json (engines bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, package.json (engines bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, package.json (packageManager bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, package.json (packageManager yarn@bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, package.json (packageManager yarn@bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, package.json (packageManager yarn@bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, package.json (packageManager yarn@bun@1.1.0)) (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, package.json (engines bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, package.json (engines bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, package.json (engines bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, package.json (engines bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, package.json (packageManager bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, package.json (packageManager bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, package.json (packageManager bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, package.json (packageManager bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, package.json (packageManager yarn@bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, package.json (packageManager yarn@bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (windows-11-arm, package.json (packageManager yarn@bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, package.json (packageManager yarn@bun@1.1.0)) without specified field (push) Has been cancelled
🧪 Test / setup-bun from (macos-latest, download url) (push) Has been cancelled
🧪 Test / setup-bun from (ubuntu-latest, download url) (push) Has been cancelled
🧪 Test / setup-bun from (windows-latest, download url) (push) Has been cancelled
🧪 Test / test installing deps from custom registries (ubuntu-latest) (push) Has been cancelled
* feat: add bun- prefix to cache keys

Extract cache key generation into a shared `getCacheKey` function in
utils.ts that both action.ts and cache-save.ts import.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-05 17:36:05 +01:00
Jozef Steinhübl
196aaa2bd2 perf: avoid unnecessary api calls (#161)
* perf: avoid unnecessary api calls

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-05 16:04:59 +01:00
7 changed files with 293 additions and 115 deletions

70
dist/cache-save/index.js generated vendored

File diff suppressed because one or more lines are too long

92
dist/setup/index.js generated vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,3 @@
import { createHash } from "node:crypto";
import { homedir } from "node:os";
import { join } from "node:path";
import {
@@ -16,7 +15,7 @@ import { getExecOutput } from "@actions/exec";
import { Registry } from "./registry";
import { writeBunfig } from "./bunfig";
import { saveState } from "@actions/core";
import { addExtension } from "./utils";
import { addExtension, getCacheKey } from "./utils";
import { getDownloadUrl } from "./download-url";
import { cwd } from "node:process";
@@ -90,7 +89,7 @@ export default async (options: Input): Promise<Output> => {
if (!revision) {
if (cacheEnabled) {
const cacheKey = createHash("sha1").update(url).digest("base64");
const cacheKey = getCacheKey(url);
const cacheRestored = await restoreCache([bunPath], cacheKey);
if (cacheRestored) {

View File

@@ -1,11 +1,11 @@
import { saveCache } from "@actions/cache";
import { getState, warning } from "@actions/core";
import { CacheState } from "./action";
import { createHash } from "node:crypto";
import { getCacheKey } from "./utils";
(async () => {
const state: CacheState = JSON.parse(getState("cache"));
if (state.cacheEnabled && !state.cacheHit) {
const cacheKey = createHash("sha1").update(state.url).digest("base64");
const cacheKey = getCacheKey(state.url);
try {
await saveCache([state.bunPath], cacheKey);

View File

@@ -1,4 +1,9 @@
import { compareVersions, satisfies, validate } from "compare-versions";
import {
compareVersions,
satisfies,
validate,
validateStrict,
} from "compare-versions";
import { Input } from "./action";
import { getArchitecture, getAvx2, getPlatform, request } from "./utils";
@@ -12,40 +17,48 @@ export async function getDownloadUrl(options: Input): Promise<string> {
}
async function getSemverDownloadUrl(options: Input): Promise<string> {
const res = (await (
await request("https://api.github.com/repos/oven-sh/bun/git/refs/tags", {
headers: options.token
? { "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, ""))
.filter(Boolean);
const { version, os, arch, avx2, profile } = options;
let tag: string | undefined;
if (validateStrict(version)) {
tag = `bun-v${version}`;
}
let tag = tags.find((t) => t === version);
if (!tag) {
tags = tags.filter((t) => validate(t)).sort(compareVersions);
const res = (await (
await request("https://api.github.com/repos/oven-sh/bun/git/refs/tags", {
headers: options.token
? { "Authorization": `Bearer ${options.token}` }
: {},
})
).json()) as { ref: string }[];
const matchedTag =
version === "latest" || !version
? tags.at(-1)
: tags.filter((t) => satisfies(t, version)).at(-1);
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, ""))
.filter(Boolean);
if (!matchedTag) {
throw new Error(`No Bun release found matching version '${version}'`);
tag = tags.find((t) => t === version);
if (!tag) {
tags = tags.filter((t) => validate(t)).sort(compareVersions);
const matchedTag =
version === "latest" || !version
? tags.at(-1)
: tags.filter((t) => satisfies(t, version)).at(-1);
if (!matchedTag) {
throw new Error(`No Bun release found matching version '${version}'`);
}
tag = `bun-v${matchedTag}`;
} else if (validate(tag)) {
tag = `bun-v${tag}`;
}
tag = `bun-v${matchedTag}`;
} else if (validate(tag)) {
tag = `bun-v${tag}`;
}
const eversion = encodeURIComponent(tag ?? version);

View File

@@ -1,8 +1,13 @@
import { debug, warning } from "@actions/core";
import { info } from "node:console";
import { createHash } from "node:crypto";
import { existsSync, readFileSync, renameSync } from "node:fs";
import { resolve, basename } from "node:path";
export function getCacheKey(url: string): string {
return `bun-${createHash("sha1").update(url).digest("base64")}`;
}
export async function request(
url: string,
init?: RequestInit,

161
tests/download-url.spec.ts Normal file
View File

@@ -0,0 +1,161 @@
import { afterEach, beforeEach, describe, expect, it, spyOn } from "bun:test";
import { getDownloadUrl } from "../src/download-url";
import * as utils from "../src/utils";
const MOCK_TAGS = [
{ ref: "refs/tags/bun-v0.5.0" },
{ ref: "refs/tags/bun-v1.0.0" },
{ ref: "refs/tags/bun-v1.0.1" },
{ ref: "refs/tags/bun-v1.1.0" },
{ ref: "refs/tags/canary" },
];
describe("getDownloadUrl", () => {
let requestSpy: ReturnType<typeof spyOn>;
beforeEach(() => {
requestSpy = spyOn(utils, "request").mockResolvedValue({
json: async () => MOCK_TAGS,
} as Response);
});
afterEach(() => {
requestSpy.mockRestore();
});
describe("Custom URL", () => {
it("should return customUrl if provided", async () => {
const url = await getDownloadUrl({
customUrl: "https://example.com/bun.zip",
});
expect(url).toBe("https://example.com/bun.zip");
expect(requestSpy).toHaveBeenCalledTimes(0);
});
});
describe("Optimization (No API Call)", () => {
it("should construct URL directly for specific version 1.0.0", async () => {
const url = await getDownloadUrl({
version: "1.0.0",
os: "linux",
arch: "x64",
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/bun-v1.0.0/bun-linux-x64.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(0);
});
it("should construct URL directly for specific version 0.5.0", async () => {
const url = await getDownloadUrl({
version: "0.5.0",
os: "darwin",
arch: "aarch64",
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/bun-v0.5.0/bun-darwin-aarch64.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(0);
});
it("should handle avx2=false (baseline) without API call", async () => {
const url = await getDownloadUrl({
version: "1.1.0",
os: "linux",
arch: "x64",
avx2: false,
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-linux-x64-baseline.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(0);
});
it("should handle profile=true without API call", async () => {
const url = await getDownloadUrl({
version: "1.1.0",
os: "linux",
arch: "x64",
profile: true,
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-linux-x64-profile.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(0);
});
});
describe("API Lookup (Dynamic Versions)", () => {
it("should call API and resolve 'latest' to the newest version", async () => {
const url = await getDownloadUrl({
version: "latest",
os: "linux",
arch: "x64",
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-linux-x64.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(1);
});
it("should call API and resolve semver range '^1.0.0'", async () => {
const url = await getDownloadUrl({
version: "^1.0.0",
os: "linux",
arch: "x64",
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-linux-x64.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(1);
});
it("should call API and resolve 'canary'", async () => {
const url = await getDownloadUrl({
version: "canary",
os: "linux",
arch: "x64",
});
expect(url).toBe(
"https://github.com/oven-sh/bun/releases/download/canary/bun-linux-x64.zip",
);
expect(requestSpy).toHaveBeenCalledTimes(1);
});
it("should throw error if semver range matches nothing", async () => {
expect(
getDownloadUrl({
version: "^2.0.0",
os: "linux",
arch: "x64",
}),
).rejects.toThrow("No Bun release found matching version '^2.0.0'");
expect(requestSpy).toHaveBeenCalledTimes(1);
});
});
describe("Token Handling", () => {
it("should pass token to API request when resolving dynamic versions", async () => {
await getDownloadUrl({
version: "latest",
token: "my-secret-token",
os: "linux",
arch: "x64",
});
expect(requestSpy).toHaveBeenCalledWith(
expect.stringContaining("api.github.com"),
expect.objectContaining({
headers: { Authorization: "Bearer my-secret-token" },
}),
);
});
});
});