1
0
Fork 0
mirror of https://github.com/docker/login-action.git synced 2025-04-01 20:50:06 +02:00

Merge branch 'docker:master' into master

This commit is contained in:
Sean Barlow 2022-08-05 20:56:04 -05:00 committed by GitHub
commit f78f167fed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 13175 additions and 7072 deletions

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
/coverage
/node_modules

23
.eslintrc.json Normal file
View file

@ -0,0 +1,23 @@
{
"env": {
"node": true,
"es2021": true,
"jest/globals": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"jest",
"prettier"
]
}

View file

@ -2,20 +2,24 @@
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license)
to the public under the [project's open source license](LICENSE).
## Submitting a pull request ## Submitting a pull request
1. [Fork](https://github.com/docker/login-action/fork) and clone the repository 1. [Fork](https://github.com/docker/login-action/fork) and clone the repository
2. Configure and install the dependencies: `yarn install` 2. Configure and install the dependencies: `yarn install`
4. Create a new branch: `git checkout -b my-branch-name` 3. Create a new branch: `git checkout -b my-branch-name`
5. Make your change 4. Make your changes
6. Run pre-checkin: `yarn run pre-checkin` 5. Make sure the tests pass: `docker buildx bake test`
7. Push to your fork and [submit a pull request](https://github.com/docker/login-action/compare) 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin`
8. Pat your self on the back and wait for your pull request to be reviewed and merged. 7. Validate all code has correctly formatted and built: `docker buildx bake validate`
8. Push to your fork and [submit a pull request](https://github.com/docker/login-action/compare)
9. Pat your self on the back and wait for your pull request to be reviewed and merged.
Here are a few things you can do that will increase the likelihood of your pull request being accepted: Here are a few things you can do that will increase the likelihood of your pull request being accepted:
- Write tests.
- Make sure the `README.md` and any other relevant **documentation are kept up-to-date**. - Make sure the `README.md` and any other relevant **documentation are kept up-to-date**.
- We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**. - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as **separate pull requests**.
@ -24,5 +28,5 @@ Here are a few things you can do that will increase the likelihood of your pull
## Resources ## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) - [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
- [GitHub Help](https://help.github.com) - [GitHub Help](https://docs.github.com/en)

View file

@ -30,4 +30,5 @@ about: Create a report to help us improve
### Logs ### Logs
> Download the [log file of your build](https://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#downloading-logs) and [attach it](https://help.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue. > Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
> and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.

View file

@ -4,19 +4,15 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
time: "06:00"
timezone: "Europe/Paris"
labels: labels:
- ":game_die: dependencies" - "dependencies"
- ":robot: bot" - "bot"
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
time: "06:00"
timezone: "Europe/Paris"
allow: allow:
- dependency-type: "production" - dependency-type: "production"
labels: labels:
- ":game_die: dependencies" - "dependencies"
- ":robot: bot" - "bot"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

77
.github/labels.yml vendored
View file

@ -1,77 +0,0 @@
## more info https://github.com/crazy-max/ghaction-github-labeler
- # automerge
name: ":bell: automerge"
color: "8f4fbc"
description: ""
- # bot
name: ":robot: bot"
color: "69cde9"
description: ""
- # bug
name: ":bug: bug"
color: "b60205"
description: ""
- # dependencies
name: ":game_die: dependencies"
color: "0366d6"
description: ""
- # documentation
name: ":memo: documentation"
color: "c5def5"
description: ""
- # duplicate
name: ":busts_in_silhouette: duplicate"
color: "cccccc"
description: ""
- # enhancement
name: ":sparkles: enhancement"
color: "0054ca"
description: ""
- # feature request
name: ":bulb: feature request"
color: "0e8a16"
description: ""
- # feedback
name: ":mega: feedback"
color: "03a9f4"
description: ""
- # future maybe
name: ":rocket: future maybe"
color: "fef2c0"
description: ""
- # good first issue
name: ":hatching_chick: good first issue"
color: "7057ff"
description: ""
- # help wanted
name: ":pray: help wanted"
color: "4caf50"
description: ""
- # hold
name: ":hand: hold"
color: "24292f"
description: ""
- # invalid
name: ":no_entry_sign: invalid"
color: "e6e6e6"
description: ""
- # maybe bug
name: ":interrobang: maybe bug"
color: "ff5722"
description: ""
- # needs more info
name: ":thinking: needs more info"
color: "795548"
description: ""
- # question
name: ":question: question"
color: "3f51b5"
description: ""
- # upstream
name: ":eyes: upstream"
color: "fbca04"
description: ""
- # wontfix
name: ":coffin: wontfix"
color: "ffffff"
description: ""

View file

@ -3,12 +3,52 @@ name: ci
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: '0 10 * * *' # everyday at 10am - cron: '0 10 * * *'
push: push:
branches: branches:
- master - 'master'
- 'releases/v*'
jobs: jobs:
stop-docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Stop docker
run: |
sudo systemctl stop docker
-
name: Login to GitHub Container Registry
uses: ./
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
logout:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
logout:
- false
- true
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Login to GitHub Container Registry
uses: ./
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
logout: ${{ matrix.logout }}
dind: dind:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
@ -16,7 +56,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- -
name: Login to GitHub Container Registry name: Login to GitHub Container Registry
uses: ./ uses: ./
@ -36,19 +76,32 @@ jobs:
docker image prune -a -f >/dev/null 2>&1 docker image prune -a -f >/dev/null 2>&1
docker pull ghcr.io/docker-ghactiontest/test docker pull ghcr.io/docker-ghactiontest/test
acr:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Login to ACR
uses: ./
with:
registry: ${{ secrets.AZURE_REGISTRY_NAME }}.azurecr.io
username: ${{ secrets.AZURE_CLIENT_ID }}
password: ${{ secrets.AZURE_CLIENT_SECRET }}
dockerhub: dockerhub:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- ubuntu-20.04 - ubuntu-latest
- ubuntu-18.04 - windows-latest
- ubuntu-16.04
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- -
name: Login to Docker Hub name: Login to Docker Hub
uses: ./ uses: ./
@ -56,87 +109,130 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
# ecr: ecr:
# runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
# strategy: strategy:
# fail-fast: false fail-fast: false
# matrix: matrix:
# os: os:
# - ubuntu-20.04 - ubuntu-latest
# - ubuntu-18.04 - windows-latest
# - ubuntu-16.04
# steps:
# -
# name: Checkout
# uses: actions/checkout@v2
# -
# name: Login to ECR
# uses: ./
# with:
# registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
# username: ${{ secrets.AWS_ACCESS_KEY_ID }}
# password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
#
# 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
# -
# 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
github-package:
runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- -
name: Login to GitHub Package Registry name: Login to ECR
uses: ./ uses: ./
with: with:
registry: docker.pkg.github.com registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com
username: ${{ github.repository_owner }} username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
github-container: ecr-aws-creds:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
-
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: us-east-1
-
name: Login to ECR
uses: ./
with:
registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com
ecr-public:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Login to Public ECR
uses: ./
with:
registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
env:
AWS_REGION: us-east-1
ecr-public-aws-creds:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
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: us-east-1
-
name: Login to ECR
uses: ./
with:
registry: public.ecr.aws
github-container:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
- -
name: Login to GitHub Container Registry name: Login to GitHub Container Registry
uses: ./ uses: ./
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }} username: ${{ github.actor }}
password: ${{ secrets.GHCR_PAT }} password: ${{ secrets.GITHUB_TOKEN }}
gitlab: gitlab:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- -
name: Login to GitLab name: Login to GitLab
uses: ./ uses: ./
@ -145,30 +241,42 @@ jobs:
username: ${{ secrets.GITLAB_USERNAME }} username: ${{ secrets.GITLAB_USERNAME }}
password: ${{ secrets.GITLAB_TOKEN }} password: ${{ secrets.GITLAB_TOKEN }}
# google-artifact: google-artifact:
# runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
# steps: strategy:
# - fail-fast: false
# name: Checkout matrix:
# uses: actions/checkout@v2 os:
# - - ubuntu-latest
# name: Login to Google Artifact Registry - windows-latest
# uses: ./ steps:
# with: -
# registry: ${{ secrets.GAR_LOCATION }}-docker.pkg.dev name: Checkout
# username: _json_key uses: actions/checkout@v3
# password: ${{ secrets.GAR_JSON_KEY }} -
# name: Login to Google Artifact Registry
# google-container: uses: ./
# runs-on: ubuntu-latest with:
# steps: registry: ${{ secrets.GAR_LOCATION }}-docker.pkg.dev
# - username: _json_key
# name: Checkout password: ${{ secrets.GAR_JSON_KEY }}
# uses: actions/checkout@v2
# - google-container:
# name: Login to Google Container Registry runs-on: ${{ matrix.os }}
# uses: ./ strategy:
# with: fail-fast: false
# registry: gcr.io matrix:
# username: _json_key os:
# password: ${{ secrets.GCR_JSON_KEY }} - ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Login to Google Container Registry
uses: ./
with:
registry: gcr.io
username: _json_key
password: ${{ secrets.GCR_JSON_KEY }}

View file

@ -1,20 +0,0 @@
name: labels
on:
push:
branches:
- 'master'
paths:
- '.github/labels.yml'
- '.github/workflows/labels.yml'
jobs:
labeler:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Run Labeler
uses: crazy-max/ghaction-github-labeler@v3

View file

@ -3,38 +3,32 @@ name: test
on: on:
push: push:
branches: branches:
- master - 'master'
- releases/v* - 'releases/v*'
paths-ignore:
- '**.md'
pull_request: pull_request:
paths-ignore: branches:
- '**.md' - 'master'
- 'releases/v*'
jobs: jobs:
test: test:
runs-on: ${{ matrix.os }} runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
- ubuntu-18.04
- ubuntu-16.04
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- -
name: Install name: Validate
run: yarn install uses: docker/bake-action@v2
with:
targets: validate
- -
name: Test name: Test
run: yarn run test uses: docker/bake-action@v2
with:
targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v3
if: success()
with: with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml file: ./coverage/clover.xml

View file

@ -1,5 +1,5 @@
{ {
"printWidth": 120, "printWidth": 240,
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"semi": true, "semi": true,

293
README.md
View file

@ -1,6 +1,6 @@
[![GitHub release](https://img.shields.io/github/release/docker/login-action.svg?style=flat-square)](https://github.com/docker/login-action/releases/latest) [![GitHub release](https://img.shields.io/github/release/docker/login-action.svg?style=flat-square)](https://github.com/docker/login-action/releases/latest)
[![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--login-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-login) [![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--login-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-login)
[![CI workflow](https://img.shields.io/github/workflow/status/docker/login-action/test?label=ci&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=ci) [![CI workflow](https://img.shields.io/github/workflow/status/docker/login-action/ci?label=ci&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=ci)
[![Test workflow](https://img.shields.io/github/workflow/status/docker/login-action/test?label=test&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=test) [![Test workflow](https://img.shields.io/github/workflow/status/docker/login-action/test?label=test&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=test)
[![Codecov](https://img.shields.io/codecov/c/github/docker/login-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/login-action) [![Codecov](https://img.shields.io/codecov/c/github/docker/login-action?logo=codecov&style=flat-square)](https://codecov.io/gh/docker/login-action)
@ -8,18 +8,12 @@
GitHub Action to login against a Docker registry. GitHub Action to login against a Docker registry.
> :bulb: See also:
> * [setup-buildx](https://github.com/docker/setup-buildx-action) action
> * [setup-qemu](https://github.com/docker/setup-qemu-action) action
> * [build-push](https://github.com/docker/build-push-action) action
![Screenshot](.github/docker-login.png) ![Screenshot](.github/docker-login.png)
___ ___
* [Usage](#usage) * [Usage](#usage)
* [Docker Hub](#docker-hub) * [Docker Hub](#docker-hub)
* [GitHub Packages Docker Registry](#github-packages-docker-registry)
* [GitHub Container Registry](#github-container-registry) * [GitHub Container Registry](#github-container-registry)
* [GitLab](#gitlab) * [GitLab](#gitlab)
* [Azure Container Registry (ACR)](#azure-container-registry-acr) * [Azure Container Registry (ACR)](#azure-container-registry-acr)
@ -28,10 +22,10 @@ ___
* [AWS Elastic Container Registry (ECR)](#aws-elastic-container-registry-ecr) * [AWS Elastic Container Registry (ECR)](#aws-elastic-container-registry-ecr)
* [AWS Public Elastic Container Registry (ECR)](#aws-public-elastic-container-registry-ecr) * [AWS Public Elastic Container Registry (ECR)](#aws-public-elastic-container-registry-ecr)
* [OCI Oracle Cloud Infrastructure Registry (OCIR)](#oci-oracle-cloud-infrastructure-registry-ocir) * [OCI Oracle Cloud Infrastructure Registry (OCIR)](#oci-oracle-cloud-infrastructure-registry-ocir)
* [Quay.io](#quayio)
* [Customizing](#customizing) * [Customizing](#customizing)
* [inputs](#inputs) * [inputs](#inputs)
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot) * [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
* [Limitation](#limitation)
## Usage ## Usage
@ -45,7 +39,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -53,52 +47,24 @@ jobs:
steps: steps:
- -
name: Login to Docker Hub name: Login to Docker Hub
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
``` ```
### GitHub Packages Docker Registry
> :warning: GitHub Packages Docker Registry (aka `docker.pkg.github.com`) **is deprecated** and will sunset early next
> year. It's strongly advised to [migrate to GitHub Container Registry](https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images)
> instead.
You can configure the Docker client to use [GitHub Packages to publish and retrieve docker images](https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages).
```yaml
name: ci
on:
push:
branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to GitHub Packages Docker Registry
uses: docker/login-action@v1
with:
registry: docker.pkg.github.com
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
```
### GitHub Container Registry ### GitHub Container Registry
To authenticate against the [GitHub Container Registry](https://docs.github.com/en/packages/getting-started-with-github-container-registry), To authenticate against the [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry),
you will need to create a new [personal access token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) use the [`GITHUB_TOKEN`](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) for the best
with the [appropriate scopes](https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images#authenticating-with-the-container-registry). security and experience.
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -106,13 +72,19 @@ jobs:
steps: steps:
- -
name: Login to GitHub Container Registry name: Login to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.actor }}
password: ${{ secrets.CR_PAT }} password: ${{ secrets.GITHUB_TOKEN }}
``` ```
You may need to [manage write and read access of GitHub Actions](https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#upgrading-a-workflow-that-accesses-ghcrio)
for repositories in the container settings.
You can also use a [personal access token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
with the [appropriate scopes](https://docs.github.com/en/packages/getting-started-with-github-container-registry/migrating-to-github-container-registry-for-docker-images#authenticating-with-the-container-registry).
### GitLab ### GitLab
```yaml ```yaml
@ -120,7 +92,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -128,7 +100,7 @@ jobs:
steps: steps:
- -
name: Login to GitLab name: Login to GitLab
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: registry.gitlab.com registry: registry.gitlab.com
username: ${{ secrets.GITLAB_USERNAME }} username: ${{ secrets.GITLAB_USERNAME }}
@ -146,7 +118,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -154,7 +126,7 @@ jobs:
steps: steps:
- -
name: Login to ACR name: Login to ACR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: <registry-name>.azurecr.io registry: <registry-name>.azurecr.io
username: ${{ secrets.AZURE_CLIENT_ID }} username: ${{ secrets.AZURE_CLIENT_ID }}
@ -170,17 +142,57 @@ jobs:
> Google Container Registry, use the information [on this page](https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr) > Google Container Registry, use the information [on this page](https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr)
> to learn about transitioning to Google Artifact Registry. > to learn about transitioning to Google Artifact Registry.
Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control). You can use either workload identity federation based keyless authentication or service account based authentication.
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) #### Workload identity federation based authentication
called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`.
Configure the workload identity federation for github actions in gcloud (for steps, [refer here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation)). In the steps, your service account should the ability to push to GCR. Then use google-github-actions/auth action for authentication using workload identity like below:
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: master branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v0'
with:
token_format: 'access_token'
workload_identity_provider: '<workload_identity_provider>'
service_account: '<service_account>'
- name: Login to GCR
uses: docker/login-action@v2
with:
registry: gcr.io
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
```
> Replace `<workload_identity_provider>` with configured workload identity provider. For steps to configure, [refer here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation).
> Replace `<service_account>` with configured service account in workload identity provider which has access to push to GCR
#### Service account based authentication
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`,
or `_json_key_base64` if you use a base64-encoded key.
```yaml
name: ci
on:
push:
branches: main
jobs: jobs:
login: login:
@ -188,7 +200,7 @@ jobs:
steps: steps:
- -
name: Login to GCR name: Login to GCR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: gcr.io registry: gcr.io
username: _json_key username: _json_key
@ -197,17 +209,59 @@ jobs:
### Google Artifact Registry (GAR) ### Google Artifact Registry (GAR)
Use a service account with the ability to push to GAR and [configure access control](https://cloud.google.com/artifact-registry/docs/access-control). You can use either workload identity federation based keyless authentication or service account based authentication.
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) #### Workload identity federation based authentication
called `GAR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`.
Configure the workload identity federation for github actions in gcloud (for steps, [refer here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation)). In the steps, your service account should the ability to push to GAR. Then use google-github-actions/auth action for authentication using workload identity like below:
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: master branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v0'
with:
token_format: 'access_token'
workload_identity_provider: '<workload_identity_provider>'
service_account: '<service_account>'
- name: Login to GAR
uses: docker/login-action@v2
with:
registry: <location>-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
```
> Replace `<workload_identity_provider>` with configured workload identity provider
> Replace `<service_account>` with configured service account in workload identity provider which has access to push to GCR
> Replace `<location>` with the regional or multi-regional [location](https://cloud.google.com/artifact-registry/docs/repo-organize#locations)
> of the repository where the image is stored.
#### Service account based authentication
Use a service account with the ability to push to GAR and [configure access control](https://cloud.google.com/artifact-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 `GAR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`,
or `_json_key_base64` if you use a base64-encoded key.
```yaml
name: ci
on:
push:
branches: main
jobs: jobs:
login: login:
@ -215,7 +269,7 @@ jobs:
steps: steps:
- -
name: Login to GAR name: Login to GAR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: <location>-docker.pkg.dev registry: <location>-docker.pkg.dev
username: _json_key username: _json_key
@ -227,7 +281,7 @@ jobs:
### AWS Elastic Container Registry (ECR) ### 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). Use an IAM user with the ability to [push to ECR with `AmazonEC2ContainerRegistryPowerUser` managed policy for example](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html#AmazonEC2ContainerRegistryPowerUser).
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) 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. in your GitHub repo.
@ -236,7 +290,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -244,13 +298,40 @@ jobs:
steps: steps:
- -
name: Login to ECR name: Login to ECR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
username: ${{ secrets.AWS_ACCESS_KEY_ID }} username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
``` ```
If you need to log in to Amazon ECR registries associated with other accounts, you can use the `AWS_ACCOUNT_IDS`
environment variable:
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to ECR
uses: docker/login-action@v2
with:
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
env:
AWS_ACCOUNT_IDS: 012345678910,023456789012
```
> Only available with [AWS CLI version 1](https://docs.aws.amazon.com/cli/latest/reference/ecr/get-login.html)
You can also use the [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) action in You can also use the [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) action in
combination with this action: combination with this action:
@ -259,7 +340,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -274,7 +355,7 @@ jobs:
aws-region: <region> aws-region: <region>
- -
name: Login to ECR name: Login to ECR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
``` ```
@ -283,7 +364,7 @@ jobs:
### AWS Public Elastic Container Registry (ECR) ### AWS Public 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). Use an IAM user with the ability to [push to ECR Public with `AmazonElasticContainerRegistryPublicPowerUser` managed policy for example](https://docs.aws.amazon.com/AmazonECR/latest/public/public-ecr-managed-policies.html#AmazonElasticContainerRegistryPublicPowerUser).
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) 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. in your GitHub repo.
@ -292,7 +373,7 @@ name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -300,7 +381,7 @@ jobs:
steps: steps:
- -
name: Login to Public ECR name: Login to Public ECR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: public.ecr.aws registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY_ID }} username: ${{ secrets.AWS_ACCESS_KEY_ID }}
@ -311,48 +392,22 @@ jobs:
> Replace `<region>` with its respective value (default `us-east-1`). > Replace `<region>` with its respective value (default `us-east-1`).
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 Public ECR
uses: docker/login-action@v1
with:
registry: public.ecr.aws
```
> Replace `<region>` with its respective value.
### OCI Oracle Cloud Infrastructure Registry (OCIR) ### OCI Oracle Cloud Infrastructure Registry (OCIR)
To push into OCIR in specific tenancy the [username](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#LogintoOracleCloudInfrastructureRegistryfromtheDockerCLI) To push into OCIR in specific tenancy the [username](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#LogintoOracleCloudInfrastructureRegistryfromtheDockerCLI)
must be placed in format `<tenancy>/<username>` (in case of federated tenancy use the format `<tenancy-namespace>/oracleidentitycloudservice/<username>`). must be placed in format `<tenancy>/<username>` (in case of federated tenancy use the format
For password [create an auth token](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#GetanAuthToken). Save username and token `<tenancy-namespace>/oracleidentitycloudservice/<username>`).
[as a 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.
For password [create an auth token](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#GetanAuthToken).
Save username and token [as a 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 ```yaml
name: ci name: ci
on: on:
push: push:
branches: master branches: main
jobs: jobs:
login: login:
@ -360,14 +415,39 @@ jobs:
steps: steps:
- -
name: Login to OCIR name: Login to OCIR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: <region>.ocir.io registry: <region>.ocir.io
username: ${{ secrets.OCI_USERNAME }} username: ${{ secrets.OCI_USERNAME }}
password: ${{ secrets.OCI_TOKEN }} password: ${{ secrets.OCI_TOKEN }}
``` ```
> Replace `<region>` with their respective values from [availability regions](https://docs.cloud.oracle.com/iaas/Content/Registry/Concepts/registryprerequisites.htm#Availab) > Replace `<region>` with their respective values from [availability regions](https://docs.cloud.oracle.com/iaas/Content/Registry/Concepts/registryprerequisites.htm#Availab)
### Quay.io
Use a [Robot account](https://docs.quay.io/glossary/robot-accounts.html) with the ability to push to a public/private Quay.io repository.
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to Quay.io
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_ROBOT_TOKEN }}
```
## Customizing ## Customizing
### inputs ### inputs
@ -379,6 +459,7 @@ Following inputs can be used as `step.with` keys
| `registry` | String | | Server address of Docker registry. If not set then will default to Docker Hub | | `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 | | `username` | String | | Username used to log against the Docker registry |
| `password` | String | | Password or personal access token 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 | | `logout` | Bool | `true` | Log out from the Docker registry at the end of a job |
## Keep up-to-date with GitHub Dependabot ## Keep up-to-date with GitHub Dependabot
@ -396,7 +477,3 @@ updates:
schedule: schedule:
interval: "daily" interval: "daily"
``` ```
## Limitation
This action is only available for Linux [virtual environments](https://help.github.com/en/articles/virtual-environments-for-github-actions#supported-virtual-environments-and-hardware-resources).

View file

@ -1,4 +1,5 @@
import * as semver from 'semver'; import {beforeEach, describe, expect, jest, test} from '@jest/globals';
import {AuthorizationData} from '@aws-sdk/client-ecr';
import * as aws from '../src/aws'; import * as aws from '../src/aws';
describe('isECR', () => { describe('isECR', () => {
@ -6,9 +7,11 @@ describe('isECR', () => {
['registry.gitlab.com', false], ['registry.gitlab.com', false],
['gcr.io', false], ['gcr.io', false],
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', true], ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', true],
['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', true],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', true],
['public.ecr.aws', true] ['public.ecr.aws', true]
])('given registry %p', async (registry, expected) => { ])('given registry %p', async (registry, expected) => {
expect(await aws.isECR(registry)).toEqual(expected); expect(aws.isECR(registry)).toEqual(expected);
}); });
}); });
@ -17,50 +20,137 @@ describe('isPubECR', () => {
['registry.gitlab.com', false], ['registry.gitlab.com', false],
['gcr.io', false], ['gcr.io', false],
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', false], ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', false],
['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', false],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', false],
['public.ecr.aws', true] ['public.ecr.aws', true]
])('given registry %p', async (registry, expected) => { ])('given registry %p', async (registry, expected) => {
expect(await aws.isPubECR(registry)).toEqual(expected); expect(aws.isPubECR(registry)).toEqual(expected);
});
});
describe('getCLI', () => {
it('exists', async () => {
const awsPath = await aws.getCLI();
console.log(`awsPath: ${awsPath}`);
expect(awsPath).not.toEqual('');
});
});
describe('execCLI', () => {
it('--version not empty', async () => {
const cliCmdOutput = await aws.execCLI(['--version']);
console.log(`cliCmdOutput: ${cliCmdOutput}`);
expect(cliCmdOutput).not.toEqual('');
}, 100000);
});
describe('getCLIVersion', () => {
it('valid', async () => {
const cliVersion = await aws.getCLIVersion();
console.log(`cliVersion: ${cliVersion}`);
expect(semver.valid(cliVersion)).not.toBeNull();
}, 100000);
});
describe('parseCLIVersion', () => {
test.each([
['v1', 'aws-cli/1.18.120 Python/2.7.17 Linux/5.3.0-1034-azure botocore/1.17.43', '1.18.120'],
['v2', 'aws-cli/2.0.41 Python/3.7.3 Linux/4.19.104-microsoft-standard exe/x86_64.ubuntu.18', '2.0.41']
])('given aws %p', async (version, stdout, expected) => {
expect(await aws.parseCLIVersion(stdout)).toEqual(expected);
}); });
}); });
describe('getRegion', () => { describe('getRegion', () => {
test.each([ test.each([
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', 'eu-west-3'], ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', 'eu-west-3'],
['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', 'cn-north-1'],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 'cn-northwest-1'],
['public.ecr.aws', 'us-east-1'] ['public.ecr.aws', 'us-east-1']
])('given registry %p', async (registry, expected) => { ])('given registry %p', async (registry, expected) => {
expect(await aws.getRegion(registry)).toEqual(expected); expect(aws.getRegion(registry)).toEqual(expected);
});
});
describe('getAccountIDs', () => {
test.each([
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', undefined, ['012345678901']],
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', '012345678910,023456789012', ['012345678901', '012345678910', '023456789012']],
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', '012345678901,012345678910,023456789012', ['012345678901', '012345678910', '023456789012']],
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', '012345678910,023456789012', ['390948362332', '012345678910', '023456789012']],
['public.ecr.aws', undefined, []]
])('given registry %p', async (registry, accountIDsEnv, expected) => {
if (accountIDsEnv) {
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
}
expect(aws.getAccountIDs(registry)).toEqual(expected);
});
});
const mockEcrGetAuthToken = jest.fn();
const mockEcrPublicGetAuthToken = jest.fn();
jest.mock('@aws-sdk/client-ecr', () => {
return {
ECR: jest.fn(() => ({
getAuthorizationToken: mockEcrGetAuthToken
}))
};
});
jest.mock('@aws-sdk/client-ecr-public', () => {
return {
ECRPUBLIC: jest.fn(() => ({
getAuthorizationToken: mockEcrPublicGetAuthToken
}))
};
});
describe('getRegistriesData', () => {
beforeEach(() => {
jest.clearAllMocks();
delete process.env.AWS_ACCOUNT_IDS;
});
// prettier-ignore
test.each([
[
'012345678901.dkr.ecr.aws-region-1.amazonaws.com',
'dkr.ecr.aws-region-1.amazonaws.com', undefined,
[
{
registry: '012345678901.dkr.ecr.aws-region-1.amazonaws.com',
username: '012345678901',
password: 'world'
}
]
],
[
'012345678901.dkr.ecr.eu-west-3.amazonaws.com',
'dkr.ecr.eu-west-3.amazonaws.com',
'012345678910,023456789012',
[
{
registry: '012345678901.dkr.ecr.eu-west-3.amazonaws.com',
username: '012345678901',
password: 'world'
},
{
registry: '012345678910.dkr.ecr.eu-west-3.amazonaws.com',
username: '012345678910',
password: 'world'
},
{
registry: '023456789012.dkr.ecr.eu-west-3.amazonaws.com',
username: '023456789012',
password: 'world'
}
]
],
[
'public.ecr.aws',
undefined,
undefined,
[
{
registry: 'public.ecr.aws',
username: 'AWS',
password: 'world'
}
]
]
])('given registry %p', async (registry, fqdn, accountIDsEnv, expected: aws.RegistryData[]) => {
if (accountIDsEnv) {
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
}
const accountIDs = aws.getAccountIDs(registry);
const authData: AuthorizationData[] = [];
if (accountIDs.length == 0) {
mockEcrPublicGetAuthToken.mockImplementation(() => {
return Promise.resolve({
authorizationData: {
authorizationToken: Buffer.from(`AWS:world`).toString('base64'),
}
});
});
} else {
aws.getAccountIDs(registry).forEach(accountID => {
authData.push({
authorizationToken: Buffer.from(`${accountID}:world`).toString('base64'),
proxyEndpoint: `${accountID}.${fqdn}`
});
});
mockEcrGetAuthToken.mockImplementation(() => {
return Promise.resolve({
authorizationData: authData
});
});
}
const regData = await aws.getRegistriesData(registry);
expect(regData).toEqual(expected);
}); });
}); });

View file

@ -1,10 +1,10 @@
import osm = require('os'); import {expect, test} from '@jest/globals';
import {getInputs} from '../src/context'; import {getInputs} from '../src/context';
test('with password and username getInputs does not throw error', async () => { test('with password and username getInputs does not throw error', async () => {
process.env['INPUT_USERNAME'] = 'dbowie'; process.env['INPUT_USERNAME'] = 'dbowie';
process.env['INPUT_PASSWORD'] = 'groundcontrol'; process.env['INPUT_PASSWORD'] = 'groundcontrol';
process.env['INPUT_LOGOUT'] = 'true';
expect(() => { expect(() => {
getInputs(); getInputs();
}).not.toThrowError(); }).not.toThrowError();

View file

@ -1,49 +1,50 @@
import {expect, jest, test} from '@jest/globals';
import {loginStandard, logout} from '../src/docker'; import {loginStandard, logout} from '../src/docker';
import * as path from 'path'; import * as path from 'path';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
process.env['RUNNER_TEMP'] = path.join(__dirname, 'runner'); process.env['RUNNER_TEMP'] = path.join(__dirname, 'runner');
test('loginStandard calls exec', async () => { test('loginStandard calls exec', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'exec'); // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// don't let exec try to actually run the commands // @ts-ignore
execSpy.mockImplementation(() => {}); const execSpy = jest.spyOn(exec, 'getExecOutput').mockImplementation(async () => {
return {
exitCode: expect.any(Number),
stdout: expect.any(Function),
stderr: expect.any(Function)
};
});
const username: string = 'dbowie'; const username = 'dbowie';
const password: string = 'groundcontrol'; const password = 'groundcontrol';
const registry: string = 'https://ghcr.io'; const registry = 'https://ghcr.io';
await loginStandard(registry, username, password); await loginStandard(registry, username, password);
expect(execSpy).toHaveBeenCalledWith(`docker`, ['login', '--password-stdin', '--username', username, registry], { expect(execSpy).toHaveBeenCalledWith(`docker`, ['login', '--password-stdin', '--username', username, registry], {
input: Buffer.from(password), input: Buffer.from(password),
silent: true, silent: true,
ignoreReturnCode: true, ignoreReturnCode: true
listeners: expect.objectContaining({
stdout: expect.any(Function),
stderr: expect.any(Function)
})
}); });
}); });
test('logout calls exec', async () => { test('logout calls exec', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'exec'); // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// don't let exec try to actually run the commands // @ts-ignore
execSpy.mockImplementation(() => {}); const execSpy = jest.spyOn(exec, 'getExecOutput').mockImplementation(async () => {
return {
exitCode: expect.any(Number),
stdout: expect.any(Function),
stderr: expect.any(Function)
};
});
const registry: string = 'https://ghcr.io'; const registry = 'https://ghcr.io';
await logout(registry); await logout(registry);
expect(execSpy).toHaveBeenCalledWith(`docker`, ['logout', registry], { expect(execSpy).toHaveBeenCalledWith(`docker`, ['logout', registry], {
silent: false, ignoreReturnCode: true
ignoreReturnCode: true,
input: Buffer.from(''),
listeners: expect.objectContaining({
stdout: expect.any(Function),
stderr: expect.any(Function)
})
}); });
}); });

View file

@ -1,3 +1,4 @@
import {expect, jest, test} from '@jest/globals';
import osm = require('os'); import osm = require('os');
import {run} from '../src/main'; import {run} from '../src/main';
@ -6,74 +7,65 @@ import * as stateHelper from '../src/state-helper';
import * as core from '@actions/core'; 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 () => { test('errors without username and password', async () => {
const platSpy = jest.spyOn(osm, 'platform'); jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
platSpy.mockImplementation(() => 'linux'); process.env['INPUT_LOGOUT'] = 'true'; // default value
const coreSpy = jest.spyOn(core, 'setFailed');
const coreSpy: jest.SpyInstance = jest.spyOn(core, 'setFailed');
await run(); await run();
expect(coreSpy).toHaveBeenCalledWith('Username and password required'); expect(coreSpy).toHaveBeenCalledWith('Username and password required');
}); });
test('successful with username and password', async () => { test('successful with username and password', async () => {
const platSpy = jest.spyOn(osm, 'platform'); jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
platSpy.mockImplementation(() => 'linux'); const setRegistrySpy = jest.spyOn(stateHelper, 'setRegistry');
const setLogoutSpy = jest.spyOn(stateHelper, 'setLogout');
const dockerSpy = jest.spyOn(docker, 'login').mockImplementation(jest.fn());
const setRegistrySpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setRegistry'); const username = 'dbowie';
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; process.env[`INPUT_USERNAME`] = username;
const password: string = 'groundcontrol'; const password = 'groundcontrol';
process.env[`INPUT_PASSWORD`] = password; process.env[`INPUT_PASSWORD`] = password;
const ecr = 'auto';
process.env['INPUT_ECR'] = ecr;
const logout = false;
process.env['INPUT_LOGOUT'] = String(logout);
await run(); await run();
expect(setRegistrySpy).toHaveBeenCalledWith(''); expect(setRegistrySpy).toHaveBeenCalledWith('');
expect(setLogoutSpy).toHaveBeenCalledWith(''); expect(setLogoutSpy).toHaveBeenCalledWith(logout);
expect(dockerSpy).toHaveBeenCalledWith('', username, password); expect(dockerSpy).toHaveBeenCalledWith('', username, password, ecr);
}); });
test('calls docker login', async () => { test('calls docker login', async () => {
const platSpy = jest.spyOn(osm, 'platform'); jest.spyOn(osm, 'platform').mockImplementation(() => 'linux');
platSpy.mockImplementation(() => 'linux'); const setRegistrySpy = jest.spyOn(stateHelper, 'setRegistry');
const setLogoutSpy = jest.spyOn(stateHelper, 'setLogout');
const dockerSpy = jest.spyOn(docker, 'login');
dockerSpy.mockImplementation(jest.fn());
const setRegistrySpy: jest.SpyInstance = jest.spyOn(stateHelper, 'setRegistry'); const username = 'dbowie';
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; process.env[`INPUT_USERNAME`] = username;
const password: string = 'groundcontrol'; const password = 'groundcontrol';
process.env[`INPUT_PASSWORD`] = password; process.env[`INPUT_PASSWORD`] = password;
const registry: string = 'ghcr.io'; const registry = 'ghcr.io';
process.env[`INPUT_REGISTRY`] = registry; process.env[`INPUT_REGISTRY`] = registry;
const logout: string = 'true'; const ecr = 'auto';
process.env['INPUT_LOGOUT'] = logout; process.env['INPUT_ECR'] = ecr;
const logout = true;
process.env['INPUT_LOGOUT'] = String(logout);
await run(); await run();
expect(setRegistrySpy).toHaveBeenCalledWith(registry); expect(setRegistrySpy).toHaveBeenCalledWith(registry);
expect(setLogoutSpy).toHaveBeenCalledWith(logout); expect(setLogoutSpy).toHaveBeenCalledWith(logout);
expect(dockerSpy).toHaveBeenCalledWith(registry, username, password); expect(dockerSpy).toHaveBeenCalledWith(registry, username, password, ecr);
}); });

View file

@ -16,12 +16,16 @@ inputs:
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: false required: false
ecr:
description: 'Specifies whether the given registry is ECR (auto, true or false)'
default: 'auto'
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'
required: false required: false
runs: runs:
using: 'node12' using: 'node16'
main: 'dist/index.js' main: 'dist/index.js'
post: 'dist/index.js' post: 'dist/index.js'

3
codecov.yml Normal file
View file

@ -0,0 +1,3 @@
comment: false
github_checks:
annotations: false

78
dev.Dockerfile Normal file
View file

@ -0,0 +1,78 @@
# syntax=docker/dockerfile:1
ARG NODE_VERSION=16
ARG DOCKER_VERSION=20.10.13
ARG BUILDX_VERSION=0.8.1
FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git
WORKDIR /src
FROM base AS deps
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn install && mkdir /vendor && cp yarn.lock /vendor
FROM scratch AS vendor-update
COPY --from=deps /vendor /
FROM deps AS vendor-validate
RUN --mount=type=bind,target=.,rw <<EOT
set -e
git add -A
cp -rf /vendor/* .
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
git status --porcelain -- yarn.lock
exit 1
fi
EOT
FROM deps AS build
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run build && mkdir /out && cp -Rf dist /out/
FROM scratch AS build-update
COPY --from=build /out /
FROM build AS build-validate
RUN --mount=type=bind,target=.,rw <<EOT
set -e
git add -A
cp -rf /out/* .
if [ -n "$(git status --porcelain -- dist)" ]; then
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
git status --porcelain -- dist
exit 1
fi
EOT
FROM deps AS format
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run format \
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
FROM scratch AS format-update
COPY --from=format /out /
FROM deps AS lint
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
yarn run lint
FROM docker:${DOCKER_VERSION} as docker
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/node_modules \
--mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
--mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
yarn run test --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage /

4239
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

1
dist/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

9468
dist/licenses.txt generated vendored Normal file

File diff suppressed because it is too large Load diff

1
dist/sourcemap-register.js generated vendored Normal file

File diff suppressed because one or more lines are too long

53
docker-bake.hcl Normal file
View file

@ -0,0 +1,53 @@
group "default" {
targets = ["build"]
}
group "pre-checkin" {
targets = ["vendor-update", "format", "build"]
}
group "validate" {
targets = ["lint", "build-validate", "vendor-validate"]
}
target "build" {
dockerfile = "dev.Dockerfile"
target = "build-update"
output = ["."]
}
target "build-validate" {
dockerfile = "dev.Dockerfile"
target = "build-validate"
output = ["type=cacheonly"]
}
target "format" {
dockerfile = "dev.Dockerfile"
target = "format-update"
output = ["."]
}
target "lint" {
dockerfile = "dev.Dockerfile"
target = "lint"
output = ["type=cacheonly"]
}
target "vendor-update" {
dockerfile = "dev.Dockerfile"
target = "vendor-update"
output = ["."]
}
target "vendor-validate" {
dockerfile = "dev.Dockerfile"
target = "vendor-validate"
output = ["type=cacheonly"]
}
target "test" {
dockerfile = "dev.Dockerfile"
target = "test-coverage"
output = ["./coverage"]
}

View file

@ -2,11 +2,9 @@ module.exports = {
clearMocks: true, clearMocks: true,
moduleFileExtensions: ['js', 'ts'], moduleFileExtensions: ['js', 'ts'],
setupFiles: ["dotenv/config"], setupFiles: ["dotenv/config"],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'], testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: { transform: {
'^.+\\.ts$': 'ts-jest' '^.+\\.ts$': 'ts-jest'
}, },
verbose: false verbose: true
} }

View file

@ -3,11 +3,11 @@
"description": "GitHub Action to login against a Docker registry", "description": "GitHub Action to login against a Docker registry",
"main": "lib/main.js", "main": "lib/main.js",
"scripts": { "scripts": {
"build": "tsc && ncc build", "build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
"format": "prettier --write **/*.ts", "lint": "eslint src/**/*.ts __tests__/**/*.ts",
"format-check": "prettier --check **/*.ts", "format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
"test": "jest --coverage", "test": "jest --coverage",
"pre-checkin": "yarn run format && yarn run build" "all": "yarn run build && yarn run format && yarn test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -27,22 +27,28 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.6.0",
"@actions/exec": "^1.0.4", "@actions/exec": "^1.1.1",
"@actions/io": "^1.0.2", "@actions/io": "^1.1.2",
"semver": "^7.3.2" "@aws-sdk/client-ecr": "^3.53.0",
"@aws-sdk/client-ecr-public": "^3.53.0",
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.3", "@types/node": "^16.11.26",
"@types/node": "^14.0.14", "@typescript-eslint/eslint-plugin": "^5.14.0",
"@vercel/ncc": "^0.23.0", "@typescript-eslint/parser": "^5.14.0",
"dotenv": "^8.2.0", "@vercel/ncc": "^0.33.3",
"jest": "^26.1.0", "dotenv": "^16.0.0",
"jest-circus": "^26.1.0", "eslint": "^8.11.0",
"jest-runtime": "^26.1.0", "eslint-config-prettier": "^8.5.0",
"prettier": "^2.0.5", "eslint-plugin-jest": "^26.1.1",
"ts-jest": "^26.1.1", "eslint-plugin-prettier": "^4.0.0",
"typescript": "^3.9.5", "jest": "^27.2.5",
"typescript-formatter": "^7.2.2" "prettier": "^2.3.1",
"ts-jest": "^27.1.2",
"ts-node": "^10.7.0",
"typescript": "^4.4.4"
} }
} }

View file

@ -1,59 +1,133 @@
import * as semver from 'semver'; import * as core from '@actions/core';
import * as io from '@actions/io'; import {ECR} from '@aws-sdk/client-ecr';
import * as execm from './exec'; import {ECRPUBLIC} from '@aws-sdk/client-ecr-public';
import {NodeHttpHandler} from '@aws-sdk/node-http-handler';
import {HttpProxyAgent} from 'http-proxy-agent';
import {HttpsProxyAgent} from 'https-proxy-agent';
export const isECR = async (registry: string): Promise<boolean> => { const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/;
return registry.includes('amazonaws') || (await isPubECR(registry));
export const isECR = (registry: string): boolean => {
return ecrRegistryRegex.test(registry) || isPubECR(registry);
}; };
export const isPubECR = async (registry: string): Promise<boolean> => { export const isPubECR = (registry: string): boolean => {
return registry === 'public.ecr.aws'; return registry === 'public.ecr.aws';
}; };
export const getRegion = async (registry: string): Promise<string> => { export const getRegion = (registry: string): string => {
if (await isPubECR(registry)) { if (isPubECR(registry)) {
return process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1'; return process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';
} }
return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); const matches = registry.match(ecrRegistryRegex);
};
export const getCLI = async (): Promise<string> => {
return io.which('aws', true);
};
export const execCLI = async (args: string[]): Promise<string> => {
return execm.exec(await getCLI(), args, true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
} else if (res.stderr != '') {
return res.stderr.trim();
} else {
return res.stdout.trim();
}
});
};
export const getCLIVersion = async (): Promise<string> => {
return parseCLIVersion(await execCLI(['--version']));
};
export const parseCLIVersion = async (stdout: string): Promise<string> => {
const matches = /aws-cli\/([0-9.]+)/.exec(stdout);
if (!matches) { if (!matches) {
throw new Error(`Cannot parse AWS CLI version`); return '';
} }
return semver.clean(matches[1]); return matches[3];
}; };
export const getDockerLoginCmd = async (cliVersion: string, registry: string, region: string): Promise<string> => { export const getAccountIDs = (registry: string): string[] => {
let ecrCmd = (await isPubECR(registry)) ? 'ecr-public' : 'ecr'; if (isPubECR(registry)) {
if (semver.satisfies(cliVersion, '>=2.0.0')) { return [];
return execCLI([ecrCmd, 'get-login-password', '--region', region]).then(pwd => { }
return `docker login --username AWS --password ${pwd} ${registry}`; const matches = registry.match(ecrRegistryRegex);
if (!matches) {
return [];
}
const accountIDs: Array<string> = [matches[2]];
if (process.env.AWS_ACCOUNT_IDS) {
accountIDs.push(...process.env.AWS_ACCOUNT_IDS.split(','));
}
return accountIDs.filter((item, index) => accountIDs.indexOf(item) === index);
};
export interface RegistryData {
registry: string;
username: string;
password: string;
}
export const getRegistriesData = async (registry: string, username?: string, password?: string): Promise<RegistryData[]> => {
const region = getRegion(registry);
const accountIDs = getAccountIDs(registry);
const authTokenRequest = {};
if (accountIDs.length > 0) {
core.debug(`Requesting AWS ECR auth token for ${accountIDs.join(', ')}`);
authTokenRequest['registryIds'] = accountIDs;
}
let httpProxyAgent;
const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || '';
if (httpProxy) {
core.debug(`Using http proxy ${httpProxy}`);
httpProxyAgent = new HttpProxyAgent(httpProxy);
}
let httpsProxyAgent;
const httpsProxy = process.env.https_proxy || process.env.HTTPS_PROXY || '';
if (httpsProxy) {
core.debug(`Using https proxy ${httpsProxy}`);
httpsProxyAgent = new HttpsProxyAgent(httpsProxy);
}
const credentials =
username && password
? {
accessKeyId: username,
secretAccessKey: password
}
: undefined;
if (isPubECR(registry)) {
core.info(`AWS Public ECR detected with ${region} region`);
const ecrPublic = new ECRPUBLIC({
customUserAgent: 'docker-login-action',
credentials,
region: region,
requestHandler: new NodeHttpHandler({
httpAgent: httpProxyAgent,
httpsAgent: httpsProxyAgent
})
}); });
const authTokenResponse = await ecrPublic.getAuthorizationToken(authTokenRequest);
if (!authTokenResponse.authorizationData || !authTokenResponse.authorizationData.authorizationToken) {
throw new Error('Could not retrieve an authorization token from AWS Public ECR');
}
const authToken = Buffer.from(authTokenResponse.authorizationData.authorizationToken, 'base64').toString('utf-8');
const creds = authToken.split(':', 2);
return [
{
registry: 'public.ecr.aws',
username: creds[0],
password: creds[1]
}
];
} else { } else {
return execCLI([ecrCmd, 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => { core.info(`AWS ECR detected with ${region} region`);
return dockerLoginCmd; const ecr = new ECR({
customUserAgent: 'docker-login-action',
credentials,
region: region,
requestHandler: new NodeHttpHandler({
httpAgent: httpProxyAgent,
httpsAgent: httpsProxyAgent
})
}); });
const authTokenResponse = await ecr.getAuthorizationToken(authTokenRequest);
if (!Array.isArray(authTokenResponse.authorizationData) || !authTokenResponse.authorizationData.length) {
throw new Error('Could not retrieve an authorization token from AWS ECR');
}
const regDatas: RegistryData[] = [];
for (const authData of authTokenResponse.authorizationData) {
const authToken = Buffer.from(authData.authorizationToken || '', 'base64').toString('utf-8');
const creds = authToken.split(':', 2);
regDatas.push({
registry: authData.proxyEndpoint || '',
username: creds[0],
password: creds[1]
});
}
return regDatas;
} }
}; };

View file

@ -4,7 +4,8 @@ export interface Inputs {
registry: string; registry: string;
username: string; username: string;
password: string; password: string;
logout: string; ecr: string;
logout: boolean;
} }
export function getInputs(): Inputs { export function getInputs(): Inputs {
@ -12,6 +13,7 @@ export function getInputs(): Inputs {
registry: core.getInput('registry'), registry: core.getInput('registry'),
username: core.getInput('username'), username: core.getInput('username'),
password: core.getInput('password'), password: core.getInput('password'),
logout: core.getInput('logout') ecr: core.getInput('ecr'),
logout: core.getBooleanInput('logout')
}; };
} }

View file

@ -1,9 +1,9 @@
import * as core from '@actions/core';
import * as aws from './aws'; import * as aws from './aws';
import * as execm from './exec'; import * as core from '@actions/core';
import * as exec from '@actions/exec';
export async function login(registry: string, username: string, password: string): Promise<void> { export async function login(registry: string, username: string, password: string, ecr: string): Promise<void> {
if (await aws.isECR(registry)) { if (/true/i.test(ecr) || (ecr == 'auto' && aws.isECR(registry))) {
await loginECR(registry, username, password); await loginECR(registry, username, password);
} else { } else {
await loginStandard(registry, username, password); await loginStandard(registry, username, password);
@ -11,11 +11,15 @@ export async function login(registry: string, username: string, password: string
} }
export async function logout(registry: string): Promise<void> { export async function logout(registry: string): Promise<void> {
await execm.exec('docker', ['logout', registry], false).then(res => { await exec
if (res.stderr != '' && !res.success) { .getExecOutput('docker', ['logout', registry], {
core.warning(res.stderr); ignoreReturnCode: true
} })
}); .then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
core.warning(res.stderr.trim());
}
});
} }
export async function loginStandard(registry: string, username: string, password: string): Promise<void> { export async function loginStandard(registry: string, username: string, password: string): Promise<void> {
@ -23,45 +27,45 @@ export async function loginStandard(registry: string, username: string, password
throw new Error('Username and password required'); throw new Error('Username and password required');
} }
let loginArgs: Array<string> = ['login', '--password-stdin']; const loginArgs: Array<string> = ['login', '--password-stdin'];
loginArgs.push('--username', username); loginArgs.push('--username', username);
loginArgs.push(registry); loginArgs.push(registry);
if (registry) { if (registry) {
core.info(`🔑 Logging into ${registry}...`); core.info(`Logging into ${registry}...`);
} else { } else {
core.info(`🔑 Logging into Docker Hub...`); core.info(`Logging into Docker Hub...`);
} }
await execm.exec('docker', loginArgs, true, password).then(res => { await exec
if (res.stderr != '' && !res.success) { .getExecOutput('docker', loginArgs, {
throw new Error(res.stderr); ignoreReturnCode: true,
} silent: true,
core.info('🎉 Login Succeeded!'); input: Buffer.from(password)
}); })
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
core.info(`Login Succeeded!`);
});
} }
export async function loginECR(registry: string, username: string, password: string): Promise<void> { export async function loginECR(registry: string, username: string, password: string): Promise<void> {
const cliPath = await aws.getCLI(); core.info(`Retrieving registries data through AWS SDK...`);
const cliVersion = await aws.getCLIVersion(); const regDatas = await aws.getRegistriesData(registry, username, password);
const region = await aws.getRegion(registry); for (const regData of regDatas) {
core.info(`Logging into ${regData.registry}...`);
if (await aws.isPubECR(registry)) { await exec
core.info(`💡 AWS Public ECR detected with ${region} region`); .getExecOutput('docker', ['login', '--password-stdin', '--username', regData.username, regData.registry], {
} else { ignoreReturnCode: true,
core.info(`💡 AWS ECR detected with ${region} region`); silent: true,
input: Buffer.from(regData.password)
})
.then(res => {
if (res.stderr.length > 0 && res.exitCode != 0) {
throw new Error(res.stderr.trim());
}
core.info('Login Succeeded!');
});
} }
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;
core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`);
const loginCmd = await aws.getDockerLoginCmd(cliVersion, registry, region);
core.info(`🔑 Logging into ${registry}...`);
execm.exec(loginCmd, [], true).then(res => {
if (res.stderr != '' && !res.success) {
throw new Error(res.stderr);
}
core.info('🎉 Login Succeeded!');
});
} }

View file

@ -1,40 +0,0 @@
import * as actionsExec from '@actions/exec';
import {ExecOptions} from '@actions/exec';
export interface ExecResult {
success: boolean;
stdout: string;
stderr: string;
}
export const exec = async (
command: string,
args: string[] = [],
silent: boolean,
stdin?: string
): Promise<ExecResult> => {
let stdout: string = '';
let stderr: string = '';
const options: ExecOptions = {
silent: silent,
ignoreReturnCode: true,
input: Buffer.from(stdin || '')
};
options.listeners = {
stdout: (data: Buffer) => {
stdout += data.toString();
},
stderr: (data: Buffer) => {
stderr += data.toString();
}
};
const returnCode: number = await actionsExec.exec(command, args, options);
return {
success: returnCode === 0,
stdout: stdout.trim(),
stderr: stderr.trim()
};
};

View file

@ -1,19 +1,14 @@
import * as os from 'os';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {getInputs, Inputs} from './context'; import * as context from './context';
import * as docker from './docker'; import * as docker from './docker';
import * as stateHelper from './state-helper'; import * as stateHelper from './state-helper';
export async function run(): Promise<void> { export async function run(): Promise<void> {
try { try {
if (os.platform() !== 'linux') { const input: context.Inputs = context.getInputs();
throw new Error('Only supported on linux platform'); stateHelper.setRegistry(input.registry);
} stateHelper.setLogout(input.logout);
await docker.login(input.registry, input.username, input.password, input.ecr);
const {registry, username, password, logout} = getInputs();
stateHelper.setRegistry(registry);
stateHelper.setLogout(logout);
await docker.login(registry, username, password);
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }

View file

@ -8,7 +8,7 @@ export function setRegistry(registry: string) {
core.saveState('registry', registry); core.saveState('registry', registry);
} }
export function setLogout(logout: string) { export function setLogout(logout: boolean) {
core.saveState('logout', logout); core.saveState('logout', logout);
} }

View file

@ -2,17 +2,18 @@
"compilerOptions": { "compilerOptions": {
"target": "es6", "target": "es6",
"module": "commonjs", "module": "commonjs",
"lib": [
"es6",
"dom"
],
"newLine": "lf", "newLine": "lf",
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true, "strict": true,
"noImplicitAny": false, "noImplicitAny": false,
"esModuleInterop": true, "useUnknownInCatchVariables": false,
"sourceMap": true
}, },
"exclude": ["node_modules", "**/*.test.ts"] "exclude": [
"node_modules",
"**/*.test.ts",
"jest.config.ts"
]
} }

4955
yarn.lock

File diff suppressed because it is too large Load diff