Compare commits

..

No commits in common. "master" and "v1.4.1" have entirely different histories.

45 changed files with 7336 additions and 17689 deletions

View File

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

View File

@ -1,3 +0,0 @@
/dist/**
/coverage/**
/node_modules/**

View File

@ -1,24 +0,0 @@
{
"env": {
"node": true,
"es6": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/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"
]
}

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* @crazy-max

View File

@ -1,3 +0,0 @@
# Code of conduct
- [Moby community guidelines](https://github.com/moby/moby/blob/master/CONTRIBUTING.md#moby-community-guidelines)

View File

@ -2,24 +2,20 @@
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://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license) 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).
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`
3. Create a new branch: `git checkout -b my-branch-name` 4. Create a new branch: `git checkout -b my-branch-name`
4. Make your changes 5. Make your change
5. Make sure the tests pass: `docker buildx bake test` 6. Run pre-checkin: `yarn run pre-checkin`
6. Format code and build javascript artifacts: `docker buildx bake pre-checkin` 7. Push to your fork and [submit a pull request](https://github.com/docker/login-action/compare)
7. Validate all code has correctly formatted and built: `docker buildx bake validate` 8. Pat your self on the back and wait for your pull request to be reviewed and merged.
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**.
@ -28,5 +24,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://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
- [GitHub Help](https://docs.github.com/en) - [GitHub Help](https://help.github.com)

View File

@ -1,101 +0,0 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
name: Bug Report
description: Report a bug
labels:
- status/triage
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to report a bug!
If this is a security issue please report it to the [Docker Security team](mailto:security@docker.com).
- type: checkboxes
attributes:
label: Contributing guidelines
description: >
Make sure you've read the contributing guidelines before proceeding.
options:
- label: I've read the [contributing guidelines](https://github.com/docker/login-action/blob/master/.github/CONTRIBUTING.md) and wholeheartedly agree
required: true
- type: checkboxes
attributes:
label: "I've found a bug, and:"
description: |
Make sure that your request fulfills all of the following requirements.
If one requirement cannot be satisfied, explain in detail why.
options:
- label: The documentation does not mention anything about my problem
- label: There are no open or closed issues that are related to my problem
- type: textarea
attributes:
label: Description
description: >
Provide a brief description of the bug in 1-2 sentences.
validations:
required: true
- type: textarea
attributes:
label: Expected behaviour
description: >
Describe precisely what you'd expect to happen.
validations:
required: true
- type: textarea
attributes:
label: Actual behaviour
description: >
Describe precisely what is actually happening.
validations:
required: true
- type: input
attributes:
label: Repository URL
description: >
Enter the URL of the repository where you are experiencing the
issue. If your repository is private, provide a link to a minimal
repository that reproduces the issue.
- type: input
attributes:
label: Workflow run URL
description: >
Enter the URL of the GitHub Action workflow run if public (e.g.
`https://github.com/<user>/<repo>/actions/runs/<id>`)
- type: textarea
attributes:
label: YAML workflow
description: |
Provide the YAML of the workflow that's causing the issue.
Make sure to remove any sensitive information.
render: yaml
validations:
required: true
- type: textarea
attributes:
label: Workflow logs
description: >
[Attach](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files)
the [log file of your workflow run](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs)
and make sure to remove any sensitive information.
- type: textarea
attributes:
label: BuildKit logs
description: >
If applicable, provide the [BuildKit container logs](https://docs.docker.com/build/ci/github-actions/configure-builder/#buildkit-container-logs)
render: text
- type: textarea
attributes:
label: Additional info
description: |
Provide any additional information that could be useful.

33
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,33 @@
---
name: Bug report
about: Create a report to help us improve
---
### Behaviour
#### Steps to reproduce this issue
1.
2.
3.
#### Expected behaviour
> Tell us what should happen
#### Actual behaviour
> Tell us what happens instead
### Configuration
* Repository URL (if public):
* Build URL (if public):
```yml
# paste your YAML workflow file here and remove sensitive data
```
### 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.

View File

@ -1,9 +0,0 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: true
contact_links:
- name: Questions and Discussions
url: https://github.com/docker/login-action/discussions/new
about: Use Github Discussions to ask questions and/or open discussion topics.
- name: Documentation
url: https://docs.docker.com/build/ci/github-actions/
about: Read the documentation.

View File

@ -1,15 +0,0 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
name: Feature request
description: Missing functionality? Come tell us about it!
labels:
- kind/enhancement
- status/triage
body:
- type: textarea
id: description
attributes:
label: Description
description: What is the feature you want to see?
validations:
required: true

12
.github/SECURITY.md vendored
View File

@ -1,12 +0,0 @@
# Reporting security issues
The project maintainers take security seriously. If you discover a security
issue, please bring it to their attention right away!
**Please _DO NOT_ file a public issue**, instead send your report privately to
[security@docker.com](mailto:security@docker.com).
Security reports are greatly appreciated, and we will publicly thank you for it.
We also like to send gifts&mdash;if you'd like Docker swag, make sure to let
us know. We currently do not offer a paid security bounty program, but are not
ruling it out in the future.

29
.github/SUPPORT.md vendored Normal file
View File

@ -0,0 +1,29 @@
# Support [![](https://isitmaintained.com/badge/resolution/docker/login-action.svg)](https://isitmaintained.com/project/docker/login-action)
## Reporting an issue
Please do a search in [open issues](https://github.com/docker/login-action/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed.
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment.
:+1: - upvote
:-1: - downvote
If you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.
## Writing good bug reports and feature requests
File a single issue per problem and feature request.
* Do not enumerate multiple bugs or feature requests in the same issue.
* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.
The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.
You are now ready to [create a new issue](https://github.com/docker/login-action/issues/new/choose)!
## Closure policy
* Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines.
* Issues that go a week without a response from original poster are subject to closure at our discretion.

View File

@ -4,23 +4,19 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
time: "06:00"
timezone: "Europe/Paris"
labels: labels:
- "dependencies" - ":game_die: dependencies"
- "bot" - ":robot: bot"
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
versioning-strategy: "increase" time: "06:00"
groups: timezone: "Europe/Paris"
aws-sdk-dependencies:
patterns:
- "*aws-sdk*"
proxy-agent-dependencies:
patterns:
- "*-proxy-agent"
allow: allow:
- dependency-type: "production" - dependency-type: "production"
labels: labels:
- "dependencies" - ":game_die: dependencies"
- "bot" - ":robot: bot"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

77
.github/labels.yml vendored Normal file
View File

@ -0,0 +1,77 @@
## 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

@ -1,288 +1,119 @@
name: ci name: ci
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
workflow_dispatch:
schedule:
- cron: '0 10 * * *'
push: push:
branches: branches:
- 'master' - master
- 'releases/v*' - releases/v*
jobs: jobs:
stop-docker: # dockerhub:
runs-on: ubuntu-latest # runs-on: ${{ matrix.os }}
steps: # strategy:
- # fail-fast: false
name: Checkout # matrix:
uses: actions/checkout@v4 # os:
- # - ubuntu-20.04
name: Stop docker # - ubuntu-18.04
run: | # - ubuntu-16.04
sudo systemctl stop docker # logout:
- # - true
name: Login to GitHub Container Registry # - false
uses: ./ # steps:
with: # -
registry: ghcr.io # name: Checkout
username: ${{ github.actor }} # uses: actions/checkout@v2.3.2
password: ${{ secrets.GITHUB_TOKEN }} # -
# 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
logout: gpr:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
logout: logout:
- false
- true - true
- false
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2.3.2
- -
name: Login to GitHub Container Registry name: Login to GitHub Package Registry
uses: ./ uses: ./
with: with:
registry: ghcr.io registry: docker.pkg.github.com
username: ${{ github.actor }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
logout: ${{ matrix.logout }} logout: ${{ matrix.logout }}
dind:
runs-on: ubuntu-latest
env:
DOCKER_CONFIG: $HOME/.docker
steps:
- -
name: Checkout name: Clear
uses: actions/checkout@v4 if: always()
-
name: Login to GitHub Container Registry
uses: ./
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_PAT }}
-
name: DinD
uses: docker://docker
with:
entrypoint: docker
args: pull ghcr.io/docker-ghactiontest/test
-
name: Pull private image
run: | run: |
docker image prune -a -f >/dev/null 2>&1 rm -f ${HOME}/.docker/config.json
docker pull ghcr.io/docker-ghactiontest/test
acr: # gitlab:
runs-on: ubuntu-latest # runs-on: ubuntu-latest
steps: # strategy:
- # fail-fast: false
name: Checkout # matrix:
uses: actions/checkout@v4 # logout:
- # - true
name: Login to ACR # - false
uses: ./ # steps:
with: # -
registry: ${{ secrets.AZURE_REGISTRY_NAME }}.azurecr.io # name: Checkout
username: ${{ secrets.AZURE_CLIENT_ID }} # uses: actions/checkout@v2.3.2
password: ${{ secrets.AZURE_CLIENT_SECRET }} # -
# name: Login to GitLab
dockerhub: # uses: ./
runs-on: ${{ matrix.os }} # with:
strategy: # registry: registry.gitlab.com
fail-fast: false # username: ${{ secrets.GITLAB_USERNAME_TEST }}
matrix: # password: ${{ secrets.GITLAB_PASSWORD_TEST }}
os: # logout: ${{ matrix.logout }}
- ubuntu-latest # -
- windows-latest # name: Clear
steps: # if: always()
- # run: |
name: Checkout # rm -f ${HOME}/.docker/config.json
uses: actions/checkout@v4 #
- # ecr:
name: Login to Docker Hub # runs-on: ${{ matrix.os }}
uses: ./ # strategy:
with: # fail-fast: false
username: ${{ secrets.DOCKERHUB_USERNAME }} # matrix:
password: ${{ secrets.DOCKERHUB_TOKEN }} # os:
# - ubuntu-20.04
ecr: # - ubuntu-18.04
runs-on: ${{ matrix.os }} # - ubuntu-16.04
strategy: # logout:
fail-fast: false # - true
matrix: # - false
os: # steps:
- ubuntu-latest # -
- windows-latest # name: Checkout
steps: # uses: actions/checkout@v2.3.1
- # -
name: Checkout # name: Login to ECR
uses: actions/checkout@v4 # uses: ./
- # with:
name: Login to ECR # registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
uses: ./ # username: ${{ secrets.AWS_ACCESS_KEY_ID }}
with: # password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.us-east-1.amazonaws.com # logout: ${{ matrix.logout }}
username: ${{ secrets.AWS_ACCESS_KEY_ID }} # -
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # name: Clear
# if: always()
ecr-aws-creds: # run: |
runs-on: ${{ matrix.os }} # rm -f ${HOME}/.docker/config.json
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
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@v4
-
name: Login to Public ECR
continue-on-error: ${{ matrix.os == 'windows-latest' }}
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@v4
-
name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
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 Public ECR
continue-on-error: ${{ matrix.os == 'windows-latest' }}
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@v4
-
name: Login to GitHub Container Registry
uses: ./
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
gitlab:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Login to GitLab
uses: ./
with:
registry: registry.gitlab.com
username: ${{ secrets.GITLAB_USERNAME }}
password: ${{ secrets.GITLAB_TOKEN }}
google-artifact:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Login to Google Artifact Registry
uses: ./
with:
registry: ${{ secrets.GAR_LOCATION }}-docker.pkg.dev
username: _json_key
password: ${{ secrets.GAR_JSON_KEY }}
google-container:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Login to Google Container Registry
uses: ./
with:
registry: gcr.io
username: _json_key
password: ${{ secrets.GCR_JSON_KEY }}

View File

@ -1,50 +0,0 @@
name: codeql
on:
push:
branches:
- 'master'
- 'releases/v*'
paths:
- '.github/workflows/codeql.yml'
- 'dist/**'
- 'src/**'
pull_request:
paths:
- '.github/workflows/codeql.yml'
- 'dist/**'
- 'src/**'
permissions:
actions: read
contents: read
security-events: write
jobs:
analyze:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language:
- javascript-typescript
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config: |
paths:
- src
-
name: Autobuild
uses: github/codeql-action/autobuild@v3
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

20
.github/workflows/labels.yml vendored Normal file
View File

@ -0,0 +1,20 @@
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.3.2
-
name: Run Labeler
uses: crazy-max/ghaction-github-labeler@v3.0.0

View File

@ -1,31 +1,40 @@
name: test name: test
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
push: push:
branches: branches:
- 'master' - master
- 'releases/v*' - releases/v*
paths-ignore:
- '**.md'
pull_request: pull_request:
paths-ignore:
- '**.md'
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
- ubuntu-18.04
- ubuntu-16.04
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2.3.2
-
name: Install
run: yarn install
- -
name: Test name: Test
uses: docker/bake-action@v4 run: yarn run test
with:
targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v1.0.13
if: success()
with: with:
file: ./coverage/clover.xml
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml

View File

@ -1,45 +0,0 @@
name: validate
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- 'master'
- 'releases/v*'
pull_request:
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
targets: ${{ steps.targets.outputs.matrix }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Targets matrix
id: targets
run: |
echo "matrix=$(docker buildx bake validate --print | jq -cr '.group.validate.targets')" >> $GITHUB_OUTPUT
validate:
runs-on: ubuntu-latest
needs:
- prepare
strategy:
fail-fast: false
matrix:
target: ${{ fromJson(needs.prepare.outputs.targets) }}
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Validate
uses: docker/bake-action@v4
with:
targets: ${{ matrix.target }}

5
.gitignore vendored
View File

@ -1,6 +1,11 @@
/.dev
node_modules/ node_modules/
lib lib
# Jetbrains
/.idea
/*.iml
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore # Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs # Logs
logs logs

View File

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

399
README.md
View File

@ -1,46 +1,48 @@
[![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/actions/workflow/status/docker/login-action/ci.yml?branch=master&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/test?label=ci&logo=github&style=flat-square)](https://github.com/docker/login-action/actions?workflow=ci)
[![Test workflow](https://img.shields.io/github/actions/workflow/status/docker/login-action/test.yml?branch=master&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)
## About ## About
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) * [DockerHub](#dockerhub)
* [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)
* [Google Container Registry (GCR)](#google-container-registry-gcr) * [Google Container Registry (GCR)](#google-container-registry-gcr)
* [Google Artifact Registry (GAR)](#google-artifact-registry-gar)
* [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)
* [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
### DockerHub ### DockerHub
When authenticating to [Docker Hub](https://hub.docker.com) with GitHub Actions, To authenticate against [DockerHub](https://hub.docker.com) it's strongly recommended to create a
use a [personal access token](https://docs.docker.com/docker-hub/access-tokens/). [personal access token](https://docs.docker.com/docker-hub/access-tokens/) as an alternative to your password.
Don't use your account password.
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: main branches: master
jobs: jobs:
login: login:
@ -48,24 +50,52 @@ jobs:
steps: steps:
- -
name: Login to DockerHub name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
``` ```
### GitHub Container Registry ### GitHub Packages Docker Registry
To authenticate to the [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry), > :warning: GitHub Packages Docker Registry (aka `docker.pkg.github.com`) **is deprecated** and will sunset early next
use the [`GITHUB_TOKEN`](https://docs.github.com/en/actions/reference/authentication-in-a-workflow) > 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)
secret. > 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 ```yaml
name: ci name: ci
on: on:
push: push:
branches: main 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
To authenticate against the [GitHub Container Registry](https://docs.github.com/en/packages/getting-started-with-github-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)
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).
```yaml
name: ci
on:
push:
branches: master
jobs: jobs:
login: login:
@ -73,19 +103,13 @@ jobs:
steps: steps:
- -
name: Login to GitHub Container Registry name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v1
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.CR_PAT }}
``` ```
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
@ -93,7 +117,7 @@ name: ci
on: on:
push: push:
branches: main branches: master
jobs: jobs:
login: login:
@ -101,30 +125,25 @@ jobs:
steps: steps:
- -
name: Login to GitLab name: Login to GitLab
uses: docker/login-action@v3 uses: docker/login-action@v1
with: with:
registry: registry.gitlab.com registry: registry.gitlab.com
username: ${{ secrets.GITLAB_USERNAME }} username: ${{ secrets.GITLAB_USERNAME }}
password: ${{ secrets.GITLAB_PASSWORD }} password: ${{ secrets.GITLAB_PASSWORD }}
``` ```
If you have [Two-Factor Authentication](https://gitlab.com/help/user/profile/account/two_factor_authentication)
enabled, use a [Personal Access Token](https://gitlab.com/help/user/profile/personal_access_tokens)
instead of a password.
### Azure Container Registry (ACR) ### Azure Container Registry (ACR)
[Create a service principal](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-service-principal#create-a-service-principal) [Create a service principal](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-auth-service-principal#create-a-service-principal)
with access to your container registry through the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) with access to your container registry through the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)
and take note of the generated service principal's ID (also called _client ID_) and take note of the generated service principal's ID (also called _client ID_) and password (also called _client secret_).
and password (also called _client secret_).
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: main branches: master
jobs: jobs:
login: login:
@ -132,7 +151,7 @@ jobs:
steps: steps:
- -
name: Login to ACR name: Login to ACR
uses: docker/login-action@v3 uses: docker/login-action@v1
with: with:
registry: <registry-name>.azurecr.io registry: <registry-name>.azurecr.io
username: ${{ secrets.AZURE_CLIENT_ID }} username: ${{ secrets.AZURE_CLIENT_ID }}
@ -143,70 +162,17 @@ jobs:
### Google Container Registry (GCR) ### Google Container Registry (GCR)
> [Google Artifact Registry](#google-artifact-registry-gar) is the evolution of Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control).
> Google Container Registry. As a fully-managed service with support for both Then create and download the JSON key for this service account and save content of `.json` file
> container images and non-container artifacts. If you currently use Google [as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository)
> Container Registry, use the information [on this page](https://cloud.google.com/artifact-registry/docs/transition/transition-from-gcr) called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`.
> to learn about transitioning to Google Artifact Registry.
You can authenticate with workload identity federation or a service account.
#### Workload identity federation
Configure the workload identity federation for GitHub Actions in Google Cloud,
[see here](https://github.com/google-github-actions/auth#setting-up-workload-identity-federation).
Your service account must have permission to push to GCR. Use the
`google-github-actions/auth` action to authenticate using workload identity as
shown in the following example:
```yaml ```yaml
name: ci name: ci
on: on:
push: push:
branches: main branches: master
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v1
with:
token_format: access_token
workload_identity_provider: <workload_identity_provider>
service_account: <service_account>
-
name: Login to GCR
uses: docker/login-action@v3
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, [see 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 permission to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control).
Download the key for the service account as a JSON file. Save the contents of
the 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)
named `GCR_JSON_KEY` in your GitHub repository. 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:
@ -214,96 +180,17 @@ jobs:
steps: steps:
- -
name: Login to GCR name: Login to GCR
uses: docker/login-action@v3 uses: docker/login-action@v1
with: with:
registry: gcr.io registry: gcr.io
username: _json_key username: _json_key
password: ${{ secrets.GCR_JSON_KEY }} password: ${{ secrets.GCR_JSON_KEY }}
``` ```
### Google Artifact Registry (GAR)
You can authenticate with workload identity federation or a service account.
#### Workload identity federation
Download the key for the service account as a JSON file. Save the contents of
the 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)
named `GCR_JSON_KEY` in your GitHub repository. 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:
login:
runs-on: ubuntu-latest
steps:
-
name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v1
with:
token_format: access_token
workload_identity_provider: <workload_identity_provider>
service_account: <service_account>
-
name: Login to GAR
uses: docker/login-action@v3
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 permission to push to GAR and [configure access control](https://cloud.google.com/artifact-registry/docs/access-control).
Download the key for the service account as a JSON file. Save the contents of
the 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)
named `GCR_JSON_KEY` in your GitHub repository. 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:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to GAR
uses: docker/login-action@v3
with:
registry: <location>-docker.pkg.dev
username: _json_key
password: ${{ secrets.GAR_JSON_KEY }}
```
> 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.
### AWS Elastic Container Registry (ECR) ### AWS Elastic Container Registry (ECR)
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). Use an IAM user with the [ability to push to ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html).
Download the access keys and save them as `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.
```yaml ```yaml
@ -311,7 +198,7 @@ name: ci
on: on:
push: push:
branches: main branches: master
jobs: jobs:
login: login:
@ -319,170 +206,26 @@ jobs:
steps: steps:
- -
name: Login to ECR name: Login to ECR
uses: docker/login-action@v3 uses: docker/login-action@v1
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@v3
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 combination with this action:
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: <region>
-
name: Login to ECR
uses: docker/login-action@v3
with:
registry: <aws-account-number>.dkr.ecr.<region>.amazonaws.com
```
> Replace `<aws-account-number>` and `<region>` with their respective values. > Replace `<aws-account-number>` and `<region>` with their respective values.
### AWS Public Elastic Container Registry (ECR)
Use an IAM user with permission to push to ECR Public, for example using [managed policies](https://docs.aws.amazon.com/AmazonECR/latest/userguide/security-iam-awsmanpol.html#security-iam-awsmanpol-AmazonEC2ContainerRegistryPowerUser).
Download the access keys and save them as `AWS_ACCESS_KEY_ID` and
`AWS_SECRET_ACCESS_KEY` [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 repository.
```yaml
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to Public ECR
uses: docker/login-action@v3
with:
registry: public.ecr.aws
username: ${{ secrets.AWS_ACCESS_KEY_ID }}
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
env:
AWS_REGION: <region>
```
> Replace `<region>` with its respective value (default `us-east-1`).
### 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)
must be placed in format `<tenancy>/<username>` (in case of federated tenancy use the format
`<tenancy-namespace>/oracleidentitycloudservice/<username>`).
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
name: ci
on:
push:
branches: main
jobs:
login:
runs-on: ubuntu-latest
steps:
-
name: Login to OCIR
uses: docker/login-action@v3
with:
registry: <region>.ocir.io
username: ${{ secrets.OCI_USERNAME }}
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)
### Quay.io
Use a [Robot account](https://docs.quay.io/glossary/robot-accounts.html) with
permission to push to a 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@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_ROBOT_TOKEN }}
```
## Customizing ## Customizing
### inputs ### inputs
The following inputs can be used as `step.with` keys: Following inputs can be used as `step.with` keys
| Name | Type | Default | Description | | Name | Type | Default | Description |
|------------|--------|---------|-------------------------------------------------------------------------------| |------------------|---------|-----------------------------|------------------------------------|
| `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 for authenticating to the Docker registry | | `username` | String | | Username used to log against the Docker registry |
| `password` | String | | Password or personal access token for authenticating 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
@ -500,3 +243,7 @@ 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,157 +1,54 @@
import {beforeEach, describe, expect, jest, test} from '@jest/globals'; import * as semver from 'semver';
import {AuthorizationData} from '@aws-sdk/client-ecr';
import * as aws from '../src/aws'; import * as aws from '../src/aws';
describe('isECR', () => { describe('isECR', () => {
test.each([ test.each([
['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]
])('given registry %p', async (registry, expected) => { ])('given registry %p', async (registry, expected) => {
expect(aws.isECR(registry)).toEqual(expected); expect(await aws.isECR(registry)).toEqual(expected);
}); });
}); });
describe('isPubECR', () => { 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([ test.each([
['registry.gitlab.com', false], ['v1', 'aws-cli/1.18.120 Python/2.7.17 Linux/5.3.0-1034-azure botocore/1.17.43', '1.18.120'],
['gcr.io', false], ['v2', 'aws-cli/2.0.41 Python/3.7.3 Linux/4.19.104-microsoft-standard exe/x86_64.ubuntu.18', '2.0.41']
['012345678901.dkr.ecr.eu-west-3.amazonaws.com', false], ])('given aws %p', async (version, stdout, expected) => {
['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', false], expect(await aws.parseCLIVersion(stdout)).toEqual(expected);
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', false],
['public.ecr.aws', true]
])('given registry %p', async (registry, expected) => {
expect(aws.isPubECR(registry)).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'], 'given registry %p',
['876820548815.dkr.ecr.cn-north-1.amazonaws.com.cn', 'cn-north-1'], async (registry, expected) => {
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 'cn-northwest-1'], expect(await aws.getRegion(registry)).toEqual(expected);
['public.ecr.aws', 'us-east-1']
])('given registry %p', async (registry, 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,12 +0,0 @@
import {expect, test} from '@jest/globals';
import {getInputs} from '../src/context';
test('with password and username getInputs does not throw error', async () => {
process.env['INPUT_USERNAME'] = 'dbowie';
process.env['INPUT_PASSWORD'] = 'groundcontrol';
process.env['INPUT_LOGOUT'] = 'true';
expect(() => {
getInputs();
}).not.toThrow();
});

View File

@ -1,51 +0,0 @@
import {expect, jest, test} from '@jest/globals';
import * as path from 'path';
import {loginStandard, logout} from '../src/docker';
import {Exec} from '@docker/actions-toolkit/lib/exec';
process.env['RUNNER_TEMP'] = path.join(__dirname, 'runner');
test('loginStandard calls exec', async () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const execSpy = jest.spyOn(Exec, 'getExecOutput').mockImplementation(async () => {
return {
exitCode: expect.any(Number),
stdout: expect.any(Function),
stderr: expect.any(Function)
};
});
const username = 'dbowie';
const password = 'groundcontrol';
const registry = 'https://ghcr.io';
await loginStandard(registry, username, password);
expect(execSpy).toHaveBeenCalledWith(`docker`, ['login', '--password-stdin', '--username', username, registry], {
input: Buffer.from(password),
silent: true,
ignoreReturnCode: true
});
});
test('logout calls exec', async () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const execSpy = jest.spyOn(Exec, 'getExecOutput').mockImplementation(async () => {
return {
exitCode: expect.any(Number),
stdout: expect.any(Function),
stderr: expect.any(Function)
};
});
const registry = 'https://ghcr.io';
await logout(registry);
expect(execSpy).toHaveBeenCalledWith(`docker`, ['logout', registry], {
ignoreReturnCode: true
});
});

View File

@ -15,17 +15,13 @@ inputs:
required: false required: false
password: password:
description: 'Password or personal access token used to log against the Docker registry' description: 'Password or personal access token used to log against the Docker registry'
required: false required: true
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: 'node20' using: 'node12'
main: 'dist/index.js' main: 'dist/index.js'
post: 'dist/index.js' post: 'dist/index.js'

View File

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

View File

@ -1,71 +0,0 @@
# syntax=docker/dockerfile:1
ARG NODE_VERSION=20
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 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 \
yarn run test --coverage --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage /

4234
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

1
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

12394
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load Diff

1
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -1,53 +0,0 @@
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"]
}

12
jest.config.js Normal file
View File

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

View File

@ -1,30 +0,0 @@
import fs from 'fs';
import os from 'os';
import path from 'path';
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-login-action-')).split(path.sep).join(path.posix.sep);
process.env = Object.assign({}, process.env, {
TEMP: tmpDir,
GITHUB_REPOSITORY: 'docker/login-action',
RUNNER_TEMP: path.join(tmpDir, 'runner-temp').split(path.sep).join(path.posix.sep),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache').split(path.sep).join(path.posix.sep)
}) as {
[key: string]: string;
};
module.exports = {
clearMocks: true,
testEnvironment: 'node',
moduleFileExtensions: ['js', 'ts'],
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
moduleNameMapper: {
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
},
collectCoverageFrom: ['src/**/{!(main.ts),}.ts'],
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__tests__/'],
verbose: true
};

View File

@ -3,15 +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": "ncc build src/main.ts --source-map --minify --license licenses.txt", "build": "tsc && ncc build",
"lint": "yarn run prettier && yarn run eslint", "format": "prettier --write **/*.ts",
"format": "yarn run prettier:fix && yarn run eslint:fix", "format-check": "prettier --check **/*.ts",
"eslint": "eslint --max-warnings=0 .", "test": "jest --coverage",
"eslint:fix": "eslint --fix .", "pre-checkin": "yarn run format && yarn run build"
"prettier": "prettier --check \"./**/*.ts\"",
"prettier:fix": "prettier --write \"./**/*.ts\"",
"test": "jest",
"all": "yarn run build && yarn run format && yarn test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -22,29 +18,31 @@
"docker", "docker",
"login" "login"
], ],
"author": "Docker Inc.", "author": "Docker",
"license": "Apache-2.0", "contributors": [
{
"name": "CrazyMax",
"url": "https://crazymax.dev"
}
],
"license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.1", "@actions/core": "^1.2.6",
"@aws-sdk/client-ecr": "^3.529.1", "@actions/exec": "^1.0.4",
"@aws-sdk/client-ecr-public": "^3.529.1", "@actions/io": "^1.0.2",
"@docker/actions-toolkit": "^0.18.0", "semver": "^7.3.2"
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.4"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.5.9", "@types/jest": "^26.0.3",
"@typescript-eslint/eslint-plugin": "^6.6.0", "@types/node": "^14.0.14",
"@typescript-eslint/parser": "^6.6.0", "@vercel/ncc": "^0.23.0",
"@vercel/ncc": "^0.38.0", "dotenv": "^8.2.0",
"eslint": "^8.48.0", "jest": "^26.1.0",
"eslint-config-prettier": "^9.0.0", "jest-circus": "^26.1.0",
"eslint-plugin-jest": "^27.2.3", "jest-runtime": "^26.1.0",
"eslint-plugin-prettier": "^5.0.0", "prettier": "^2.0.5",
"jest": "^29.6.4", "ts-jest": "^26.1.1",
"prettier": "^3.0.3", "typescript": "^3.9.5",
"ts-jest": "^29.1.1", "typescript-formatter": "^7.2.2"
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
} }
} }

View File

@ -1,137 +1,51 @@
import * as core from '@actions/core'; import * as semver from 'semver';
import {ECR} from '@aws-sdk/client-ecr'; import * as io from '@actions/io';
import {ECRPUBLIC} from '@aws-sdk/client-ecr-public'; import * as execm from './exec';
import {NodeHttpHandler} from '@smithy/node-http-handler';
import {HttpProxyAgent} from 'http-proxy-agent';
import {HttpsProxyAgent} from 'https-proxy-agent';
const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/; export const isECR = async (registry: string): Promise<boolean> => {
return registry.includes('amazonaws');
export const isECR = (registry: string): boolean => {
return ecrRegistryRegex.test(registry) || isPubECR(registry);
}; };
export const isPubECR = (registry: string): boolean => { export const getRegion = async (registry: string): Promise<string> => {
return registry === 'public.ecr.aws'; return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws'));
}; };
export const getRegion = (registry: string): string => { export const getCLI = async (): Promise<string> => {
if (isPubECR(registry)) { return io.which('aws', true);
return process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';
}
const matches = registry.match(ecrRegistryRegex);
if (!matches) {
return '';
}
return matches[3];
}; };
export const getAccountIDs = (registry: string): string[] => { export const execCLI = async (args: string[]): Promise<string> => {
if (isPubECR(registry)) { return execm.exec(await getCLI(), args, true).then(res => {
return []; if (res.stderr != '' && !res.success) {
} throw new Error(res.stderr);
const matches = registry.match(ecrRegistryRegex); } else if (res.stderr != '') {
if (!matches) { return res.stderr.trim();
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);
core.setSecret(creds[0]); // redacted in workflow logs
core.setSecret(creds[1]); // redacted in workflow logs
return [
{
registry: 'public.ecr.aws',
username: creds[0],
password: creds[1]
}
];
} else { } else {
core.info(`AWS ECR detected with ${region} region`); return res.stdout.trim();
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);
core.setSecret(creds[0]); // redacted in workflow logs
core.setSecret(creds[1]); // redacted in workflow logs
regDatas.push({
registry: authData.proxyEndpoint || '',
username: creds[0],
password: creds[1]
}); });
};
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) {
throw new Error(`Cannot parse AWS CLI version`);
} }
return regDatas; return semver.clean(matches[1]);
};
export const getDockerLoginCmd = async (cliVersion: string, registry: string, region: string): Promise<string> => {
if (semver.satisfies(cliVersion, '>=2.0.0')) {
return execCLI(['ecr', 'get-login-password', '--region', region]).then(pwd => {
return `docker login --username AWS --password ${pwd} ${registry}`;
});
} else {
return execCLI(['ecr', 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => {
return dockerLoginCmd;
});
} }
}; };

View File

@ -4,16 +4,14 @@ export interface Inputs {
registry: string; registry: string;
username: string; username: string;
password: string; password: string;
ecr: string; logout: string;
logout: boolean;
} }
export function getInputs(): Inputs { export async function getInputs(): Promise<Inputs> {
return { return {
registry: core.getInput('registry'), registry: core.getInput('registry'),
username: core.getInput('username'), username: core.getInput('username'),
password: core.getInput('password'), password: core.getInput('password', {required: true}),
ecr: core.getInput('ecr'), logout: core.getInput('logout')
logout: core.getBooleanInput('logout')
}; };
} }

View File

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

40
src/exec.ts Normal file
View File

@ -0,0 +1,40 @@
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,21 +1,34 @@
import * as actionsToolkit from '@docker/actions-toolkit'; import * as os from 'os';
import * as core from '@actions/core';
import * as context from './context'; import {getInputs, Inputs} from './context';
import * as docker from './docker'; import * as docker from './docker';
import * as stateHelper from './state-helper'; import * as stateHelper from './state-helper';
export async function main(): Promise<void> { async function run(): Promise<void> {
const input: context.Inputs = context.getInputs(); try {
stateHelper.setRegistry(input.registry); if (os.platform() !== 'linux') {
stateHelper.setLogout(input.logout); core.setFailed('Only supported on linux platform');
await docker.login(input.registry, input.username, input.password, input.ecr); return;
} }
async function post(): Promise<void> { let inputs: Inputs = await getInputs();
stateHelper.setRegistry(inputs.registry);
stateHelper.setLogout(inputs.logout);
await docker.login(inputs.registry, inputs.username, inputs.password);
} catch (error) {
core.setFailed(error.message);
}
}
async function logout(): Promise<void> {
if (!stateHelper.logout) { if (!stateHelper.logout) {
return; return;
} }
await docker.logout(stateHelper.registry); await docker.logout(stateHelper.registry);
} }
actionsToolkit.run(main, post); if (!stateHelper.IsPost) {
run();
} else {
logout();
}

View File

@ -1,5 +1,6 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
export const IsPost = !!process.env['STATE_isPost'];
export const registry = process.env['STATE_registry'] || ''; export const registry = process.env['STATE_registry'] || '';
export const logout = /true/i.test(process.env['STATE_logout'] || ''); export const logout = /true/i.test(process.env['STATE_logout'] || '');
@ -7,6 +8,10 @@ export function setRegistry(registry: string) {
core.saveState('registry', registry); core.saveState('registry', registry);
} }
export function setLogout(logout: boolean) { export function setLogout(logout: string) {
core.saveState('logout', logout); core.saveState('logout', logout);
} }
if (!IsPost) {
core.saveState('isPost', 'true');
}

View File

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

6302
yarn.lock

File diff suppressed because it is too large Load Diff