1
0
Fork 0
mirror of https://github.com/docker/login-action.git synced 2025-03-31 12:10:05 +02:00

Added input parameters which retry docker.login() in case of error

Signed-off-by: eegiazarov <52110484+eegiazarov@users.noreply.github.com>
This commit is contained in:
eegiazarov 2022-09-08 22:49:03 +03:00
parent dd4fa0671b
commit c43cbe2c6a
6 changed files with 75 additions and 11 deletions

View file

@ -454,13 +454,15 @@ jobs:
Following inputs can be used as `step.with` keys
| Name | Type | Default | Description |
|------------------|---------|-----------------------------|------------------------------------|
| `registry` | String | | Server address of Docker registry. If not set then will default to Docker Hub |
| `username` | String | | Username used to log against the Docker registry |
| `password` | String | | Password or personal access token used to log against the Docker registry |
| `ecr` | String | `auto` | Specifies whether the given registry is ECR (`auto`, `true` or `false`) |
| `logout` | Bool | `true` | Log out from the Docker registry at the end of a job |
| Name | Type | Default | Description |
|------------ --------|--------|---------|------------------------------------|
| `registry` | String | | Server address of Docker registry. If not set then will default to Docker Hub |
| `username` | String | | Username used to log against the Docker registry |
| `password` | String | | Password or personal access token used to log against the Docker registry |
| `ecr` | String | `auto` | Specifies whether the given registry is ECR (`auto`, `true` or `false`) |
| `logout` | Bool | `true` | Log out from the Docker registry at the end of a job |
| `retries` | String | `3` | Maximum retries in case of errors (limit of 50 hardcoded) |
| `retryErrorPattern` | String | | Regexp to match error message |
## Keep up-to-date with GitHub Dependabot

View file

@ -70,3 +70,23 @@ test('calls docker login', async () => {
expect(setLogoutSpy).toHaveBeenCalledWith(logout);
expect(dockerSpy).toHaveBeenCalledWith(registry, username, password, ecr);
});
test('retried error without username and password', async () => {
const platSpy = jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
const setFailedSpy = jest.spyOn(core, 'setFailed');
const warningSpy = jest.spyOn(core, 'warning');
const dockerSpy = jest.spyOn(docker, 'login');
dockerSpy.mockImplementation(() => {
throw Error('Username and password required');
});
process.env['INPUT_LOGOUT'] = 'true'; // default value
process.env['INPUT_RETRYERRORPATTERN'] = '.*and password.*';
process.env['INPUT_RETRIES'] = '5';
await run();
expect(warningSpy).toHaveBeenCalledWith('Error <<<Username and password required>>> is recoverable, retrying...');
expect(warningSpy).toBeCalledTimes(4);
expect(setFailedSpy).toHaveBeenCalledWith('Username and password required');
});

View file

@ -24,6 +24,13 @@ inputs:
description: 'Log out from the Docker registry at the end of a job'
default: 'true'
required: false
retryErrorPattern:
description: "Regexp to match error message"
required: false
retries:
description: "Maximum retries in case of errors (limit of 50 hardcoded)"
default: "3"
required: false
runs:
using: 'node12'

22
dist/index.js generated vendored
View file

@ -185,7 +185,9 @@ function getInputs() {
username: core.getInput('username'),
password: core.getInput('password'),
ecr: core.getInput('ecr'),
logout: core.getBooleanInput('logout')
logout: core.getBooleanInput('logout'),
retryErrorPattern: core.getInput('retryErrorPattern'),
retries: core.getInput('retries')
};
}
exports.getInputs = getInputs;
@ -329,7 +331,23 @@ async function run() {
const input = context.getInputs();
stateHelper.setRegistry(input.registry);
stateHelper.setLogout(input.logout);
await docker.login(input.registry, input.username, input.password, input.ecr);
let retryErrorPattern = input.retryErrorPattern;
let attemptCount = parseInt(input.retries);
if (isNaN(attemptCount))
attemptCount = 3;
attemptCount = Math.min(attemptCount, 50);
// eslint-disable-next-line no-constant-condition
while (true) {
try {
await docker.login(input.registry, input.username, input.password, input.ecr);
break;
}
catch (error) {
if (!retryErrorPattern || !RegExp(retryErrorPattern).test(error.message) || --attemptCount <= 0)
throw error;
core.warning(`Error <<<${error.message}>>> is recoverable, retrying...`);
}
}
}
catch (error) {
core.setFailed(error.message);

View file

@ -6,6 +6,8 @@ export interface Inputs {
password: string;
ecr: string;
logout: boolean;
retryErrorPattern: string;
retries: string;
}
export function getInputs(): Inputs {
@ -14,6 +16,8 @@ export function getInputs(): Inputs {
username: core.getInput('username'),
password: core.getInput('password'),
ecr: core.getInput('ecr'),
logout: core.getBooleanInput('logout')
logout: core.getBooleanInput('logout'),
retryErrorPattern: core.getInput('retryErrorPattern'),
retries: core.getInput('retries')
};
}

View file

@ -8,7 +8,20 @@ export async function run(): Promise<void> {
const input: context.Inputs = context.getInputs();
stateHelper.setRegistry(input.registry);
stateHelper.setLogout(input.logout);
await docker.login(input.registry, input.username, input.password, input.ecr);
let retryErrorPattern = input.retryErrorPattern;
let attemptCount = parseInt(input.retries);
if (isNaN(attemptCount)) attemptCount = 3;
attemptCount = Math.min(attemptCount, 50);
// eslint-disable-next-line no-constant-condition
while (true) {
try {
await docker.login(input.registry, input.username, input.password, input.ecr);
break;
} catch (error: any) {
if (!retryErrorPattern || !RegExp(retryErrorPattern).test(error.message) || --attemptCount <= 0) throw error;
core.warning(`Error <<<${error.message}>>> is recoverable, retrying...`);
}
}
} catch (error: any) {
core.setFailed(error.message);
}