Skip to content

Commit 8c296f9

Browse files
feat: implement wildcard resolution into the action (#93)
* feat: remove retry attempts * [autofix.ci] apply automated fixes * feat: get download url from github's api * [autofix.ci] apply automated fixes * fix: add token property to action definition & fix satisfies params * [autofix.ci] apply automated fixes * fix: getPlatform, getArchitecture + eversion * [autofix.ci] apply automated fixes * fix: duplicate v * [autofix.ci] apply automated fixes * fix: check if valid semver and add bun-v * [autofix.ci] apply automated fixes * refactor: wrap validation * [autofix.ci] apply automated fixes * ci(format): use bun bun install is rqeuired for patches * ci(format): use bun bun install is rqeuired for patches * [autofix.ci] apply automated fixes * feat: bring back support for sha downloads * [autofix.ci] apply automated fixes * fix: add bearer prefix for token * [autofix.ci] apply automated fixes * fix: proper error when artifact is not found * [autofix.ci] apply automated fixes * conflicts * autofix build * fix * fix * fix * fix * fix * autofix build * fix * [autofix.ci] apply automated fixes * fix * [autofix.ci] apply automated fixes * fix * [autofix.ci] apply automated fixes * fix * fix * [autofix.ci] apply automated fixes * fix * fix * [autofix.ci] apply automated fixes * fix: drop sha support for now * [autofix.ci] apply automated fixes * fix: filter tags * [autofix.ci] apply automated fixes * docs: token * docs: token * docs: token * refactor: cleanup * [autofix.ci] apply automated fixes * refactor: cleanup --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent b7a1c7c commit 8c296f9

13 files changed

Lines changed: 389 additions & 164 deletions

File tree

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,86 @@
11
name: ⚖️ Compare Bun Version
2-
description: Compare the version of Bun to a specified version
2+
description: Compare the installed Bun version against a version specification.
33

44
inputs:
55
bun-version:
6-
description: The version of Bun to compare against
6+
description: The version spec to compare against (e.g., '1.1.0', 'canary', '>1.2.0', '1.x').
77
required: true
8-
default: "1.1.0"
98

109
runs:
1110
using: composite
1211
steps:
13-
- name: 🛠️ Get installed Bun version
12+
- name: 🛠️ Get installed Bun version and revision
1413
id: bun
1514
shell: bash
1615
run: |
17-
bun --version
18-
echo "version=$(bun --version)" >> $GITHUB_OUTPUT
16+
echo "version=$(bun --version | tr -d '\r\n')" >> $GITHUB_OUTPUT
17+
echo "revision=$(bun --revision 2>/dev/null || true)" >> $GITHUB_OUTPUT
1918
2019
- name: ⚖️ Compare versions
2120
shell: bash
21+
env:
22+
REQUESTED_SPEC: ${{ inputs.bun-version }}
23+
ACTUAL_VERSION: ${{ steps.bun.outputs.version }}
24+
ACTUAL_REVISION: ${{ steps.bun.outputs.revision }}
2225
run: |
23-
if [[ "${{ steps.bun.outputs.version }}" == "${{ inputs.bun-version }}" ]]; then
24-
echo "Version is ${{ inputs.bun-version }}"
25-
else
26-
echo "Expected version to be ${{ inputs.bun-version }}, got ${{ steps.bun.outputs.version }}"
27-
exit 1
26+
set -euo pipefail
27+
28+
# Function to compare two semantic versions (e.g., version_compare 1.2.3 1.10.0)
29+
# Returns: 0 if v1 == v2, 1 if v1 > v2, 2 if v1 < v2
30+
version_compare() {
31+
if [[ "$1" == "$2" ]]; then return 0; fi
32+
local lowest=$(printf '%s\n' "$1" "$2" | sort -V | head -n1)
33+
if [[ "$1" == "$lowest" ]]; then return 2; else return 1; fi
34+
}
35+
36+
echo "Requested spec: ${REQUESTED_SPEC}"
37+
echo "Actual version: ${ACTUAL_VERSION}"
38+
39+
# Case 1: 'latest' - always passes
40+
if [[ "${REQUESTED_SPEC}" == "latest" ]]; then
41+
echo "OK: Skipping explicit version check for 'latest'."
42+
exit 0
43+
fi
44+
45+
# Case 2: 'canary' - check for 'canary' in revision or version string
46+
if [[ "${REQUESTED_SPEC}" == "canary" ]]; then
47+
if [[ "${ACTUAL_REVISION}" == *canary* ]] || [[ "${ACTUAL_VERSION}" == *canary* ]]; then
48+
echo "OK: Detected canary build (version: ${ACTUAL_VERSION}, revision: ${ACTUAL_REVISION:-n/a})."
49+
exit 0
50+
else
51+
echo "Error: Expected a canary build, but got ${ACTUAL_VERSION} (revision: ${ACTUAL_REVISION:-n/a})."
52+
exit 1
53+
fi
54+
fi
55+
56+
# Case 3: Semver ranges (e.g., >1.0.0, <2, 1.x, 1.1.0)
57+
op_part=$(echo "${REQUESTED_SPEC}" | sed -E 's/^([><=]*).*/\1/')
58+
version_part=$(echo "${REQUESTED_SPEC}" | sed -E 's/^[><= ]*//')
59+
60+
op="${op_part:-==}"
61+
version_base="${version_part//.x/}"
62+
63+
# Handle wildcards like '1.x' or '1'
64+
if [[ "${version_part}" == *.x* ]] || { [[ ! "${version_part}" == *.* ]] && [[ "${op}" == "==" ]]; }; then
65+
if [[ "${ACTUAL_VERSION}" == "${version_base}" || "${ACTUAL_VERSION}" == "${version_base}".* ]]; then
66+
echo "OK: Version ${ACTUAL_VERSION} matches wildcard spec '${REQUESTED_SPEC}'."
67+
exit 0
68+
else
69+
echo "Error: Version ${ACTUAL_VERSION} does not match wildcard spec '${REQUESTED_SPEC}'."
70+
exit 1
71+
fi
2872
fi
73+
74+
# Perform comparison for >, <, >=, <=, ==
75+
version_compare "${ACTUAL_VERSION}" "${version_part}" && result=0 || result=$?
76+
77+
case "${op}" in
78+
'==') if [[ ${result} -ne 0 ]]; then echo "Error: Expected version ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;;
79+
'>') if [[ ${result} -ne 1 ]]; then echo "Error: Expected version > ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;;
80+
'<') if [[ ${result} -ne 2 ]]; then echo "Error: Expected version < ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;;
81+
'>=') if [[ ${result} -eq 2 ]]; then echo "Error: Expected version >= ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;;
82+
'<=') if [[ ${result} -eq 1 ]]; then echo "Error: Expected version <= ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;;
83+
*) echo "Error: Unsupported operator '${op}' in spec '${REQUESTED_SPEC}'." && exit 1 ;;
84+
esac
85+
86+
echo "OK: Version ${ACTUAL_VERSION} satisfies spec '${REQUESTED_SPEC}'."

.github/workflows/test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ jobs:
5454
- latest
5555
- canary
5656
- "1.1.0"
57+
- "1.x"
58+
- "1"
59+
- "> 1.0.0"
60+
- "< 2"
5761
# https://github.com/oven-sh/setup-bun/issues/37
5862
# - "1.x"
5963
# - "1"
@@ -78,6 +82,11 @@ jobs:
7882
run: |
7983
bun --version
8084
85+
- name: ⚖️ Verify Bun version
86+
uses: ./.github/actions/compare-bun-version
87+
with:
88+
bun-version: ${{ matrix.bun-version }}
89+
8190
setup-bun-from-file:
8291
name: setup-bun from (${{ matrix.os }}, ${{ matrix.file.name }})
8392
runs-on: ${{ matrix.os }}

README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,15 @@ If you need to override the download URL, you can use the `bun-download-url` inp
6666

6767
## Inputs
6868

69-
| Name | Description | Default | Examples |
70-
| ------------------ | ----------------------------------------------------- | ----------- | ------------------------------------------------ |
71-
| `bun-version` | The version of Bun to download and install. | `latest` | `canary`, `1.0.0` |
72-
| `bun-version-file` | The version of Bun to download and install from file. | `undefined` | `package.json`, `.bun-version`, `.tool-versions` |
73-
| `bun-download-url` | URL to download .zip file for Bun release | | |
74-
| `registry-url` | Registry URL where some private package is stored. | `undefined` | `"https://npm.pkg.github.com/"` |
75-
| `scope` | Scope for private packages. | `undefined` | `"@foo"`, `"@orgname"` |
76-
| `no-cache` | Disable caching of the downloaded executable. | `false` | `true`, `false` |
69+
| Name | Description | Default | Examples |
70+
| ------------------ | --------------------------------------------------------------------------------- | --------------------- | ------------------------------------------------ |
71+
| `bun-version` | The version of Bun to download and install. | `latest` | `canary`, `1.0.0`, `1.0.x` |
72+
| `bun-version-file` | The version of Bun to download and install from file. | `undefined` | `package.json`, `.bun-version`, `.tool-versions` |
73+
| `bun-download-url` | URL to download .zip file for Bun release | | |
74+
| `registry-url` | Registry URL where some private package is stored. | `undefined` | `"https://npm.pkg.github.com/"` |
75+
| `scope` | Scope for private packages. | `undefined` | `"@foo"`, `"@orgname"` |
76+
| `no-cache` | Disable caching of the downloaded executable. | `false` | `true`, `false` |
77+
| `token` | Personal access token (PAT) used to fetch tags from the `oven-sh/bun` repository. | `${{ github.token }}` | `${{ secrets.GITHUB_TOKEN }}` |
7778

7879
## Outputs
7980

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ inputs:
3939
type: boolean
4040
default: false
4141
description: Disable caching of bun executable.
42+
token:
43+
required: false
44+
default: ${{ github.token }}
45+
description: Personal access token (PAT) used to fetch tags from oven-sh/bun repository. Recommended for resolving wildcard/range versions to avoid GitHub API rate limiting.
4246

4347
outputs:
4448
bun-version:

bun.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/setup/index.js

Lines changed: 110 additions & 109 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,17 @@
2828
"@actions/glob": "^0.4.0",
2929
"@actions/io": "^1.1.2",
3030
"@actions/tool-cache": "^2.0.1",
31-
"@iarna/toml": "^2.2.5"
31+
"@iarna/toml": "^2.2.5",
32+
"compare-versions": "^6.1.1"
3233
},
3334
"devDependencies": {
3435
"@types/bun": "^1.1.13",
3536
"@types/node": "^20.8.2",
3637
"esbuild": "^0.19.2",
3738
"prettier": "^3.4.2",
3839
"typescript": "^4.9.5"
40+
},
41+
"patchedDependencies": {
42+
"compare-versions@6.1.1": "patches/compare-versions@6.1.1.patch"
3943
}
4044
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
diff --git a/lib/esm/satisfies.js b/lib/esm/satisfies.js
2+
index 7586b71657332f855431c4dd4f05e9394fd9aac3..a6ec29bfc98907c67ed4af71fca73bd8bff88798 100644
3+
--- a/lib/esm/satisfies.js
4+
+++ b/lib/esm/satisfies.js
5+
@@ -40,8 +40,9 @@ export const satisfies = (version, range) => {
6+
// else range of either "~" or "^" is assumed
7+
const [v1, v2, v3, , vp] = validateAndParse(version);
8+
const [r1, r2, r3, , rp] = validateAndParse(range);
9+
- const v = [v1, v2, v3];
10+
+ const v = [v1, v2 !== null && v2 !== void 0 ? v2 : 'x', v3 !== null && v3 !== void 0 ? v3 : 'x'];
11+
const r = [r1, r2 !== null && r2 !== void 0 ? r2 : 'x', r3 !== null && r3 !== void 0 ? r3 : 'x'];
12+
+
13+
// validate pre-release
14+
if (rp) {
15+
if (!vp)
16+
diff --git a/lib/esm/utils.js b/lib/esm/utils.js
17+
index b5cc8b9927ab38fc67032c133b531e95ec4cec15..ec56105fd2d806aa922f1488a27b02c56aff1865 100644
18+
--- a/lib/esm/utils.js
19+
+++ b/lib/esm/utils.js
20+
@@ -28,7 +28,7 @@ const compareStrings = (a, b) => {
21+
};
22+
export const compareSegments = (a, b) => {
23+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
24+
- const r = compareStrings(a[i] || '0', b[i] || '0');
25+
+ const r = compareStrings(a[i] || 'x', b[i] || 'x');
26+
if (r !== 0)
27+
return r;
28+
}
29+
diff --git a/lib/umd/index.js b/lib/umd/index.js
30+
index 2cfef261bca520e21ed41fc14950732b8aa6339b..1059784db86635f3aaaba83b5a72c5015e1d8490 100644
31+
--- a/lib/umd/index.js
32+
+++ b/lib/umd/index.js
33+
@@ -152,7 +152,7 @@
34+
// else range of either "~" or "^" is assumed
35+
const [v1, v2, v3, , vp] = validateAndParse(version);
36+
const [r1, r2, r3, , rp] = validateAndParse(range);
37+
- const v = [v1, v2, v3];
38+
+ const v = [v1, v2 !== null && v2 !== void 0 ? v2 : 'x', v3 !== null && v3 !== void 0 ? v3 : 'x'];
39+
const r = [r1, r2 !== null && r2 !== void 0 ? r2 : 'x', r3 !== null && r3 !== void 0 ? r3 : 'x'];
40+
// validate pre-release
41+
if (rp) {
42+
diff --git a/package.json b/package.json
43+
index b05b3daf706d7ba4e594233f8791fc3007a8e2cd..e51e76b86f95e9ebf0b5dba3b82aeb119628528d 100644
44+
--- a/package.json
45+
+++ b/package.json
46+
@@ -26,7 +26,7 @@
47+
"prepublishOnly": "npm run build",
48+
"test": "c8 --reporter=lcov mocha"
49+
},
50+
- "main": "./lib/umd/index.js",
51+
+ "main": "./lib/src/index.ts",
52+
"module": "./lib/esm/index.js",
53+
"types": "./lib/esm/index.d.ts",
54+
"sideEffects": false,
55+
diff --git a/src/satisfies.ts b/src/satisfies.ts
56+
index 66cb171d7f32e68fdda6929d2da223b97a053737..6b4973f037843f264338a01efdc4ace5dcf042cd 100644
57+
--- a/src/satisfies.ts
58+
+++ b/src/satisfies.ts
59+
@@ -43,7 +43,7 @@ export const satisfies = (version: string, range: string): boolean => {
60+
// else range of either "~" or "^" is assumed
61+
const [v1, v2, v3, , vp] = validateAndParse(version);
62+
const [r1, r2, r3, , rp] = validateAndParse(range);
63+
- const v = [v1, v2, v3];
64+
+ const v = [v1, v2 ?? 'x', v3 ?? 'x'];
65+
const r = [r1, r2 ?? 'x', r3 ?? 'x'];
66+
67+
// validate pre-release

src/action.ts

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import { addPath, info, warning } from "@actions/core";
1313
import { isFeatureAvailable, restoreCache } from "@actions/cache";
1414
import { downloadTool, extractZip } from "@actions/tool-cache";
1515
import { getExecOutput } from "@actions/exec";
16-
import { writeBunfig, Registry } from "./bunfig";
16+
import { Registry } from "./registry";
17+
import { writeBunfig } from "./bunfig";
1718
import { saveState } from "@actions/core";
18-
import { addExtension, retry } from "./utils";
19+
import { addExtension } from "./utils";
20+
import { getDownloadUrl } from "./download-url";
1921
import { cwd } from "node:process";
2022

2123
export type Input = {
@@ -27,6 +29,7 @@ export type Input = {
2729
profile?: boolean;
2830
registries?: Registry[];
2931
noCache?: boolean;
32+
token?: string;
3033
};
3134

3235
export type Output = {
@@ -48,7 +51,7 @@ export default async (options: Input): Promise<Output> => {
4851
const bunfigPath = join(cwd(), "bunfig.toml");
4952
writeBunfig(bunfigPath, options.registries);
5053

51-
const url = getDownloadUrl(options);
54+
const url = await getDownloadUrl(options);
5255
const cacheEnabled = isCacheEnabled(options);
5356

5457
const binPath = join(homedir(), ".bun", "bin");
@@ -105,8 +108,7 @@ export default async (options: Input): Promise<Output> => {
105108

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

@@ -192,24 +194,6 @@ function isCacheEnabled(options: Input): boolean {
192194
return isFeatureAvailable();
193195
}
194196

195-
function getDownloadUrl(options: Input): string {
196-
const { customUrl } = options;
197-
if (customUrl) {
198-
return customUrl;
199-
}
200-
const { version, os, arch, avx2, profile } = options;
201-
const eversion = encodeURIComponent(version ?? "latest");
202-
const eos = encodeURIComponent(os ?? process.platform);
203-
const earch = encodeURIComponent(arch ?? process.arch);
204-
const eavx2 = encodeURIComponent(avx2 ?? true);
205-
const eprofile = encodeURIComponent(profile ?? false);
206-
const { href } = new URL(
207-
`${eversion}/${eos}/${earch}?avx2=${eavx2}&profile=${eprofile}`,
208-
"https://bun.sh/download/",
209-
);
210-
return href;
211-
}
212-
213197
async function extractBun(path: string): Promise<string> {
214198
for (const entry of readdirSync(path, { withFileTypes: true })) {
215199
const { name } = entry;

0 commit comments

Comments
 (0)