diff --git a/README.md b/README.md index d5a023ba..aebf1d3a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This action makes it easy to quickly write a script in your workflow that uses the GitHub API and the workflow run context. -To use this action, provide an input named `script` that contains the body of an asynchronous function call. +To use this action, provide an input named `script` that contains the body of an asynchronous function call. The following arguments will be provided: - `github` A pre-authenticated @@ -83,6 +83,47 @@ output of a github-script step. For some workflows, string encoding is preferred script: return "I will be string (not JSON) encoded!" ``` +## Retries + +By default, requests made with the `github` instance will not be retried. You can configure this with the `retries` option: + +```yaml +- uses: actions/github-script@v6 + id: my-script + with: + result-encoding: string + retries: 3 + script: | + github.rest.issues.get({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }) +``` + +In this example, request failures from `github.rest.issues.get()` will be retried up to 3 times. + +You can also configure which status codes should be exempt from retries via the `retry-exempt-status-codes` option: + +```yaml +- uses: actions/github-script@v6 + id: my-script + with: + result-encoding: string + retries: 3 + retry-exempt-status-codes: 400,401 + script: | + github.rest.issues.get({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }) +``` + +By default, the following status codes will not be retried: `400, 401, 403, 404, 422` [(source)](https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14). + +These retries are implemented using the [octokit/plugin-retry.js](https://github.com/octokit/plugin-retry.js) plugin. The retries use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) to space out retries. ([source](https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/error-request.ts#L13)) + ## Examples Note that `github-token` is optional in this action, and the input is there @@ -354,8 +395,11 @@ jobs: To import an ESM file, you'll need to reference your script by an absolute path and ensure you have a `package.json` file with `"type": "module"` specified. For a script in your repository `src/print-stuff.js`: + ```js -export default function printStuff() { console.log('stuff') } +export default function printStuff() { + console.log('stuff') +} ``` ```yaml diff --git a/__test__/get-retry-options.test.ts b/__test__/get-retry-options.test.ts index 95b08d72..345212c3 100644 --- a/__test__/get-retry-options.test.ts +++ b/__test__/get-retry-options.test.ts @@ -4,11 +4,7 @@ import {getRetryOptions} from '../src/retry-options' describe('getRequestOptions', () => { test('retries disabled if retries == 0', async () => { - const [retryOptions, requestOptions] = getRetryOptions(0, 8, [ - 400, - 500, - 502 - ]) + const [retryOptions, requestOptions] = getRetryOptions(0, [400, 500, 502]) expect(retryOptions.enabled).toBe(false) expect(retryOptions.doNotRetry).toBeFalsy() @@ -17,54 +13,29 @@ describe('getRequestOptions', () => { }) test('properties set if retries > 0', async () => { - const [retryOptions, requestOptions] = getRetryOptions(1, 8, [ - 400, - 500, - 502 - ]) + const [retryOptions, requestOptions] = getRetryOptions(1, [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 - ]) + const [retryOptions, requestOptions] = getRetryOptions(1, [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, []) + test('retryOptions.doNotRetry not set if exemptStatusCodes isEmpty', async () => { + const [retryOptions, requestOptions] = getRetryOptions(1, []) expect(retryOptions.enabled).toBe(true) expect(retryOptions.doNotRetry).toBeUndefined() expect(requestOptions.retries).toEqual(1) - expect(requestOptions.retryAfter).toEqual(0) }) }) diff --git a/action.yml b/action.yml index 0a8fd2b1..bdbdbaa7 100644 --- a/action.yml +++ b/action.yml @@ -29,9 +29,9 @@ inputs: retry-after: description: "The number of seconds between retries. No effect unless `retries` is set." default: "0" - do-not-retry: + retry-exempt-status-codes: description: "A comma separated list of status codes that will NOT be retried. Example: '400,500'. No effect unless `retries` is set." - default: "" + default: "400, 401, 403, 404, 422" # from https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14 outputs: result: description: The return value of the script, stringified with `JSON.stringify` diff --git a/dist/index.js b/dist/index.js index f652b681..f1ef62d8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -13340,7 +13340,7 @@ function callAsyncFunction(args, source) { // CONCATENATED MODULE: ./src/retry-options.ts -function getRetryOptions(retries, retryAfter, doNotRetry) { +function getRetryOptions(retries, exemptStatusCodes) { var _a; if (retries <= 0) { return [{ enabled: false }, {}]; @@ -13348,14 +13348,13 @@ function getRetryOptions(retries, retryAfter, doNotRetry) { const retryOptions = { enabled: true }; - if (doNotRetry.length > 0) { - retryOptions.doNotRetry = doNotRetry; + if (exemptStatusCodes.length > 0) { + retryOptions.doNotRetry = exemptStatusCodes; } const requestOptions = { - retries, - retryAfter: retryAfter + retries }; - 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]'})`); + Object(core.info)(`GitHub client configured with: (retries: ${requestOptions.retries}, retry-exempt-status-code: ${(_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) { @@ -13410,9 +13409,8 @@ async function main() { 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 exemptStatusCodes = parseNumberArray(Object(core.getInput)('retry-exempt-status-codes')); + const [retryOpts, requestOpts] = getRetryOptions(retries, exemptStatusCodes); const opts = {}; if (debug === 'true') opts.log = console; diff --git a/src/main.ts b/src/main.ts index 5027c66e..75d7d220 100644 --- a/src/main.ts +++ b/src/main.ts @@ -30,13 +30,10 @@ async function main(): Promise { const userAgent = core.getInput('user-agent') const previews = core.getInput('previews') const retries = parseInt(core.getInput('retries')) - const retryAfter = parseInt(core.getInput('retry-after')) - const doNotRetry = parseNumberArray(core.getInput('do-not-retry')) - const [retryOpts, requestOpts] = getRetryOptions( - retries, - retryAfter, - doNotRetry + const exemptStatusCodes = parseNumberArray( + core.getInput('retry-exempt-status-codes') ) + const [retryOpts, requestOpts] = getRetryOptions(retries, exemptStatusCodes) const opts: Options = {} if (debug === 'true') opts.log = console diff --git a/src/retry-options.ts b/src/retry-options.ts index 2c32dde2..6f8e90e5 100644 --- a/src/retry-options.ts +++ b/src/retry-options.ts @@ -7,13 +7,11 @@ export type RetryOptions = { export type RequestOptions = { retries?: number - retryAfter?: number } export function getRetryOptions( retries: number, - retryAfter: number, - doNotRetry: number[] + exemptStatusCodes: number[] ): [RetryOptions, RequestOptions] { if (retries <= 0) { return [{enabled: false}, {}] @@ -23,19 +21,18 @@ export function getRetryOptions( enabled: true } - if (doNotRetry.length > 0) { - retryOptions.doNotRetry = doNotRetry + if (exemptStatusCodes.length > 0) { + retryOptions.doNotRetry = exemptStatusCodes } const requestOptions: RequestOptions = { - retries, - retryAfter: retryAfter + retries } core.info( `GitHub client configured with: (retries: ${ requestOptions.retries - }, retryAfter: ${requestOptions.retryAfter}, doNotRetry: ${ + }, retry-exempt-status-code: ${ retryOptions?.doNotRetry ?? 'octokit default: [400, 401, 403, 404, 422]' })` )