Compare commits

...

13 Commits

Author SHA1 Message Date
CrazyMax
34e505eb5e Update CHANGELOG 2020-08-20 16:45:26 +02:00
CrazyMax
2c57607524 Refactor 2020-08-20 16:40:33 +02:00
CrazyMax
26618cd0df Retrieve command 2020-08-20 16:24:35 +02:00
CrazyMax
da3da99964 Builtin exec 2020-08-20 16:14:02 +02:00
CrazyMax
b7cd11b1fa Unsilent 2020-08-20 16:12:46 +02:00
CrazyMax
16b2f90c24 Display AWS CLI version 2020-08-20 16:10:17 +02:00
CrazyMax
826c451920 Log AWS region 2020-08-20 16:03:38 +02:00
CrazyMax
f37c715508 Add support for AWS Elastic Container Registry (ECR)
Add example for Google Container Registry (GCR)
2020-08-20 15:59:41 +02:00
dependabot[bot]
e6dc03b339 Bump actions/checkout from v2.3.1 to v2.3.2 (#1)
Bumps [actions/checkout](https://github.com/actions/checkout) from v2.3.1 to v2.3.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2.3.1...2036a08e25fa78bbd946711a407b529a0a1204bf)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-08-17 09:34:12 +00:00
CrazyMax
ef43051dd2 Typo 2020-08-16 02:04:19 +02:00
CrazyMax
a9078ed4ca Update CHANGELOG 2020-08-15 15:38:24 +02:00
CrazyMax
161192d780 Add examples for GitLab and GitHub Package Registry 2020-08-15 15:38:12 +02:00
CrazyMax
c252382ab9 Add tests again GitLab and GitHub Package Registry 2020-08-15 15:36:37 +02:00
10 changed files with 501 additions and 56 deletions

View File

@@ -7,7 +7,84 @@ on:
- releases/v* - releases/v*
jobs: jobs:
main: dockerhub:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
logout:
- true
- false
steps:
-
name: Checkout
uses: actions/checkout@v2.3.2
-
name: Login to DockerHub
uses: ./
with:
username: ${{ secrets.DOCKERHUB_USERNAME_TEST }}
password: ${{ secrets.DOCKERHUB_PASSWORD_TEST }}
logout: ${{ matrix.logout }}
-
name: Clear
if: always()
run: |
rm -f ${HOME}/.docker/config.json
gpr:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
logout:
- true
- false
steps:
-
name: Checkout
uses: actions/checkout@v2.3.2
-
name: Login to GitHub Package Registry
uses: ./
with:
registry: docker.pkg.github.com
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
logout: ${{ matrix.logout }}
-
name: Clear
if: always()
run: |
rm -f ${HOME}/.docker/config.json
gitlab:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
logout:
- true
- false
steps:
-
name: Checkout
uses: actions/checkout@v2.3.2
-
name: Login to GitLab
uses: ./
with:
registry: registry.gitlab.com
username: ${{ secrets.GITLAB_USERNAME_TEST }}
password: ${{ secrets.GITLAB_PASSWORD_TEST }}
logout: ${{ matrix.logout }}
-
name: Clear
if: always()
run: |
rm -f ${HOME}/.docker/config.json
ecr:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
@@ -20,11 +97,12 @@ jobs:
name: Checkout name: Checkout
uses: actions/checkout@v2.3.1 uses: actions/checkout@v2.3.1
- -
name: Login name: Login to ECR
uses: ./ uses: ./
with: with:
username: ${{ secrets.DOCKER_USERNAME_TEST }} registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
password: ${{ secrets.DOCKER_PASSWORD_TEST }} username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
logout: ${{ matrix.logout }} logout: ${{ matrix.logout }}
- -
name: Clear name: Clear

View File

@@ -14,7 +14,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2.3.1 uses: actions/checkout@v2.3.2
- -
name: Run Labeler name: Run Labeler
if: success() if: success()

View File

@@ -14,7 +14,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2.3.1 uses: actions/checkout@v2.3.2
- -
name: Install name: Install
run: yarn install run: yarn install

View File

@@ -1,5 +1,18 @@
# Changelog # Changelog
## 1.2.0 (2020/08/20)
* Add support for AWS Elastic Container Registry (ECR)
* Add example for Google Container Registry (GCR)
## 1.1.1 (2020/08/16)
* Typo
## 1.1.0 (2020/08/15)
* Add tests and examples for GitLab and GitHub Package Registry
## 1.0.1 (2020/08/15) ## 1.0.1 (2020/08/15)
* Add LICENSE * Add LICENSE

123
README.md
View File

@@ -15,6 +15,11 @@ If you are interested, [check out](https://git.io/Je09Y) my other :octocat: GitH
___ ___
* [Usage](#usage) * [Usage](#usage)
* [DockerHub](#dockerhub)
* [GitHub Package Registry](#github-package-registry)
* [GitLab](#gitlab)
* [Google Container Registry (GCR)](#gitlab)
* [AWS Elastic Container Registry (ECR)](#gitlab)
* [Customizing](#customizing) * [Customizing](#customizing)
* [inputs](#inputs) * [inputs](#inputs)
* [Limitation](#limitation) * [Limitation](#limitation)
@@ -23,13 +28,14 @@ ___
## Usage ## Usage
### DockerHub
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: master branches: master
tags:
jobs: jobs:
login: login:
@@ -42,10 +48,121 @@ jobs:
name: Login to DockerHub name: Login to DockerHub
uses: crazy-max/ghaction-docker-login@v1 uses: crazy-max/ghaction-docker-login@v1
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKERHUB_PASSWORD }}
``` ```
### GitHub Package Registry
```yaml
name: ci
on:
push:
branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to GitHub Package Registry
uses: crazy-max/ghaction-docker-login@v1
with:
registry: docker.pkg.github.com
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
```
### GitLab
```yaml
name: ci
on:
push:
branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to GitLab
uses: crazy-max/ghaction-docker-login@v1
with:
registry: registry.gitlab.com
username: ${{ secrets.GITLAB_USERNAME }}
password: ${{ secrets.GITLAB_PASSWORD }}
```
### Google Container Registry (GCR)
Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control).
Then create and download the JSON key for this service account and save content of `.json` file
[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`.
```yaml
name: ci
on:
push:
branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to GCR
uses: crazy-max/ghaction-docker-login@v1
with:
registry: gcr.io
username: _json_key
password: ${{ secrets.GCR_JSON_KEY }}
```
### AWS Elastic Container Registry (ECR)
Use an IAM user with the [ability to push to ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html).
Then create and download access keys and save `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [as secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
in your GitHub repo.
```yaml
name: ci
on:
push:
branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Login to ECR
uses: crazy-max/ghaction-docker-login@v1
with:
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
```
> Replace `<aws-account-number>` and `<region>` with their respective values.
## Customizing ## Customizing
### inputs ### inputs

214
dist/index.js generated vendored
View File

@@ -953,6 +953,32 @@ class ExecState extends events.EventEmitter {
/***/ }), /***/ }),
/***/ 34:
/***/ (function(__unusedmodule, exports) {
"use strict";
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 });
exports.getRegion = exports.isECR = void 0;
exports.isECR = (registry) => __awaiter(void 0, void 0, void 0, function* () {
return registry.includes('amazonaws');
});
exports.getRegion = (registry) => __awaiter(void 0, void 0, void 0, function* () {
return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws'));
});
//# sourceMappingURL=ecr.js.map
/***/ }),
/***/ 87: /***/ 87:
/***/ (function(module) { /***/ (function(module) {
@@ -1048,7 +1074,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const os = __importStar(__webpack_require__(87)); const os = __importStar(__webpack_require__(87));
const core = __importStar(__webpack_require__(470)); const core = __importStar(__webpack_require__(470));
const exec = __importStar(__webpack_require__(807)); const context_1 = __webpack_require__(482);
const docker = __importStar(__webpack_require__(231));
const stateHelper = __importStar(__webpack_require__(153)); const stateHelper = __importStar(__webpack_require__(153));
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@@ -1057,22 +1084,10 @@ function run() {
core.setFailed('Only supported on linux platform'); core.setFailed('Only supported on linux platform');
return; return;
} }
const registry = core.getInput('registry'); let inputs = yield context_1.getInputs();
stateHelper.setRegistry(registry); stateHelper.setRegistry(inputs.registry);
stateHelper.setLogout(core.getInput('logout')); stateHelper.setLogout(inputs.logout);
const username = core.getInput('username'); yield docker.login(inputs.registry, inputs.username, inputs.password);
const password = core.getInput('password', { required: true });
let loginArgs = ['login', '--password', password];
if (username) {
loginArgs.push('--username', username);
}
loginArgs.push(registry);
yield exec.exec('docker', loginArgs, true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
} }
catch (error) { catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
@@ -1084,11 +1099,7 @@ function logout() {
if (!stateHelper.logout) { if (!stateHelper.logout) {
return; return;
} }
yield exec.exec('docker', ['logout', stateHelper.registry], false).then(res => { yield docker.logout(stateHelper.registry);
if (res.stderr != '' && !res.success) {
core.warning(res.stderr);
}
});
}); });
} }
if (!stateHelper.IsPost) { if (!stateHelper.IsPost) {
@@ -1101,6 +1112,114 @@ else {
/***/ }), /***/ }),
/***/ 231:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
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 });
exports.loginECR = exports.loginStandard = exports.logout = exports.login = void 0;
const exec = __importStar(__webpack_require__(986));
const core = __importStar(__webpack_require__(470));
const ecr = __importStar(__webpack_require__(34));
const execm = __importStar(__webpack_require__(807));
function login(registry, username, password) {
return __awaiter(this, void 0, void 0, function* () {
if (yield ecr.isECR(registry)) {
yield loginECR(registry, username, password);
}
else {
yield loginStandard(registry, username, password);
}
});
}
exports.login = login;
function logout(registry) {
return __awaiter(this, void 0, void 0, function* () {
yield execm.exec('docker', ['logout', registry], false).then(res => {
if (res.stderr != '' && !res.success) {
core.warning(res.stderr);
}
});
});
}
exports.logout = logout;
function loginStandard(registry, username, password) {
return __awaiter(this, void 0, void 0, function* () {
let loginArgs = ['login', '--password', password];
if (username) {
loginArgs.push('--username', username);
}
loginArgs.push(registry);
if (registry) {
core.info(`🔑 Logging into ${registry}...`);
}
else {
core.info(`🔑 Logging into DockerHub...`);
}
yield execm.exec('docker', loginArgs, true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
});
}
exports.loginStandard = loginStandard;
function loginECR(registry, username, password) {
return __awaiter(this, void 0, void 0, function* () {
yield exec.exec('aws', ['--version']);
const ecrRegion = yield ecr.getRegion(registry);
process.env.AWS_ACCESS_KEY_ID = username;
process.env.AWS_SECRET_ACCESS_KEY = password;
core.info(`⬇️ Retrieving docker login command for ECR region ${ecrRegion}...`);
yield execm.exec('aws', ['ecr', 'get-login', '--region', ecrRegion, '--no-include-email'], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info(`🔑 Logging into ${registry}...`);
execm.exec(res.stdout, [], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
});
});
}
exports.loginECR = loginECR;
//# sourceMappingURL=docker.js.map
/***/ }),
/***/ 357: /***/ 357:
/***/ (function(module) { /***/ (function(module) {
@@ -1436,6 +1555,57 @@ exports.getState = getState;
/***/ }), /***/ }),
/***/ 482:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
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 });
exports.getInputs = void 0;
const core = __importStar(__webpack_require__(470));
function getInputs() {
return __awaiter(this, void 0, void 0, function* () {
return {
registry: core.getInput('registry'),
username: core.getInput('username'),
password: core.getInput('password', { required: true }),
logout: core.getInput('logout')
};
});
}
exports.getInputs = getInputs;
//# sourceMappingURL=context.js.map
/***/ }),
/***/ 614: /***/ 614:
/***/ (function(module) { /***/ (function(module) {

17
src/context.ts Normal file
View File

@@ -0,0 +1,17 @@
import * as core from '@actions/core';
export interface Inputs {
registry: string;
username: string;
password: string;
logout: string;
}
export async function getInputs(): Promise<Inputs> {
return {
registry: core.getInput('registry'),
username: core.getInput('username'),
password: core.getInput('password', {required: true}),
logout: core.getInput('logout')
};
}

61
src/docker.ts Normal file
View File

@@ -0,0 +1,61 @@
import * as exec from '@actions/exec';
import * as core from '@actions/core';
import * as ecr from './ecr';
import * as execm from './exec';
export async function login(registry: string, username: string, password: string): Promise<void> {
if (await ecr.isECR(registry)) {
await loginECR(registry, username, password);
} else {
await loginStandard(registry, username, password);
}
}
export async function logout(registry: string): Promise<void> {
await execm.exec('docker', ['logout', registry], false).then(res => {
if (res.stderr != '' && !res.success) {
core.warning(res.stderr);
}
});
}
export async function loginStandard(registry: string, username: string, password: string): Promise<void> {
let loginArgs: Array<string> = ['login', '--password', password];
if (username) {
loginArgs.push('--username', username);
}
loginArgs.push(registry);
if (registry) {
core.info(`🔑 Logging into ${registry}...`);
} else {
core.info(`🔑 Logging into DockerHub...`);
}
await execm.exec('docker', loginArgs, true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
}
export async function loginECR(registry: string, username: string, password: string): Promise<void> {
await exec.exec('aws', ['--version']);
const ecrRegion = await ecr.getRegion(registry);
process.env.AWS_ACCESS_KEY_ID = username;
process.env.AWS_SECRET_ACCESS_KEY = password;
core.info(`⬇️ Retrieving docker login command for ECR region ${ecrRegion}...`);
await execm.exec('aws', ['ecr', 'get-login', '--region', ecrRegion, '--no-include-email'], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info(`🔑 Logging into ${registry}...`);
execm.exec(res.stdout, [], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
});
}

7
src/ecr.ts Normal file
View File

@@ -0,0 +1,7 @@
export const isECR = async (registry: string): Promise<boolean> => {
return registry.includes('amazonaws');
};
export const getRegion = async (registry: string): Promise<string> => {
return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws'));
};

View File

@@ -1,6 +1,7 @@
import * as os from 'os'; import * as os from 'os';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as exec from './exec'; import {getInputs, Inputs} from './context';
import * as docker from './docker';
import * as stateHelper from './state-helper'; import * as stateHelper from './state-helper';
async function run(): Promise<void> { async function run(): Promise<void> {
@@ -10,25 +11,10 @@ async function run(): Promise<void> {
return; return;
} }
const registry: string = core.getInput('registry'); let inputs: Inputs = await getInputs();
stateHelper.setRegistry(registry); stateHelper.setRegistry(inputs.registry);
stateHelper.setLogout(core.getInput('logout')); stateHelper.setLogout(inputs.logout);
await docker.login(inputs.registry, inputs.username, inputs.password);
const username: string = core.getInput('username');
const password: string = core.getInput('password', {required: true});
let loginArgs: Array<string> = ['login', '--password', password];
if (username) {
loginArgs.push('--username', username);
}
loginArgs.push(registry);
await exec.exec('docker', loginArgs, true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }
@@ -38,11 +24,7 @@ async function logout(): Promise<void> {
if (!stateHelper.logout) { if (!stateHelper.logout) {
return; return;
} }
await exec.exec('docker', ['logout', stateHelper.registry], false).then(res => { await docker.logout(stateHelper.registry);
if (res.stderr != '' && !res.success) {
core.warning(res.stderr);
}
});
} }
if (!stateHelper.IsPost) { if (!stateHelper.IsPost) {