Skip to content

Commit f227091

Browse files
feat: retry only on specific exit code (#58)
* feat: retry only on specific exit code * Run ci_cd on all push events * dedupe step IDs * add assertions for retry_on_exit_code tests * minor: implemented suggested fix from @andersfischernielsen * docs: update readme to reflect new retry_on_exit_code input Co-authored-by: Anders Fischer-Nielsen <[email protected]>
1 parent 7106228 commit f227091

File tree

5 files changed

+63
-14
lines changed

5 files changed

+63
-14
lines changed

.github/workflows/ci_cd.yml

+37-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
name: CI/CD
22
on:
33
push:
4-
branches:
5-
- '**'
4+
65
jobs:
76
# runs on branch pushes only
87
ci:
@@ -79,6 +78,42 @@ jobs:
7978
command: node -e "process.exit(1)"
8079
on_retry_command: node -e "console.log('this is a retry command')"
8180

81+
- name: retry_on_exit_code (with expected error code)
82+
id: retry_on_exit_code_expected
83+
uses: ./
84+
continue-on-error: true
85+
with:
86+
timeout_minutes: 1
87+
retry_on_exit_code: 2
88+
max_attempts: 3
89+
command: node -e "process.exit(2)"
90+
- uses: nick-invision/assert-action@v1
91+
with:
92+
expected: failure
93+
actual: ${{ steps.retry_on_exit_code_expected.outcome }}
94+
- uses: nick-invision/assert-action@v1
95+
with:
96+
expected: 3
97+
actual: ${{ steps.retry_on_exit_code_expected.outputs.total_attempts }}
98+
99+
- name: retry_on_exit_code (with unexpected error code)
100+
id: retry_on_exit_code_unexpected
101+
uses: ./
102+
continue-on-error: true
103+
with:
104+
timeout_minutes: 1
105+
retry_on_exit_code: 2
106+
max_attempts: 3
107+
command: node -e "process.exit(1)"
108+
- uses: nick-invision/assert-action@v1
109+
with:
110+
expected: failure
111+
actual: ${{ steps.retry_on_exit_code_unexpected.outcome }}
112+
- uses: nick-invision/assert-action@v1
113+
with:
114+
expected: 1
115+
actual: ${{ steps.retry_on_exit_code_unexpected.outputs.total_attempts }}
116+
82117
- name: on-retry-cmd (on-retry fails)
83118
id: on-retry-cmd-fails
84119
uses: ./

README.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Retries an Action step on failure or timeout. This is currently intended to replace the `run` step for moody commands.
44

5-
**NOTE:** Ownership of this project was transferred to my personal account `nick-fields` from my work account `nick-invision`. Details [here](#Ownership)
5+
**NOTE:** Ownership of this project was transferred to my personal account `nick-fields` from my work account `nick-invision`. Details [here](#Ownership)
66

77
---
88

@@ -56,6 +56,10 @@ Retries an Action step on failure or timeout. This is currently intended to repl
5656

5757
**Optional** Exit successfully even if an error occurs. Same as native continue-on-error behavior, but for use in composite actions. Defaults to `false`
5858

59+
### `retry_on_exit_code`
60+
61+
**Optional** Specific exit code to retry on. This will only retry for the given error code and fail immediately other error codes.
62+
5963
## Outputs
6064

6165
### `total_attempts`
@@ -233,6 +237,6 @@ NodeJS is required for this action to run. This runs without issue on all GitHub
233237

234238
## **Ownership**
235239

236-
As of 2022/02/15 ownership of this project has been transferred to my personal account `nick-fields` from my work account `nick-invision` due to me leaving InVision. I am the author and have been the primary maintainer since day one and will continue to maintain this as needed.
240+
As of 2022/02/15 ownership of this project has been transferred to my personal account `nick-fields` from my work account `nick-invision` due to me leaving InVision. I am the author and have been the primary maintainer since day one and will continue to maintain this as needed.
237241

238242
Existing workflow references to `nick-invision/retry@<whatever>` no longer work and must be updated to `nick-fields/retry@<whatever>`.

action.yml

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ inputs:
3939
new_command_on_retry:
4040
description: Command to run if the first attempt fails. This command will be called on all subsequent attempts.
4141
required: false
42+
retry_on_exit_code:
43+
description: Specific exit code to retry on. This will only retry for the given error code and fail immediately other error codes.
44+
required: false
4245
outputs:
4346
total_attempts:
4447
description: The final number of attempts made

dist/index.js

+14-10
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ var WARNING_ON_RETRY = core_1.getInput('warning_on_retry').toLowerCase() === 'tr
289289
var ON_RETRY_COMMAND = core_1.getInput('on_retry_command');
290290
var CONTINUE_ON_ERROR = getInputBoolean('continue_on_error');
291291
var NEW_COMMAND_ON_RETRY = core_1.getInput('new_command_on_retry');
292+
var RETRY_ON_EXIT_CODE = getInputNumber('retry_on_exit_code', false);
292293
var OS = process.platform;
293294
var OUTPUT_TOTAL_ATTEMPTS_KEY = 'total_attempts';
294295
var OUTPUT_EXIT_CODE_KEY = 'exit_code';
@@ -479,17 +480,17 @@ function runAction() {
479480
attempt = 1;
480481
_a.label = 2;
481482
case 2:
482-
if (!(attempt <= MAX_ATTEMPTS)) return [3 /*break*/, 12];
483+
if (!(attempt <= MAX_ATTEMPTS)) return [3 /*break*/, 13];
483484
_a.label = 3;
484485
case 3:
485-
_a.trys.push([3, 5, , 11]);
486+
_a.trys.push([3, 5, , 12]);
486487
// just keep overwriting attempts output
487488
core_1.setOutput(OUTPUT_TOTAL_ATTEMPTS_KEY, attempt);
488489
return [4 /*yield*/, runCmd(attempt)];
489490
case 4:
490491
_a.sent();
491492
core_1.info("Command completed after " + attempt + " attempt(s).");
492-
return [3 /*break*/, 12];
493+
return [3 /*break*/, 13];
493494
case 5:
494495
error_2 = _a.sent();
495496
if (!(attempt === MAX_ATTEMPTS)) return [3 /*break*/, 6];
@@ -499,24 +500,27 @@ function runAction() {
499500
// error: timeout
500501
throw error_2;
501502
case 7:
502-
if (!(exit > 0 && RETRY_ON === 'timeout')) return [3 /*break*/, 8];
503+
if (!(RETRY_ON_EXIT_CODE && RETRY_ON_EXIT_CODE !== exit)) return [3 /*break*/, 8];
504+
throw error_2;
505+
case 8:
506+
if (!(exit > 0 && RETRY_ON === 'timeout')) return [3 /*break*/, 9];
503507
// error: error
504508
throw error_2;
505-
case 8: return [4 /*yield*/, runRetryCmd()];
506-
case 9:
509+
case 9: return [4 /*yield*/, runRetryCmd()];
510+
case 10:
507511
_a.sent();
508512
if (WARNING_ON_RETRY) {
509513
core_1.warning("Attempt " + attempt + " failed. Reason: " + error_2.message);
510514
}
511515
else {
512516
core_1.info("Attempt " + attempt + " failed. Reason: " + error_2.message);
513517
}
514-
_a.label = 10;
515-
case 10: return [3 /*break*/, 11];
516-
case 11:
518+
_a.label = 11;
519+
case 11: return [3 /*break*/, 12];
520+
case 12:
517521
attempt++;
518522
return [3 /*break*/, 2];
519-
case 12: return [2 /*return*/];
523+
case 13: return [2 /*return*/];
520524
}
521525
});
522526
});

src/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const WARNING_ON_RETRY = getInput('warning_on_retry').toLowerCase() === 'true';
1818
const ON_RETRY_COMMAND = getInput('on_retry_command');
1919
const CONTINUE_ON_ERROR = getInputBoolean('continue_on_error');
2020
const NEW_COMMAND_ON_RETRY = getInput('new_command_on_retry');
21+
const RETRY_ON_EXIT_CODE = getInputNumber('retry_on_exit_code', false);
2122

2223
const OS = process.platform;
2324
const OUTPUT_TOTAL_ATTEMPTS_KEY = 'total_attempts';
@@ -187,6 +188,8 @@ async function runAction() {
187188
} else if (!done && RETRY_ON === 'error') {
188189
// error: timeout
189190
throw error;
191+
} else if (RETRY_ON_EXIT_CODE && RETRY_ON_EXIT_CODE !== exit){
192+
throw error;
190193
} else if (exit > 0 && RETRY_ON === 'timeout') {
191194
// error: error
192195
throw error;

0 commit comments

Comments
 (0)