diff --git a/dist/index.js b/dist/index.js index de75da91..37e4b64e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -44,6 +44,7 @@ const core = __importStar(__nccwpck_require__(2186)); const github = __importStar(__nccwpck_require__(5438)); const path = __importStar(__nccwpck_require__(1017)); const glob = __importStar(__nccwpck_require__(1957)); +const attempt_1 = __nccwpck_require__(6494); const releaseByTag = 'GET /repos/{owner}/{repo}/releases/tags/{tag}'; const createRelease = 'POST /repos/{owner}/{repo}/releases'; const repoAssets = 'GET /repos/{owner}/{repo}/releases/{release_id}/assets'; @@ -93,10 +94,14 @@ function upload_to_release(release, file, asset_name, tag, overwrite, octokit) { core.debug(`No pre-existing asset called ${asset_name} found in release ${tag}. All good.`); } core.debug(`Uploading ${file} to ${asset_name} in release ${tag}.`); - const uploaded_asset = yield octokit.request(uploadAssets, Object.assign(Object.assign({}, repo()), { release_id: release.data.id, url: release.data.upload_url, name: asset_name, data: file_bytes, headers: { - 'content-type': 'binary/octet-stream', - 'content-length': file_size - } })); + const uploaded_asset = yield (0, attempt_1.retry)(() => __awaiter(this, void 0, void 0, function* () { + return octokit.request(uploadAssets, Object.assign(Object.assign({}, repo()), { release_id: release.data.id, url: release.data.upload_url, name: asset_name, data: file_bytes, headers: { + 'content-type': 'binary/octet-stream', + 'content-length': file_size + } })); + }), { + maxAttempts: 3 + }); return uploaded_asset.data.browser_download_url; }); } @@ -2146,6 +2151,168 @@ function checkBypass(reqUrl) { exports.checkBypass = checkBypass; //# sourceMappingURL=proxy.js.map +/***/ }), + +/***/ 6494: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +function applyDefaults(options) { + if (!options) { + options = {}; + } + return { + delay: (options.delay === undefined) ? 200 : options.delay, + initialDelay: (options.initialDelay === undefined) ? 0 : options.initialDelay, + minDelay: (options.minDelay === undefined) ? 0 : options.minDelay, + maxDelay: (options.maxDelay === undefined) ? 0 : options.maxDelay, + factor: (options.factor === undefined) ? 0 : options.factor, + maxAttempts: (options.maxAttempts === undefined) ? 3 : options.maxAttempts, + timeout: (options.timeout === undefined) ? 0 : options.timeout, + jitter: (options.jitter === true), + handleError: (options.handleError === undefined) ? null : options.handleError, + handleTimeout: (options.handleTimeout === undefined) ? null : options.handleTimeout, + beforeAttempt: (options.beforeAttempt === undefined) ? null : options.beforeAttempt, + calculateDelay: (options.calculateDelay === undefined) ? null : options.calculateDelay + }; +} +async function sleep(delay) { + return new Promise((resolve, reject) => { + setTimeout(resolve, delay); + }); +} +exports.sleep = sleep; +function defaultCalculateDelay(context, options) { + let delay = options.delay; + if (delay === 0) { + // no delay between attempts + return 0; + } + if (options.factor) { + delay *= Math.pow(options.factor, context.attemptNum - 1); + if (options.maxDelay !== 0) { + delay = Math.min(delay, options.maxDelay); + } + } + if (options.jitter) { + // Jitter will result in a random value between `minDelay` and + // calculated delay for a given attempt. + // See https://www.awsarchitectureblog.com/2015/03/backoff.html + // We're using the "full jitter" strategy. + const min = Math.ceil(options.minDelay); + const max = Math.floor(delay); + delay = Math.floor(Math.random() * (max - min + 1)) + min; + } + return Math.round(delay); +} +exports.defaultCalculateDelay = defaultCalculateDelay; +async function retry(attemptFunc, attemptOptions) { + const options = applyDefaults(attemptOptions); + for (const prop of [ + 'delay', + 'initialDelay', + 'minDelay', + 'maxDelay', + 'maxAttempts', + 'timeout' + ]) { + const value = options[prop]; + if (!Number.isInteger(value) || (value < 0)) { + throw new Error(`Value for ${prop} must be an integer greater than or equal to 0`); + } + } + if ((options.factor.constructor !== Number) || (options.factor < 0)) { + throw new Error(`Value for factor must be a number greater than or equal to 0`); + } + if (options.delay < options.minDelay) { + throw new Error(`delay cannot be less than minDelay (delay: ${options.delay}, minDelay: ${options.minDelay}`); + } + const context = { + attemptNum: 0, + attemptsRemaining: options.maxAttempts ? options.maxAttempts : -1, + aborted: false, + abort() { + context.aborted = true; + } + }; + const calculateDelay = options.calculateDelay || defaultCalculateDelay; + async function makeAttempt() { + if (options.beforeAttempt) { + options.beforeAttempt(context, options); + } + if (context.aborted) { + const err = new Error(`Attempt aborted`); + err.code = 'ATTEMPT_ABORTED'; + throw err; + } + const onError = async (err) => { + if (options.handleError) { + await options.handleError(err, context, options); + } + if (context.aborted || (context.attemptsRemaining === 0)) { + throw err; + } + // We are about to try again so increment attempt number + context.attemptNum++; + const delay = calculateDelay(context, options); + if (delay) { + await sleep(delay); + } + return makeAttempt(); + }; + if (context.attemptsRemaining > 0) { + context.attemptsRemaining--; + } + if (options.timeout) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + if (options.handleTimeout) { + // If calling handleTimeout throws an error that is not wrapped in a promise + // we want to catch the error and reject. + try { + resolve(options.handleTimeout(context, options)); + } + catch (e) { + reject(e); + } + } + else { + const err = new Error(`Retry timeout (attemptNum: ${context.attemptNum}, timeout: ${options.timeout})`); + err.code = 'ATTEMPT_TIMEOUT'; + reject(err); + } + }, options.timeout); + attemptFunc(context, options).then((result) => { + clearTimeout(timer); + resolve(result); + }).catch((err) => { + clearTimeout(timer); + // Calling resolve with a Promise that rejects here will result + // in an unhandled rejection. Calling `reject` with errors + // does not result in an unhandled rejection + onError(err).then(resolve).catch(reject); + }); + }); + } + else { + // No timeout provided so wait indefinitely for the returned promise + // to be resolved. + return attemptFunc(context, options).catch(onError); + } + } + const initialDelay = options.calculateDelay + ? options.calculateDelay(context, options) + : options.initialDelay; + if (initialDelay) { + await sleep(initialDelay); + } + return makeAttempt(); +} +exports.retry = retry; + + /***/ }), /***/ 334: diff --git a/src/main.ts b/src/main.ts index d2dc7804..b45d3461 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,7 +5,7 @@ import * as core from '@actions/core' import * as github from '@actions/github' import * as path from 'path' import * as glob from 'glob' -import { retry } from '@lifeomic/attempt' +import {retry} from '@lifeomic/attempt' const releaseByTag = 'GET /repos/{owner}/{repo}/releases/tags/{tag}' as const const createRelease = 'POST /repos/{owner}/{repo}/releases' as const @@ -95,10 +95,11 @@ async function upload_to_release( } core.debug(`Uploading ${file} to ${asset_name} in release ${tag}.`) - const uploaded_asset: UploadAssetResp = await retry(async () => { - return octokit.request(uploadAssets, { - ...repo(), - release_id: release.data.id, + const uploaded_asset: UploadAssetResp = await retry( + async () => { + return octokit.request(uploadAssets, { + ...repo(), + release_id: release.data.id, url: release.data.upload_url, name: asset_name, data: file_bytes, @@ -106,11 +107,12 @@ async function upload_to_release( 'content-type': 'binary/octet-stream', 'content-length': file_size } - } - ) - }, { - maxAttempts: 3 - }) + }) + }, + { + maxAttempts: 3 + } + ) return uploaded_asset.data.browser_download_url }