refactor and add tests for retry options

This commit is contained in:
Luke Tomlinson
2022-09-23 11:45:39 -04:00
parent 355d8955d8
commit 660d907517
4 changed files with 293 additions and 185 deletions

View File

@@ -0,0 +1,70 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {getRetryOptions} from '../src/retry-options'
describe('getRequestOptions', () => {
test('retries disabled if retries == 0', async () => {
const [retryOptions, requestOptions] = getRetryOptions(0, 8, [
400,
500,
502
])
expect(retryOptions.enabled).toBe(false)
expect(retryOptions.doNotRetry).toBeFalsy()
expect(requestOptions.retries).toBeFalsy()
})
test('properties set if retries > 0', async () => {
const [retryOptions, requestOptions] = getRetryOptions(1, 8, [
400,
500,
502
])
expect(retryOptions.enabled).toBe(true)
expect(retryOptions.doNotRetry).toEqual([400, 500, 502])
expect(requestOptions.retries).toEqual(1)
expect(requestOptions.retryAfter).toEqual(8)
})
test('properties set if retries > 0', async () => {
const [retryOptions, requestOptions] = getRetryOptions(1, 8, [
400,
500,
502
])
expect(retryOptions.enabled).toBe(true)
expect(retryOptions.doNotRetry).toEqual([400, 500, 502])
expect(requestOptions.retries).toEqual(1)
expect(requestOptions.retryAfter).toEqual(8)
})
test('retryAfter can be set to zero', async () => {
const [retryOptions, requestOptions] = getRetryOptions(1, 0, [
400,
500,
502
])
expect(retryOptions.enabled).toBe(true)
expect(retryOptions.doNotRetry).toEqual([400, 500, 502])
expect(requestOptions.retries).toEqual(1)
expect(requestOptions.retryAfter).toEqual(0)
})
test('retryOptions.doNotRetry not set if doNotRetry isEmpty', async () => {
const [retryOptions, requestOptions] = getRetryOptions(1, 0, [])
expect(retryOptions.enabled).toBe(true)
expect(retryOptions.doNotRetry).toBeUndefined()
expect(requestOptions.retries).toEqual(1)
expect(requestOptions.retryAfter).toEqual(0)
})
})

300
dist/index.js vendored
View File

@@ -40,7 +40,7 @@ module.exports =
/******/ // the startup function /******/ // the startup function
/******/ function startup() { /******/ function startup() {
/******/ // Load entry module and return exports /******/ // Load entry module and return exports
/******/ return __webpack_require__(272); /******/ return __webpack_require__(858);
/******/ }; /******/ };
/******/ // initialize runtime /******/ // initialize runtime
/******/ runtime(__webpack_require__); /******/ runtime(__webpack_require__);
@@ -7084,150 +7084,6 @@ exports.implementation = class URLImpl {
}; };
/***/ }),
/***/ 272:
/***/ (function(__unusedmodule, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js
var core = __webpack_require__(186);
// EXTERNAL MODULE: ./node_modules/@actions/exec/lib/exec.js
var exec = __webpack_require__(514);
// EXTERNAL MODULE: ./node_modules/@actions/github/lib/github.js
var lib_github = __webpack_require__(438);
// EXTERNAL MODULE: ./node_modules/@actions/glob/lib/glob.js
var glob = __webpack_require__(90);
// EXTERNAL MODULE: ./node_modules/@actions/io/lib/io.js
var io = __webpack_require__(436);
// EXTERNAL MODULE: ./node_modules/@octokit/plugin-retry/dist-node/index.js
var dist_node = __webpack_require__(745);
// CONCATENATED MODULE: ./src/async-function.ts
const AsyncFunction = Object.getPrototypeOf(async () => null).constructor;
function callAsyncFunction(args, source) {
const fn = new AsyncFunction(...Object.keys(args), source);
return fn(...Object.values(args));
}
// EXTERNAL MODULE: external "path"
var external_path_ = __webpack_require__(622);
// CONCATENATED MODULE: ./src/wrap-require.ts
const wrapRequire = new Proxy(require, {
apply: (target, thisArg, [moduleID]) => {
if (moduleID.startsWith('.')) {
moduleID = Object(external_path_.resolve)(moduleID);
return target.apply(thisArg, [moduleID]);
}
const modulePath = target.resolve.apply(thisArg, [
moduleID,
{
// Webpack does not have an escape hatch for getting the actual
// module, other than `eval`.
paths: [process.cwd()]
}
]);
return target.apply(thisArg, [modulePath]);
},
get: (target, prop, receiver) => {
Reflect.get(target, prop, receiver);
}
});
// CONCATENATED MODULE: ./src/main.ts
process.on('unhandledRejection', handleError);
main().catch(handleError);
async function main() {
const token = Object(core.getInput)('github-token', { required: true });
const debug = Object(core.getInput)('debug');
const userAgent = Object(core.getInput)('user-agent');
const previews = Object(core.getInput)('previews');
const retries = parseInt(Object(core.getInput)('retries'));
const retryAfter = parseInt(Object(core.getInput)('retry-after'));
const doNotRetry = parseNumberArray(Object(core.getInput)('do-not-retry'));
const opts = {};
if (debug === 'true')
opts.log = console;
if (userAgent != null)
opts.userAgent = userAgent;
if (previews != null)
opts.previews = previews.split(',');
if (retries > 0) {
if (doNotRetry.length > 0) {
opts.retry = { doNotRetry };
}
opts.request = {
retries,
retryAfter
};
Object(core.info)(`GitHub client configured with: (retries: ${retries}, retryAfter: ${retryAfter}, doNotRetry: ${doNotRetry.length == 0
? 'octokit default: [400, 401, 403, 404, 422]'
: doNotRetry})`);
}
else {
opts.retry = {
enabled: false
};
}
const github = Object(lib_github.getOctokit)(token, opts, dist_node.retry);
const script = Object(core.getInput)('script', { required: true });
// Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors.
const result = await callAsyncFunction({
require: wrapRequire,
__original_require__: require,
github,
context: lib_github.context,
core: core,
exec: exec,
glob: glob,
io: io
}, script);
let encoding = Object(core.getInput)('result-encoding');
encoding = encoding ? encoding : 'json';
let output;
switch (encoding) {
case 'json':
output = JSON.stringify(result);
break;
case 'string':
output = String(result);
break;
default:
throw new Error('"result-encoding" must be either "string" or "json"');
}
Object(core.setOutput)('result', output);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function handleError(err) {
console.error(err);
Object(core.setFailed)(`Unhandled error: ${err}`);
}
function parseNumberArray(listString) {
if (!listString) {
return [];
}
const split = listString.trim().split(',');
return split.map(x => parseInt(x));
}
/***/ }), /***/ }),
/***/ 274: /***/ 274:
@@ -13449,6 +13305,160 @@ function expand(str, isTop) {
/***/ }),
/***/ 858:
/***/ (function(__unusedmodule, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js
var core = __webpack_require__(186);
// EXTERNAL MODULE: ./node_modules/@actions/exec/lib/exec.js
var exec = __webpack_require__(514);
// EXTERNAL MODULE: ./node_modules/@actions/github/lib/github.js
var lib_github = __webpack_require__(438);
// EXTERNAL MODULE: ./node_modules/@actions/glob/lib/glob.js
var glob = __webpack_require__(90);
// EXTERNAL MODULE: ./node_modules/@actions/io/lib/io.js
var io = __webpack_require__(436);
// EXTERNAL MODULE: ./node_modules/@octokit/plugin-retry/dist-node/index.js
var dist_node = __webpack_require__(745);
// CONCATENATED MODULE: ./src/async-function.ts
const AsyncFunction = Object.getPrototypeOf(async () => null).constructor;
function callAsyncFunction(args, source) {
const fn = new AsyncFunction(...Object.keys(args), source);
return fn(...Object.values(args));
}
// CONCATENATED MODULE: ./src/retry-options.ts
function getRetryOptions(retries, retryAfter, doNotRetry) {
var _a;
if (retries <= 0) {
return [{ enabled: false }, {}];
}
const retryOptions = {
enabled: true
};
if (doNotRetry.length > 0) {
retryOptions.doNotRetry = doNotRetry;
}
const requestOptions = {
retries,
retryAfter: retryAfter
};
Object(core.info)(`GitHub client configured with: (retries: ${requestOptions.retries}, retryAfter: ${requestOptions.retryAfter}, doNotRetry: ${(_a = retryOptions === null || retryOptions === void 0 ? void 0 : retryOptions.doNotRetry) !== null && _a !== void 0 ? _a : 'octokit default: [400, 401, 403, 404, 422]'})`);
return [retryOptions, requestOptions];
}
function parseNumberArray(listString) {
if (!listString) {
return [];
}
const split = listString.trim().split(',');
return split.map(x => parseInt(x));
}
// EXTERNAL MODULE: external "path"
var external_path_ = __webpack_require__(622);
// CONCATENATED MODULE: ./src/wrap-require.ts
const wrapRequire = new Proxy(require, {
apply: (target, thisArg, [moduleID]) => {
if (moduleID.startsWith('.')) {
moduleID = Object(external_path_.resolve)(moduleID);
return target.apply(thisArg, [moduleID]);
}
const modulePath = target.resolve.apply(thisArg, [
moduleID,
{
// Webpack does not have an escape hatch for getting the actual
// module, other than `eval`.
paths: [process.cwd()]
}
]);
return target.apply(thisArg, [modulePath]);
},
get: (target, prop, receiver) => {
Reflect.get(target, prop, receiver);
}
});
// CONCATENATED MODULE: ./src/main.ts
process.on('unhandledRejection', handleError);
main().catch(handleError);
async function main() {
const token = Object(core.getInput)('github-token', { required: true });
const debug = Object(core.getInput)('debug');
const userAgent = Object(core.getInput)('user-agent');
const previews = Object(core.getInput)('previews');
const retries = parseInt(Object(core.getInput)('retries'));
const retryAfter = parseInt(Object(core.getInput)('retry-after'));
const doNotRetry = parseNumberArray(Object(core.getInput)('do-not-retry'));
const [retryOpts, requestOpts] = getRetryOptions(retries, retryAfter, doNotRetry);
const opts = {};
if (debug === 'true')
opts.log = console;
if (userAgent != null)
opts.userAgent = userAgent;
if (previews != null)
opts.previews = previews.split(',');
if (retryOpts)
opts.retry = retryOpts;
if (requestOpts)
opts.request = requestOpts;
const github = Object(lib_github.getOctokit)(token, opts, dist_node.retry);
const script = Object(core.getInput)('script', { required: true });
// Using property/value shorthand on `require` (e.g. `{require}`) causes compilation errors.
const result = await callAsyncFunction({
require: wrapRequire,
__original_require__: require,
github,
context: lib_github.context,
core: core,
exec: exec,
glob: glob,
io: io
}, script);
let encoding = Object(core.getInput)('result-encoding');
encoding = encoding ? encoding : 'json';
let output;
switch (encoding) {
case 'json':
output = JSON.stringify(result);
break;
case 'string':
output = String(result);
break;
default:
throw new Error('"result-encoding" must be either "string" or "json"');
}
Object(core.setOutput)('result', output);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function handleError(err) {
console.error(err);
Object(core.setFailed)(`Unhandled error: ${err}`);
}
/***/ }), /***/ }),
/***/ 871: /***/ 871:

View File

@@ -5,6 +5,12 @@ import * as glob from '@actions/glob'
import * as io from '@actions/io' import * as io from '@actions/io'
import {retry} from '@octokit/plugin-retry' import {retry} from '@octokit/plugin-retry'
import {callAsyncFunction} from './async-function' import {callAsyncFunction} from './async-function'
import {
getRetryOptions,
parseNumberArray,
RequestOptions,
RetryOptions
} from './retry-options'
import {wrapRequire} from './wrap-require' import {wrapRequire} from './wrap-require'
process.on('unhandledRejection', handleError) process.on('unhandledRejection', handleError)
@@ -14,14 +20,8 @@ type Options = {
log?: Console log?: Console
userAgent?: string userAgent?: string
previews?: string[] previews?: string[]
retry?: { retry?: RetryOptions
doNotRetry?: number[] request?: RequestOptions
enabled?: boolean
}
request?: {
retries: number
retryAfter: number
}
} }
async function main(): Promise<void> { async function main(): Promise<void> {
@@ -32,34 +32,18 @@ async function main(): Promise<void> {
const retries = parseInt(core.getInput('retries')) const retries = parseInt(core.getInput('retries'))
const retryAfter = parseInt(core.getInput('retry-after')) const retryAfter = parseInt(core.getInput('retry-after'))
const doNotRetry = parseNumberArray(core.getInput('do-not-retry')) const doNotRetry = parseNumberArray(core.getInput('do-not-retry'))
const [retryOpts, requestOpts] = getRetryOptions(
retries,
retryAfter,
doNotRetry
)
const opts: Options = {} const opts: Options = {}
if (debug === 'true') opts.log = console if (debug === 'true') opts.log = console
if (userAgent != null) opts.userAgent = userAgent if (userAgent != null) opts.userAgent = userAgent
if (previews != null) opts.previews = previews.split(',') if (previews != null) opts.previews = previews.split(',')
if (retryOpts) opts.retry = retryOpts
if (retries > 0) { if (requestOpts) opts.request = requestOpts
if (doNotRetry.length > 0) {
opts.retry = {doNotRetry}
}
opts.request = {
retries,
retryAfter
}
core.info(
`GitHub client configured with: (retries: ${retries}, retryAfter: ${retryAfter}, doNotRetry: ${
doNotRetry.length == 0
? 'octokit default: [400, 401, 403, 404, 422]'
: doNotRetry
})`
)
} else {
opts.retry = {
enabled: false
}
}
const github = getOctokit(token, opts, retry) const github = getOctokit(token, opts, retry)
@@ -104,12 +88,3 @@ function handleError(err: any): void {
console.error(err) console.error(err)
core.setFailed(`Unhandled error: ${err}`) core.setFailed(`Unhandled error: ${err}`)
} }
function parseNumberArray(listString: string): number[] {
if (!listString) {
return []
}
const split = listString.trim().split(',')
return split.map(x => parseInt(x))
}

53
src/retry-options.ts Normal file
View File

@@ -0,0 +1,53 @@
import * as core from '@actions/core'
export type RetryOptions = {
doNotRetry?: number[]
enabled?: boolean
}
export type RequestOptions = {
retries?: number
retryAfter?: number
}
export function getRetryOptions(
retries: number,
retryAfter: number,
doNotRetry: number[]
): [RetryOptions, RequestOptions] {
if (retries <= 0) {
return [{enabled: false}, {}]
}
const retryOptions: RetryOptions = {
enabled: true
}
if (doNotRetry.length > 0) {
retryOptions.doNotRetry = doNotRetry
}
const requestOptions: RequestOptions = {
retries,
retryAfter: retryAfter
}
core.info(
`GitHub client configured with: (retries: ${
requestOptions.retries
}, retryAfter: ${requestOptions.retryAfter}, doNotRetry: ${
retryOptions?.doNotRetry ?? 'octokit default: [400, 401, 403, 404, 422]'
})`
)
return [retryOptions, requestOptions]
}
export function parseNumberArray(listString: string): number[] {
if (!listString) {
return []
}
const split = listString.trim().split(',')
return split.map(x => parseInt(x))
}