mirror of
https://github.com/docker/login-action.git
synced 2025-08-14 20:38:29 +08:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
adb73476b6 | ||
|
5df5104555 | ||
|
39ef12fb7a | ||
|
1c402b7c97 | ||
|
1c2cf9942d | ||
|
4b15841c41 |
BIN
.github/docker-login.png
vendored
BIN
.github/docker-login.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -117,3 +117,34 @@ jobs:
|
|||||||
# if: always()
|
# if: always()
|
||||||
# run: |
|
# run: |
|
||||||
# rm -f ${HOME}/.docker/config.json
|
# rm -f ${HOME}/.docker/config.json
|
||||||
|
#
|
||||||
|
# ecr-aws-creds:
|
||||||
|
# runs-on: ${{ matrix.os }}
|
||||||
|
# strategy:
|
||||||
|
# fail-fast: false
|
||||||
|
# matrix:
|
||||||
|
# os:
|
||||||
|
# - ubuntu-20.04
|
||||||
|
# - ubuntu-18.04
|
||||||
|
# - ubuntu-16.04
|
||||||
|
# steps:
|
||||||
|
# -
|
||||||
|
# name: Checkout
|
||||||
|
# uses: actions/checkout@v2.3.1
|
||||||
|
# -
|
||||||
|
# name: Configure AWS Credentials
|
||||||
|
# uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
# with:
|
||||||
|
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
# aws-region: ${{ secrets.AWS_REGION }}
|
||||||
|
# -
|
||||||
|
# name: Login to ECR
|
||||||
|
# uses: ./
|
||||||
|
# with:
|
||||||
|
# registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
|
||||||
|
# -
|
||||||
|
# name: Clear
|
||||||
|
# if: always()
|
||||||
|
# run: |
|
||||||
|
# rm -f ${HOME}/.docker/config.json
|
||||||
|
28
README.md
28
README.md
@@ -213,6 +213,34 @@ jobs:
|
|||||||
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also use the [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) action in
|
||||||
|
combination with this action:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
login:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws-region: <region>
|
||||||
|
-
|
||||||
|
name: Login to ECR
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
|
||||||
|
```
|
||||||
|
|
||||||
> Replace `<aws-account-number>` and `<region>` with their respective values.
|
> Replace `<aws-account-number>` and `<region>` with their respective values.
|
||||||
|
|
||||||
## Customizing
|
## Customizing
|
||||||
|
11
__tests__/context.test.ts
Normal file
11
__tests__/context.test.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import osm = require('os');
|
||||||
|
|
||||||
|
import {getInputs} from '../src/context';
|
||||||
|
|
||||||
|
test('with password and username getInputs does not throw error', async () => {
|
||||||
|
process.env['INPUT_USERNAME'] = 'dbowie';
|
||||||
|
process.env['INPUT_PASSWORD'] = 'groundcontrol';
|
||||||
|
expect(() => {
|
||||||
|
getInputs();
|
||||||
|
}).not.toThrowError();
|
||||||
|
});
|
49
__tests__/docker.test.ts
Normal file
49
__tests__/docker.test.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import {loginStandard, logout} from '../src/docker';
|
||||||
|
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
process.env['RUNNER_TEMP'] = path.join(__dirname, 'runner');
|
||||||
|
|
||||||
|
test('loginStandard calls exec', async () => {
|
||||||
|
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'exec');
|
||||||
|
// don't let exec try to actually run the commands
|
||||||
|
execSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const username: string = 'dbowie';
|
||||||
|
const password: string = 'groundcontrol';
|
||||||
|
const registry: string = 'https://ghcr.io';
|
||||||
|
|
||||||
|
await loginStandard(registry, username, password);
|
||||||
|
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`docker`, ['login', '--password-stdin', '--username', username, registry], {
|
||||||
|
input: Buffer.from(password),
|
||||||
|
silent: true,
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
listeners: expect.objectContaining({
|
||||||
|
stdout: expect.any(Function),
|
||||||
|
stderr: expect.any(Function)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('logout calls exec', async () => {
|
||||||
|
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'exec');
|
||||||
|
// don't let exec try to actually run the commands
|
||||||
|
execSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const registry: string = 'https://ghcr.io';
|
||||||
|
|
||||||
|
await logout(registry);
|
||||||
|
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`docker`, ['logout', registry], {
|
||||||
|
silent: false,
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
input: Buffer.from(''),
|
||||||
|
listeners: expect.objectContaining({
|
||||||
|
stdout: expect.any(Function),
|
||||||
|
stderr: expect.any(Function)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
79
__tests__/main.test.ts
Normal file
79
__tests__/main.test.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import osm = require('os');
|
||||||
|
|
||||||
|
import {run} from '../src/main';
|
||||||
|
import * as docker from '../src/docker';
|
||||||
|
import * as stateHelper from '../src/state-helper';
|
||||||
|
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
|
test('errors when not run on linux platform', async () => {
|
||||||
|
const platSpy = jest.spyOn(osm, 'platform');
|
||||||
|
platSpy.mockImplementation(() => 'netbsd');
|
||||||
|
|
||||||
|
const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed');
|
||||||
|
|
||||||
|
await run();
|
||||||
|
|
||||||
|
expect(coreSpy).toHaveBeenCalledWith('Only supported on linux platform');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('errors without username and password', async () => {
|
||||||
|
const platSpy = jest.spyOn(osm, 'platform');
|
||||||
|
platSpy.mockImplementation(() => 'linux');
|
||||||
|
|
||||||
|
const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed');
|
||||||
|
|
||||||
|
await run();
|
||||||
|
|
||||||
|
expect(coreSpy).toHaveBeenCalledWith('Username and password required');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('successful with username and password', async () => {
|
||||||
|
const platSpy = jest.spyOn(osm, 'platform');
|
||||||
|
platSpy.mockImplementation(() => 'linux');
|
||||||
|
|
||||||
|
const setRegistrySpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setRegistry');
|
||||||
|
const setLogoutSpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setLogout');
|
||||||
|
const dockerSpy: jest.SpyInstance = jest.spyOn(docker, 'login');
|
||||||
|
dockerSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const username: string = 'dbowie';
|
||||||
|
process.env[`INPUT_USERNAME`] = username;
|
||||||
|
|
||||||
|
const password: string = 'groundcontrol';
|
||||||
|
process.env[`INPUT_PASSWORD`] = password;
|
||||||
|
|
||||||
|
await run();
|
||||||
|
|
||||||
|
expect(setRegistrySpy).toHaveBeenCalledWith('');
|
||||||
|
expect(setLogoutSpy).toHaveBeenCalledWith('');
|
||||||
|
expect(dockerSpy).toHaveBeenCalledWith('', username, password);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls docker login', async () => {
|
||||||
|
const platSpy = jest.spyOn(osm, 'platform');
|
||||||
|
platSpy.mockImplementation(() => 'linux');
|
||||||
|
|
||||||
|
const setRegistrySpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setRegistry');
|
||||||
|
const setLogoutSpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setLogout');
|
||||||
|
const dockerSpy: jest.SpyInstance = jest.spyOn(docker, 'login');
|
||||||
|
dockerSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
const username: string = 'dbowie';
|
||||||
|
process.env[`INPUT_USERNAME`] = username;
|
||||||
|
|
||||||
|
const password: string = 'groundcontrol';
|
||||||
|
process.env[`INPUT_PASSWORD`] = password;
|
||||||
|
|
||||||
|
const registry: string = 'ghcr.io';
|
||||||
|
process.env[`INPUT_REGISTRY`] = registry;
|
||||||
|
|
||||||
|
const logout: string = 'true';
|
||||||
|
process.env['INPUT_LOGOUT'] = logout;
|
||||||
|
|
||||||
|
await run();
|
||||||
|
|
||||||
|
expect(setRegistrySpy).toHaveBeenCalledWith(registry);
|
||||||
|
expect(setLogoutSpy).toHaveBeenCalledWith(logout);
|
||||||
|
expect(dockerSpy).toHaveBeenCalledWith(registry, username, password);
|
||||||
|
});
|
@@ -15,7 +15,7 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
password:
|
password:
|
||||||
description: 'Password or personal access token used to log against the Docker registry'
|
description: 'Password or personal access token used to log against the Docker registry'
|
||||||
required: true
|
required: false
|
||||||
logout:
|
logout:
|
||||||
description: 'Log out from the Docker registry at the end of a job'
|
description: 'Log out from the Docker registry at the end of a job'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
|
47
dist/index.js
generated
vendored
47
dist/index.js
generated
vendored
@@ -496,6 +496,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.run = void 0;
|
||||||
const os = __importStar(__webpack_require__(87));
|
const os = __importStar(__webpack_require__(87));
|
||||||
const core = __importStar(__webpack_require__(186));
|
const core = __importStar(__webpack_require__(186));
|
||||||
const context_1 = __webpack_require__(842);
|
const context_1 = __webpack_require__(842);
|
||||||
@@ -505,19 +506,19 @@ function run() {
|
|||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
if (os.platform() !== 'linux') {
|
if (os.platform() !== 'linux') {
|
||||||
core.setFailed('Only supported on linux platform');
|
throw new Error('Only supported on linux platform');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
let inputs = yield context_1.getInputs();
|
const { registry, username, password, logout } = context_1.getInputs();
|
||||||
stateHelper.setRegistry(inputs.registry);
|
stateHelper.setRegistry(registry);
|
||||||
stateHelper.setLogout(inputs.logout);
|
stateHelper.setLogout(logout);
|
||||||
yield docker.login(inputs.registry, inputs.username, inputs.password);
|
yield docker.login(registry, username, password);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
exports.run = run;
|
||||||
function logout() {
|
function logout() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
if (!stateHelper.logout) {
|
if (!stateHelper.logout) {
|
||||||
@@ -3061,10 +3062,11 @@ function logout(registry) {
|
|||||||
exports.logout = logout;
|
exports.logout = logout;
|
||||||
function loginStandard(registry, username, password) {
|
function loginStandard(registry, username, password) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let loginArgs = ['login', '--password-stdin'];
|
if (!username || !password) {
|
||||||
if (username) {
|
throw new Error('Username and password required');
|
||||||
loginArgs.push('--username', username);
|
|
||||||
}
|
}
|
||||||
|
let loginArgs = ['login', '--password-stdin'];
|
||||||
|
loginArgs.push('--username', username);
|
||||||
loginArgs.push(registry);
|
loginArgs.push(registry);
|
||||||
if (registry) {
|
if (registry) {
|
||||||
core.info(`🔑 Logging into ${registry}...`);
|
core.info(`🔑 Logging into ${registry}...`);
|
||||||
@@ -3087,8 +3089,8 @@ function loginECR(registry, username, password) {
|
|||||||
const cliVersion = yield aws.getCLIVersion();
|
const cliVersion = yield aws.getCLIVersion();
|
||||||
const region = yield aws.getRegion(registry);
|
const region = yield aws.getRegion(registry);
|
||||||
core.info(`💡 AWS ECR detected with ${region} region`);
|
core.info(`💡 AWS ECR detected with ${region} region`);
|
||||||
process.env.AWS_ACCESS_KEY_ID = username;
|
process.env.AWS_ACCESS_KEY_ID = username || process.env.AWS_ACCESS_KEY_ID;
|
||||||
process.env.AWS_SECRET_ACCESS_KEY = password;
|
process.env.AWS_SECRET_ACCESS_KEY = password || process.env.AWS_SECRET_ACCESS_KEY;
|
||||||
core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`);
|
core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`);
|
||||||
const loginCmd = yield aws.getDockerLoginCmd(cliVersion, registry, region);
|
const loginCmd = yield aws.getDockerLoginCmd(cliVersion, registry, region);
|
||||||
core.info(`🔑 Logging into ${registry}...`);
|
core.info(`🔑 Logging into ${registry}...`);
|
||||||
@@ -3640,27 +3642,16 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
__setModuleDefault(result, mod);
|
__setModuleDefault(result, mod);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getInputs = void 0;
|
exports.getInputs = void 0;
|
||||||
const core = __importStar(__webpack_require__(186));
|
const core = __importStar(__webpack_require__(186));
|
||||||
function getInputs() {
|
function getInputs() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return {
|
||||||
return {
|
registry: core.getInput('registry'),
|
||||||
registry: core.getInput('registry'),
|
username: core.getInput('username'),
|
||||||
username: core.getInput('username'),
|
password: core.getInput('password'),
|
||||||
password: core.getInput('password', { required: true }),
|
logout: core.getInput('logout')
|
||||||
logout: core.getInput('logout')
|
};
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
exports.getInputs = getInputs;
|
exports.getInputs = getInputs;
|
||||||
//# sourceMappingURL=context.js.map
|
//# sourceMappingURL=context.js.map
|
||||||
|
@@ -7,11 +7,11 @@ export interface Inputs {
|
|||||||
logout: string;
|
logout: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getInputs(): Promise<Inputs> {
|
export function getInputs(): Inputs {
|
||||||
return {
|
return {
|
||||||
registry: core.getInput('registry'),
|
registry: core.getInput('registry'),
|
||||||
username: core.getInput('username'),
|
username: core.getInput('username'),
|
||||||
password: core.getInput('password', {required: true}),
|
password: core.getInput('password'),
|
||||||
logout: core.getInput('logout')
|
logout: core.getInput('logout')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -19,10 +19,12 @@ export async function logout(registry: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loginStandard(registry: string, username: string, password: string): Promise<void> {
|
export async function loginStandard(registry: string, username: string, password: string): Promise<void> {
|
||||||
let loginArgs: Array<string> = ['login', '--password-stdin'];
|
if (!username || !password) {
|
||||||
if (username) {
|
throw new Error('Username and password required');
|
||||||
loginArgs.push('--username', username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loginArgs: Array<string> = ['login', '--password-stdin'];
|
||||||
|
loginArgs.push('--username', username);
|
||||||
loginArgs.push(registry);
|
loginArgs.push(registry);
|
||||||
|
|
||||||
if (registry) {
|
if (registry) {
|
||||||
@@ -44,8 +46,8 @@ export async function loginECR(registry: string, username: string, password: str
|
|||||||
const region = await aws.getRegion(registry);
|
const region = await aws.getRegion(registry);
|
||||||
core.info(`💡 AWS ECR detected with ${region} region`);
|
core.info(`💡 AWS ECR detected with ${region} region`);
|
||||||
|
|
||||||
process.env.AWS_ACCESS_KEY_ID = username;
|
process.env.AWS_ACCESS_KEY_ID = username || process.env.AWS_ACCESS_KEY_ID;
|
||||||
process.env.AWS_SECRET_ACCESS_KEY = password;
|
process.env.AWS_SECRET_ACCESS_KEY = password || process.env.AWS_SECRET_ACCESS_KEY;
|
||||||
|
|
||||||
core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`);
|
core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`);
|
||||||
const loginCmd = await aws.getDockerLoginCmd(cliVersion, registry, region);
|
const loginCmd = await aws.getDockerLoginCmd(cliVersion, registry, region);
|
||||||
|
13
src/main.ts
13
src/main.ts
@@ -4,17 +4,16 @@ import {getInputs, Inputs} from './context';
|
|||||||
import * as docker from './docker';
|
import * as docker from './docker';
|
||||||
import * as stateHelper from './state-helper';
|
import * as stateHelper from './state-helper';
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (os.platform() !== 'linux') {
|
if (os.platform() !== 'linux') {
|
||||||
core.setFailed('Only supported on linux platform');
|
throw new Error('Only supported on linux platform');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputs: Inputs = await getInputs();
|
const {registry, username, password, logout} = getInputs();
|
||||||
stateHelper.setRegistry(inputs.registry);
|
stateHelper.setRegistry(registry);
|
||||||
stateHelper.setLogout(inputs.logout);
|
stateHelper.setLogout(logout);
|
||||||
await docker.login(inputs.registry, inputs.username, inputs.password);
|
await docker.login(registry, username, password);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user