Skip to content

Commit

Permalink
PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
luketomlinson committed Sep 23, 2022
1 parent 3cca041 commit 3faaff9
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 61 deletions.
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
39 changes: 5 additions & 34 deletions __test__/get-retry-options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
})
})
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
16 changes: 7 additions & 9 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13340,22 +13340,21 @@ 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 }, {}];
}
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) {
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 3 additions & 6 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@ async function main(): Promise<void> {
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
Expand Down
13 changes: 5 additions & 8 deletions src/retry-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}, {}]
Expand All @@ -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]'
})`
)
Expand Down

0 comments on commit 3faaff9

Please sign in to comment.