mirror of
https://github.com/oven-sh/setup-bun.git
synced 2026-05-22 14:10:47 +00:00
fix: use native Windows ARM64 binary for Bun >= 1.3.10 (#165)
Bun v1.3.10 ships native Windows ARM64 binaries. Update getArchitecture() and getAvx2() to be version-aware so that windows-11-arm runners download bun-windows-aarch64.zip instead of falling back to bun-windows-x64-baseline.zip. The x64 fallback is preserved for older versions that lack ARM64 assets. Closes #164 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,7 @@ jobs:
|
|||||||
- latest
|
- latest
|
||||||
- canary
|
- canary
|
||||||
- "1.1.0"
|
- "1.1.0"
|
||||||
|
- "1.3.10"
|
||||||
- "1.x"
|
- "1.x"
|
||||||
- "1"
|
- "1"
|
||||||
- "> 1.0.0"
|
- "> 1.0.0"
|
||||||
|
|||||||
+46
-46
File diff suppressed because one or more lines are too long
+5
-3
@@ -61,13 +61,15 @@ async function getSemverDownloadUrl(options: Input): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const eversion = encodeURIComponent(tag ?? version);
|
const resolvedTag = tag ?? version;
|
||||||
|
const eversion = encodeURIComponent(resolvedTag);
|
||||||
const eos = encodeURIComponent(os ?? getPlatform());
|
const eos = encodeURIComponent(os ?? getPlatform());
|
||||||
const earch = encodeURIComponent(
|
const earch = encodeURIComponent(
|
||||||
getArchitecture(os ?? getPlatform(), arch ?? process.arch),
|
getArchitecture(os ?? getPlatform(), arch ?? process.arch, resolvedTag),
|
||||||
);
|
);
|
||||||
const eavx2 = encodeURIComponent(
|
const eavx2 = encodeURIComponent(
|
||||||
getAvx2(os ?? getPlatform(), arch ?? process.arch, avx2) === false
|
getAvx2(os ?? getPlatform(), arch ?? process.arch, avx2, resolvedTag) ===
|
||||||
|
false
|
||||||
? "-baseline"
|
? "-baseline"
|
||||||
: "",
|
: "",
|
||||||
);
|
);
|
||||||
|
|||||||
+41
-14
@@ -3,6 +3,10 @@ import { info } from "node:console";
|
|||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import { existsSync, readFileSync, renameSync } from "node:fs";
|
import { existsSync, readFileSync, renameSync } from "node:fs";
|
||||||
import { resolve, basename } from "node:path";
|
import { resolve, basename } from "node:path";
|
||||||
|
import { compareVersions, validate } from "compare-versions";
|
||||||
|
|
||||||
|
// First Bun version that ships native Windows ARM64 binaries.
|
||||||
|
const WINDOWS_ARM64_MIN_VERSION = "1.3.10";
|
||||||
|
|
||||||
export function getCacheKey(url: string): string {
|
export function getCacheKey(url: string): string {
|
||||||
return `bun-${createHash("sha1").update(url).digest("base64")}`;
|
return `bun-${createHash("sha1").update(url).digest("base64")}`;
|
||||||
@@ -47,28 +51,51 @@ export function getPlatform(): string {
|
|||||||
return platform;
|
return platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getArchitecture(os: string, arch: string): string {
|
export function hasNativeWindowsArm64(version?: string): boolean {
|
||||||
if (os === "windows" && (arch === "aarch64" || arch === "arm64")) {
|
if (!version) return false;
|
||||||
warning(
|
const cleaned = version.replace(/^bun-v/, "");
|
||||||
[
|
// Non-semver versions like "canary" represent latest builds which ship ARM64.
|
||||||
"⚠️ Bun does not provide native arm64 builds for Windows.",
|
if (!validate(cleaned)) return true;
|
||||||
"Using x64 baseline build which will run through Microsoft's x64 emulation layer.",
|
return compareVersions(cleaned, WINDOWS_ARM64_MIN_VERSION) >= 0;
|
||||||
"This may result in reduced performance and potential compatibility issues.",
|
}
|
||||||
"💡 For best performance, consider using x64 Windows runners or other platforms with native support.",
|
|
||||||
].join("\n"),
|
|
||||||
);
|
|
||||||
|
|
||||||
return "x64";
|
export function getArchitecture(
|
||||||
|
os: string,
|
||||||
|
arch: string,
|
||||||
|
version?: string,
|
||||||
|
): string {
|
||||||
|
if (os === "windows" && (arch === "aarch64" || arch === "arm64")) {
|
||||||
|
if (!hasNativeWindowsArm64(version)) {
|
||||||
|
warning(
|
||||||
|
[
|
||||||
|
"⚠️ This version of Bun does not provide native arm64 builds for Windows.",
|
||||||
|
"Using x64 baseline build which will run through Microsoft's x64 emulation layer.",
|
||||||
|
"This may result in reduced performance and potential compatibility issues.",
|
||||||
|
"💡 For best performance, consider using Bun >= 1.3.10, x64 Windows runners, or other platforms with native support.",
|
||||||
|
].join("\n"),
|
||||||
|
);
|
||||||
|
|
||||||
|
return "x64";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arch === "arm64") return "aarch64";
|
if (arch === "arm64") return "aarch64";
|
||||||
return arch;
|
return arch;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAvx2(os: string, arch: string, avx2?: boolean): boolean {
|
export function getAvx2(
|
||||||
// Temporary workaround for absence of arm64 builds on Windows (#130)
|
os: string,
|
||||||
|
arch: string,
|
||||||
|
avx2?: boolean,
|
||||||
|
version?: string,
|
||||||
|
): boolean {
|
||||||
|
// Workaround for absence of arm64 builds on Windows before 1.3.10 (#130)
|
||||||
if (os === "windows" && (arch === "aarch64" || arch === "arm64")) {
|
if (os === "windows" && (arch === "aarch64" || arch === "arm64")) {
|
||||||
return false;
|
if (!hasNativeWindowsArm64(version)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Native ARM64 builds don't use AVX2 suffix
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return avx2 ?? true;
|
return avx2 ?? true;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ const MOCK_TAGS = [
|
|||||||
{ ref: "refs/tags/bun-v1.0.0" },
|
{ ref: "refs/tags/bun-v1.0.0" },
|
||||||
{ ref: "refs/tags/bun-v1.0.1" },
|
{ ref: "refs/tags/bun-v1.0.1" },
|
||||||
{ ref: "refs/tags/bun-v1.1.0" },
|
{ ref: "refs/tags/bun-v1.1.0" },
|
||||||
|
{ ref: "refs/tags/bun-v1.3.9" },
|
||||||
|
{ ref: "refs/tags/bun-v1.3.10" },
|
||||||
|
{ ref: "refs/tags/bun-v1.4.0" },
|
||||||
{ ref: "refs/tags/canary" },
|
{ ref: "refs/tags/canary" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -98,7 +101,7 @@ describe("getDownloadUrl", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(url).toBe(
|
expect(url).toBe(
|
||||||
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-linux-x64.zip",
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-linux-x64.zip",
|
||||||
);
|
);
|
||||||
expect(requestSpy).toHaveBeenCalledTimes(1);
|
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
@@ -111,7 +114,7 @@ describe("getDownloadUrl", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(url).toBe(
|
expect(url).toBe(
|
||||||
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-linux-x64.zip",
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-linux-x64.zip",
|
||||||
);
|
);
|
||||||
expect(requestSpy).toHaveBeenCalledTimes(1);
|
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
@@ -141,6 +144,86 @@ describe("getDownloadUrl", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Windows ARM64", () => {
|
||||||
|
it("should use native aarch64 binary for Bun >= 1.3.10", async () => {
|
||||||
|
const url = await getDownloadUrl({
|
||||||
|
version: "1.3.10",
|
||||||
|
os: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(url).toBe(
|
||||||
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.3.10/bun-windows-aarch64.zip",
|
||||||
|
);
|
||||||
|
expect(requestSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use native aarch64 binary for Bun 1.4.0", async () => {
|
||||||
|
const url = await getDownloadUrl({
|
||||||
|
version: "1.4.0",
|
||||||
|
os: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(url).toBe(
|
||||||
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-windows-aarch64.zip",
|
||||||
|
);
|
||||||
|
expect(requestSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fall back to x64-baseline for Bun < 1.3.10", async () => {
|
||||||
|
const url = await getDownloadUrl({
|
||||||
|
version: "1.1.0",
|
||||||
|
os: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(url).toBe(
|
||||||
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.1.0/bun-windows-x64-baseline.zip",
|
||||||
|
);
|
||||||
|
expect(requestSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fall back to x64-baseline for Bun 1.3.9", async () => {
|
||||||
|
const url = await getDownloadUrl({
|
||||||
|
version: "1.3.9",
|
||||||
|
os: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(url).toBe(
|
||||||
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.3.9/bun-windows-x64-baseline.zip",
|
||||||
|
);
|
||||||
|
expect(requestSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use native aarch64 for dynamic version resolving to >= 1.3.10", async () => {
|
||||||
|
const url = await getDownloadUrl({
|
||||||
|
version: "^1.3.0",
|
||||||
|
os: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(url).toBe(
|
||||||
|
"https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-windows-aarch64.zip",
|
||||||
|
);
|
||||||
|
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use native aarch64 for canary on Windows ARM64", async () => {
|
||||||
|
const url = await getDownloadUrl({
|
||||||
|
version: "canary",
|
||||||
|
os: "windows",
|
||||||
|
arch: "arm64",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(url).toBe(
|
||||||
|
"https://github.com/oven-sh/bun/releases/download/canary/bun-windows-aarch64.zip",
|
||||||
|
);
|
||||||
|
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("Token Handling", () => {
|
describe("Token Handling", () => {
|
||||||
it("should pass token to API request when resolving dynamic versions", async () => {
|
it("should pass token to API request when resolving dynamic versions", async () => {
|
||||||
await getDownloadUrl({
|
await getDownloadUrl({
|
||||||
|
|||||||
+85
-32
@@ -1,7 +1,32 @@
|
|||||||
import { afterEach, describe, expect, it, spyOn } from "bun:test";
|
import { afterEach, describe, expect, it, spyOn } from "bun:test";
|
||||||
import { getArchitecture, getAvx2 } from "../src/utils";
|
import { getArchitecture, getAvx2, hasNativeWindowsArm64 } from "../src/utils";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
|
describe("hasNativeWindowsArm64", () => {
|
||||||
|
it("should return true for version >= 1.3.10", () => {
|
||||||
|
expect(hasNativeWindowsArm64("bun-v1.3.10")).toBe(true);
|
||||||
|
expect(hasNativeWindowsArm64("bun-v1.3.11")).toBe(true);
|
||||||
|
expect(hasNativeWindowsArm64("bun-v1.4.0")).toBe(true);
|
||||||
|
expect(hasNativeWindowsArm64("bun-v2.0.0")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false for version < 1.3.10", () => {
|
||||||
|
expect(hasNativeWindowsArm64("bun-v1.3.9")).toBe(false);
|
||||||
|
expect(hasNativeWindowsArm64("bun-v1.2.0")).toBe(false);
|
||||||
|
expect(hasNativeWindowsArm64("bun-v1.0.0")).toBe(false);
|
||||||
|
expect(hasNativeWindowsArm64("bun-v0.5.0")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true for non-semver versions like canary", () => {
|
||||||
|
expect(hasNativeWindowsArm64("canary")).toBe(true);
|
||||||
|
expect(hasNativeWindowsArm64("latest")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false for undefined version", () => {
|
||||||
|
expect(hasNativeWindowsArm64(undefined)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("getArchitecture", () => {
|
describe("getArchitecture", () => {
|
||||||
let warningSpy: ReturnType<typeof spyOn>;
|
let warningSpy: ReturnType<typeof spyOn>;
|
||||||
|
|
||||||
@@ -9,30 +34,54 @@ describe("getArchitecture", () => {
|
|||||||
warningSpy?.mockRestore();
|
warningSpy?.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return x64 for Windows with arm64 architecture", () => {
|
it("should return aarch64 for Windows arm64 with Bun >= 1.3.10", () => {
|
||||||
|
warningSpy = spyOn(core, "warning");
|
||||||
|
const result = getArchitecture("windows", "arm64", "bun-v1.3.10");
|
||||||
|
|
||||||
|
expect(result).toBe("aarch64");
|
||||||
|
expect(warningSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return aarch64 for Windows aarch64 with Bun >= 1.3.10", () => {
|
||||||
|
warningSpy = spyOn(core, "warning");
|
||||||
|
const result = getArchitecture("windows", "aarch64", "bun-v1.4.0");
|
||||||
|
|
||||||
|
expect(result).toBe("aarch64");
|
||||||
|
expect(warningSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return x64 for Windows arm64 with Bun < 1.3.10", () => {
|
||||||
|
warningSpy = spyOn(core, "warning");
|
||||||
|
const result = getArchitecture("windows", "arm64", "bun-v1.2.0");
|
||||||
|
|
||||||
|
expect(result).toBe("x64");
|
||||||
|
expect(warningSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining(
|
||||||
|
"⚠️ This version of Bun does not provide native arm64 builds for Windows."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return x64 for Windows aarch64 with Bun < 1.3.10", () => {
|
||||||
|
warningSpy = spyOn(core, "warning");
|
||||||
|
const result = getArchitecture("windows", "aarch64", "bun-v1.0.0");
|
||||||
|
|
||||||
|
expect(result).toBe("x64");
|
||||||
|
expect(warningSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining(
|
||||||
|
"⚠️ This version of Bun does not provide native arm64 builds for Windows."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return x64 for Windows arm64 with no version (fallback)", () => {
|
||||||
warningSpy = spyOn(core, "warning");
|
warningSpy = spyOn(core, "warning");
|
||||||
const result = getArchitecture("windows", "arm64");
|
const result = getArchitecture("windows", "arm64");
|
||||||
|
|
||||||
expect(result).toBe("x64");
|
expect(result).toBe("x64");
|
||||||
expect(warningSpy).toHaveBeenCalledTimes(1);
|
expect(warningSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(warningSpy).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining(
|
|
||||||
"⚠️ Bun does not provide native arm64 builds for Windows."
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return x64 for Windows with aarch64 architecture", () => {
|
|
||||||
warningSpy = spyOn(core, "warning");
|
|
||||||
const result = getArchitecture("windows", "aarch64");
|
|
||||||
|
|
||||||
expect(result).toBe("x64");
|
|
||||||
expect(warningSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(warningSpy).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining(
|
|
||||||
"⚠️ Bun does not provide native arm64 builds for Windows."
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return aarch64 for non-Windows platforms with arm64", () => {
|
it("should return aarch64 for non-Windows platforms with arm64", () => {
|
||||||
@@ -77,24 +126,28 @@ describe("getArchitecture", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("getAvx2", () => {
|
describe("getAvx2", () => {
|
||||||
it("should return false when called with os: 'windows' and arch: 'arm64'", () => {
|
it("should return false for Windows arm64 with Bun < 1.3.10", () => {
|
||||||
const result = getAvx2("windows", "arm64");
|
expect(getAvx2("windows", "arm64", undefined, "bun-v1.2.0")).toBe(false);
|
||||||
expect(result).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return false when called with os: 'windows' and arch: 'aarch64'", () => {
|
it("should return false for Windows aarch64 with Bun < 1.3.10", () => {
|
||||||
const result = getAvx2("windows", "aarch64");
|
expect(getAvx2("windows", "aarch64", undefined, "bun-v1.0.0")).toBe(false);
|
||||||
expect(result).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return false when called with os: 'windows', arch: 'arm64', and avx2: true", () => {
|
it("should return false for Windows arm64 with no version (fallback)", () => {
|
||||||
const result = getAvx2("windows", "arm64", true);
|
expect(getAvx2("windows", "arm64")).toBe(false);
|
||||||
expect(result).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return false when called with os: 'windows', arch: 'aarch64', and avx2: false", () => {
|
it("should return false for Windows aarch64 with no version (fallback)", () => {
|
||||||
const result = getAvx2("windows", "aarch64", false);
|
expect(getAvx2("windows", "aarch64")).toBe(false);
|
||||||
expect(result).toBe(false);
|
});
|
||||||
|
|
||||||
|
it("should return true for Windows arm64 with Bun >= 1.3.10", () => {
|
||||||
|
expect(getAvx2("windows", "arm64", undefined, "bun-v1.3.10")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true for Windows aarch64 with Bun >= 1.3.10", () => {
|
||||||
|
expect(getAvx2("windows", "aarch64", undefined, "bun-v1.4.0")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the provided avx2 value (true) when specified and not on Windows ARM64", () => {
|
it("should return the provided avx2 value (true) when specified and not on Windows ARM64", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user