mirror of
https://github.com/docker/build-push-action.git
synced 2024-12-25 08:12:17 -05:00
commit
e01a38bb45
32 changed files with 22626 additions and 292 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/dist/** linguist-generated=true
|
||||||
|
/lib/** linguist-generated=true
|
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* @crazy-max
|
29
.github/CONTRIBUTING.md
vendored
Normal file
29
.github/CONTRIBUTING.md
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Submitting a pull request
|
||||||
|
|
||||||
|
1. [Fork](https://github.com/docker/build-push-action/fork) and clone the repository
|
||||||
|
2. Configure and install the dependencies: `yarn install`
|
||||||
|
3. Make sure the tests pass on your machine: `yarn run test`
|
||||||
|
4. Create a new branch: `git checkout -b my-branch-name`
|
||||||
|
5. Make your change, add tests, and make sure the tests still pass
|
||||||
|
6. Run pre-checkin: `yarn run pre-checkin`
|
||||||
|
7. Push to your fork and [submit a pull request](https://github.com/docker/build-push-action/compare)
|
||||||
|
8. 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:
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
- 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**.
|
||||||
|
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||||
|
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
||||||
|
- [GitHub Help](https://help.github.com)
|
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal 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.
|
31
.github/SUPPORT.md
vendored
Normal file
31
.github/SUPPORT.md
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Support [![](https://isitmaintained.com/badge/resolution/docker/build-push-action.svg)](https://isitmaintained.com/project/docker/build-push-action)
|
||||||
|
|
||||||
|
First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md).
|
||||||
|
|
||||||
|
## Reporting an issue
|
||||||
|
|
||||||
|
Please do a search in [open issues](https://github.com/docker/build-push-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/build-push-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.
|
BIN
.github/build-push-action.png
vendored
Normal file
BIN
.github/build-push-action.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
allow:
|
||||||
|
- dependency-type: "production"
|
241
.github/workflows/ci.yml
vendored
Normal file
241
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- v2-working-branch # remove when merged to master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- v2-working-branch # remove when merged to master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
git-context:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
buildx-version:
|
||||||
|
- latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Run local registry
|
||||||
|
run: |
|
||||||
|
docker run -d -p 5000:5000 registry:2
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2.3.1
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
with:
|
||||||
|
version: ${{ matrix.buildx-version }}
|
||||||
|
driver-opts: network=host
|
||||||
|
buildkitd-flags: --allow-insecure-entitlement security.insecure
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
file: ./test/Dockerfile
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
allow: network.host,security.insecure
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
localhost:5000/name/app:latest
|
||||||
|
localhost:5000/name/app:1.0.0
|
||||||
|
secrets: |
|
||||||
|
GIT_AUTH_TOKEN=${{ github.token }}
|
||||||
|
-
|
||||||
|
name: Inspect
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
|
-
|
||||||
|
name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
|
||||||
|
path-context:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
buildx-version:
|
||||||
|
- ""
|
||||||
|
- latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Run local registry
|
||||||
|
run: |
|
||||||
|
docker run -d -p 5000:5000 registry:2
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2.3.1
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
with:
|
||||||
|
version: ${{ matrix.buildx-version }}
|
||||||
|
driver-opts: network=host
|
||||||
|
buildkitd-flags: --allow-insecure-entitlement security.insecure
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
context: ./test
|
||||||
|
file: ./test/Dockerfile
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
allow: network.host,security.insecure
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
localhost:5000/name/app:latest
|
||||||
|
localhost:5000/name/app:1.0.0
|
||||||
|
-
|
||||||
|
name: Inspect
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
|
-
|
||||||
|
name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
|
||||||
|
multi:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
buildx-version:
|
||||||
|
- ""
|
||||||
|
- latest
|
||||||
|
dockerfile:
|
||||||
|
- multi
|
||||||
|
- multi-sudo
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Run local registry
|
||||||
|
run: |
|
||||||
|
docker run -d -p 5000:5000 registry:2
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2.3.1
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
with:
|
||||||
|
version: ${{ matrix.buildx-version }}
|
||||||
|
driver-opts: network=host
|
||||||
|
buildkitd-flags: --allow-insecure-entitlement security.insecure
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
context: ./test
|
||||||
|
file: ./test/Dockerfile-${{ matrix.dockerfile }}
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
allow: network.host,security.insecure
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
localhost:5000/name/app:latest
|
||||||
|
localhost:5000/name/app:1.0.0
|
||||||
|
-
|
||||||
|
name: Inspect
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
|
-
|
||||||
|
name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
|
||||||
|
github-cache:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Run local registry
|
||||||
|
run: |
|
||||||
|
docker run -d -p 5000:5000 registry:2
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2.3.1
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
with:
|
||||||
|
driver-opts: network=host
|
||||||
|
buildkitd-flags: --allow-insecure-entitlement security.insecure
|
||||||
|
-
|
||||||
|
name: Cache Docker layers
|
||||||
|
uses: actions/cache@v2
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache
|
||||||
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
context: ./test
|
||||||
|
file: ./test/Dockerfile-multi-golang
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
allow: network.host,security.insecure
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
localhost:5000/name/app:latest
|
||||||
|
localhost:5000/name/app:1.0.0
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
|
-
|
||||||
|
name: Inspect
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
|
-
|
||||||
|
name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
-
|
||||||
|
name: Cache hit
|
||||||
|
run: echo ${{ steps.cache.outputs.cache-hit }}
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
37
.github/workflows/main.yml
vendored
37
.github/workflows/main.yml
vendored
|
@ -1,37 +0,0 @@
|
||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 3
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Run local registry
|
|
||||||
run: docker run -d -p 5000:5000 registry:2
|
|
||||||
|
|
||||||
- name: Build and push image
|
|
||||||
uses: ./
|
|
||||||
env:
|
|
||||||
DOCKER_BUILDKIT: 1
|
|
||||||
with:
|
|
||||||
registry: localhost:5000
|
|
||||||
repository: temp/workflow
|
|
||||||
tags: foo
|
|
||||||
|
|
||||||
- name: Remove local image
|
|
||||||
run: docker image rm localhost:5000/temp/workflow:foo
|
|
||||||
|
|
||||||
- name: Run image from registry
|
|
||||||
run: docker run localhost:5000/temp/workflow:foo
|
|
32
.github/workflows/test.yml
vendored
Normal file
32
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
name: test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- v2-working-branch # remove when merged to master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- v2-working-branch # remove when merged to master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2.3.1
|
||||||
|
-
|
||||||
|
name: Install
|
||||||
|
run: yarn install
|
||||||
|
-
|
||||||
|
name: Test
|
||||||
|
run: yarn run test
|
||||||
|
# -
|
||||||
|
# name: Upload coverage
|
||||||
|
# uses: codecov/codecov-action@v1.0.7
|
||||||
|
# if: success()
|
||||||
|
# with:
|
||||||
|
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
# file: ./coverage/clover.xml
|
95
.gitignore
vendored
Normal file
95
.gitignore
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
node_modules
|
||||||
|
lib
|
||||||
|
|
||||||
|
# Jetbrains
|
||||||
|
/.idea
|
||||||
|
/*.iml
|
||||||
|
|
||||||
|
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
11
.prettierrc.json
Normal file
11
.prettierrc.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"printWidth": 120,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": false,
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"parser": "typescript"
|
||||||
|
}
|
52
CHANGELOG.md
Normal file
52
CHANGELOG.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2.0.0 (2020/??/??)
|
||||||
|
|
||||||
|
v2 of Build Push action uses Docker [Buildx](https://github.com/docker/buildx). It's also rewritten as
|
||||||
|
a [typescript-action](https://github.com/actions/typescript-action/) to be as closed as possible of
|
||||||
|
the [GitHub Runner](https://github.com/actions/virtual-environments) during its execution (#71 #92).
|
||||||
|
|
||||||
|
* Rename `path` input to `context`
|
||||||
|
* Rename `dockerfile` input to `file`
|
||||||
|
* Rename `always_pull` input to `pull`
|
||||||
|
* Add `builder` input to be able to choose a builder instance through our [setup-buildx action](https://github.com/docker/setup-buildx-action)
|
||||||
|
* Add [`platforms`](https://github.com/docker/buildx#---platformvaluevalue) input
|
||||||
|
* Add [`allow`](https://github.com/docker/buildx#--allowentitlement) input
|
||||||
|
* Add [`load`](https://github.com/docker/buildx#--load) input
|
||||||
|
* Add [`outputs`](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) input
|
||||||
|
* Add [`cache-from`](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) input
|
||||||
|
* Add [`cache-to`](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) input
|
||||||
|
* Add `secrets` input
|
||||||
|
* Review `tags` input
|
||||||
|
* Remove `repository`, `username`, `password`, `registry`, `cache_froms` inputs
|
||||||
|
* Remove `tag_with_sha`, `tag_with_ref`, `add_git_labels` inputs
|
||||||
|
* Handle Git context
|
||||||
|
* Add `digest` output
|
||||||
|
* Login support moved to [docker/login-action](https://github.com/docker/login-action) repo
|
||||||
|
* Enhanced examples in README
|
||||||
|
* Tests and/or CI workflows
|
||||||
|
|
||||||
|
## 1.1.0 (2020/04/23)
|
||||||
|
|
||||||
|
* Add cache-from support fixing #7
|
||||||
|
* Add GCR example
|
||||||
|
|
||||||
|
## 1.0.1 (2020/03/23)
|
||||||
|
|
||||||
|
* Clarify dockerfile and path inputs
|
||||||
|
* Rename LICENCE to LICENSE
|
||||||
|
* Use v1 of docker/gihub-actions image
|
||||||
|
* Logs in before building image
|
||||||
|
|
||||||
|
## 1.0.0 (2020/03/18)
|
||||||
|
|
||||||
|
* Build and push Docker images to Docker Hub or your own private registry.
|
||||||
|
* Log in to Hub or private registry.
|
||||||
|
* Static tags and labels.
|
||||||
|
* Auto tagging by git ref.
|
||||||
|
* Auto tagging by git SHA.
|
||||||
|
* Auto labelling with opencontainers standards.
|
||||||
|
* Build arguments.
|
||||||
|
* Multi-stage build targets.
|
||||||
|
|
||||||
|
Backed by Docker image [docker/github-action:v1.0](https://hub.docker.com/repository/docker/docker/github-actions/)
|
|
@ -1,3 +0,0 @@
|
||||||
FROM alpine:3
|
|
||||||
|
|
||||||
ENTRYPOINT ["echo", "docker github actions"]
|
|
563
README.md
563
README.md
|
@ -1,243 +1,418 @@
|
||||||
# build-push-action
|
[![GitHub release](https://img.shields.io/github/release/docker/build-push-action.svg?style=flat-square)](https://github.com/docker/build-push-action/releases/latest)
|
||||||
|
[![GitHub marketplace](https://img.shields.io/badge/marketplace-docker--build--push-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/docker-build-push)
|
||||||
|
[![CI workflow](https://img.shields.io/github/workflow/status/docker/build-push-action/ci?label=ci&logo=github&style=flat-square)](https://github.com/docker/build-push-action/actions?workflow=ci)
|
||||||
|
[![Test workflow](https://img.shields.io/github/workflow/status/docker/build-push-action/test?label=test&logo=github&style=flat-square)](https://github.com/docker/build-push-action/actions?workflow=test)
|
||||||
|
|
||||||
Builds and pushes Docker images and will log in to a Docker registry if required.
|
## About
|
||||||
|
|
||||||
Suggestions and issues can be posted on the repositories [issues page](https://github.com/docker/build-push-action/issues).
|
GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx).
|
||||||
|
|
||||||
[Inputs](#Inputs)
|
> :bulb: See also:
|
||||||
* [repository](#repository)
|
> * [login](https://github.com/docker/login-action) action
|
||||||
* [username](#username)
|
> * [setup-buildx](https://github.com/docker/setup-buildx-action) action
|
||||||
* [password](#password)
|
> * [setup-qemu](https://github.com/docker/setup-qemu-action) action
|
||||||
* [registry](#registry)
|
|
||||||
* [tags](#tags)
|
|
||||||
* [tag_with_ref](#tag_with_ref)
|
|
||||||
* [tag_with_sha](#tag_with_sha)
|
|
||||||
* [path](#path)
|
|
||||||
* [dockerfile](#dockerfile)
|
|
||||||
* [target](#target)
|
|
||||||
* [always_pull](#always_pull)
|
|
||||||
* [build_args](#build_args)
|
|
||||||
* [cache_froms](#cache_froms)
|
|
||||||
* [labels](#labels)
|
|
||||||
* [add_git_labels](#add_git_labels)
|
|
||||||
* [push](#push)
|
|
||||||
|
|
||||||
[Example usage](#Example-usage)
|
![Screenshot](.github/build-push-action.png)
|
||||||
|
|
||||||
## Inputs
|
___
|
||||||
|
|
||||||
### `repository`
|
* [Usage](#usage)
|
||||||
|
* [Git context](#git-context)
|
||||||
|
* [Path context](#path-context)
|
||||||
|
* [Isolated builders](#isolated-builders)
|
||||||
|
* [Multi-platform image](#multi-platform-image)
|
||||||
|
* [Leverage GitHub cache](#leverage-github-cache)
|
||||||
|
* [Complete workflow](#complete-workflow)
|
||||||
|
* [Customizing](#customizing)
|
||||||
|
* [inputs](#inputs)
|
||||||
|
* [outputs](#outputs)
|
||||||
|
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
|
||||||
|
* [Limitation](#limitation)
|
||||||
|
|
||||||
**Required** Docker repository to tag the image with.
|
## Usage
|
||||||
|
|
||||||
### `username`
|
This action uses our [setup-buildx](https://github.com/docker/setup-buildx-action) action that extends the
|
||||||
|
`docker build` command named [buildx](https://github.com/docker/buildx) with the full support of the features
|
||||||
|
provided by [Moby BuildKit](https://github.com/moby/buildkit) builder toolkit. This includes multi-arch build,
|
||||||
|
build-secrets, remote cache, etc. and different builder deployment/namespacing options.
|
||||||
|
|
||||||
Username used to log in to a Docker registry. If not set then no login will occur.
|
### Git context
|
||||||
|
|
||||||
### `password`
|
The default behavior of this action is to use the Git context invoked by your workflow (`https://github.com/owner/repo#ref`).
|
||||||
|
|
||||||
Password or personal access token used to log in to a Docker registry. If not set then no login will occur.
|
|
||||||
|
|
||||||
### `registry`
|
|
||||||
|
|
||||||
Server address of Docker registry. If not set then will default to Docker Hub.
|
|
||||||
|
|
||||||
### `tags`
|
|
||||||
|
|
||||||
Comma-delimited list of tags. These will be added to the registry/repository to form the image's tags.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
tags: tag1,tag2
|
name: ci
|
||||||
```
|
|
||||||
|
|
||||||
### `tag_with_ref`
|
on:
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
|
||||||
Boolean value. Defaults to `false`.
|
jobs:
|
||||||
|
main:
|
||||||
Automatically tags the built image with the git reference. The format of the tag depends on the type of git reference with all forward slashes replaced with `-`.
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
For pushes to a branch the reference will be `refs/heads/{branch-name}` and the tag will be `{branch-name}`. If `{branch-name}` is master then the tag will be `latest`.
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
For pull requests the reference will be `refs/pull/{pull-request}` and the tag will be `pr-{pull-request}`.
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
For git tags the reference will be `refs/tags/{git-tag}` and the tag will be `{git-tag}`.
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
Examples:
|
uses: docker/login-action@v1
|
||||||
|
|
||||||
|Git Reference|Image tag|
|
|
||||||
|---|---|
|
|
||||||
|`refs/heads/master`|`latest`|
|
|
||||||
|`refs/heads/mybranch`|`mybranch`|
|
|
||||||
|`refs/heads/my/branch`|`my-branch`|
|
|
||||||
|`refs/pull/2/merge`|`pr-2-merge`|
|
|
||||||
|`refs/tags/v1.0.0`|`v1.0.0`|
|
|
||||||
|
|
||||||
### `tag_with_sha`
|
|
||||||
|
|
||||||
Boolean value. Defaults to `false`.
|
|
||||||
|
|
||||||
Automatically tags the built image with the git short SHA prefixed with `sha-`.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|Git SHA|Image tag|
|
|
||||||
|---|---|
|
|
||||||
|`676cae2f85471aeff6776463c72881ebd902dcf9`|`sha-676cae2`|
|
|
||||||
|
|
||||||
### `path`
|
|
||||||
|
|
||||||
Path to the build context. Defaults to `.`
|
|
||||||
|
|
||||||
### `dockerfile`
|
|
||||||
|
|
||||||
Path to the Dockerfile. Defaults to `{path}/Dockerfile`
|
|
||||||
|
|
||||||
Note when set this path is **not** relative to the `path` input but is instead relative to the current working directory.
|
|
||||||
|
|
||||||
### `target`
|
|
||||||
|
|
||||||
Sets the target stage to build.
|
|
||||||
|
|
||||||
### `always_pull`
|
|
||||||
|
|
||||||
Boolean value. Defaults to `false`.
|
|
||||||
|
|
||||||
Always attempt to pull a newer version of the image.
|
|
||||||
|
|
||||||
### `build_args`
|
|
||||||
|
|
||||||
Comma-delimited list of build-time variables.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
build_args: arg1=value1,arg2=value2
|
|
||||||
```
|
|
||||||
|
|
||||||
### `cache_froms`
|
|
||||||
|
|
||||||
Comma-delimited list of images to consider as cache sources.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```yaml
|
|
||||||
cache_froms: myorg/baseimage:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### `labels`
|
|
||||||
|
|
||||||
Comma-delimited list of labels to add to the built image.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
labels: label_name_1=label_value_1,label_name_2=label_value_2
|
|
||||||
```
|
|
||||||
|
|
||||||
### `add_git_labels`
|
|
||||||
|
|
||||||
Boolean value. Defaults to `false`.
|
|
||||||
|
|
||||||
Adds labels with git repository information to the built image based on the standards set out in https://github.com/opencontainers/image-spec/blob/master/annotations.md.
|
|
||||||
|
|
||||||
The labels are:
|
|
||||||
|
|
||||||
|Label key|Example value|Description|
|
|
||||||
|---|---|---|
|
|
||||||
|`org.opencontainers.image.created`|`2020-03-06T23:00:00Z`|Date and time on which the image was built (string, date-time as defined by RFC 3339).|
|
|
||||||
|`org.opencontainers.image.source`|`https://github.com/myorg/myrepository`|URL to the GitHub repository.|
|
|
||||||
|`org.opencontainers.image.revision`|`676cae2f85471aeff6776463c72881ebd902dcf9`|The full git SHA of this commit.|
|
|
||||||
|
|
||||||
|
|
||||||
### `push`
|
|
||||||
|
|
||||||
Boolean value. Defaults to `true`.
|
|
||||||
|
|
||||||
Whether to push the built image.
|
|
||||||
|
|
||||||
## Example usage
|
|
||||||
|
|
||||||
The following will build the root Dockerfile, tag the image as `myorg/myrepository:latest`, log in to Docker Hub using GitHub secrets, and push the image to the Docker Hub repository `myorg/myrepository`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Build and push Docker images
|
|
||||||
uses: docker/build-push-action@v1
|
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
repository: myorg/myrepository
|
-
|
||||||
tags: latest
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
-
|
||||||
|
name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
```
|
```
|
||||||
|
|
||||||
The following will build the root Dockerfile, tag the image with the git reference and SHA as described above, log in to Docker Hub using GitHub secrets, and push the image to the Docker Hub repository `myorg/myrepository`:
|
If you use this action in a private repository, you have to pass the [GitHub Token](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token)
|
||||||
|
as a secret named `GIT_AUTH_TOKEN` to be able to authenticate against it with buildx:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
-
|
||||||
- name: Checkout code
|
name: Build and push
|
||||||
uses: actions/checkout@v2
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
secrets: |
|
||||||
|
GIT_AUTH_TOKEN=${{ github.token }}
|
||||||
|
```
|
||||||
|
|
||||||
- name: Build and push Docker images
|
### Path context
|
||||||
uses: docker/build-push-action@v1
|
|
||||||
|
You can also use the `PATH` context alongside the [`actions/checkout`](https://github.com/actions/checkout/) action.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
path-context:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
repository: myorg/myrepository
|
-
|
||||||
tag_with_ref: true
|
name: Build and push
|
||||||
tag_with_sha: true
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/386
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
The following will only push the image when the event that kicked off the workflow was a push of a git tag:
|
### Isolated builders
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
name: ci
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Build and push Docker images
|
on:
|
||||||
uses: docker/build-push-action@v1
|
push:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
multi-builders:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
id: builder1
|
||||||
|
-
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
id: builder2
|
||||||
|
-
|
||||||
|
name: Builder 1 name
|
||||||
|
run: echo ${{ steps.builder1.outputs.name }}
|
||||||
|
-
|
||||||
|
name: Builder 2 name
|
||||||
|
run: echo ${{ steps.builder2.outputs.name }}
|
||||||
|
-
|
||||||
|
name: Build against builder1
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.builder1.outputs.name }}
|
||||||
|
target: mytarget1
|
||||||
|
-
|
||||||
|
name: Build against builder2
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.builder2.outputs.name }}
|
||||||
|
target: mytarget2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-platform image
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
multi:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
repository: myorg/myrepository
|
-
|
||||||
tag_with_ref: true
|
name: Build and push
|
||||||
push: ${{ startsWith(github.ref, 'refs/tags/') }}
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
user/app:latest
|
||||||
|
user/app:1.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
The following builds the `mytarget` stage and pushes that:
|
### Leverage GitHub cache
|
||||||
|
|
||||||
|
You can leverage [GitHub cache](https://docs.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows)
|
||||||
|
using [@actions/cache](https://github.com/actions/cache) with this action.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
name: ci
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Build and push Docker images
|
on:
|
||||||
uses: docker/build-push-action@v1
|
push:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
github-cache:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
-
|
||||||
|
name: Cache Docker layers
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache
|
||||||
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
repository: myorg/myrepository
|
-
|
||||||
tag_with_ref: true
|
name: Build and push
|
||||||
target: mytarget
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
|
-
|
||||||
|
name: Image digest
|
||||||
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
```
|
```
|
||||||
|
|
||||||
The following will build the root Dockerfile, tag the image as `myorg/myrepository:latest`, log in to Google Container Registry using GitHub secrets (where `DOCKER_PASSWORD` is a [JSON key](https://cloud.google.com/container-registry/docs/advanced-authentication#json-key)), and push the image to the GCR repository `myorg/myrepository`:
|
### Complete workflow
|
||||||
|
|
||||||
|
* On `pull_request` event, Docker image `name/app:edge` is **built**.
|
||||||
|
* On `push` event, Docker image `name/app:edge` is **built** and **pushed** to DockerHub.
|
||||||
|
* On `schedule` event, Docker image `name/app:nightly` is **built** and **pushed** to DockerHub.
|
||||||
|
* On `push tags` event, Docker image `name/app:<version>` and `name/app:latest` is **built** and **pushed** to DockerHub.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
name: ci
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Build and push Docker images
|
on:
|
||||||
uses: docker/build-push-action@v1
|
schedule:
|
||||||
|
- cron: '0 10 * * *' # everyday at 10am
|
||||||
|
push:
|
||||||
|
branches: master
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
pull_request:
|
||||||
|
branches: master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Prepare
|
||||||
|
id: prep
|
||||||
|
run: |
|
||||||
|
DOCKER_IMAGE=name/app
|
||||||
|
VERSION=edge
|
||||||
|
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/v}
|
||||||
|
fi
|
||||||
|
if [ "${{ github.event_name }}" = "schedule" ]; then
|
||||||
|
VERSION=nightly
|
||||||
|
fi
|
||||||
|
TAGS="${DOCKER_IMAGE}:${VERSION}"
|
||||||
|
if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||||
|
TAGS="$TAGS,${DOCKER_IMAGE}:latest"
|
||||||
|
fi
|
||||||
|
echo ::set-output name=tags::${TAGS}
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
with:
|
with:
|
||||||
username: _json_key
|
platforms: all
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@master
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
registry: gcr.io
|
-
|
||||||
repository: myorg/myrepository
|
name: Build and push
|
||||||
tags: latest
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/386
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.prep.outputs.tags }}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Customizing
|
||||||
|
|
||||||
|
### inputs
|
||||||
|
|
||||||
|
Following inputs can be used as `step.with` keys
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---------------------|---------|------------------------------------|
|
||||||
|
| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) |
|
||||||
|
| `context` | String | Build's context is the set of files located in the specified [`PATH` or `URL`](https://docs.docker.com/engine/reference/commandline/build/) (default [Git context](#git-context)) |
|
||||||
|
| `file` | String | Path to the Dockerfile (default `Dockerfile`) |
|
||||||
|
| `build-args` | List | List of build-time variables |
|
||||||
|
| `labels` | List | List of metadata for an image |
|
||||||
|
| `tags` | List | List of tags |
|
||||||
|
| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) |
|
||||||
|
| `target` | String | Sets the target stage to build |
|
||||||
|
| `allow` | List | List of [extra privileged entitlement](https://github.com/docker/buildx#--allowentitlement) (eg. `network.host,security.insecure`) |
|
||||||
|
| `no-cache` | Bool | Do not use cache when building the image (default `false`) |
|
||||||
|
| `platforms` | List | List of [target platforms](https://github.com/docker/buildx#---platformvaluevalue) for build |
|
||||||
|
| `load` | Bool | [Load](https://github.com/docker/buildx#--load) is a shorthand for `--output=type=docker` (default `false`) |
|
||||||
|
| `push` | Bool | [Push](https://github.com/docker/buildx#--push) is a shorthand for `--output=type=registry` (default `false`) |
|
||||||
|
| `outputs` | CSV | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) |
|
||||||
|
| `cache-from` | CSV | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) |
|
||||||
|
| `cache-to` | CSV | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) |
|
||||||
|
| `secrets` | CSV | List of secrets to expose to the build (eg. `key=value`, `GIT_AUTH_TOKEN=mytoken`) |
|
||||||
|
|
||||||
|
> `List` type can be a comma or newline-delimited string
|
||||||
|
> ```yaml
|
||||||
|
> tags: name/app:latest,name/app:1.0.0
|
||||||
|
> ```
|
||||||
|
> ```yaml
|
||||||
|
> tags: |
|
||||||
|
> name/app:latest
|
||||||
|
> name/app:1.0.0
|
||||||
|
> ```
|
||||||
|
|
||||||
|
> `CSV` type must be a newline-delimited string
|
||||||
|
> ```yaml
|
||||||
|
> cache-from: user/app:cache
|
||||||
|
> ```
|
||||||
|
> ```yaml
|
||||||
|
> cache-from: |
|
||||||
|
> user/app:cache
|
||||||
|
> type=local,src=path/to/dir
|
||||||
|
> ```
|
||||||
|
|
||||||
|
### outputs
|
||||||
|
|
||||||
|
Following outputs are available
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---------------|---------|---------------------------------------|
|
||||||
|
| `digest` | String | Image content-addressable identifier also called a digest |
|
||||||
|
|
||||||
|
## Keep up-to-date with GitHub Dependabot
|
||||||
|
|
||||||
|
Since [Dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-github-dependabot)
|
||||||
|
has [native GitHub Actions support](https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#package-ecosystem),
|
||||||
|
to enable it on your GitHub repo all you need to do is add the `.github/dependabot.yml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Maintain dependencies for GitHub Actions
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
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).
|
||||||
|
|
36
__tests__/buildx.test.ts
Normal file
36
__tests__/buildx.test.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as buildx from '../src/buildx';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
const digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||||
|
|
||||||
|
describe('getImageID', () => {
|
||||||
|
it('matches', async () => {
|
||||||
|
const imageIDFile = await buildx.getImageIDFile();
|
||||||
|
console.log(`imageIDFile: ${imageIDFile}`);
|
||||||
|
await fs.writeFileSync(imageIDFile, digest);
|
||||||
|
const imageID = await buildx.getImageID();
|
||||||
|
console.log(`imageID: ${imageID}`);
|
||||||
|
expect(imageID).toEqual(digest);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getVersion', () => {
|
||||||
|
it('valid', async () => {
|
||||||
|
await exec.exec('docker', ['buildx', 'version']);
|
||||||
|
const version = await buildx.getVersion();
|
||||||
|
console.log(`version: ${version}`);
|
||||||
|
expect(semver.valid(version)).not.toBeNull();
|
||||||
|
}, 100000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('parseVersion', () => {
|
||||||
|
test.each([
|
||||||
|
['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||||
|
['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||||
|
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2']
|
||||||
|
])('given %p', async (stdout, expected) => {
|
||||||
|
expect(await buildx.parseVersion(stdout)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
74
__tests__/context.test.ts
Normal file
74
__tests__/context.test.ts
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import * as context from '../src/context';
|
||||||
|
|
||||||
|
describe('getInputList', () => {
|
||||||
|
it('handles single line correctly', async () => {
|
||||||
|
await setInput('foo', 'bar');
|
||||||
|
const res = await context.getInputList('foo');
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['bar']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles multiple lines correctly', async () => {
|
||||||
|
setInput('foo', 'bar\nbaz');
|
||||||
|
const res = await context.getInputList('foo');
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles comma correctly', async () => {
|
||||||
|
setInput('foo', 'bar,baz');
|
||||||
|
const res = await context.getInputList('foo');
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles different new lines correctly', async () => {
|
||||||
|
setInput('foo', 'bar\r\nbaz');
|
||||||
|
const res = await context.getInputList('foo');
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles different new lines and comma correctly', async () => {
|
||||||
|
setInput('foo', 'bar\r\nbaz,bat');
|
||||||
|
const res = await context.getInputList('foo');
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['bar', 'baz', 'bat']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles multiple lines and ignoring comma correctly', async () => {
|
||||||
|
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
||||||
|
const res = await context.getInputList('cache-from', true);
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles different new lines and ignoring comma correctly', async () => {
|
||||||
|
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
||||||
|
const res = await context.getInputList('cache-from', true);
|
||||||
|
console.log(res);
|
||||||
|
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('asyncForEach', () => {
|
||||||
|
it('executes async tasks sequentially', async () => {
|
||||||
|
const testValues = [1, 2, 3, 4, 5];
|
||||||
|
const results: number[] = [];
|
||||||
|
|
||||||
|
await context.asyncForEach(testValues, async value => {
|
||||||
|
results.push(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(results).toEqual(testValues);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
|
||||||
|
function getInputName(name: string): string {
|
||||||
|
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInput(name: string, value: string): void {
|
||||||
|
process.env[getInputName(name)] = value;
|
||||||
|
}
|
115
action.yml
115
action.yml
|
@ -1,66 +1,75 @@
|
||||||
name: Build and push Docker images
|
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
|
||||||
description: Builds and pushes Docker images and will log in to a Docker registry if required
|
name: Docker Build Push
|
||||||
author: Docker
|
description: Build and push Docker images with Buildx
|
||||||
|
author: docker
|
||||||
branding:
|
branding:
|
||||||
icon: 'anchor'
|
icon: 'anchor'
|
||||||
color: 'blue'
|
color: 'blue'
|
||||||
runs:
|
|
||||||
using: docker
|
|
||||||
image: docker://docker/github-actions:v1
|
|
||||||
args:
|
|
||||||
- build-push
|
|
||||||
inputs:
|
inputs:
|
||||||
username:
|
builder:
|
||||||
description: Username used to log in to a Docker registry. If not set then no login will occur
|
description: "Builder instance"
|
||||||
required: false
|
required: false
|
||||||
password:
|
context:
|
||||||
description: Password or personal access token used to log in to a Docker registry. If not set then no login will occur
|
description: "Build's context is the set of files located in the specified PATH or URL"
|
||||||
required: false
|
required: false
|
||||||
registry:
|
default: '.'
|
||||||
description: Server address of Docker registry. If not set then will default to Docker Hub
|
file:
|
||||||
|
description: "Path to the Dockerfile"
|
||||||
required: false
|
required: false
|
||||||
repository:
|
default: './Dockerfile'
|
||||||
description: Docker repository to tag the image with
|
build-args:
|
||||||
required: true
|
description: "List of build-time variables"
|
||||||
tags:
|
|
||||||
description: Comma-delimited list of tags. These will be added to the registry/repository to form the image's tags
|
|
||||||
required: false
|
|
||||||
tag_with_ref:
|
|
||||||
description: Automatically tags the built image with the git reference as per the readme
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
tag_with_sha:
|
|
||||||
description: Automatically tags the built image with the git short SHA as per the readme
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
path:
|
|
||||||
description: Path to the build context
|
|
||||||
required: false
|
|
||||||
default: "."
|
|
||||||
dockerfile:
|
|
||||||
description: Path to the Dockerfile (Default is '{path}/Dockerfile')
|
|
||||||
required: false
|
|
||||||
target:
|
|
||||||
description: Sets the target stage to build
|
|
||||||
required: false
|
|
||||||
always_pull:
|
|
||||||
description: Always attempt to pull a newer version of the image
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
build_args:
|
|
||||||
description: Comma-delimited list of build-time variables
|
|
||||||
required: false
|
|
||||||
cache_froms:
|
|
||||||
description: Comma-delimited list of images to consider as cache sources
|
|
||||||
required: false
|
required: false
|
||||||
labels:
|
labels:
|
||||||
description: Comma-delimited list of labels to add to the built image
|
description: "List of metadata for an image"
|
||||||
required: false
|
required: false
|
||||||
add_git_labels:
|
tags:
|
||||||
description: Adds labels with git repository information to the built image
|
description: "List of tags"
|
||||||
required: false
|
required: false
|
||||||
default: false
|
pull:
|
||||||
|
description: "Always attempt to pull a newer version of the image"
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
target:
|
||||||
|
description: "Sets the target stage to build"
|
||||||
|
required: false
|
||||||
|
allow:
|
||||||
|
description: "List of extra privileged entitlement (eg. network.host,security.insecure)"
|
||||||
|
required: false
|
||||||
|
no-cache:
|
||||||
|
description: "Do not use cache when building the image"
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
platforms:
|
||||||
|
description: "List of target platforms for build"
|
||||||
|
required: false
|
||||||
|
load:
|
||||||
|
description: "Load is a shorthand for --output=type=docker"
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
push:
|
push:
|
||||||
description: Whether to push the image
|
description: "Push is a shorthand for --output=type=registry"
|
||||||
required: false
|
required: false
|
||||||
default: true
|
default: 'false'
|
||||||
|
outputs:
|
||||||
|
description: "List of output destinations (format: type=local,dest=path)"
|
||||||
|
required: false
|
||||||
|
cache-from:
|
||||||
|
description: "List of external cache sources for buildx (eg. user/app:cache, type=local,src=path/to/dir)"
|
||||||
|
required: false
|
||||||
|
cache-to:
|
||||||
|
description: "List of cache export destinations for buildx (eg. user/app:cache, type=local,dest=path/to/dir)"
|
||||||
|
required: false
|
||||||
|
secrets:
|
||||||
|
description: "List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)"
|
||||||
|
required: false
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
digest:
|
||||||
|
description: 'Image content-addressable identifier also called a digest'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
main: 'dist/index.js'
|
||||||
|
post: 'dist/index.js'
|
||||||
|
|
17195
dist/index.js
generated
vendored
Normal file
17195
dist/index.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
12
jest.config.js
Normal file
12
jest.config.js
Normal 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
|
||||||
|
}
|
51
package.json
Normal file
51
package.json
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "docker-build-push",
|
||||||
|
"description": "Build and push Docker images",
|
||||||
|
"main": "lib/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc && ncc build",
|
||||||
|
"format": "prettier --write **/*.ts",
|
||||||
|
"format-check": "prettier --check **/*.ts",
|
||||||
|
"test": "jest --coverage",
|
||||||
|
"pre-checkin": "yarn run format && yarn run build"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/docker/build-push-action.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"actions",
|
||||||
|
"docker",
|
||||||
|
"build",
|
||||||
|
"push"
|
||||||
|
],
|
||||||
|
"author": "Docker",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "CrazyMax",
|
||||||
|
"url": "https://crazymax.dev"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.2.4",
|
||||||
|
"@actions/exec": "^1.0.4",
|
||||||
|
"@actions/github": "^4.0.0",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"tmp": "^0.2.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^26.0.3",
|
||||||
|
"@types/node": "^14.0.14",
|
||||||
|
"@types/tmp": "^0.2.0",
|
||||||
|
"@vercel/ncc": "^0.23.0",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"jest": "^26.1.0",
|
||||||
|
"jest-circus": "^26.1.0",
|
||||||
|
"jest-runtime": "^26.1.0",
|
||||||
|
"prettier": "^2.0.5",
|
||||||
|
"ts-jest": "^26.1.1",
|
||||||
|
"typescript": "^3.9.5",
|
||||||
|
"typescript-formatter": "^7.2.2"
|
||||||
|
}
|
||||||
|
}
|
53
src/buildx.ts
Normal file
53
src/buildx.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import tmp from 'tmp';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as context from './context';
|
||||||
|
import * as exec from './exec';
|
||||||
|
|
||||||
|
export async function getImageIDFile(): Promise<string> {
|
||||||
|
return path.join(context.tmpDir, 'iidfile');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getImageID(): Promise<string | undefined> {
|
||||||
|
const iidFile = await getImageIDFile();
|
||||||
|
if (!fs.existsSync(iidFile)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSecret(kvp: string): Promise<string> {
|
||||||
|
const [key, value] = kvp.split('=');
|
||||||
|
const secretFile = tmp.tmpNameSync({
|
||||||
|
tmpdir: context.tmpDir
|
||||||
|
});
|
||||||
|
await fs.writeFileSync(secretFile, value);
|
||||||
|
return `id=${key},src=${secretFile}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function isAvailable(): Promise<Boolean> {
|
||||||
|
return await exec.exec(`docker`, ['buildx'], true).then(res => {
|
||||||
|
if (res.stderr != '' && !res.success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return res.success;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVersion(): Promise<string> {
|
||||||
|
return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => {
|
||||||
|
if (res.stderr != '' && !res.success) {
|
||||||
|
throw new Error(res.stderr);
|
||||||
|
}
|
||||||
|
return parseVersion(res.stdout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function parseVersion(stdout: string): Promise<string> {
|
||||||
|
const matches = /\sv?([0-9.]+)/.exec(stdout);
|
||||||
|
if (!matches) {
|
||||||
|
throw new Error(`Cannot parse Buildx version`);
|
||||||
|
}
|
||||||
|
return semver.clean(matches[1]);
|
||||||
|
}
|
138
src/context.ts
Normal file
138
src/context.ts
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
import * as buildx from './buildx';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as github from '@actions/github';
|
||||||
|
|
||||||
|
export const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-build-push-'));
|
||||||
|
|
||||||
|
export interface Inputs {
|
||||||
|
context: string;
|
||||||
|
file: string;
|
||||||
|
buildArgs: string[];
|
||||||
|
labels: string[];
|
||||||
|
tags: string[];
|
||||||
|
pull: boolean;
|
||||||
|
target: string;
|
||||||
|
allow: string[];
|
||||||
|
noCache: boolean;
|
||||||
|
builder: string;
|
||||||
|
platforms: string[];
|
||||||
|
load: boolean;
|
||||||
|
push: boolean;
|
||||||
|
outputs: string[];
|
||||||
|
cacheFrom: string[];
|
||||||
|
cacheTo: string[];
|
||||||
|
secrets: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getInputs(): Promise<Inputs> {
|
||||||
|
return {
|
||||||
|
context:
|
||||||
|
core.getInput('context') ||
|
||||||
|
`https://github.com/${github.context.repo.owner}/${github.context.repo.repo}#${github.context.ref}`,
|
||||||
|
file: core.getInput('file') || 'Dockerfile',
|
||||||
|
buildArgs: await getInputList('build-args'),
|
||||||
|
labels: await getInputList('labels'),
|
||||||
|
tags: await getInputList('tags'),
|
||||||
|
pull: /true/i.test(core.getInput('pull')),
|
||||||
|
target: core.getInput('target'),
|
||||||
|
allow: await getInputList('allow'),
|
||||||
|
noCache: /true/i.test(core.getInput('no-cache')),
|
||||||
|
builder: core.getInput('builder'),
|
||||||
|
platforms: await getInputList('platforms'),
|
||||||
|
load: /true/i.test(core.getInput('load')),
|
||||||
|
push: /true/i.test(core.getInput('push')),
|
||||||
|
outputs: await getInputList('outputs', true),
|
||||||
|
cacheFrom: await getInputList('cache-from', true),
|
||||||
|
cacheTo: await getInputList('cache-to', true),
|
||||||
|
secrets: await getInputList('secrets', true)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||||
|
let args: Array<string> = ['buildx'];
|
||||||
|
args.push.apply(args, await getBuildArgs(inputs, buildxVersion));
|
||||||
|
args.push.apply(args, await getCommonArgs(inputs));
|
||||||
|
args.push(inputs.context);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBuildArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||||
|
let args: Array<string> = ['build'];
|
||||||
|
await asyncForEach(inputs.buildArgs, async buildArg => {
|
||||||
|
args.push('--build-arg', buildArg);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.labels, async label => {
|
||||||
|
args.push('--label', label);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.tags, async tag => {
|
||||||
|
args.push('--tag', tag);
|
||||||
|
});
|
||||||
|
if (inputs.target) {
|
||||||
|
args.push('--target', inputs.target);
|
||||||
|
}
|
||||||
|
if (inputs.allow.length > 0) {
|
||||||
|
args.push('--allow', inputs.allow.join(','));
|
||||||
|
}
|
||||||
|
if (inputs.platforms.length > 0) {
|
||||||
|
args.push('--platform', inputs.platforms.join(','));
|
||||||
|
}
|
||||||
|
if (inputs.platforms.length == 0 || semver.satisfies(buildxVersion, '>=0.4.2')) {
|
||||||
|
args.push('--iidfile', await buildx.getImageIDFile());
|
||||||
|
}
|
||||||
|
await asyncForEach(inputs.outputs, async output => {
|
||||||
|
args.push('--output', output);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.cacheFrom, async cacheFrom => {
|
||||||
|
args.push('--cache-from', cacheFrom);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.cacheTo, async cacheTo => {
|
||||||
|
args.push('--cache-to', cacheTo);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.secrets, async secret => {
|
||||||
|
args.push('--secret', await buildx.getSecret(secret));
|
||||||
|
});
|
||||||
|
if (inputs.file) {
|
||||||
|
args.push('--file', inputs.file);
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCommonArgs(inputs: Inputs): Promise<Array<string>> {
|
||||||
|
let args: Array<string> = [];
|
||||||
|
if (inputs.noCache) {
|
||||||
|
args.push('--no-cache');
|
||||||
|
}
|
||||||
|
if (inputs.builder) {
|
||||||
|
args.push('--builder', inputs.builder);
|
||||||
|
}
|
||||||
|
if (inputs.pull) {
|
||||||
|
args.push('--pull');
|
||||||
|
}
|
||||||
|
if (inputs.load) {
|
||||||
|
args.push('--load');
|
||||||
|
}
|
||||||
|
if (inputs.push) {
|
||||||
|
args.push('--push');
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
|
||||||
|
const items = core.getInput(name);
|
||||||
|
if (items == '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.reduce<string[]>((acc, line) => acc.concat(!ignoreComma ? line.split(',') : line).map(pat => pat.trim()), []);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const asyncForEach = async (array, callback) => {
|
||||||
|
for (let index = 0; index < array.length; index++) {
|
||||||
|
await callback(array[index], index, array);
|
||||||
|
}
|
||||||
|
};
|
34
src/exec.ts
Normal file
34
src/exec.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import * as aexec 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): Promise<ExecResult> => {
|
||||||
|
let stdout: string = '';
|
||||||
|
let stderr: string = '';
|
||||||
|
|
||||||
|
const options: ExecOptions = {
|
||||||
|
silent: silent,
|
||||||
|
ignoreReturnCode: true
|
||||||
|
};
|
||||||
|
options.listeners = {
|
||||||
|
stdout: (data: Buffer) => {
|
||||||
|
stdout += data.toString();
|
||||||
|
},
|
||||||
|
stderr: (data: Buffer) => {
|
||||||
|
stderr += data.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const returnCode: number = await aexec.exec(command, args, options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: returnCode === 0,
|
||||||
|
stdout: stdout.trim(),
|
||||||
|
stderr: stderr.trim()
|
||||||
|
};
|
||||||
|
};
|
53
src/main.ts
Normal file
53
src/main.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import * as buildx from './buildx';
|
||||||
|
import * as context from './context';
|
||||||
|
import * as stateHelper from './state-helper';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
|
if (os.platform() !== 'linux') {
|
||||||
|
core.setFailed('Only supported on linux platform');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await buildx.isAvailable())) {
|
||||||
|
core.setFailed(`Buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stateHelper.setTmpDir(context.tmpDir);
|
||||||
|
|
||||||
|
const buildxVersion = await buildx.getVersion();
|
||||||
|
core.info(`📣 Buildx version: ${buildxVersion}`);
|
||||||
|
|
||||||
|
let inputs: context.Inputs = await context.getInputs();
|
||||||
|
|
||||||
|
core.info(`🏃 Starting build...`);
|
||||||
|
const args: string[] = await context.getArgs(inputs, buildxVersion);
|
||||||
|
await exec.exec('docker', args);
|
||||||
|
|
||||||
|
const imageID = await buildx.getImageID();
|
||||||
|
if (imageID) {
|
||||||
|
core.info('🛒 Extracting digest...');
|
||||||
|
core.info(`${imageID}`);
|
||||||
|
core.setOutput('digest', imageID);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cleanup(): Promise<void> {
|
||||||
|
if (stateHelper.tmpDir.length > 0) {
|
||||||
|
core.info(`🚿 Removing temp folder ${stateHelper.tmpDir}`);
|
||||||
|
fs.rmdirSync(stateHelper.tmpDir, {recursive: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateHelper.IsPost) {
|
||||||
|
run();
|
||||||
|
} else {
|
||||||
|
cleanup();
|
||||||
|
}
|
12
src/state-helper.ts
Normal file
12
src/state-helper.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
|
export const IsPost = !!process.env['STATE_isPost'];
|
||||||
|
export const tmpDir = process.env['STATE_tmpDir'] || '';
|
||||||
|
|
||||||
|
export function setTmpDir(tmpDir: string) {
|
||||||
|
core.saveState('tmpDir', tmpDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsPost) {
|
||||||
|
core.saveState('isPost', 'true');
|
||||||
|
}
|
3
test/Dockerfile
Normal file
3
test/Dockerfile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
FROM alpine
|
||||||
|
|
||||||
|
RUN echo "Hello world!"
|
8
test/Dockerfile-multi
Normal file
8
test/Dockerfile-multi
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
ARG BUILDPLATFORM
|
||||||
|
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
COPY --from=build /log /log
|
30
test/Dockerfile-multi-golang
Normal file
30
test/Dockerfile-multi-golang
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
FROM --platform=${BUILDPLATFORM:-linux/amd64} tonistiigi/xx:golang AS xgo
|
||||||
|
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.13-alpine AS builder
|
||||||
|
|
||||||
|
ENV CGO_ENABLED 0
|
||||||
|
ENV GO111MODULE on
|
||||||
|
ENV GOPROXY https://goproxy.io
|
||||||
|
COPY --from=xgo / /
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
RUN go env
|
||||||
|
|
||||||
|
RUN apk --update --no-cache add \
|
||||||
|
build-base \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
&& rm -rf /tmp/* /var/cache/apk/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV DIUN_VERSION="v4.4.0"
|
||||||
|
|
||||||
|
RUN git clone --branch ${DIUN_VERSION} https://github.com/crazy-max/diun .
|
||||||
|
RUN go mod download
|
||||||
|
RUN go build -ldflags "-w -s -X 'main.version=test'" -v -o diun cmd/main.go
|
||||||
|
|
||||||
|
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:latest
|
||||||
|
|
||||||
|
COPY --from=builder /app/diun /usr/local/bin/diun
|
||||||
|
COPY --from=builder /usr/local/go/lib/time/zoneinfo.zip /usr/local/go/lib/time/zoneinfo.zip
|
||||||
|
RUN diun --version
|
22
test/Dockerfile-multi-sudo
Normal file
22
test/Dockerfile-multi-sudo
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
ARG BUILDPLATFORM
|
||||||
|
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
|
||||||
|
|
||||||
|
RUN apk --update --no-cache add \
|
||||||
|
shadow \
|
||||||
|
sudo \
|
||||||
|
&& addgroup -g 1200 buildx \
|
||||||
|
&& adduser -u 1200 -G buildx -s /sbin/nologin -D buildx \
|
||||||
|
&& echo 'buildx ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
|
||||||
|
&& rm -rf /tmp/* /var/cache/apk/*
|
||||||
|
|
||||||
|
USER buildx
|
||||||
|
RUN sudo chown buildx. /log
|
||||||
|
USER root
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
|
||||||
|
COPY --from=build /log /log
|
||||||
|
RUN ls -al /log
|
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": [
|
||||||
|
"es6",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"newLine": "lf",
|
||||||
|
"outDir": "./lib",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"**/*.test.ts"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue