mirror of
https://github.com/nick-fields/retry.git
synced 2026-02-10 07:05:29 +00:00
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 <andersfischern@me.com>
This commit is contained in:
39
.github/workflows/ci_cd.yml
vendored
39
.github/workflows/ci_cd.yml
vendored
@@ -1,8 +1,7 @@
|
|||||||
name: CI/CD
|
name: CI/CD
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
jobs:
|
jobs:
|
||||||
# runs on branch pushes only
|
# runs on branch pushes only
|
||||||
ci:
|
ci:
|
||||||
@@ -79,6 +78,42 @@ jobs:
|
|||||||
command: node -e "process.exit(1)"
|
command: node -e "process.exit(1)"
|
||||||
on_retry_command: node -e "console.log('this is a retry command')"
|
on_retry_command: node -e "console.log('this is a retry command')"
|
||||||
|
|
||||||
|
- name: retry_on_exit_code (with expected error code)
|
||||||
|
id: retry_on_exit_code_expected
|
||||||
|
uses: ./
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
timeout_minutes: 1
|
||||||
|
retry_on_exit_code: 2
|
||||||
|
max_attempts: 3
|
||||||
|
command: node -e "process.exit(2)"
|
||||||
|
- uses: nick-invision/assert-action@v1
|
||||||
|
with:
|
||||||
|
expected: failure
|
||||||
|
actual: ${{ steps.retry_on_exit_code_expected.outcome }}
|
||||||
|
- uses: nick-invision/assert-action@v1
|
||||||
|
with:
|
||||||
|
expected: 3
|
||||||
|
actual: ${{ steps.retry_on_exit_code_expected.outputs.total_attempts }}
|
||||||
|
|
||||||
|
- name: retry_on_exit_code (with unexpected error code)
|
||||||
|
id: retry_on_exit_code_unexpected
|
||||||
|
uses: ./
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
timeout_minutes: 1
|
||||||
|
retry_on_exit_code: 2
|
||||||
|
max_attempts: 3
|
||||||
|
command: node -e "process.exit(1)"
|
||||||
|
- uses: nick-invision/assert-action@v1
|
||||||
|
with:
|
||||||
|
expected: failure
|
||||||
|
actual: ${{ steps.retry_on_exit_code_unexpected.outcome }}
|
||||||
|
- uses: nick-invision/assert-action@v1
|
||||||
|
with:
|
||||||
|
expected: 1
|
||||||
|
actual: ${{ steps.retry_on_exit_code_unexpected.outputs.total_attempts }}
|
||||||
|
|
||||||
- name: on-retry-cmd (on-retry fails)
|
- name: on-retry-cmd (on-retry fails)
|
||||||
id: on-retry-cmd-fails
|
id: on-retry-cmd-fails
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ Retries an Action step on failure or timeout. This is currently intended to repl
|
|||||||
|
|
||||||
**Optional** Exit successfully even if an error occurs. Same as native continue-on-error behavior, but for use in composite actions. Defaults to `false`
|
**Optional** Exit successfully even if an error occurs. Same as native continue-on-error behavior, but for use in composite actions. Defaults to `false`
|
||||||
|
|
||||||
|
### `retry_on_exit_code`
|
||||||
|
|
||||||
|
**Optional** Specific exit code to retry on. This will only retry for the given error code and fail immediately other error codes.
|
||||||
|
|
||||||
## Outputs
|
## Outputs
|
||||||
|
|
||||||
### `total_attempts`
|
### `total_attempts`
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ inputs:
|
|||||||
new_command_on_retry:
|
new_command_on_retry:
|
||||||
description: Command to run if the first attempt fails. This command will be called on all subsequent attempts.
|
description: Command to run if the first attempt fails. This command will be called on all subsequent attempts.
|
||||||
required: false
|
required: false
|
||||||
|
retry_on_exit_code:
|
||||||
|
description: Specific exit code to retry on. This will only retry for the given error code and fail immediately other error codes.
|
||||||
|
required: false
|
||||||
outputs:
|
outputs:
|
||||||
total_attempts:
|
total_attempts:
|
||||||
description: The final number of attempts made
|
description: The final number of attempts made
|
||||||
|
|||||||
24
dist/index.js
vendored
24
dist/index.js
vendored
@@ -289,6 +289,7 @@ var WARNING_ON_RETRY = core_1.getInput('warning_on_retry').toLowerCase() === 'tr
|
|||||||
var ON_RETRY_COMMAND = core_1.getInput('on_retry_command');
|
var ON_RETRY_COMMAND = core_1.getInput('on_retry_command');
|
||||||
var CONTINUE_ON_ERROR = getInputBoolean('continue_on_error');
|
var CONTINUE_ON_ERROR = getInputBoolean('continue_on_error');
|
||||||
var NEW_COMMAND_ON_RETRY = core_1.getInput('new_command_on_retry');
|
var NEW_COMMAND_ON_RETRY = core_1.getInput('new_command_on_retry');
|
||||||
|
var RETRY_ON_EXIT_CODE = getInputNumber('retry_on_exit_code', false);
|
||||||
var OS = process.platform;
|
var OS = process.platform;
|
||||||
var OUTPUT_TOTAL_ATTEMPTS_KEY = 'total_attempts';
|
var OUTPUT_TOTAL_ATTEMPTS_KEY = 'total_attempts';
|
||||||
var OUTPUT_EXIT_CODE_KEY = 'exit_code';
|
var OUTPUT_EXIT_CODE_KEY = 'exit_code';
|
||||||
@@ -479,17 +480,17 @@ function runAction() {
|
|||||||
attempt = 1;
|
attempt = 1;
|
||||||
_a.label = 2;
|
_a.label = 2;
|
||||||
case 2:
|
case 2:
|
||||||
if (!(attempt <= MAX_ATTEMPTS)) return [3 /*break*/, 12];
|
if (!(attempt <= MAX_ATTEMPTS)) return [3 /*break*/, 13];
|
||||||
_a.label = 3;
|
_a.label = 3;
|
||||||
case 3:
|
case 3:
|
||||||
_a.trys.push([3, 5, , 11]);
|
_a.trys.push([3, 5, , 12]);
|
||||||
// just keep overwriting attempts output
|
// just keep overwriting attempts output
|
||||||
core_1.setOutput(OUTPUT_TOTAL_ATTEMPTS_KEY, attempt);
|
core_1.setOutput(OUTPUT_TOTAL_ATTEMPTS_KEY, attempt);
|
||||||
return [4 /*yield*/, runCmd(attempt)];
|
return [4 /*yield*/, runCmd(attempt)];
|
||||||
case 4:
|
case 4:
|
||||||
_a.sent();
|
_a.sent();
|
||||||
core_1.info("Command completed after " + attempt + " attempt(s).");
|
core_1.info("Command completed after " + attempt + " attempt(s).");
|
||||||
return [3 /*break*/, 12];
|
return [3 /*break*/, 13];
|
||||||
case 5:
|
case 5:
|
||||||
error_2 = _a.sent();
|
error_2 = _a.sent();
|
||||||
if (!(attempt === MAX_ATTEMPTS)) return [3 /*break*/, 6];
|
if (!(attempt === MAX_ATTEMPTS)) return [3 /*break*/, 6];
|
||||||
@@ -499,11 +500,14 @@ function runAction() {
|
|||||||
// error: timeout
|
// error: timeout
|
||||||
throw error_2;
|
throw error_2;
|
||||||
case 7:
|
case 7:
|
||||||
if (!(exit > 0 && RETRY_ON === 'timeout')) return [3 /*break*/, 8];
|
if (!(RETRY_ON_EXIT_CODE && RETRY_ON_EXIT_CODE !== exit)) return [3 /*break*/, 8];
|
||||||
|
throw error_2;
|
||||||
|
case 8:
|
||||||
|
if (!(exit > 0 && RETRY_ON === 'timeout')) return [3 /*break*/, 9];
|
||||||
// error: error
|
// error: error
|
||||||
throw error_2;
|
throw error_2;
|
||||||
case 8: return [4 /*yield*/, runRetryCmd()];
|
case 9: return [4 /*yield*/, runRetryCmd()];
|
||||||
case 9:
|
case 10:
|
||||||
_a.sent();
|
_a.sent();
|
||||||
if (WARNING_ON_RETRY) {
|
if (WARNING_ON_RETRY) {
|
||||||
core_1.warning("Attempt " + attempt + " failed. Reason: " + error_2.message);
|
core_1.warning("Attempt " + attempt + " failed. Reason: " + error_2.message);
|
||||||
@@ -511,12 +515,12 @@ function runAction() {
|
|||||||
else {
|
else {
|
||||||
core_1.info("Attempt " + attempt + " failed. Reason: " + error_2.message);
|
core_1.info("Attempt " + attempt + " failed. Reason: " + error_2.message);
|
||||||
}
|
}
|
||||||
_a.label = 10;
|
_a.label = 11;
|
||||||
case 10: return [3 /*break*/, 11];
|
case 11: return [3 /*break*/, 12];
|
||||||
case 11:
|
case 12:
|
||||||
attempt++;
|
attempt++;
|
||||||
return [3 /*break*/, 2];
|
return [3 /*break*/, 2];
|
||||||
case 12: return [2 /*return*/];
|
case 13: return [2 /*return*/];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const WARNING_ON_RETRY = getInput('warning_on_retry').toLowerCase() === 'true';
|
|||||||
const ON_RETRY_COMMAND = getInput('on_retry_command');
|
const ON_RETRY_COMMAND = getInput('on_retry_command');
|
||||||
const CONTINUE_ON_ERROR = getInputBoolean('continue_on_error');
|
const CONTINUE_ON_ERROR = getInputBoolean('continue_on_error');
|
||||||
const NEW_COMMAND_ON_RETRY = getInput('new_command_on_retry');
|
const NEW_COMMAND_ON_RETRY = getInput('new_command_on_retry');
|
||||||
|
const RETRY_ON_EXIT_CODE = getInputNumber('retry_on_exit_code', false);
|
||||||
|
|
||||||
const OS = process.platform;
|
const OS = process.platform;
|
||||||
const OUTPUT_TOTAL_ATTEMPTS_KEY = 'total_attempts';
|
const OUTPUT_TOTAL_ATTEMPTS_KEY = 'total_attempts';
|
||||||
@@ -187,6 +188,8 @@ async function runAction() {
|
|||||||
} else if (!done && RETRY_ON === 'error') {
|
} else if (!done && RETRY_ON === 'error') {
|
||||||
// error: timeout
|
// error: timeout
|
||||||
throw error;
|
throw error;
|
||||||
|
} else if (RETRY_ON_EXIT_CODE && RETRY_ON_EXIT_CODE !== exit){
|
||||||
|
throw error;
|
||||||
} else if (exit > 0 && RETRY_ON === 'timeout') {
|
} else if (exit > 0 && RETRY_ON === 'timeout') {
|
||||||
// error: error
|
// error: error
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
Reference in New Issue
Block a user