Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4d14e03ff | ||
|
|
8f24390df0 | ||
|
|
932c3b236c | ||
|
|
9e6479509b | ||
|
|
194c60efc3 | ||
|
|
d3603274ac | ||
|
|
0f37bd8169 | ||
|
|
12944059f7 | ||
|
|
8642d99a51 | ||
|
|
40646b1808 | ||
|
|
94177e527c |
25
.github/workflows/release.yml
vendored
Normal file
25
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: Release new action version
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
TAG_NAME:
|
||||||
|
description: 'Tag name that the major tag will point to'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update_tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/publish-action@v0.3.0
|
||||||
|
with:
|
||||||
|
source-tag: ${{ env.TAG_NAME }}
|
||||||
73
.github/workflows/test.yml
vendored
73
.github/workflows/test.yml
vendored
@@ -16,18 +16,14 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
bun-version: canary
|
|
||||||
os:
|
os:
|
||||||
- ubuntu-latest
|
- ubuntu-latest
|
||||||
- macos-latest
|
- macos-latest
|
||||||
|
- windows-latest
|
||||||
bun-version:
|
bun-version:
|
||||||
- latest
|
- latest
|
||||||
- canary
|
- canary
|
||||||
- "0.8.1" # last version before 1.0
|
- "1.1.0"
|
||||||
- "0.x"
|
|
||||||
- "1.0.0"
|
|
||||||
- "1.x"
|
- "1.x"
|
||||||
- "1"
|
- "1"
|
||||||
- "> 1.0.0"
|
- "> 1.0.0"
|
||||||
@@ -38,13 +34,18 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: ./
|
uses: ./
|
||||||
|
id: setup_bun
|
||||||
with:
|
with:
|
||||||
bun-version: ${{ matrix.bun-version }}
|
bun-version: ${{ matrix.bun-version }}
|
||||||
|
|
||||||
- name: Run Bun
|
- name: Run Bun
|
||||||
|
id: run_bun
|
||||||
run: |
|
run: |
|
||||||
bun --version
|
bun --version
|
||||||
|
|
||||||
setup-bun-from-package-json-version:
|
setup-bun-from-package-json-version:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -52,27 +53,73 @@ jobs:
|
|||||||
os:
|
os:
|
||||||
- ubuntu-latest
|
- ubuntu-latest
|
||||||
- macos-latest
|
- macos-latest
|
||||||
|
- windows-latest
|
||||||
packageManager:
|
packageManager:
|
||||||
- bun@1.0.0
|
- bun@1.1.0
|
||||||
- yarn@bun@1.0.0
|
- yarn@bun@1.1.0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup package.json
|
- name: Setup package.json
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "$(jq '. += {"packageManager": "${{ matrix.packageManager }}"}' package.json)" > package.json
|
echo "$(jq '. += {"packageManager": "${{ matrix.packageManager }}"}' package.json)" > package.json
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
||||||
- name: Run Bun
|
- name: Run Bun
|
||||||
id: bun
|
id: bun
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
bun --version
|
bun --version
|
||||||
echo "version=$(bun --version)" >> $GITHUB_OUTPUT
|
echo "version=$(bun --version)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Check version
|
- name: Check version
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ steps.bun.outputs.version }}" == "1.0.0" ]]; then
|
if [[ "${{ steps.bun.outputs.version }}" == "1.1.0" ]]; then
|
||||||
echo "Version is 1.0.0"
|
echo "Version is 1.1.0"
|
||||||
else
|
else
|
||||||
echo "Expected version to be 1.0.0, got ${{ steps.bun.outputs.version }}"
|
echo "Expected version to be 1.1.0, got ${{ steps.bun.outputs.version }}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
setup-bun-from-tool-versions:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- macos-latest
|
||||||
|
- windows-latest
|
||||||
|
content:
|
||||||
|
- "bun 1.1.0"
|
||||||
|
- "bun1.1.0"
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Setup package.json
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "bun ${{ matrix.content }}" > .tool-versions
|
||||||
|
|
||||||
|
- name: Setup Bun
|
||||||
|
uses: ./
|
||||||
|
|
||||||
|
- name: Run Bun
|
||||||
|
id: bun
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
bun --version
|
||||||
|
echo "version=$(bun --version)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Check version
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [[ "${{ steps.bun.outputs.version }}" == "1.1.0" ]]; then
|
||||||
|
echo "Version is 1.1.0"
|
||||||
|
else
|
||||||
|
echo "Expected version to be 1.1.0, got ${{ steps.bun.outputs.version }}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
@@ -25,16 +25,21 @@ If you need to authenticate with a private registry, you can set the `BUN_AUTH_T
|
|||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
env:
|
env:
|
||||||
BUN_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
BUN_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
run: bun install
|
run: bun install --frozen-lockfile
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Node.js not needed
|
||||||
|
|
||||||
|
In most cases, you shouldn't need to use the [setup-node](https://github.com/actions/setup-node) GitHub Action.
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
|
|
||||||
| Name | Description | Default | Examples |
|
| Name | Description | Default | Examples |
|
||||||
| -------------- | -------------------------------------------------- | ----------- | ------------------------------- |
|
| -------------- | -------------------------------------------------- | ----------- | ------------------------------- |
|
||||||
| `bun-version` | The version of Bun to download and install. | `latest` | `canary`, `1.0.0`, `1.0.x` |
|
| `bun-version` | The version of Bun to download and install. | `latest` | `canary`, `1.0.0`, `1.0.x` |
|
||||||
| `registry-url` | Registry URL where some private package is stored. | `undefined` | `"https://npm.pkg.github.com/"` |
|
| `registry-url` | Registry URL where some private package is stored. | `undefined` | `"https://npm.pkg.github.com/"` |
|
||||||
| `scope` | Scope for private pacakages. | `undefined` | `"@foo"`, `"@orgname"` |
|
| `scope` | Scope for private packages. | `undefined` | `"@foo"`, `"@orgname"` |
|
||||||
|
| `no-cache` | Disable caching of the downloaded executable. | `false` | `true`, `false` |
|
||||||
|
|
||||||
## Outputs
|
## Outputs
|
||||||
|
|
||||||
|
|||||||
14
action.yml
14
action.yml
@@ -5,6 +5,9 @@ branding:
|
|||||||
icon: play-circle
|
icon: play-circle
|
||||||
color: white
|
color: white
|
||||||
inputs:
|
inputs:
|
||||||
|
bun-download-url:
|
||||||
|
description: "Override the URL to download Bun from. This skips version resolution and verifying AVX2 support."
|
||||||
|
required: false
|
||||||
bun-version:
|
bun-version:
|
||||||
description: 'The version of Bun to install. (e.g. "latest", "canary", "1.0.0", "1.0.x", <sha>)'
|
description: 'The version of Bun to install. (e.g. "latest", "canary", "1.0.0", "1.0.x", <sha>)'
|
||||||
required: false
|
required: false
|
||||||
@@ -14,6 +17,11 @@ inputs:
|
|||||||
scope:
|
scope:
|
||||||
required: false
|
required: false
|
||||||
description: "The scope for authenticating with the package registry."
|
description: "The scope for authenticating with the package registry."
|
||||||
|
no-cache:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: "Disable caching of bun executable."
|
||||||
outputs:
|
outputs:
|
||||||
bun-version:
|
bun-version:
|
||||||
description: The version of Bun that was installed.
|
description: The version of Bun that was installed.
|
||||||
@@ -22,5 +30,7 @@ outputs:
|
|||||||
cache-hit:
|
cache-hit:
|
||||||
description: If the version of Bun was cached.
|
description: If the version of Bun was cached.
|
||||||
runs:
|
runs:
|
||||||
using: node20
|
using: "node20"
|
||||||
main: dist/index.js
|
main: "dist/setup/index.js"
|
||||||
|
post: "dist/cache-save/index.js"
|
||||||
|
post-if: success()
|
||||||
|
|||||||
68
dist/cache-save/index.js
generated
vendored
Normal file
68
dist/cache-save/index.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
64
dist/index.js → dist/setup/index.js
generated
vendored
64
dist/index.js → dist/setup/index.js
generated
vendored
File diff suppressed because one or more lines are too long
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "setup-bun",
|
"name": "setup-bun",
|
||||||
"version": "1.1.1",
|
"version": "1.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "setup-bun",
|
"name": "setup-bun",
|
||||||
"version": "1.1.1",
|
"version": "1.2.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^3.1.4",
|
"@actions/cache": "^3.1.4",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "setup-bun",
|
"name": "setup-bun",
|
||||||
"version": "1.1.1",
|
"version": "1.2.1",
|
||||||
"description": "Setup Bun on GitHub Actions.",
|
"description": "Setup Bun on GitHub Actions.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bun",
|
"bun",
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
"author": "xHyroM",
|
"author": "xHyroM",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write src *.yml *.json *.md",
|
"format": "prettier --write src *.yml *.json *.md",
|
||||||
"build": "esbuild --target=node20 --outdir=dist --bundle --minify --platform=node --format=cjs src/index.ts",
|
"build": "esbuild --target=node20 --outfile=dist/setup/index.js --bundle --minify --platform=node --format=cjs src/index.ts && esbuild --target=node20 --outfile=dist/cache-save/index.js --bundle --minify --platform=node --format=cjs src/cache-save.ts",
|
||||||
"start": "npm run build && node dist/index.js"
|
"start": "npm run build && node dist/setup/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^3.1.4",
|
"@actions/cache": "^3.1.4",
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import {
|
|||||||
copyFileSync,
|
copyFileSync,
|
||||||
} from "node:fs";
|
} from "node:fs";
|
||||||
import { addPath, info, warning } from "@actions/core";
|
import { addPath, info, warning } from "@actions/core";
|
||||||
import { isFeatureAvailable, restoreCache, saveCache } from "@actions/cache";
|
import { isFeatureAvailable, restoreCache } from "@actions/cache";
|
||||||
import { downloadTool, extractZip } from "@actions/tool-cache";
|
import { downloadTool, extractZip } from "@actions/tool-cache";
|
||||||
import { getExecOutput } from "@actions/exec";
|
import { getExecOutput } from "@actions/exec";
|
||||||
import { writeBunfig } from "./bunfig";
|
import { writeBunfig } from "./bunfig";
|
||||||
|
import { saveState } from "@actions/core";
|
||||||
|
import { retry } from "./utils";
|
||||||
|
|
||||||
export type Input = {
|
export type Input = {
|
||||||
customUrl?: string;
|
customUrl?: string;
|
||||||
@@ -22,6 +24,7 @@ export type Input = {
|
|||||||
profile?: boolean;
|
profile?: boolean;
|
||||||
scope?: string;
|
scope?: string;
|
||||||
registryUrl?: string;
|
registryUrl?: string;
|
||||||
|
noCache?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Output = {
|
export type Output = {
|
||||||
@@ -30,6 +33,13 @@ export type Output = {
|
|||||||
cacheHit: boolean;
|
cacheHit: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CacheState = {
|
||||||
|
cacheEnabled: boolean;
|
||||||
|
cacheHit: boolean;
|
||||||
|
bunPath: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default async (options: Input): Promise<Output> => {
|
export default async (options: Input): Promise<Output> => {
|
||||||
const bunfigPath = join(process.cwd(), "bunfig.toml");
|
const bunfigPath = join(process.cwd(), "bunfig.toml");
|
||||||
writeBunfig(bunfigPath, options);
|
writeBunfig(bunfigPath, options);
|
||||||
@@ -77,17 +87,8 @@ export default async (options: Input): Promise<Output> => {
|
|||||||
|
|
||||||
if (!cacheHit) {
|
if (!cacheHit) {
|
||||||
info(`Downloading a new version of Bun: ${url}`);
|
info(`Downloading a new version of Bun: ${url}`);
|
||||||
const zipPath = await downloadTool(url);
|
// TODO: remove this, temporary fix for https://github.com/oven-sh/setup-bun/issues/73
|
||||||
const extractedZipPath = await extractZip(zipPath);
|
revision = await retry(async () => await downloadBun(url, bunPath), 3);
|
||||||
const extractedBunPath = await extractBun(extractedZipPath);
|
|
||||||
try {
|
|
||||||
renameSync(extractedBunPath, bunPath);
|
|
||||||
} catch {
|
|
||||||
// If mv does not work, try to copy the file instead.
|
|
||||||
// For example: EXDEV: cross-device link not permitted
|
|
||||||
copyFileSync(extractedBunPath, bunPath);
|
|
||||||
}
|
|
||||||
revision = await getRevision(bunPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!revision) {
|
if (!revision) {
|
||||||
@@ -96,15 +97,17 @@ export default async (options: Input): Promise<Output> => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cacheEnabled && !cacheHit) {
|
|
||||||
try {
|
|
||||||
await saveCache([bunPath], url);
|
|
||||||
} catch (error) {
|
|
||||||
warning("Failed to save Bun to cache.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [version] = revision.split("+");
|
const [version] = revision.split("+");
|
||||||
|
|
||||||
|
const cacheState: CacheState = {
|
||||||
|
cacheEnabled,
|
||||||
|
cacheHit,
|
||||||
|
bunPath,
|
||||||
|
url,
|
||||||
|
};
|
||||||
|
|
||||||
|
saveState("cache", JSON.stringify(cacheState));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version,
|
version,
|
||||||
revision,
|
revision,
|
||||||
@@ -112,8 +115,29 @@ export default async (options: Input): Promise<Output> => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function downloadBun(
|
||||||
|
url: string,
|
||||||
|
bunPath: string
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
const zipPath = await downloadTool(url);
|
||||||
|
const extractedZipPath = await extractZip(zipPath);
|
||||||
|
const extractedBunPath = await extractBun(extractedZipPath);
|
||||||
|
try {
|
||||||
|
renameSync(extractedBunPath, bunPath);
|
||||||
|
} catch {
|
||||||
|
// If mv does not work, try to copy the file instead.
|
||||||
|
// For example: EXDEV: cross-device link not permitted
|
||||||
|
copyFileSync(extractedBunPath, bunPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await getRevision(bunPath);
|
||||||
|
}
|
||||||
|
|
||||||
function isCacheEnabled(options: Input): boolean {
|
function isCacheEnabled(options: Input): boolean {
|
||||||
const { customUrl, version } = options;
|
const { customUrl, version, noCache } = options;
|
||||||
|
if (noCache) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (customUrl) {
|
if (customUrl) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/cache-save.ts
Normal file
15
src/cache-save.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { saveCache } from "@actions/cache";
|
||||||
|
import { getState, warning } from "@actions/core";
|
||||||
|
import { CacheState } from "./action";
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const state: CacheState = JSON.parse(getState("cache"));
|
||||||
|
if (state.cacheEnabled && !state.cacheHit) {
|
||||||
|
try {
|
||||||
|
await saveCache([state.bunPath], state.url);
|
||||||
|
process.exit(0);
|
||||||
|
} catch (error) {
|
||||||
|
warning("Failed to save Bun to cache.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
37
src/index.ts
37
src/index.ts
@@ -1,7 +1,13 @@
|
|||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { existsSync, readFileSync } from "node:fs";
|
import { existsSync, readFileSync } from "node:fs";
|
||||||
import { getInput, setOutput, setFailed, warning } from "@actions/core";
|
import {
|
||||||
|
getInput,
|
||||||
|
setOutput,
|
||||||
|
setFailed,
|
||||||
|
warning,
|
||||||
|
getBooleanInput,
|
||||||
|
} from "@actions/core";
|
||||||
import runAction from "./action.js";
|
import runAction from "./action.js";
|
||||||
|
|
||||||
if (!process.env.RUNNER_TEMP) {
|
if (!process.env.RUNNER_TEMP) {
|
||||||
@@ -30,17 +36,44 @@ function readVersionFromPackageJson(): string | undefined {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readVersionFromToolVersions(): string | undefined {
|
||||||
|
const cwd = process.env.GITHUB_WORKSPACE;
|
||||||
|
if (!cwd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = join(cwd, ".tool-versions");
|
||||||
|
try {
|
||||||
|
if (!existsSync(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = readFileSync(path, "utf8").match(/^bun\s(?<version>.*?)$/m);
|
||||||
|
|
||||||
|
return match?.groups?.version;
|
||||||
|
} catch (error) {
|
||||||
|
const { message } = error as Error;
|
||||||
|
warning(`Failed to read .tool-versions: ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runAction({
|
runAction({
|
||||||
version: getInput("bun-version") || readVersionFromPackageJson() || undefined,
|
version:
|
||||||
|
getInput("bun-version") ||
|
||||||
|
readVersionFromPackageJson() ||
|
||||||
|
readVersionFromToolVersions() ||
|
||||||
|
undefined,
|
||||||
customUrl: getInput("bun-download-url") || undefined,
|
customUrl: getInput("bun-download-url") || undefined,
|
||||||
registryUrl: getInput("registry-url") || undefined,
|
registryUrl: getInput("registry-url") || undefined,
|
||||||
scope: getInput("scope") || undefined,
|
scope: getInput("scope") || undefined,
|
||||||
|
noCache: getBooleanInput("no-cache") || false,
|
||||||
})
|
})
|
||||||
.then(({ version, revision, cacheHit }) => {
|
.then(({ version, revision, cacheHit }) => {
|
||||||
setOutput("bun-version", version);
|
setOutput("bun-version", version);
|
||||||
setOutput("bun-revision", revision);
|
setOutput("bun-revision", revision);
|
||||||
setOutput("cache-hit", cacheHit);
|
setOutput("cache-hit", cacheHit);
|
||||||
|
process.exit(0);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setFailed(error);
|
setFailed(error);
|
||||||
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
14
src/utils.ts
Normal file
14
src/utils.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export function retry<T>(
|
||||||
|
fn: () => Promise<T>,
|
||||||
|
retries: number,
|
||||||
|
timeout = 10000
|
||||||
|
): Promise<T> {
|
||||||
|
return fn().catch((err) => {
|
||||||
|
if (retries <= 0) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, timeout)).then(() =>
|
||||||
|
retry(fn, retries - 1, timeout)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user