mirror of
https://github.com/docker/build-push-action.git
synced 2025-06-14 07:07:12 +02:00
Compare commits
332 Commits
Author | SHA1 | Date | |
---|---|---|---|
1104d47137 | |||
838bf90c88 | |||
337a09d182 | |||
37abcedcc1 | |||
67109bc4b2 | |||
d1b0eb0a29 | |||
a0635fe7cd | |||
f834265449 | |||
0191543e0b | |||
2a16835223 | |||
9b96801525 | |||
6afac853c9 | |||
3bfdd83cd7 | |||
316d5eb8b3 | |||
1d910c8aa2 | |||
f9ccca010f | |||
c40bf0fdf6 | |||
223ed1ebd4 | |||
fdafae777b | |||
0cb700ffba | |||
ee7989df81 | |||
74f883a069 | |||
0149503e26 | |||
26ce4f3617 | |||
ed2672fc33 | |||
472ccddef1 | |||
d235d2d5ea | |||
2f519a7883 | |||
4eb68bb2ac | |||
b4755849f0 | |||
ade1a6afe3 | |||
21d6059e1e | |||
c2c50190db | |||
a154a68da0 | |||
4ac90f5dca | |||
175d02bffe | |||
546378e7fb | |||
ffe65bfc27 | |||
d4c14fd006 | |||
6e95f19fb8 | |||
2a752d5a63 | |||
c56af95754 | |||
75aaa63262 | |||
f97d6e2850 | |||
47c00d78bf | |||
871b930e7a | |||
105bf59b00 | |||
48888e0b13 | |||
6b820ad47e | |||
e1a10350ee | |||
0f5a7d48d5 | |||
6a6e8c7c14 | |||
e189a1cb78 | |||
2cf0d6fbdc | |||
3cde535b0c | |||
83a00fb5e6 | |||
1d5915004a | |||
2e87529dad | |||
e27bcee4eb | |||
71d260c49a | |||
965c6a410d | |||
08aa123a28 | |||
1527803881 | |||
a49d9ab751 | |||
cbb574ee73 | |||
8b56e74b48 | |||
a5024d816a | |||
2235b57edd | |||
15b9e74b95 | |||
48daa618bd | |||
c84f382811 | |||
cd5d0b79ea | |||
30a32246ba | |||
1f19633b92 | |||
67af6dc1d3 | |||
988cb093f2 | |||
1cb9d22b93 | |||
5ffbca1432 | |||
a8d76c070a | |||
12b1e419c2 | |||
2a60beff0d | |||
5268745b5f | |||
a2a27346c0 | |||
05d9e522ae | |||
42863b1282 | |||
c372f73edc | |||
d17cab8f42 | |||
4c2810ab91 | |||
307a009589 | |||
f2c26aa560 | |||
a806b8fe18 | |||
ae74c4950a | |||
80c878df65 | |||
a571ccfa72 | |||
283625c36b | |||
bb751c2095 | |||
8d9444d675 | |||
c5e6528d5d | |||
ceb414dc73 | |||
dda70725ed | |||
e551b19e49 | |||
3554377aa3 | |||
a62bc1b22b | |||
c2085839e1 | |||
fcd91249e5 | |||
0ebe720aed | |||
38b45804b5 | |||
ba317382dc | |||
43721d2346 | |||
5ea21bf2ba | |||
300b1bdff7 | |||
84580d7737 | |||
a460b5e683 | |||
9f1392c9bf | |||
9472e90210 | |||
5accc8e023 | |||
f7a2a67b4c | |||
b905f177bc | |||
0779722168 | |||
fd75456293 | |||
ada965aa7b | |||
b5730d2471 | |||
839389a46c | |||
34c1caa1ce | |||
6ff230f13e | |||
75c825aabc | |||
5f7b938b8c | |||
7ae34a20f3 | |||
acb76cdd52 | |||
2d081a4fd5 | |||
ac9327eae2 | |||
7c41daf2a5 | |||
e115266953 | |||
50fa0058d9 | |||
309fb9180f | |||
db68526220 | |||
fe02965b48 | |||
5af8693d82 | |||
7f9d37fa54 | |||
d7458455bb | |||
1ca185b339 | |||
eebf87aed1 | |||
d8b0ca6f0e | |||
da767377fb | |||
8c76bb76c2 | |||
b598b2a3bd | |||
eb2857f4ca | |||
f4cf574474 | |||
5c924147ba | |||
253376207c | |||
6f7a604875 | |||
604f033158 | |||
5645ea7274 | |||
1814d3dfb3 | |||
fc5a732e0c | |||
b1aeb1103e | |||
e31f93ab9f | |||
9ed5823618 | |||
4222161e3e | |||
67ff4df4b7 | |||
91274a04da | |||
ff329397c0 | |||
04841f2a72 | |||
049b7cab08 | |||
0a196c9deb | |||
94e0a28d6a | |||
5e11b373bf | |||
6f3b90dea1 | |||
f71a68fb09 | |||
82446970f9 | |||
2cf7b61533 | |||
0732bea0f8 | |||
96daefdf52 | |||
9f46d13e71 | |||
a8f79af565 | |||
04d5124fcb | |||
541dfa92f4 | |||
291bae5a41 | |||
91520dfd9f | |||
a41d90ba13 | |||
22baeb6cdf | |||
6061a365d8 | |||
9962be8aaf | |||
375f72aff6 | |||
8ba85ead00 | |||
c6dca826de | |||
0c3d31c275 | |||
5681933133 | |||
821890eae4 | |||
d0931a71a9 | |||
326ec1ede4 | |||
b0c26e5619 | |||
3139e8d280 | |||
a66e35b9cb | |||
6a98f97e24 | |||
26f24d6851 | |||
b0b7751850 | |||
c0b121fe44 | |||
09d66c261a | |||
24d162ecb4 | |||
6484a61448 | |||
c40e0ee07a | |||
e06a3af40d | |||
2e10e1984b | |||
1a60e0d706 | |||
3530a97c47 | |||
3c507bedc4 | |||
7c64fd5e10 | |||
c65ff7ffb1 | |||
2a8d638779 | |||
900c06250b | |||
b5e5b85e1b | |||
cf25934f0f | |||
37831a7a20 | |||
ad1d2e93be | |||
e80adc3299 | |||
7594ecce5b | |||
1bc1040cae | |||
fcaaa5e487 | |||
0987321e12 | |||
94827201d1 | |||
128f05c85a | |||
a15ef4dd9f | |||
c7dab97e55 | |||
a1d2218d38 | |||
0b56a3c3b3 | |||
ae29b67b96 | |||
b44cfd9087 | |||
a437a4518f | |||
a7071c9d9a | |||
9199c83f6e | |||
93a9859764 | |||
9cbc67d577 | |||
07bca60c0f | |||
cc01c17e75 | |||
90850ba046 | |||
915370c72f | |||
f87b75314d | |||
ecbc0634e4 | |||
06b9aae8bc | |||
779802e2ee | |||
dd8c19ed49 | |||
ad44023a93 | |||
57f367c048 | |||
74242a33cc | |||
2b2d125b68 | |||
5ac438e8df | |||
ae91a8353f | |||
ca26f5b713 | |||
c9589d1941 | |||
95f997534a | |||
655d1f6b37 | |||
6f4938aa75 | |||
18fa566857 | |||
11f0499b05 | |||
f3f2d78b13 | |||
5b3f377cdd | |||
cc23ce7e44 | |||
64708ddf75 | |||
8e208dd401 | |||
bb77c476bd | |||
8e1d874ee2 | |||
3a090ce0da | |||
17822e4df4 | |||
5e92e6623e | |||
3ce082ae8d | |||
d619a7ff00 | |||
19c07384dc | |||
4cef7b9d89 | |||
5676f00637 | |||
c0c3e27be3 | |||
c9b5cc4c4e | |||
6e53d9494f | |||
01f4a7369d | |||
91bb504133 | |||
c4742793d5 | |||
e1b7f96249 | |||
5a4a26c0fc | |||
8891861577 | |||
f6a733366a | |||
eb4f14646c | |||
646552f0a1 | |||
2ec8f1d346 | |||
8f5c91aad9 | |||
6a12baa867 | |||
da940a9403 | |||
9cf6eb2b16 | |||
3c2d8e5269 | |||
d693655c74 | |||
bfea497a8e | |||
8ca2ca55d4 | |||
460e0e47f5 | |||
edb2e175f1 | |||
09f8407c80 | |||
614833a85f | |||
0ec1157bb5 | |||
22d49d64f5 | |||
9379083e42 | |||
a63b18dea2 | |||
af867d4937 | |||
33eec1587d | |||
3db4797dd2 | |||
659fcba376 | |||
080cadd33e | |||
dc4c1fca8b | |||
b280b0485b | |||
b87564a5cc | |||
d2bc6a5d16 | |||
e5f26cdae4 | |||
616efcd405 | |||
0539e1a717 | |||
636b4540ec | |||
af932bfb2e | |||
2db03de115 | |||
4643aec7c4 | |||
4a531fa5a6 | |||
565d16e074 | |||
c473874c2c | |||
b94cedd686 | |||
76c8b42a58 | |||
920f0da143 | |||
e723b420bf | |||
f9deaa080c | |||
b4c22c3e33 | |||
a8587cb818 | |||
f2a733f179 | |||
35ab0dd217 | |||
46d5afd128 | |||
a8bb35be5a | |||
5c278cd8ab | |||
3b98ff3c03 | |||
6b88c3e647 |
@ -1 +1,2 @@
|
|||||||
node_modules
|
/coverage
|
||||||
|
/node_modules
|
||||||
|
23
.eslintrc.json
Normal file
23
.eslintrc.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es2021": true,
|
||||||
|
"jest/globals": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:jest/recommended",
|
||||||
|
"plugin:prettier/recommended"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint",
|
||||||
|
"jest",
|
||||||
|
"prettier"
|
||||||
|
]
|
||||||
|
}
|
35
.github/CONTRIBUTING.md
vendored
35
.github/CONTRIBUTING.md
vendored
@ -2,33 +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://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
Contributions to this project are [released](https://docs.github.com/en/github/site-policy/github-terms-of-service#6-contributions-under-repository-license)
|
||||||
|
to the public under the [project's open source license](LICENSE).
|
||||||
|
|
||||||
## Submitting a pull request
|
## Submitting a pull request
|
||||||
|
|
||||||
1. [Fork](https://github.com/docker/build-push-action/fork) and clone the repository
|
1. [Fork](https://github.com/docker/build-push-action/fork) and clone the repository
|
||||||
2. Configure and install the dependencies: `yarn install`
|
2. Configure and install the dependencies: `yarn install`
|
||||||
3. Make sure the tests pass on your machine: `yarn run test`
|
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, add tests, and make sure the tests still pass
|
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/build-push-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/build-push-action/compare)
|
||||||
|
9. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
||||||
## Container based developer flow
|
|
||||||
|
|
||||||
If you don't want to maintain a Node developer environment that fits this project you can use containerized commands instead of invoking yarn directly.
|
|
||||||
|
|
||||||
```
|
|
||||||
# format code and build javascript artifacts
|
|
||||||
docker buildx bake pre-checkin
|
|
||||||
|
|
||||||
# validate all code has correctly formatted and built
|
|
||||||
docker buildx bake validate
|
|
||||||
|
|
||||||
# run tests
|
|
||||||
docker buildx bake test
|
|
||||||
```
|
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
@ -40,5 +27,5 @@ Here are a few things you can do that will increase the likelihood of your pull
|
|||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||||
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
- [Using Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
|
||||||
- [GitHub Help](https://help.github.com)
|
- [GitHub Help](https://docs.github.com/en)
|
||||||
|
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -5,7 +5,7 @@ about: Create a report to help us improve
|
|||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
Before sumbitting a bug report please read the [Troubleshooting doc](https://github.com/docker/build-push-action/blob/master/TROUBLESHOOTING.md).
|
Before submitting a bug report please read the [Troubleshooting doc](https://github.com/docker/build-push-action/blob/master/TROUBLESHOOTING.md).
|
||||||
|
|
||||||
### Behaviour
|
### Behaviour
|
||||||
|
|
||||||
@ -34,4 +34,4 @@ Before sumbitting a bug report please read the [Troubleshooting doc](https://git
|
|||||||
|
|
||||||
### Logs
|
### Logs
|
||||||
|
|
||||||
> Download the [log file of your build](https://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#downloading-logs) and [attach it](https://help.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.
|
> Download the [log file of your build](https://docs.github.com/en/actions/managing-workflow-runs/using-workflow-run-logs#downloading-logs) and [attach it](https://docs.github.com/en/github/managing-your-work-on-github/file-attachments-on-issues-and-pull-requests) to this issue.
|
||||||
|
BIN
.github/build-push-action.png
vendored
BIN
.github/build-push-action.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 19 KiB |
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@ -5,8 +5,8 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
labels:
|
labels:
|
||||||
- ":game_die: dependencies"
|
- "dependencies"
|
||||||
- ":robot: bot"
|
- "bot"
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
@ -14,5 +14,5 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-type: "production"
|
- dependency-type: "production"
|
||||||
labels:
|
labels:
|
||||||
- ":game_die: dependencies"
|
- "dependencies"
|
||||||
- ":robot: bot"
|
- "bot"
|
||||||
|
79
.github/labels.yml
vendored
79
.github/labels.yml
vendored
@ -1,79 +0,0 @@
|
|||||||
## more info https://github.com/crazy-max/ghaction-github-labeler
|
|
||||||
- # automerge
|
|
||||||
name: ":bell: automerge"
|
|
||||||
color: "8f4fbc"
|
|
||||||
description: ""
|
|
||||||
- # bot
|
|
||||||
name: ":robot: bot"
|
|
||||||
color: "69cde9"
|
|
||||||
description: ""
|
|
||||||
- # bug
|
|
||||||
name: ":bug: bug"
|
|
||||||
color: "b60205"
|
|
||||||
description: ""
|
|
||||||
- # dependencies
|
|
||||||
name: ":game_die: dependencies"
|
|
||||||
color: "0366d6"
|
|
||||||
description: ""
|
|
||||||
from_name: "dependencies"
|
|
||||||
- # 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: ""
|
|
||||||
from_name: "question"
|
|
||||||
- # upstream
|
|
||||||
name: ":eyes: upstream"
|
|
||||||
color: "fbca04"
|
|
||||||
description: ""
|
|
||||||
- # wontfix
|
|
||||||
name: ":coffin: wontfix"
|
|
||||||
color: "ffffff"
|
|
||||||
description: ""
|
|
778
.github/workflows/ci.yml
vendored
778
.github/workflows/ci.yml
vendored
File diff suppressed because it is too large
Load Diff
76
.github/workflows/e2e.yml
vendored
76
.github/workflows/e2e.yml
vendored
@ -2,14 +2,27 @@ name: e2e
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
buildx-version:
|
||||||
|
description: 'Buildx version or Git context'
|
||||||
|
default: 'latest'
|
||||||
|
required: false
|
||||||
|
buildkit-image:
|
||||||
|
description: 'BuildKit image'
|
||||||
|
default: 'moby/buildkit:buildx-stable-1'
|
||||||
|
required: false
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 10 * * *' # everyday at 10am
|
- cron: '0 10 * * *'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- 'master'
|
||||||
tags:
|
tags:
|
||||||
- v*
|
- v*
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILDX_VERSION: latest
|
||||||
|
BUILDKIT_IMAGE: moby/buildkit:buildx-stable-1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -32,26 +45,55 @@ jobs:
|
|||||||
slug: registry.gitlab.com/test1716/test
|
slug: registry.gitlab.com/test1716/test
|
||||||
username_secret: GITLAB_USERNAME
|
username_secret: GITLAB_USERNAME
|
||||||
password_secret: GITLAB_TOKEN
|
password_secret: GITLAB_TOKEN
|
||||||
|
-
|
||||||
|
registry: 175142243308.dkr.ecr.us-east-2.amazonaws.com
|
||||||
|
slug: 175142243308.dkr.ecr.us-east-2.amazonaws.com/sandbox/test-docker-action
|
||||||
|
username_secret: AWS_ACCESS_KEY_ID
|
||||||
|
password_secret: AWS_SECRET_ACCESS_KEY
|
||||||
|
-
|
||||||
|
registry: public.ecr.aws
|
||||||
|
slug: public.ecr.aws/q3b5f1u4/test-docker-action
|
||||||
|
username_secret: AWS_ACCESS_KEY_ID
|
||||||
|
password_secret: AWS_SECRET_ACCESS_KEY
|
||||||
|
-
|
||||||
|
registry: us-east4-docker.pkg.dev
|
||||||
|
slug: us-east4-docker.pkg.dev/sandbox-298914/docker-official-github-actions/test-docker-action
|
||||||
|
username_secret: GAR_USERNAME
|
||||||
|
password_secret: GAR_JSON_KEY
|
||||||
|
-
|
||||||
|
registry: gcr.io
|
||||||
|
slug: gcr.io/sandbox-298914/test-docker-action
|
||||||
|
username_secret: GCR_USERNAME
|
||||||
|
password_secret: GCR_JSON_KEY
|
||||||
|
-
|
||||||
|
registry: officialgithubactions.azurecr.io
|
||||||
|
slug: officialgithubactions.azurecr.io/test-docker-action
|
||||||
|
username_secret: AZURE_CLIENT_ID
|
||||||
|
password_secret: AZURE_CLIENT_SECRET
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: docker_meta
|
id: meta
|
||||||
uses: crazy-max/ghaction-docker-meta@v1
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: ${{ matrix.slug }}
|
images: ${{ matrix.slug }}
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.buildx-version || env.BUILDX_VERSION }}
|
||||||
|
driver-opts: |
|
||||||
|
image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }}
|
||||||
-
|
-
|
||||||
name: Login to Registry
|
name: Login to Registry
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ${{ matrix.registry }}
|
registry: ${{ matrix.registry }}
|
||||||
username: ${{ secrets[matrix.username_secret] }}
|
username: ${{ secrets[matrix.username_secret] }}
|
||||||
@ -61,23 +103,21 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
context: ./test
|
context: ./test
|
||||||
file: ./test/Dockerfile-multi
|
file: ./test/multi.Dockerfile
|
||||||
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=registry,ref=${{ matrix.slug }}:master
|
||||||
|
cache-to: type=inline
|
||||||
-
|
-
|
||||||
name: Inspect image
|
name: Inspect image
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
docker pull ${{ matrix.slug }}:${{ steps.docker_meta.outputs.version }}
|
docker pull ${{ matrix.slug }}:${{ steps.meta.outputs.version }}
|
||||||
docker image inspect ${{ matrix.slug }}:${{ steps.docker_meta.outputs.version }}
|
docker image inspect ${{ matrix.slug }}:${{ steps.meta.outputs.version }}
|
||||||
-
|
-
|
||||||
name: Check manifest
|
name: Check manifest
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect ${{ matrix.slug }}:${{ steps.docker_meta.outputs.version }}
|
docker buildx imagetools inspect ${{ matrix.slug }}:${{ steps.meta.outputs.version }} --format '{{json .}}'
|
||||||
-
|
|
||||||
name: Dump context
|
|
||||||
if: always()
|
|
||||||
uses: crazy-max/ghaction-dump-context@v1
|
|
||||||
|
39
.github/workflows/example.yml
vendored
39
.github/workflows/example.yml
vendored
@ -1,9 +1,9 @@
|
|||||||
# This workflow is provided just as an usage example and not for repo testing/verification
|
# This workflow is provided just as an example and not for repo testing/verification
|
||||||
name: example
|
name: example
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 10 * * 0' # everyday sunday at 10am
|
- cron: '0 10 * * 0'
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- '**'
|
- '**'
|
||||||
@ -25,17 +25,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: docker_meta
|
id: meta
|
||||||
uses: crazy-max/ghaction-docker-meta@v1
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: ${{ env.DOCKER_IMAGE }} # list of Docker images to use as base name for tags
|
images: ${{ env.DOCKER_IMAGE }}
|
||||||
tag-sha: true # add git short SHA as Docker tag
|
tags: |
|
||||||
|
type=schedule
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=pr
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
type=sha
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
with:
|
with:
|
||||||
driver-opts: network=host
|
driver-opts: network=host
|
||||||
-
|
-
|
||||||
@ -45,8 +52,8 @@ jobs:
|
|||||||
context: ./test
|
context: ./test
|
||||||
file: ./test/Dockerfile
|
file: ./test/Dockerfile
|
||||||
load: true
|
load: true
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
-
|
-
|
||||||
name: Build and push to local registry
|
name: Build and push to local registry
|
||||||
uses: ./
|
uses: ./
|
||||||
@ -54,18 +61,14 @@ jobs:
|
|||||||
context: ./test
|
context: ./test
|
||||||
file: ./test/Dockerfile
|
file: ./test/Dockerfile
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
-
|
-
|
||||||
name: Inspect image
|
name: Inspect image
|
||||||
run: |
|
run: |
|
||||||
docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }}
|
docker image inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }}
|
||||||
-
|
-
|
||||||
name: Check manifest
|
name: Check manifest
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }}
|
docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.meta.outputs.version }} --format '{{json .}}'
|
||||||
-
|
|
||||||
name: Dump context
|
|
||||||
if: always()
|
|
||||||
uses: crazy-max/ghaction-dump-context@v1
|
|
||||||
|
20
.github/workflows/labels.yml
vendored
20
.github/workflows/labels.yml
vendored
@ -1,20 +0,0 @@
|
|||||||
name: labels
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
paths:
|
|
||||||
- '.github/labels.yml'
|
|
||||||
- '.github/workflows/labels.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
labeler:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Run Labeler
|
|
||||||
uses: crazy-max/ghaction-github-labeler@v3
|
|
33
.github/workflows/test.yml
vendored
33
.github/workflows/test.yml
vendored
@ -3,41 +3,30 @@ name: test
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- 'master'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- 'master'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-containerized:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Validate
|
|
||||||
run: docker buildx bake validate
|
|
||||||
-
|
|
||||||
name: Test
|
|
||||||
run: docker buildx bake test
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Install
|
name: Validate
|
||||||
run: yarn install
|
uses: docker/bake-action@v2
|
||||||
|
with:
|
||||||
|
targets: validate
|
||||||
-
|
-
|
||||||
name: Test
|
name: Test
|
||||||
run: yarn run test
|
uses: docker/bake-action@v2
|
||||||
|
with:
|
||||||
|
targets: test
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v3
|
||||||
if: success()
|
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
file: ./coverage/clover.xml
|
file: ./coverage/clover.xml
|
||||||
|
72
.github/workflows/virtual-env.yml
vendored
Normal file
72
.github/workflows/virtual-env.yml
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
name: virtual-env
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 10 * * *'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/virtual-env.yml'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/virtual-env.yml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
os:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- ubuntu-22.04
|
||||||
|
- ubuntu-20.04
|
||||||
|
- ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: File system
|
||||||
|
run: df -ah
|
||||||
|
-
|
||||||
|
name: Mounts
|
||||||
|
run: mount
|
||||||
|
-
|
||||||
|
name: Node info
|
||||||
|
run: node -p process
|
||||||
|
-
|
||||||
|
name: NPM version
|
||||||
|
run: npm version
|
||||||
|
-
|
||||||
|
name: List install packages
|
||||||
|
run: apt list --installed
|
||||||
|
-
|
||||||
|
name: Docker daemon conf
|
||||||
|
run: |
|
||||||
|
cat /etc/docker/daemon.json
|
||||||
|
-
|
||||||
|
name: Docker info
|
||||||
|
run: docker info
|
||||||
|
-
|
||||||
|
name: Docker version
|
||||||
|
run: docker version
|
||||||
|
-
|
||||||
|
name: Cgroups
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y cgroup-tools
|
||||||
|
lscgroup
|
||||||
|
-
|
||||||
|
name: buildx version
|
||||||
|
run: docker buildx version
|
||||||
|
-
|
||||||
|
name: containerd version
|
||||||
|
run: containerd --version
|
||||||
|
-
|
||||||
|
name: Docker images
|
||||||
|
run: docker image ls
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 240,
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
|
52
Dockerfile
52
Dockerfile
@ -1,52 +0,0 @@
|
|||||||
#syntax=docker/dockerfile:1.1-experimental
|
|
||||||
|
|
||||||
FROM node:12 AS deps
|
|
||||||
WORKDIR /src
|
|
||||||
COPY package.json yarn.lock ./
|
|
||||||
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \
|
|
||||||
yarn install
|
|
||||||
|
|
||||||
FROM scratch AS update-yarn
|
|
||||||
COPY --from=deps /src/yarn.lock /
|
|
||||||
|
|
||||||
FROM deps AS validate-yarn
|
|
||||||
COPY .git .git
|
|
||||||
RUN status=$(git status --porcelain -- yarn.lock); if [ -n "$status" ]; then echo $status; exit 1; fi
|
|
||||||
|
|
||||||
FROM deps AS base
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
FROM base AS build
|
|
||||||
RUN yarn build
|
|
||||||
|
|
||||||
FROM deps AS test
|
|
||||||
COPY --from=docker /usr/local/bin/docker /usr/bin/
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG BUILDX_VERSION=v0.4.2
|
|
||||||
ENV RUNNER_TEMP=/tmp/github_runner
|
|
||||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
|
||||||
RUN mkdir -p /usr/local/lib/docker/cli-plugins && \
|
|
||||||
curl -fsSL https://github.com/docker/buildx/releases/download/$BUILDX_VERSION/buildx-$BUILDX_VERSION.$TARGETOS-$TARGETARCH > /usr/local/lib/docker/cli-plugins/docker-buildx && \
|
|
||||||
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx && \
|
|
||||||
docker buildx version
|
|
||||||
COPY . .
|
|
||||||
RUN yarn run test
|
|
||||||
|
|
||||||
FROM base AS run-format
|
|
||||||
RUN yarn run format
|
|
||||||
|
|
||||||
FROM scratch AS format
|
|
||||||
COPY --from=run-format /src/src/*.ts /src/
|
|
||||||
|
|
||||||
FROM base AS validate-format
|
|
||||||
RUN yarn run format-check
|
|
||||||
|
|
||||||
FROM scratch AS dist
|
|
||||||
COPY --from=build /src/dist/ /dist/
|
|
||||||
|
|
||||||
FROM build AS validate-build
|
|
||||||
RUN status=$(git status --porcelain -- dist); if [ -n "$status" ]; then echo $status; exit 1; fi
|
|
||||||
|
|
||||||
FROM base AS dev
|
|
||||||
ENTRYPOINT ["bash"]
|
|
697
README.md
697
README.md
@ -1,28 +1,15 @@
|
|||||||
[](https://github.com/docker/build-push-action/releases/latest)
|
[](https://github.com/docker/build-push-action/releases/latest)
|
||||||
[](https://github.com/marketplace/actions/build-and-push-docker-images)
|
[](https://github.com/marketplace/actions/build-and-push-docker-images)
|
||||||
[](https://github.com/docker/build-push-action/actions?workflow=ci)
|
[](https://github.com/docker/build-push-action/actions?workflow=ci)
|
||||||
[](https://github.com/docker/build-push-action/actions?workflow=test)
|
[](https://github.com/docker/build-push-action/actions?workflow=test)
|
||||||
[](https://codecov.io/gh/docker/build-push-action)
|
[](https://codecov.io/gh/docker/build-push-action)
|
||||||
|
|
||||||
## Upgrade from v1
|
|
||||||
|
|
||||||
`v2` of this action includes significant updates and now uses Docker [Buildx](https://github.com/docker/buildx). It
|
|
||||||
works with 3 new actions ([login](https://github.com/docker/login-action), [setup-buildx](https://github.com/docker/setup-buildx-action)
|
|
||||||
and [setup-qemu](https://github.com/docker/setup-qemu-action)) that we have created. It's also rewritten as a
|
|
||||||
[typescript-action](https://github.com/actions/typescript-action/) to be as close as possible of the
|
|
||||||
[GitHub Runner](https://github.com/actions/virtual-environments) during its execution.
|
|
||||||
|
|
||||||
[Upgrade notes](UPGRADE.md) and many [usage examples](#usage) have been added to handle most use cases but `v1` is
|
|
||||||
still available through [`releases/v1` branch](https://github.com/docker/build-push-action/tree/releases/v1).
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx).
|
GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx)
|
||||||
|
with full support of the features provided by [Moby BuildKit](https://github.com/moby/buildkit)
|
||||||
> :bulb: See also:
|
builder toolkit. This includes multi-platform build, secrets, remote cache, etc.
|
||||||
> * [login](https://github.com/docker/login-action) action
|
and different builder deployment/namespacing options.
|
||||||
> * [setup-buildx](https://github.com/docker/setup-buildx-action) action
|
|
||||||
> * [setup-qemu](https://github.com/docker/setup-qemu-action) action
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -31,84 +18,111 @@ ___
|
|||||||
* [Usage](#usage)
|
* [Usage](#usage)
|
||||||
* [Git context](#git-context)
|
* [Git context](#git-context)
|
||||||
* [Path context](#path-context)
|
* [Path context](#path-context)
|
||||||
* [Isolated builders](#isolated-builders)
|
* [Examples](#examples)
|
||||||
* [Multi-platform image](#multi-platform-image)
|
|
||||||
* [Advanced usage](#advanced-usage)
|
|
||||||
* [Push to multi-registries](#push-to-multi-registries)
|
|
||||||
* [Cache to registry](#push-to-multi-registries)
|
|
||||||
* [Local registry](#local-registry)
|
|
||||||
* [Export image to Docker](#export-image-to-docker)
|
|
||||||
* [Leverage GitHub cache](#leverage-github-cache)
|
|
||||||
* [Handle tags and labels](#handle-tags-and-labels)
|
|
||||||
* [Update DockerHub repo description](#update-dockerhub-repo-description)
|
|
||||||
* [Customizing](#customizing)
|
* [Customizing](#customizing)
|
||||||
* [inputs](#inputs)
|
* [inputs](#inputs)
|
||||||
* [outputs](#outputs)
|
* [outputs](#outputs)
|
||||||
* [Notes](#notes)
|
|
||||||
* [Multi-line secret value](#multi-line-secret-value)
|
|
||||||
* [Troubleshooting](#troubleshooting)
|
* [Troubleshooting](#troubleshooting)
|
||||||
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
|
* [Contributing](#contributing)
|
||||||
* [Limitation](#limitation)
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
This action uses our [setup-buildx](https://github.com/docker/setup-buildx-action) action that extends the
|
In the examples below we are also using 3 other actions:
|
||||||
`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,
|
* [`setup-buildx`](https://github.com/docker/setup-buildx-action) action will
|
||||||
build-secrets, remote cache, etc. and different builder deployment/namespacing options.
|
create and boot a builder using by default the [`docker-container` driver](https://docs.docker.com/build/building/drivers/docker-container/).
|
||||||
|
This is **not required but recommended** using it to be able to build
|
||||||
|
multi-platform images, export cache, etc.
|
||||||
|
* [`setup-qemu`](https://github.com/docker/setup-qemu-action) action can be
|
||||||
|
useful if you want to add emulation support with QEMU to be able to build
|
||||||
|
against more platforms.
|
||||||
|
* [`login`](https://github.com/docker/login-action) action will take care to
|
||||||
|
log in against a Docker registry.
|
||||||
|
|
||||||
### Git context
|
### Git context
|
||||||
|
|
||||||
The default behavior of this action is to use the Git context invoked by your workflow.
|
By default, this action uses the [Git context](https://docs.docker.com/engine/reference/commandline/build/#git-repositories),
|
||||||
(eg. `https://github.com/<owner>/<repo>.git#<ref>`)
|
so you don't need to use the [`actions/checkout`](https://github.com/actions/checkout/)
|
||||||
|
action to check out the repository as this will be done directly by [BuildKit](https://github.com/moby/buildkit).
|
||||||
|
|
||||||
|
The git reference will be based on the [event that triggered your workflow](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)
|
||||||
|
and will result in the following context: `https://github.com/<owner>/<repo>.git#<ref>`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches:
|
||||||
|
- 'main'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
main:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
-
|
-
|
||||||
name: Login to DockerHub
|
name: Login to Docker Hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
-
|
-
|
||||||
name: Build and push
|
name: Build and push
|
||||||
id: docker_build
|
uses: docker/build-push-action@v3
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
tags: user/app:latest
|
||||||
build-args: |
|
|
||||||
arg1=value1
|
|
||||||
arg2=value2
|
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Building from current repository automatically uses the [GitHub Token](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token)
|
Be careful because **any file mutation in the steps that precede the build step
|
||||||
as provided by `secrets` so it does not need to be passed. But if you want to authenticate against another private
|
will be ignored, including processing of the `.dockerignore` file** since
|
||||||
repository, you have to use a secret named `GIT_AUTH_TOKEN` to be able to authenticate against it with buildx:
|
the context is based on the Git reference. However, you can use the
|
||||||
|
[Path context](#path-context) using the [`context` input](#inputs) alongside
|
||||||
|
the [`actions/checkout`](https://github.com/actions/checkout/) action to remove
|
||||||
|
this restriction.
|
||||||
|
|
||||||
|
Default Git context can also be provided using the [Handlebars template](https://handlebarsjs.com/guide/)
|
||||||
|
expression `{{defaultContext}}`. Here we can use it to provide a subdirectory
|
||||||
|
to the default Git context:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
-
|
||||||
|
# Setting up Docker Buildx with docker-container driver is required
|
||||||
|
# at the moment to be able to use a subdirectory with Git context
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: "{{defaultContext}}:mysubdir"
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Warning**
|
||||||
|
>
|
||||||
|
> Subdirectory for Git context is available from [BuildKit v0.9.0](https://github.com/moby/buildkit/releases/tag/v0.9.0).
|
||||||
|
> If you're using the `docker` builder (default if `setup-buildx-action` not used),
|
||||||
|
> then BuildKit in Docker Engine will be used. As Docker Engine < v22.x.x embeds
|
||||||
|
> Buildkit 0.8.2 at the moment, it does not support this feature. It's therefore
|
||||||
|
> required to use the `setup-buildx-action` at the moment.
|
||||||
|
|
||||||
|
Building from the current repository automatically uses the [GitHub Token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication),
|
||||||
|
so it does not need to be passed. If you want to authenticate against another
|
||||||
|
private repository, you have to use a [secret](https://docs.docker.com/build/ci/github-actions/examples/#secrets)
|
||||||
|
named `GIT_AUTH_TOKEN` to be able to authenticate against it with Buildx:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
-
|
-
|
||||||
name: Build and push
|
name: Build and push
|
||||||
id: docker_build
|
uses: docker/build-push-action@v3
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
tags: user/app:latest
|
||||||
@ -116,475 +130,47 @@ repository, you have to use a secret named `GIT_AUTH_TOKEN` to be able to authen
|
|||||||
GIT_AUTH_TOKEN=${{ secrets.MYTOKEN }}
|
GIT_AUTH_TOKEN=${{ secrets.MYTOKEN }}
|
||||||
```
|
```
|
||||||
|
|
||||||
> :warning: Subdir for Git context is not yet supported ([moby/buildkit#1684](https://github.com/moby/buildkit/issues/1684))
|
|
||||||
> but you can use the [path context](#path-context) in the meantime.
|
|
||||||
|
|
||||||
> More info: https://docs.docker.com/engine/reference/commandline/build/#git-repositories
|
|
||||||
|
|
||||||
### Path context
|
### Path context
|
||||||
|
|
||||||
You can also use the `PATH` context alongside the [`actions/checkout`](https://github.com/actions/checkout/) action.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches:
|
||||||
|
- 'main'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
path-context:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
-
|
-
|
||||||
name: Login to DockerHub
|
name: Login to Docker Hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
-
|
-
|
||||||
name: Build and push
|
name: Build and push
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/386
|
|
||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
tags: user/app:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Isolated builders
|
## Examples
|
||||||
|
|
||||||
```yaml
|
See https://docs.docker.com/build/ci/github-actions/examples/.
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
multi-builders:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
id: builder1
|
|
||||||
-
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
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@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced usage
|
|
||||||
|
|
||||||
### Push to multi-registries
|
|
||||||
|
|
||||||
The following workflow will connect you to [DockerHub](https://github.com/docker/login-action#dockerhub)
|
|
||||||
and [GitHub Container Registry](https://github.com/docker/login-action#github-container-registry) and push the
|
|
||||||
image to these registries.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
multi-registries:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.CR_PAT }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
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
|
|
||||||
ghcr.io/user/app:latest
|
|
||||||
ghcr.io/user/app:1.0.0
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Cache to registry
|
|
||||||
|
|
||||||
You can import/export cache from a cache manifest or (special) image configuration on the registry.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
registry-cache:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: user/app:latest
|
|
||||||
cache-from: type=registry,ref=user/app:latest
|
|
||||||
cache-to: type=inline
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Local registry
|
|
||||||
|
|
||||||
For testing purposes you may need to create a [local registry](https://hub.docker.com/_/registry) to push images into:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
local-registry:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
registry:
|
|
||||||
image: registry:2
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
with:
|
|
||||||
driver-opts: network=host
|
|
||||||
-
|
|
||||||
name: Build and push to local registry
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: localhost:5000/name/app:latest
|
|
||||||
-
|
|
||||||
name: Inspect
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:latest
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Export image to Docker
|
|
||||||
|
|
||||||
You may want your build result to be available in the Docker client through `docker images` to be able to use it
|
|
||||||
in another step of your workflow:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
export-docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
load: true
|
|
||||||
tags: myimage:latest
|
|
||||||
-
|
|
||||||
name: Inspect
|
|
||||||
run: |
|
|
||||||
docker image inspect myimage:latest
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 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:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
github-cache:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
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:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: user/app:latest
|
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
> If you want to [export layers for all stages](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue),
|
|
||||||
> you have to specify `mode=max` attribute in `cache-to`.
|
|
||||||
|
|
||||||
### Handle tags and labels
|
|
||||||
|
|
||||||
If you come from [`v1`](https://github.com/docker/build-push-action/tree/releases/v1#readme) and want an
|
|
||||||
"automatic" tag management and [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
|
|
||||||
for labels, you can do it in a dedicated step. The following workflow will use the [Docker meta action](https://github.com/crazy-max/ghaction-docker-meta)
|
|
||||||
to handle tags and labels based on GitHub actions events and Git metadata.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 10 * * *' # everyday at 10am
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
tags:
|
|
||||||
- 'v*.*.*'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Docker meta
|
|
||||||
id: docker_meta
|
|
||||||
uses: crazy-max/ghaction-docker-meta@v1
|
|
||||||
with:
|
|
||||||
images: name/app # list of Docker images to use as base name for tags
|
|
||||||
tag-sha: true # add git short SHA as Docker tag
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/386
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Update DockerHub repo description
|
|
||||||
|
|
||||||
You can update the [DockerHub repository description](https://docs.docker.com/docker-hub/repos/) using
|
|
||||||
a third-party action called [DockerHub Description](https://github.com/peter-evans/dockerhub-description)
|
|
||||||
with this action:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: user/app:latest
|
|
||||||
-
|
|
||||||
name: Update repo description
|
|
||||||
uses: peter-evans/dockerhub-description@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
||||||
repository: user/app
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Customizing
|
## Customizing
|
||||||
|
|
||||||
@ -604,87 +190,58 @@ Following inputs can be used as `step.with` keys
|
|||||||
> tags: name/app:latest,name/app:1.0.0
|
> tags: name/app:latest,name/app:1.0.0
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|---------------------|----------|------------------------------------|
|
|--------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) |
|
| `add-hosts` | List/CSV | List of [customs host-to-IP mapping](https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host) (e.g., `docker:10.180.0.1`) |
|
||||||
| `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)) |
|
| `allow` | List/CSV | List of [extra privileged entitlement](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow) (e.g., `network.host,security.insecure`) |
|
||||||
| `file` | String | Path to the Dockerfile (default `./Dockerfile`) |
|
| `attests` | List | List of [attestation](https://docs.docker.com/build/attestations/) parameters (e.g., `type=sbom,generator=image`) |
|
||||||
| `build-args` | List | List of build-time variables |
|
| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) |
|
||||||
| `labels` | List | List of metadata for an image |
|
| `build-args` | List | List of [build-time variables](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-arg) |
|
||||||
| `tags` | List/CSV | List of tags |
|
| `build-contexts` | List | List of additional [build contexts](https://docs.docker.com/engine/reference/commandline/buildx_build/#build-context) (e.g., `name=path`) |
|
||||||
| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) |
|
| `cache-from` | List | List of [external cache sources](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-from) (e.g., `type=local,src=path/to/dir`) |
|
||||||
| `target` | String | Sets the target stage to build |
|
| `cache-to` | List | List of [cache export destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#cache-to) (e.g., `type=local,dest=path/to/dir`) |
|
||||||
| `allow` | List/CSV | List of [extra privileged entitlement](https://github.com/docker/buildx#--allowentitlement) (eg. `network.host,security.insecure`) |
|
| `cgroup-parent` | String | Optional [parent cgroup](https://docs.docker.com/engine/reference/commandline/build/#use-a-custom-parent-cgroup---cgroup-parent) for the container used in the build |
|
||||||
| `no-cache` | Bool | Do not use cache when building the image (default `false`) |
|
| `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)) |
|
||||||
| `platforms` | List/CSV | List of [target platforms](https://github.com/docker/buildx#---platformvaluevalue) for build |
|
| `file` | String | Path to the Dockerfile. (default `{context}/Dockerfile`) |
|
||||||
| `load` | Bool | [Load](https://github.com/docker/buildx#--load) is a shorthand for `--output=type=docker` (default `false`) |
|
| `labels` | List | List of metadata for an image |
|
||||||
| `push` | Bool | [Push](https://github.com/docker/buildx#--push) is a shorthand for `--output=type=registry` (default `false`) |
|
| `load` | Bool | [Load](https://docs.docker.com/engine/reference/commandline/buildx_build/#load) is a shorthand for `--output=type=docker` (default `false`) |
|
||||||
| `outputs` | List | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) |
|
| `network` | String | Set the networking mode for the `RUN` instructions during build |
|
||||||
| `cache-from` | List | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) |
|
| `no-cache` | Bool | Do not use cache when building the image (default `false`) |
|
||||||
| `cache-to` | List | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) |
|
| `no-cache-filters` | List/CSV | Do not cache specified stages |
|
||||||
| `secrets` | List | List of secrets to expose to the build (eg. `key=value`, `GIT_AUTH_TOKEN=mytoken`) |
|
| `outputs`¹ | List | List of [output destinations](https://docs.docker.com/engine/reference/commandline/buildx_build/#output) (format: `type=local,dest=path`) |
|
||||||
| `ssh` | List | List of SSH agent socket or keys to expose to the build |
|
| `platforms` | List/CSV | List of [target platforms](https://docs.docker.com/engine/reference/commandline/buildx_build/#platform) for build |
|
||||||
|
| `provenance` | Bool/String | Generate [provenance](https://docs.docker.com/build/attestations/slsa-provenance/) attestation for the build (shorthand for `--attest=type=provenance`) |
|
||||||
|
| `pull` | Bool | Always attempt to pull all referenced images (default `false`) |
|
||||||
|
| `push` | Bool | [Push](https://docs.docker.com/engine/reference/commandline/buildx_build/#push) is a shorthand for `--output=type=registry` (default `false`) |
|
||||||
|
| `sbom` | Bool/String | Generate [SBOM](https://docs.docker.com/build/attestations/sbom/) attestation for the build (shorthand for `--attest=type=sbom`) |
|
||||||
|
| `secrets` | List | List of [secrets](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`) |
|
||||||
|
| `secret-files` | List | List of [secret files](https://docs.docker.com/engine/reference/commandline/buildx_build/#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`) |
|
||||||
|
| `shm-size` | String | Size of [`/dev/shm`](https://docs.docker.com/engine/reference/commandline/buildx_build/#shm-size) (e.g., `2g`) |
|
||||||
|
| `ssh` | List | List of [SSH agent socket or keys](https://docs.docker.com/engine/reference/commandline/buildx_build/#ssh) to expose to the build |
|
||||||
|
| `tags` | List/CSV | List of tags |
|
||||||
|
| `target` | String | Sets the target stage to build |
|
||||||
|
| `ulimit` | List | [Ulimit](https://docs.docker.com/engine/reference/commandline/buildx_build/#ulimit) options (e.g., `nofile=1024:1024`) |
|
||||||
|
| `github-token` | String | GitHub Token used to authenticate against a repository for [Git context](#git-context) (default `${{ github.token }}`) |
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> * ¹ multiple `outputs` are [not yet supported](https://github.com/moby/buildkit/issues/1555)
|
||||||
|
|
||||||
### outputs
|
### outputs
|
||||||
|
|
||||||
Following outputs are available
|
Following outputs are available
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|---------------|---------|---------------------------------------|
|
|------------|---------|-----------------------|
|
||||||
| `digest` | String | Image content-addressable identifier also called a digest |
|
| `imageid` | String | Image ID |
|
||||||
|
| `digest` | String | Image digest |
|
||||||
## Notes
|
| `metadata` | JSON | Build result metadata |
|
||||||
|
|
||||||
### Multi-line secret value
|
|
||||||
|
|
||||||
To handle multi-line value for a secret, you will need to place the key-value pair between quotes:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
secrets: |
|
|
||||||
"MYSECRET=${{ secrets.GPG_KEY }}"
|
|
||||||
GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
|
||||||
"MYSECRET=aaaaaaaa
|
|
||||||
bbbbbbb
|
|
||||||
ccccccccc"
|
|
||||||
FOO=bar
|
|
||||||
"EMPTYLINE=aaaa
|
|
||||||
|
|
||||||
bbbb
|
|
||||||
ccc"
|
|
||||||
"JSON_SECRET={""key1"":""value1"",""key2"":""value2""}"
|
|
||||||
```
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|--------------------|--------------------------------------------------|
|
|
||||||
| `MYSECRET` | `***********************` |
|
|
||||||
| `GIT_AUTH_TOKEN` | `abcdefghi,jklmno=0123456789` |
|
|
||||||
| `MYSECRET` | `aaaaaaaa\nbbbbbbb\nccccccccc` |
|
|
||||||
| `FOO` | `bar` |
|
|
||||||
| `EMPTYLINE` | `aaaa\n\nbbbb\nccc` |
|
|
||||||
| `JSON_SECRET` | `{"key1":"value1","key2":"value2"}` |
|
|
||||||
|
|
||||||
> Note: all quote signs need to be doubled for escaping.
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
See [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
|
See [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
|
||||||
|
|
||||||
## Keep up-to-date with GitHub Dependabot
|
## Contributing
|
||||||
|
|
||||||
Since [Dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-github-dependabot)
|
Want to contribute? Awesome! You can find information about contributing to
|
||||||
has [native GitHub Actions support](https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#package-ecosystem),
|
this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
|
||||||
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).
|
|
||||||
|
@ -1,112 +1,9 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
* [`auto-push is currently not implemented for docker driver`](#auto-push-is-currently-not-implemented-for-docker-driver)
|
|
||||||
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
||||||
|
* [BuildKit container logs](#buildkit-container-logs)
|
||||||
## `auto-push is currently not implemented for docker driver`
|
* [With containerd](#with-containerd)
|
||||||
|
* [`repository name must be lowercase`](#repository-name-must-be-lowercase)
|
||||||
If you're using the default builder (which uses the docker driver) without using our `setup-buildx-action`, you may
|
|
||||||
encounter this error message if you try to push your image:
|
|
||||||
|
|
||||||
```
|
|
||||||
Run docker/build-push-action@v2
|
|
||||||
📣 Buildx version: 0.4.2
|
|
||||||
🏃 Starting build...
|
|
||||||
/usr/bin/docker buildx build --tag localhost:5000/name/app:latest --iidfile /tmp/docker-build-push-eYl8PB/iidfile --file ./test/Dockerfile --push ./test
|
|
||||||
auto-push is currently not implemented for docker driver
|
|
||||||
Error: buildx call failed with: auto-push is currently not implemented for docker driver
|
|
||||||
```
|
|
||||||
|
|
||||||
While waiting for an implementation to be done on buildx/buildkit, you have the following possibilities
|
|
||||||
to solve this atm:
|
|
||||||
|
|
||||||
### With `docker-container` driver and `setup-buildx`
|
|
||||||
|
|
||||||
> Recommended solution
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ env.USER }}
|
|
||||||
password: ${{ secrets.PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
tags: ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
push: true
|
|
||||||
```
|
|
||||||
|
|
||||||
### With `docker` driver
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Login
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ env.USER }}
|
|
||||||
password: ${{ secrets.PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
tags: ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
load: true
|
|
||||||
-
|
|
||||||
name: Push
|
|
||||||
run: docker push ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### With `docker` driver and `setup-buildx`
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
with:
|
|
||||||
driver: docker
|
|
||||||
-
|
|
||||||
name: Login
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ env.USER }}
|
|
||||||
password: ${{ secrets.PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
tags: ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
load: true
|
|
||||||
-
|
|
||||||
name: Push
|
|
||||||
run: docker push ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cannot push to a registry
|
## Cannot push to a registry
|
||||||
|
|
||||||
@ -118,23 +15,22 @@ While pushing to a registry, you may encounter these kinds of issues:
|
|||||||
* `failed commit on ref "manifest-sha256:...": unexpected status: 401 Unauthorized`
|
* `failed commit on ref "manifest-sha256:...": unexpected status: 401 Unauthorized`
|
||||||
* `unexpected response: 401 Unauthorized`
|
* `unexpected response: 401 Unauthorized`
|
||||||
|
|
||||||
These issues are not directly related to this action but are rather linked to [buildx](https://github.com/docker/buildx),
|
These issues are not directly related to this action but are rather linked to
|
||||||
[buildkit](https://github.com/moby/buildkit), [containerd](https://github.com/containerd/containerd) or the registry
|
[Buildx](https://github.com/docker/buildx), [BuildKit](https://github.com/moby/buildkit),
|
||||||
on which you're pushing your image. The quality of error message depends on the registry and are usually not very informative.
|
[containerd](https://github.com/containerd/containerd) or the registry on which
|
||||||
|
you're pushing your image. The quality of error message depends on the registry
|
||||||
|
and are usually not very informative.
|
||||||
|
|
||||||
To help you solve this, you should first enable debugging in the
|
### BuildKit container logs
|
||||||
[setup-buildx action step](https://github.com/docker/setup-buildx-action):
|
|
||||||
|
|
||||||
```yaml
|
To help you solve this, you have to [enable debugging in the setup-buildx](https://github.com/docker/setup-buildx-action#buildkit-container-logs)
|
||||||
-
|
action step and attach BuildKit container logs to your issue.
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
with:
|
|
||||||
buildkitd-flags: --debug
|
|
||||||
```
|
|
||||||
|
|
||||||
Next you can test pushing with [containerd action](https://github.com/crazy-max/ghaction-setup-containerd) using the
|
### With containerd
|
||||||
following workflow. If it works then open an issue on [buildkit](https://github.com/moby/buildkit) repository.
|
|
||||||
|
Next you can test pushing with [containerd action](https://github.com/crazy-max/ghaction-setup-containerd)
|
||||||
|
using the following workflow. If it works then open an issue on [BuildKit](https://github.com/moby/buildkit)
|
||||||
|
repository.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: containerd
|
name: containerd
|
||||||
@ -148,25 +44,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
with:
|
with:
|
||||||
buildkitd-flags: --debug
|
buildkitd-flags: --debug
|
||||||
-
|
-
|
||||||
name: Set up containerd
|
name: Set up containerd
|
||||||
uses: crazy-max/ghaction-setup-containerd@v1
|
uses: crazy-max/ghaction-setup-containerd@v2
|
||||||
-
|
-
|
||||||
name: Build Docker image
|
name: Build Docker image
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
platforms: linux/amd64,linux/arm64
|
||||||
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
|
||||||
tags: docker.io/user/app:latest
|
tags: docker.io/user/app:latest
|
||||||
outputs: type=oci,dest=/tmp/image.tar
|
outputs: type=oci,dest=/tmp/image.tar
|
||||||
-
|
-
|
||||||
@ -178,3 +73,65 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo ctr --debug i push --user "${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" docker.io/user/app:latest
|
sudo ctr --debug i push --user "${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" docker.io/user/app:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `repository name must be lowercase`
|
||||||
|
|
||||||
|
You may encounter this issue if you're using `github.repository` as a repo slug
|
||||||
|
in your tag:
|
||||||
|
|
||||||
|
```
|
||||||
|
#6 exporting to image
|
||||||
|
#6 exporting layers
|
||||||
|
#6 exporting layers 1.2s done
|
||||||
|
#6 exporting manifest sha256:b47f7dfb97b89ccd5de553af3c8cd94c4795884cbe5693e93946b1d95a7b1d12 0.0s done
|
||||||
|
#6 exporting config sha256:995e93fab8196893192f08a38deea6769dc4d98f86cf705eccc24ec96a3e271c 0.0s done
|
||||||
|
#6 ERROR: invalid reference format: repository name must be lowercase
|
||||||
|
------
|
||||||
|
> exporting to image:
|
||||||
|
------
|
||||||
|
error: failed to solve: invalid reference format: repository name must be lowercase
|
||||||
|
```
|
||||||
|
|
||||||
|
or a cache reference:
|
||||||
|
|
||||||
|
```
|
||||||
|
#10 importing cache manifest from ghcr.io/My-Org/repo:main
|
||||||
|
#10 ERROR: invalid reference format: repository name must be lowercase
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this issue you can use our [metadata action](https://github.com/docker/metadata-action)
|
||||||
|
to generate sanitized tags:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository }}
|
||||||
|
tags: latest
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or a dedicated step to sanitize the slug:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Sanitize repo slug
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
id: repo_slug
|
||||||
|
with:
|
||||||
|
result-encoding: string
|
||||||
|
script: return 'ghcr.io/${{ github.repository }}'.toLowerCase()
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.repo_slug.outputs.result }}:latest
|
||||||
|
```
|
||||||
|
149
UPGRADE.md
149
UPGRADE.md
@ -1,149 +0,0 @@
|
|||||||
# Upgrade notes
|
|
||||||
|
|
||||||
## v1 to v2
|
|
||||||
|
|
||||||
* Input `path` is now called `context` for consistency with other Docker build tools
|
|
||||||
* `path` defaults to current git repository so checkout action is not required in a workflow
|
|
||||||
* Rename `dockerfile` input to `file` for consistency with other Docker build tools
|
|
||||||
* Rename `always_pull` input to `pull` for consistency with other Docker build tools
|
|
||||||
* 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 to support multi-platform builds
|
|
||||||
* 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 (`cache_froms` removed)
|
|
||||||
* Add [`cache-to`](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) input
|
|
||||||
* Rename `build_args` input to `build-args` for consistency with other Docker build tools
|
|
||||||
* Add `secrets` input
|
|
||||||
* Review `tags` input
|
|
||||||
* Remove `repository` input. See [Simple workflow](#simple-workflow) for migration
|
|
||||||
* Remove `username`, `password` and `registry` inputs. Login support moved to [docker/login-action](https://github.com/docker/login-action) repo
|
|
||||||
* Remove `tag_with_sha`, `tag_with_ref`, `add_git_labels` inputs. See [Tags with ref and Git labels](#tags-with-ref-and-git-labels) for migration
|
|
||||||
* Handle Git context
|
|
||||||
* Add `digest` output
|
|
||||||
|
|
||||||
### Simple workflow
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# v1
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Build and push Docker images
|
|
||||||
uses: docker/build-push-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
repository: myorg/myrepository
|
|
||||||
always_pull: true
|
|
||||||
build_args: arg1=value1,arg2=value2
|
|
||||||
cache_froms: myorg/myrepository:latest
|
|
||||||
tags: latest
|
|
||||||
```
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# v2
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
pull: true
|
|
||||||
push: true
|
|
||||||
build-args: |
|
|
||||||
arg1=value1
|
|
||||||
arg2=value2
|
|
||||||
cache-from: type=registry,ref=myorg/myrepository:latest
|
|
||||||
cache-to: type=inline
|
|
||||||
tags: myorg/myrepository:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tags with ref and Git labels
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# v1
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Build and push Docker images
|
|
||||||
uses: docker/build-push-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
repository: myorg/myrepository
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tag_with_ref: true
|
|
||||||
tag_with_sha: true
|
|
||||||
add_git_labels: true
|
|
||||||
```
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# v2
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Prepare
|
|
||||||
id: prep
|
|
||||||
run: |
|
|
||||||
DOCKER_IMAGE=myorg/myrepository
|
|
||||||
VERSION=edge
|
|
||||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
|
||||||
VERSION=${GITHUB_REF#refs/tags/}
|
|
||||||
elif [[ $GITHUB_REF == refs/heads/* ]]; then
|
|
||||||
VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g')
|
|
||||||
elif [[ $GITHUB_REF == refs/pull/* ]]; then
|
|
||||||
VERSION=pr-${{ github.event.number }}
|
|
||||||
fi
|
|
||||||
TAGS="${DOCKER_IMAGE}:${VERSION}"
|
|
||||||
if [ "${{ github.event_name }}" = "push" ]; then
|
|
||||||
TAGS="$TAGS,${DOCKER_IMAGE}:sha-${GITHUB_SHA::8}"
|
|
||||||
fi
|
|
||||||
echo ::set-output name=version::${VERSION}
|
|
||||||
echo ::set-output name=tags::${TAGS}
|
|
||||||
echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.prep.outputs.tags }}
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.source=${{ github.event.repository.html_url }}
|
|
||||||
org.opencontainers.image.created=${{ steps.prep.outputs.created }}
|
|
||||||
org.opencontainers.image.revision=${{ github.sha }}
|
|
||||||
```
|
|
||||||
|
|
||||||
> You can also use the [Docker meta action](https://github.com/crazy-max/ghaction-docker-meta) to handle tags and
|
|
||||||
> labels based on GitHub actions events and Git metadata. A workflow example is available in the [README](README.md#handle-tags-and-labels).
|
|
@ -1,13 +1,17 @@
|
|||||||
|
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
import * as buildx from '../src/buildx';
|
import * as buildx from '../src/buildx';
|
||||||
import * as context from '../src/context';
|
import * as context from '../src/context';
|
||||||
import * as docker from '../src/docker';
|
|
||||||
|
|
||||||
const tmpNameSync = path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
const tmpNameSync = path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||||
const digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||||
|
const metadata = `{
|
||||||
|
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
||||||
|
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
||||||
|
}`;
|
||||||
|
|
||||||
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||||
const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep);
|
const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep);
|
||||||
@ -24,117 +28,118 @@ jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
|
|||||||
describe('getImageID', () => {
|
describe('getImageID', () => {
|
||||||
it('matches', async () => {
|
it('matches', async () => {
|
||||||
const imageIDFile = await buildx.getImageIDFile();
|
const imageIDFile = await buildx.getImageIDFile();
|
||||||
console.log(`imageIDFile: ${imageIDFile}`);
|
await fs.writeFileSync(imageIDFile, imageID);
|
||||||
await fs.writeFileSync(imageIDFile, digest);
|
const expected = await buildx.getImageID();
|
||||||
const imageID = await buildx.getImageID();
|
expect(expected).toEqual(imageID);
|
||||||
console.log(`imageID: ${imageID}`);
|
});
|
||||||
expect(imageID).toEqual(digest);
|
});
|
||||||
|
|
||||||
|
describe('getMetadata', () => {
|
||||||
|
it('matches', async () => {
|
||||||
|
const metadataFile = await buildx.getMetadataFile();
|
||||||
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
|
const expected = await buildx.getMetadata();
|
||||||
|
expect(expected).toEqual(metadata);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDigest', () => {
|
||||||
|
it('matches', async () => {
|
||||||
|
const metadataFile = await buildx.getMetadataFile();
|
||||||
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
|
const expected = await buildx.getDigest(metadata);
|
||||||
|
expect(expected).toEqual('sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isLocalOrTarExporter', () => {
|
describe('isLocalOrTarExporter', () => {
|
||||||
// prettier-ignore
|
|
||||||
test.each([
|
test.each([
|
||||||
[
|
[['type=registry,ref=user/app'], false],
|
||||||
[
|
[['type=docker'], false],
|
||||||
'type=registry,ref=user/app',
|
[['type=local,dest=./release-out'], true],
|
||||||
],
|
[['type=tar,dest=/tmp/image.tar'], true],
|
||||||
false
|
[['type=docker', 'type=tar,dest=/tmp/image.tar'], true],
|
||||||
],
|
[['"type=tar","dest=/tmp/image.tar"'], true],
|
||||||
[
|
[['" type= local" , dest=./release-out'], true],
|
||||||
[
|
[['.'], true]
|
||||||
'type=docker',
|
])('given %p returns %p', async (outputs: Array<string>, expected: boolean) => {
|
||||||
],
|
expect(buildx.isLocalOrTarExporter(outputs)).toEqual(expected);
|
||||||
false
|
});
|
||||||
],
|
});
|
||||||
[
|
|
||||||
[
|
describe('isAvailable', () => {
|
||||||
'type=local,dest=./release-out'
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
],
|
buildx.isAvailable();
|
||||||
true
|
|
||||||
],
|
// eslint-disable-next-line jest/no-standalone-expect
|
||||||
[
|
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||||
[
|
silent: true,
|
||||||
'type=tar,dest=/tmp/image.tar'
|
ignoreReturnCode: true
|
||||||
],
|
});
|
||||||
true
|
});
|
||||||
],
|
|
||||||
[
|
describe('isAvailable standalone', () => {
|
||||||
[
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
'type=docker',
|
buildx.isAvailable(true);
|
||||||
'type=tar,dest=/tmp/image.tar'
|
|
||||||
],
|
// eslint-disable-next-line jest/no-standalone-expect
|
||||||
true
|
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
||||||
],
|
silent: true,
|
||||||
[
|
ignoreReturnCode: true
|
||||||
[
|
});
|
||||||
'"type=tar","dest=/tmp/image.tar"'
|
|
||||||
],
|
|
||||||
true
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
'" type= local" , dest=./release-out'
|
|
||||||
],
|
|
||||||
true
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
'.'
|
|
||||||
],
|
|
||||||
true
|
|
||||||
],
|
|
||||||
])(
|
|
||||||
'given %p returns %p',
|
|
||||||
async (outputs: Array<string>, expected: boolean) => {
|
|
||||||
expect(buildx.isLocalOrTarExporter(outputs)).toEqual(expected);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getVersion', () => {
|
describe('getVersion', () => {
|
||||||
async function isDaemonRunning() {
|
it('valid', async () => {
|
||||||
return await docker.isDaemonRunning();
|
const version = await buildx.getVersion();
|
||||||
}
|
expect(semver.valid(version)).not.toBeNull();
|
||||||
(isDaemonRunning() ? it : it.skip)(
|
});
|
||||||
'valid',
|
|
||||||
async () => {
|
|
||||||
const version = await buildx.getVersion();
|
|
||||||
console.log(`version: ${version}`);
|
|
||||||
expect(semver.valid(version)).not.toBeNull();
|
|
||||||
},
|
|
||||||
100000
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('parseVersion', () => {
|
describe('parseVersion', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
['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.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||||
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2']
|
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'],
|
||||||
|
['github.com/docker/buildx f117971 f11797113e5a9b86bd976329c5dbb8a8bfdfadfa', 'f117971']
|
||||||
])('given %p', async (stdout, expected) => {
|
])('given %p', async (stdout, expected) => {
|
||||||
expect(await buildx.parseVersion(stdout)).toEqual(expected);
|
expect(buildx.parseVersion(stdout)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('satisfies', () => {
|
||||||
|
test.each([
|
||||||
|
['0.4.1', '>=0.3.2', true],
|
||||||
|
['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false],
|
||||||
|
['f117971', '>0.6.0', true]
|
||||||
|
])('given %p', async (version, range, expected) => {
|
||||||
|
expect(buildx.satisfies(version, range)).toBe(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getSecret', () => {
|
describe('getSecret', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['A_SECRET=abcdef0123456789', 'A_SECRET', 'abcdef0123456789', false],
|
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', false],
|
||||||
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false],
|
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false],
|
||||||
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false],
|
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', false, 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false],
|
||||||
['aaaaaaaa', '', '', true],
|
['aaaaaaaa', false, '', '', true],
|
||||||
['aaaaaaaa=', '', '', true],
|
['aaaaaaaa=', false, '', '', true],
|
||||||
['=bbbbbbb', '', '', true]
|
['=bbbbbbb', false, '', '', true],
|
||||||
])('given %p key and %p secret', async (kvp, key, secret, invalid) => {
|
[`foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`, true, 'foo', 'bar', false],
|
||||||
|
[`notfound=secret`, true, '', '', true]
|
||||||
|
])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => {
|
||||||
try {
|
try {
|
||||||
const secretArgs = await buildx.getSecret(kvp);
|
let secret: string;
|
||||||
|
if (file) {
|
||||||
|
secret = await buildx.getSecretFile(kvp);
|
||||||
|
} else {
|
||||||
|
secret = await buildx.getSecretString(kvp);
|
||||||
|
}
|
||||||
expect(true).toBe(!invalid);
|
expect(true).toBe(!invalid);
|
||||||
console.log(`secretArgs: ${secretArgs}`);
|
expect(secret).toEqual(`id=${exKey},src=${tmpNameSync}`);
|
||||||
expect(secretArgs).toEqual(`id=${key},src=${tmpNameSync}`);
|
expect(fs.readFileSync(tmpNameSync, 'utf-8')).toEqual(exValue);
|
||||||
const secretContent = await fs.readFileSync(tmpNameSync, 'utf-8');
|
|
||||||
console.log(`secretValue: ${secretContent}`);
|
|
||||||
expect(secretContent).toEqual(secret);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line jest/no-conditional-expect
|
||||||
expect(true).toBe(invalid);
|
expect(true).toBe(invalid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
|
import * as buildx from '../src/buildx';
|
||||||
import * as context from '../src/context';
|
import * as context from '../src/context';
|
||||||
|
|
||||||
const pgp = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
const pgp = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
@ -111,7 +113,7 @@ PejgXO0uIRolYQ3sz2tMGhx1MfBqH64=
|
|||||||
-----END PGP PRIVATE KEY BLOCK-----`;
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||||
|
|
||||||
jest.spyOn(context, 'defaultContext').mockImplementation((): string => {
|
jest.spyOn(context, 'defaultContext').mockImplementation((): string => {
|
||||||
return 'https://github.com/docker/build-push-action.git#test-jest';
|
return 'https://github.com/docker/build-push-action.git#refs/heads/test-jest';
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||||
@ -126,6 +128,8 @@ jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
|
|||||||
return path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
return path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.spyOn(buildx, 'satisfiesBuildKitVersion').mockResolvedValueOnce(true);
|
||||||
|
|
||||||
describe('getArgs', () => {
|
describe('getArgs', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
process.env = Object.keys(process.env).reduce((object, key) => {
|
process.env = Object.keys(process.env).reduce((object, key) => {
|
||||||
@ -139,149 +143,182 @@ describe('getArgs', () => {
|
|||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
test.each([
|
test.each([
|
||||||
[
|
[
|
||||||
|
0,
|
||||||
'0.4.1',
|
'0.4.1',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--file', 'Dockerfile',
|
|
||||||
'.'
|
'.'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
1,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['build-args', 'MY_ARG=val1,val2,val3\nARG=val'],
|
['build-args', `MY_ARG=val1,val2,val3
|
||||||
|
ARG=val
|
||||||
|
"MULTILINE=aaaa
|
||||||
|
bbbb
|
||||||
|
ccc"`],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--build-arg', 'MY_ARG=val1,val2,val3',
|
'--build-arg', 'MY_ARG=val1,val2,val3',
|
||||||
'--build-arg', 'ARG=val',
|
'--build-arg', 'ARG=val',
|
||||||
|
'--build-arg', `MULTILINE=aaaa\nbbbb\nccc`,
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--file', 'Dockerfile',
|
'https://github.com/docker/build-push-action.git#refs/heads/test-jest'
|
||||||
'https://github.com/docker/build-push-action.git#test-jest'
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
2,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['tags', 'name/app:7.4, name/app:latest'],
|
['tags', 'name/app:7.4, name/app:latest'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--tag', 'name/app:7.4',
|
'--tag', 'name/app:7.4',
|
||||||
'--tag', 'name/app:latest',
|
'--tag', 'name/app:latest',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'https://github.com/docker/build-push-action.git#refs/heads/test-jest'
|
||||||
'--file', 'Dockerfile',
|
|
||||||
'https://github.com/docker/build-push-action.git#test-jest'
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
3,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['labels', 'org.opencontainers.image.title=buildkit\norg.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit'],
|
['labels', 'org.opencontainers.image.title=buildkit\norg.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit'],
|
||||||
['outputs', 'type=local,dest=./release-out']
|
['outputs', 'type=local,dest=./release-out'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--label', 'org.opencontainers.image.title=buildkit',
|
'--label', 'org.opencontainers.image.title=buildkit',
|
||||||
'--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit',
|
'--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit',
|
||||||
'--output', 'type=local,dest=./release-out',
|
'--output', 'type=local,dest=./release-out',
|
||||||
'--file', 'Dockerfile',
|
|
||||||
'.'
|
'.'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
4,
|
||||||
'0.4.1',
|
'0.4.1',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['platforms', 'linux/amd64,linux/arm64']
|
['platforms', 'linux/amd64,linux/arm64'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--platform', 'linux/amd64,linux/arm64',
|
'--platform', 'linux/amd64,linux/arm64',
|
||||||
'--file', 'Dockerfile',
|
|
||||||
'.'
|
'.'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
5,
|
||||||
'0.4.1',
|
'0.4.1',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.']
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--file', 'Dockerfile',
|
|
||||||
'.'
|
'.'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
6,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--file', 'Dockerfile',
|
|
||||||
'.'
|
'.'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
7,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['github-token', 'abcdefghijklmno0123456789'],
|
['github-token', 'abcdefghijklmno0123456789'],
|
||||||
['outputs', '.']
|
['outputs', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--output', '.',
|
'--output', '.',
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--file', 'Dockerfile',
|
'https://github.com/docker/build-push-action.git#refs/heads/test-jest'
|
||||||
'https://github.com/docker/build-push-action.git#test-jest'
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
8,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', 'https://github.com/docker/build-push-action.git#heads/master'],
|
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||||
['tag', 'localhost:5000/name/app:latest'],
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
['platforms', 'linux/amd64,linux/arm64'],
|
['platforms', 'linux/amd64,linux/arm64'],
|
||||||
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--platform', 'linux/amd64,linux/arm64',
|
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
|
||||||
'--file', './test/Dockerfile',
|
'--file', './test/Dockerfile',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--platform', 'linux/amd64,linux/arm64',
|
||||||
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--builder', 'builder-git-context-2',
|
'--builder', 'builder-git-context-2',
|
||||||
'--push',
|
'--push',
|
||||||
'https://github.com/docker/build-push-action.git#heads/master'
|
'https://github.com/docker/build-push-action.git#refs/heads/master'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
9,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', 'https://github.com/docker/build-push-action.git#heads/master'],
|
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||||
['tag', 'localhost:5000/name/app:latest'],
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
['platforms', 'linux/amd64,linux/arm64'],
|
['platforms', 'linux/amd64,linux/arm64'],
|
||||||
['secrets', `GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
['secrets', `GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
||||||
@ -295,27 +332,30 @@ bbbb
|
|||||||
ccc"`],
|
ccc"`],
|
||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--platform', 'linux/amd64,linux/arm64',
|
'--file', './test/Dockerfile',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--platform', 'linux/amd64,linux/arm64',
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--secret', 'id=MYSECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=MYSECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--secret', 'id=FOO,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=FOO,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--secret', 'id=EMPTYLINE,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=EMPTYLINE,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--file', './test/Dockerfile',
|
|
||||||
'--builder', 'builder-git-context-2',
|
'--builder', 'builder-git-context-2',
|
||||||
'--push',
|
'--push',
|
||||||
'https://github.com/docker/build-push-action.git#heads/master'
|
'https://github.com/docker/build-push-action.git#refs/heads/master'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
10,
|
||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', 'https://github.com/docker/build-push-action.git#heads/master'],
|
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||||
['tag', 'localhost:5000/name/app:latest'],
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
['platforms', 'linux/amd64,linux/arm64'],
|
['platforms', 'linux/amd64,linux/arm64'],
|
||||||
['secrets', `GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
['secrets', `GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
||||||
@ -329,34 +369,321 @@ bbbb
|
|||||||
ccc`],
|
ccc`],
|
||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false'],
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
|
||||||
'build',
|
'build',
|
||||||
'--platform', 'linux/amd64,linux/arm64',
|
'--file', './test/Dockerfile',
|
||||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--platform', 'linux/amd64,linux/arm64',
|
||||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--secret', 'id=MYSECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=MYSECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--secret', 'id=FOO,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=FOO,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--secret', 'id=EMPTYLINE,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
'--secret', 'id=EMPTYLINE,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
'--file', './test/Dockerfile',
|
|
||||||
'--builder', 'builder-git-context-2',
|
'--builder', 'builder-git-context-2',
|
||||||
'--push',
|
'--push',
|
||||||
'https://github.com/docker/build-push-action.git#heads/master'
|
'https://github.com/docker/build-push-action.git#refs/heads/master'
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
11,
|
||||||
|
'0.5.1',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||||
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
|
['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`],
|
||||||
|
['file', './test/Dockerfile'],
|
||||||
|
['builder', 'builder-git-context-2'],
|
||||||
|
['network', 'host'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--file', './test/Dockerfile',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--secret', 'id=MY_SECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
|
'--builder', 'builder-git-context-2',
|
||||||
|
'--network', 'host',
|
||||||
|
'--push',
|
||||||
|
'https://github.com/docker/build-push-action.git#refs/heads/master'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
12,
|
||||||
|
'0.4.2',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['labels', 'org.opencontainers.image.title=filter_results_top_n\norg.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"'],
|
||||||
|
['outputs', 'type=local,dest=./release-out'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--label', 'org.opencontainers.image.title=filter_results_top_n',
|
||||||
|
'--label', 'org.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"',
|
||||||
|
'--output', 'type=local,dest=./release-out',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
13,
|
||||||
|
'0.6.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
|
['file', './test/Dockerfile'],
|
||||||
|
['add-hosts', 'docker:10.180.0.1,foo:10.0.0.1'],
|
||||||
|
['network', 'host'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--add-host', 'docker:10.180.0.1',
|
||||||
|
'--add-host', 'foo:10.0.0.1',
|
||||||
|
'--file', './test/Dockerfile',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'--network', 'host',
|
||||||
|
'--push',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
14,
|
||||||
|
'0.7.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['file', './test/Dockerfile'],
|
||||||
|
['add-hosts', 'docker:10.180.0.1\nfoo:10.0.0.1'],
|
||||||
|
['cgroup-parent', 'foo'],
|
||||||
|
['shm-size', '2g'],
|
||||||
|
['ulimit', `nofile=1024:1024
|
||||||
|
nproc=3`],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--add-host', 'docker:10.180.0.1',
|
||||||
|
'--add-host', 'foo:10.0.0.1',
|
||||||
|
'--cgroup-parent', 'foo',
|
||||||
|
'--file', './test/Dockerfile',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--shm-size', '2g',
|
||||||
|
'--ulimit', 'nofile=1024:1024',
|
||||||
|
'--ulimit', 'nproc=3',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
15,
|
||||||
|
'0.7.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '{{defaultContext}}:docker'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'https://github.com/docker/build-push-action.git#refs/heads/test-jest:docker'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
16,
|
||||||
|
'0.8.2',
|
||||||
|
new Map<string, string>([
|
||||||
|
['github-token', 'abcdefghijklmno0123456789'],
|
||||||
|
['context', '{{defaultContext}}:subdir'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'https://github.com/docker/build-push-action.git#refs/heads/test-jest:subdir'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
17,
|
||||||
|
'0.8.2',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
['provenance', 'true'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
18,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--provenance", 'false',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
19,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
['provenance', 'true'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--provenance", `builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
20,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
['provenance', 'mode=max'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--provenance", `mode=max,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`,
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
21,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
['provenance', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--provenance", 'false',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
22,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
['provenance', 'builder-id=foo'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--provenance", 'builder-id=foo',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
23,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
['outputs', 'type=docker'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--output", 'type=docker',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
24,
|
||||||
|
'0.10.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['load', 'true'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false'],
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
"--load",
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
])(
|
])(
|
||||||
'given %p with %p as inputs, returns %p',
|
'[%d] given %p with %p as inputs, returns %p',
|
||||||
async (buildxVersion: string, inputs: Map<string, any>, expected: Array<string>) => {
|
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
|
||||||
await inputs.forEach((value: string, name: string) => {
|
inputs.forEach((value: string, name: string) => {
|
||||||
setInput(name, value);
|
setInput(name, value);
|
||||||
});
|
});
|
||||||
const defContext = context.defaultContext();
|
const defContext = context.defaultContext();
|
||||||
const inp = await context.getInputs(defContext);
|
const inp = await context.getInputs(defContext);
|
||||||
console.log(inp);
|
|
||||||
const res = await context.getArgs(inp, defContext, buildxVersion);
|
const res = await context.getArgs(inp, defContext, buildxVersion);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(expected);
|
expect(res).toEqual(expected);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -366,63 +693,54 @@ describe('getInputList', () => {
|
|||||||
it('single line correctly', async () => {
|
it('single line correctly', async () => {
|
||||||
await setInput('foo', 'bar');
|
await setInput('foo', 'bar');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar']);
|
expect(res).toEqual(['bar']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiline correctly', async () => {
|
it('multiline correctly', async () => {
|
||||||
setInput('foo', 'bar\nbaz');
|
setInput('foo', 'bar\nbaz');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar', 'baz']);
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('empty lines correctly', async () => {
|
it('empty lines correctly', async () => {
|
||||||
setInput('foo', 'bar\n\nbaz');
|
setInput('foo', 'bar\n\nbaz');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar', 'baz']);
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('comma correctly', async () => {
|
it('comma correctly', async () => {
|
||||||
setInput('foo', 'bar,baz');
|
setInput('foo', 'bar,baz');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar', 'baz']);
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('empty result correctly', async () => {
|
it('empty result correctly', async () => {
|
||||||
setInput('foo', 'bar,baz,');
|
setInput('foo', 'bar,baz,');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar', 'baz']);
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('different new lines correctly', async () => {
|
it('different new lines correctly', async () => {
|
||||||
setInput('foo', 'bar\r\nbaz');
|
setInput('foo', 'bar\r\nbaz');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar', 'baz']);
|
expect(res).toEqual(['bar', 'baz']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('different new lines and comma correctly', async () => {
|
it('different new lines and comma correctly', async () => {
|
||||||
setInput('foo', 'bar\r\nbaz,bat');
|
setInput('foo', 'bar\r\nbaz,bat');
|
||||||
const res = await context.getInputList('foo');
|
const res = await context.getInputList('foo');
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['bar', 'baz', 'bat']);
|
expect(res).toEqual(['bar', 'baz', 'bat']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiline and ignoring comma correctly', async () => {
|
it('multiline and ignoring comma correctly', async () => {
|
||||||
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
||||||
const res = await context.getInputList('cache-from', true);
|
const res = await context.getInputList('cache-from', true);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('different new lines and ignoring comma correctly', async () => {
|
it('different new lines and ignoring comma correctly', async () => {
|
||||||
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
||||||
const res = await context.getInputList('cache-from', true);
|
const res = await context.getInputList('cache-from', true);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -436,7 +754,6 @@ ccccccccc"
|
|||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = await context.getInputList('secrets', true);
|
const res = await context.getInputList('secrets', true);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual([
|
expect(res).toEqual([
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||||
`MYSECRET=aaaaaaaa
|
`MYSECRET=aaaaaaaa
|
||||||
@ -460,7 +777,6 @@ bbbb
|
|||||||
ccc"`
|
ccc"`
|
||||||
);
|
);
|
||||||
const res = await context.getInputList('secrets', true);
|
const res = await context.getInputList('secrets', true);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual([
|
expect(res).toEqual([
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||||
`MYSECRET=aaaaaaaa
|
`MYSECRET=aaaaaaaa
|
||||||
@ -484,14 +800,7 @@ ccccccccc
|
|||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = await context.getInputList('secrets', true);
|
const res = await context.getInputList('secrets', true);
|
||||||
console.log(res);
|
expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']);
|
||||||
expect(res).toEqual([
|
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
|
||||||
'MYSECRET=aaaaaaaa',
|
|
||||||
'bbbbbbb',
|
|
||||||
'ccccccccc',
|
|
||||||
'FOO=bar'
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('large multiline values', async () => {
|
it('large multiline values', async () => {
|
||||||
@ -501,7 +810,6 @@ FOO=bar`
|
|||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = await context.getInputList('secrets', true);
|
const res = await context.getInputList('secrets', true);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']);
|
expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -515,11 +823,10 @@ ccccccccc"
|
|||||||
FOO=bar`
|
FOO=bar`
|
||||||
);
|
);
|
||||||
const res = await context.getInputList('secrets', true);
|
const res = await context.getInputList('secrets', true);
|
||||||
console.log(res);
|
|
||||||
expect(res).toEqual([
|
expect(res).toEqual([
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||||
`MYSECRET=aaaaaaaa
|
`MYSECRET=aaaaaaaa
|
||||||
bbbb\"bbb
|
bbbb"bbb
|
||||||
ccccccccc`,
|
ccccccccc`,
|
||||||
'FOO=bar'
|
'FOO=bar'
|
||||||
]);
|
]);
|
||||||
@ -539,7 +846,7 @@ describe('asyncForEach', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
|
// See: https://github.com/actions/toolkit/blob/a1b068ec31a042ff1e10a522d8fdf0b8869d53ca/packages/core/src/core.ts#L89
|
||||||
function getInputName(name: string): string {
|
function getInputName(name: string): string {
|
||||||
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
|
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
|
||||||
}
|
}
|
||||||
|
16
__tests__/docker.test.ts
Normal file
16
__tests__/docker.test.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {describe, expect, it, jest} from '@jest/globals';
|
||||||
|
import * as docker from '../src/docker';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
describe('isAvailable', () => {
|
||||||
|
it('cli', () => {
|
||||||
|
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
docker.isAvailable();
|
||||||
|
|
||||||
|
// eslint-disable-next-line jest/no-standalone-expect
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`docker`, undefined, {
|
||||||
|
silent: true,
|
||||||
|
ignoreReturnCode: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
1
__tests__/fixtures/secret.txt
Normal file
1
__tests__/fixtures/secret.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
bar
|
96
action.yml
96
action.yml
@ -7,75 +7,111 @@ branding:
|
|||||||
color: 'blue'
|
color: 'blue'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
|
add-hosts:
|
||||||
|
description: "List of a customs host-to-IP mapping (e.g., docker:10.180.0.1)"
|
||||||
|
required: false
|
||||||
|
allow:
|
||||||
|
description: "List of extra privileged entitlement (e.g., network.host,security.insecure)"
|
||||||
|
required: false
|
||||||
|
attests:
|
||||||
|
description: "List of attestation parameters (e.g., type=sbom,generator=image)"
|
||||||
|
required: false
|
||||||
|
build-args:
|
||||||
|
description: "List of build-time variables"
|
||||||
|
required: false
|
||||||
|
build-contexts:
|
||||||
|
description: "List of additional build contexts (e.g., name=path)"
|
||||||
|
required: false
|
||||||
builder:
|
builder:
|
||||||
description: "Builder instance"
|
description: "Builder instance"
|
||||||
required: false
|
required: false
|
||||||
|
cache-from:
|
||||||
|
description: "List of external cache sources for buildx (e.g., user/app:cache, type=local,src=path/to/dir)"
|
||||||
|
required: false
|
||||||
|
cache-to:
|
||||||
|
description: "List of cache export destinations for buildx (e.g., user/app:cache, type=local,dest=path/to/dir)"
|
||||||
|
required: false
|
||||||
|
cgroup-parent:
|
||||||
|
description: "Optional parent cgroup for the container used in the build"
|
||||||
|
required: false
|
||||||
context:
|
context:
|
||||||
description: "Build's context is the set of files located in the specified PATH or URL"
|
description: "Build's context is the set of files located in the specified PATH or URL"
|
||||||
required: false
|
required: false
|
||||||
file:
|
file:
|
||||||
description: "Path to the Dockerfile"
|
description: "Path to the Dockerfile"
|
||||||
required: false
|
required: false
|
||||||
default: './Dockerfile'
|
|
||||||
build-args:
|
|
||||||
description: "List of build-time variables"
|
|
||||||
required: false
|
|
||||||
labels:
|
labels:
|
||||||
description: "List of metadata for an image"
|
description: "List of metadata for an image"
|
||||||
required: false
|
required: false
|
||||||
tags:
|
load:
|
||||||
description: "List of tags"
|
description: "Load is a shorthand for --output=type=docker"
|
||||||
required: false
|
|
||||||
pull:
|
|
||||||
description: "Always attempt to pull a newer version of the image"
|
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
target:
|
network:
|
||||||
description: "Sets the target stage to build"
|
description: "Set the networking mode for the RUN instructions during build"
|
||||||
required: false
|
|
||||||
allow:
|
|
||||||
description: "List of extra privileged entitlement (eg. network.host,security.insecure)"
|
|
||||||
required: false
|
required: false
|
||||||
no-cache:
|
no-cache:
|
||||||
description: "Do not use cache when building the image"
|
description: "Do not use cache when building the image"
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
|
no-cache-filters:
|
||||||
|
description: "Do not cache specified stages"
|
||||||
|
required: false
|
||||||
|
outputs:
|
||||||
|
description: "List of output destinations (format: type=local,dest=path)"
|
||||||
|
required: false
|
||||||
platforms:
|
platforms:
|
||||||
description: "List of target platforms for build"
|
description: "List of target platforms for build"
|
||||||
required: false
|
required: false
|
||||||
load:
|
provenance:
|
||||||
description: "Load is a shorthand for --output=type=docker"
|
description: "Generate provenance attestation for the build (shorthand for --attest=type=provenance)"
|
||||||
|
required: false
|
||||||
|
pull:
|
||||||
|
description: "Always attempt to pull all referenced images"
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
push:
|
push:
|
||||||
description: "Push is a shorthand for --output=type=registry"
|
description: "Push is a shorthand for --output=type=registry"
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
outputs:
|
sbom:
|
||||||
description: "List of output destinations (format: type=local,dest=path)"
|
description: "Generate SBOM attestation for the build (shorthand for --attest=type=sbom)"
|
||||||
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
|
required: false
|
||||||
secrets:
|
secrets:
|
||||||
description: "List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)"
|
description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)"
|
||||||
|
required: false
|
||||||
|
secret-files:
|
||||||
|
description: "List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt)"
|
||||||
|
required: false
|
||||||
|
shm-size:
|
||||||
|
description: "Size of /dev/shm (e.g., 2g)"
|
||||||
|
required: false
|
||||||
|
ssh:
|
||||||
|
description: "List of SSH agent socket or keys to expose to the build"
|
||||||
|
required: false
|
||||||
|
tags:
|
||||||
|
description: "List of tags"
|
||||||
|
required: false
|
||||||
|
target:
|
||||||
|
description: "Sets the target stage to build"
|
||||||
|
required: false
|
||||||
|
ulimit:
|
||||||
|
description: "Ulimit options (e.g., nofile=1024:1024)"
|
||||||
required: false
|
required: false
|
||||||
github-token:
|
github-token:
|
||||||
description: "GitHub Token used to authenticate against a repository for Git context"
|
description: "GitHub Token used to authenticate against a repository for Git context"
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
required: false
|
required: false
|
||||||
ssh:
|
|
||||||
description: "List of SSH agent socket or keys to expose to the build"
|
|
||||||
required: false
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
|
imageid:
|
||||||
|
description: 'Image ID'
|
||||||
digest:
|
digest:
|
||||||
description: 'Image content-addressable identifier also called a digest'
|
description: 'Image digest'
|
||||||
|
metadata:
|
||||||
|
description: 'Build result metadata'
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
post: 'dist/index.js'
|
post: 'dist/index.js'
|
||||||
|
3
codecov.yml
Normal file
3
codecov.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
comment: false
|
||||||
|
github_checks:
|
||||||
|
annotations: false
|
76
dev.Dockerfile
Normal file
76
dev.Dockerfile
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
ARG NODE_VERSION=16
|
||||||
|
ARG DOCKER_VERSION=20.10.13
|
||||||
|
ARG BUILDX_VERSION=0.8.0
|
||||||
|
|
||||||
|
FROM node:${NODE_VERSION}-alpine AS base
|
||||||
|
RUN apk add --no-cache cpio findutils git
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
FROM base AS deps
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=type=cache,target=/src/node_modules \
|
||||||
|
yarn install && mkdir /vendor && cp yarn.lock /vendor
|
||||||
|
|
||||||
|
FROM scratch AS vendor-update
|
||||||
|
COPY --from=deps /vendor /
|
||||||
|
|
||||||
|
FROM deps AS vendor-validate
|
||||||
|
RUN --mount=type=bind,target=.,rw <<EOT
|
||||||
|
set -e
|
||||||
|
git add -A
|
||||||
|
cp -rf /vendor/* .
|
||||||
|
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
|
||||||
|
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
|
||||||
|
git status --porcelain -- yarn.lock
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOT
|
||||||
|
|
||||||
|
FROM deps AS build
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=type=cache,target=/src/node_modules \
|
||||||
|
yarn run build && mkdir /out && cp -Rf dist /out/
|
||||||
|
|
||||||
|
FROM scratch AS build-update
|
||||||
|
COPY --from=build /out /
|
||||||
|
|
||||||
|
FROM build AS build-validate
|
||||||
|
RUN --mount=type=bind,target=.,rw <<EOT
|
||||||
|
set -e
|
||||||
|
git add -A
|
||||||
|
cp -rf /out/* .
|
||||||
|
if [ -n "$(git status --porcelain -- dist)" ]; then
|
||||||
|
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
|
||||||
|
git status --porcelain -- dist
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOT
|
||||||
|
|
||||||
|
FROM deps AS format
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=type=cache,target=/src/node_modules \
|
||||||
|
yarn run format \
|
||||||
|
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
|
||||||
|
|
||||||
|
FROM scratch AS format-update
|
||||||
|
COPY --from=format /out /
|
||||||
|
|
||||||
|
FROM deps AS lint
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=type=cache,target=/src/node_modules \
|
||||||
|
yarn run lint
|
||||||
|
|
||||||
|
FROM docker:${DOCKER_VERSION} as docker
|
||||||
|
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||||
|
|
||||||
|
FROM deps AS test
|
||||||
|
RUN --mount=type=bind,target=.,rw \
|
||||||
|
--mount=type=cache,target=/src/node_modules \
|
||||||
|
--mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
||||||
|
--mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
||||||
|
yarn run test --coverageDirectory=/tmp/coverage
|
||||||
|
|
||||||
|
FROM scratch AS test-coverage
|
||||||
|
COPY --from=test /tmp/coverage /
|
16492
dist/index.js
generated
vendored
16492
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
1
dist/index.js.map
generated
vendored
Normal file
1
dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1083
dist/licenses.txt
generated
vendored
Normal file
1083
dist/licenses.txt
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/sourcemap-register.js
generated
vendored
Normal file
1
dist/sourcemap-register.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -3,40 +3,51 @@ group "default" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group "pre-checkin" {
|
group "pre-checkin" {
|
||||||
targets = ["update-yarn", "format", "build"]
|
targets = ["vendor-update", "format", "build"]
|
||||||
}
|
}
|
||||||
|
|
||||||
group "validate" {
|
group "validate" {
|
||||||
targets = ["validate-format", "validate-build", "validate-yarn"]
|
targets = ["lint", "build-validate", "vendor-validate"]
|
||||||
}
|
|
||||||
|
|
||||||
target "update-yarn" {
|
|
||||||
target = "update-yarn"
|
|
||||||
output = ["."]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target "build" {
|
target "build" {
|
||||||
target = "dist"
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "build-update"
|
||||||
output = ["."]
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "test" {
|
target "build-validate" {
|
||||||
target = "test"
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "build-validate"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "format" {
|
target "format" {
|
||||||
target = "format"
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "format-update"
|
||||||
output = ["."]
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "validate-format" {
|
target "lint" {
|
||||||
target = "validate-format"
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "lint"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "validate-build" {
|
target "vendor-update" {
|
||||||
target = "validate-build"
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "vendor-update"
|
||||||
|
output = ["."]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "validate-yarn" {
|
target "vendor-validate" {
|
||||||
target = "validate-yarn"
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "vendor-validate"
|
||||||
|
output = ["type=cacheonly"]
|
||||||
|
}
|
||||||
|
|
||||||
|
target "test" {
|
||||||
|
dockerfile = "dev.Dockerfile"
|
||||||
|
target = "test-coverage"
|
||||||
|
output = ["./coverage"]
|
||||||
}
|
}
|
||||||
|
3
docs/advanced/cache.md
Normal file
3
docs/advanced/cache.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Cache
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#cache)
|
3
docs/advanced/copy-between-registries.md
Normal file
3
docs/advanced/copy-between-registries.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Copy images between registries
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#copy-images-between-registries)
|
3
docs/advanced/dockerhub-desc.md
Normal file
3
docs/advanced/dockerhub-desc.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Update Docker Hub repo description
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#update-docker-hub-repository-description)
|
3
docs/advanced/export-docker.md
Normal file
3
docs/advanced/export-docker.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Export image to Docker
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#export-image-to-docker)
|
3
docs/advanced/isolated-builders.md
Normal file
3
docs/advanced/isolated-builders.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Isolated builders
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/configure-builder/#isolated-builders)
|
3
docs/advanced/local-registry.md
Normal file
3
docs/advanced/local-registry.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Local registry
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#local-registry)
|
3
docs/advanced/multi-platform.md
Normal file
3
docs/advanced/multi-platform.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Multi-platform image
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#multi-platform-images)
|
3
docs/advanced/named-contexts.md
Normal file
3
docs/advanced/named-contexts.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Named contexts
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#named-contexts)
|
3
docs/advanced/push-multi-registries.md
Normal file
3
docs/advanced/push-multi-registries.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Push to multi-registries
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#push-to-multi-registries)
|
3
docs/advanced/secrets.md
Normal file
3
docs/advanced/secrets.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Secrets
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#secrets)
|
3
docs/advanced/share-image-jobs.md
Normal file
3
docs/advanced/share-image-jobs.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Share built image between jobs
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#share-built-image-between-jobs)
|
3
docs/advanced/tags-labels.md
Normal file
3
docs/advanced/tags-labels.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Handle tags and labels
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#manage-tags-and-labels)
|
3
docs/advanced/test-before-push.md
Normal file
3
docs/advanced/test-before-push.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Test your image before pushing it
|
||||||
|
|
||||||
|
This page has moved to [Docker Docs website](https://docs.docker.com/build/ci/github-actions/examples/#test-your-image-before-pushing-it)
|
@ -1,12 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
clearMocks: false,
|
|
||||||
moduleFileExtensions: ['js', 'ts'],
|
|
||||||
setupFiles: ["dotenv/config"],
|
|
||||||
testEnvironment: 'node',
|
|
||||||
testMatch: ['**/*.test.ts'],
|
|
||||||
testRunner: 'jest-circus/runner',
|
|
||||||
transform: {
|
|
||||||
'^.+\\.ts$': 'ts-jest'
|
|
||||||
},
|
|
||||||
verbose: false
|
|
||||||
}
|
|
23
jest.config.ts
Normal file
23
jest.config.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
process.env = Object.assign({}, process.env, {
|
||||||
|
RUNNER_TEMP: '/tmp/github_runner',
|
||||||
|
RUNNER_TOOL_CACHE: '/tmp/github_tool_cache',
|
||||||
|
GITHUB_REPOSITORY: 'docker/build-push-action',
|
||||||
|
GITHUB_RUN_ID: '123456789'
|
||||||
|
}) as {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
clearMocks: false,
|
||||||
|
testEnvironment: 'node',
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
setupFiles: ['dotenv/config'],
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
};
|
48
package.json
48
package.json
@ -3,11 +3,11 @@
|
|||||||
"description": "Build and push Docker images",
|
"description": "Build and push Docker images",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && ncc build",
|
"build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
|
||||||
"format": "prettier --write **/*.ts",
|
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
|
||||||
"test": "jest --coverage",
|
"test": "jest --coverage",
|
||||||
"pre-checkin": "yarn run format && yarn run build"
|
"all": "yarn run build && yarn run format && yarn test"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -28,26 +28,32 @@
|
|||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.0.4",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^4.0.0",
|
"@actions/github": "^5.1.1",
|
||||||
"csv-parse": "^4.14.1",
|
"csv-parse": "^5.3.3",
|
||||||
"semver": "^7.3.4",
|
"handlebars": "^4.7.7",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
|
"semver": "^7.3.7",
|
||||||
"tmp": "^0.2.1"
|
"tmp": "^0.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/csv-parse": "^1.2.2",
|
"@types/csv-parse": "^1.2.2",
|
||||||
"@types/jest": "^26.0.3",
|
"@types/node": "^16.11.26",
|
||||||
"@types/node": "^14.0.14",
|
"@types/semver": "^7.3.9",
|
||||||
"@types/tmp": "^0.2.0",
|
"@types/tmp": "^0.2.3",
|
||||||
"@vercel/ncc": "^0.23.0",
|
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||||
"dotenv": "^8.2.0",
|
"@typescript-eslint/parser": "^5.14.0",
|
||||||
"jest": "^26.1.0",
|
"@vercel/ncc": "^0.33.3",
|
||||||
"jest-circus": "^26.1.0",
|
"dotenv": "^16.0.0",
|
||||||
"jest-runtime": "^26.1.0",
|
"eslint": "^8.11.0",
|
||||||
"prettier": "^2.0.5",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"ts-jest": "^26.1.1",
|
"eslint-plugin-jest": "^26.1.1",
|
||||||
"typescript": "^3.9.5",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"typescript-formatter": "^7.2.2"
|
"jest": "^27.2.5",
|
||||||
|
"prettier": "^2.3.1",
|
||||||
|
"ts-jest": "^27.1.2",
|
||||||
|
"ts-node": "^10.7.0",
|
||||||
|
"typescript": "^4.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
259
src/buildx.ts
259
src/buildx.ts
@ -1,10 +1,25 @@
|
|||||||
import csvparse from 'csv-parse/lib/sync';
|
import {parse} from 'csv-parse/sync';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
import * as context from './context';
|
import * as context from './context';
|
||||||
import * as exec from './exec';
|
|
||||||
|
export type Builder = {
|
||||||
|
name?: string;
|
||||||
|
driver?: string;
|
||||||
|
nodes: Node[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Node = {
|
||||||
|
name?: string;
|
||||||
|
endpoint?: string;
|
||||||
|
'driver-opts'?: Array<string>;
|
||||||
|
status?: string;
|
||||||
|
'buildkitd-flags'?: string;
|
||||||
|
buildkit?: string;
|
||||||
|
platforms?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export async function getImageIDFile(): Promise<string> {
|
export async function getImageIDFile(): Promise<string> {
|
||||||
return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
|
return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
|
||||||
@ -15,36 +30,81 @@ export async function getImageID(): Promise<string | undefined> {
|
|||||||
if (!fs.existsSync(iidFile)) {
|
if (!fs.existsSync(iidFile)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSecret(kvp: string): Promise<string> {
|
export async function getMetadataFile(): Promise<string> {
|
||||||
|
return path.join(context.tmpDir(), 'metadata-file').split(path.sep).join(path.posix.sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMetadata(): Promise<string | undefined> {
|
||||||
|
const metadataFile = await getMetadataFile();
|
||||||
|
if (!fs.existsSync(metadataFile)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const content = fs.readFileSync(metadataFile, {encoding: 'utf-8'}).trim();
|
||||||
|
if (content === 'null') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDigest(metadata: string | undefined): Promise<string | undefined> {
|
||||||
|
if (metadata === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const metadataJSON = JSON.parse(metadata);
|
||||||
|
if (metadataJSON['containerimage.digest']) {
|
||||||
|
return metadataJSON['containerimage.digest'];
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSecretString(kvp: string): Promise<string> {
|
||||||
|
return getSecret(kvp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSecretFile(kvp: string): Promise<string> {
|
||||||
|
return getSecret(kvp, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSecret(kvp: string, file: boolean): Promise<string> {
|
||||||
const delimiterIndex = kvp.indexOf('=');
|
const delimiterIndex = kvp.indexOf('=');
|
||||||
const key = kvp.substring(0, delimiterIndex);
|
const key = kvp.substring(0, delimiterIndex);
|
||||||
const value = kvp.substring(delimiterIndex + 1);
|
let value = kvp.substring(delimiterIndex + 1);
|
||||||
if (key.length == 0 || value.length == 0) {
|
if (key.length == 0 || value.length == 0) {
|
||||||
throw new Error(`${kvp} is not a valid secret`);
|
throw new Error(`${kvp} is not a valid secret`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
if (!fs.existsSync(value)) {
|
||||||
|
throw new Error(`secret file ${value} not found`);
|
||||||
|
}
|
||||||
|
value = fs.readFileSync(value, {encoding: 'utf-8'});
|
||||||
|
}
|
||||||
|
|
||||||
const secretFile = context.tmpNameSync({
|
const secretFile = context.tmpNameSync({
|
||||||
tmpdir: context.tmpDir()
|
tmpdir: context.tmpDir()
|
||||||
});
|
});
|
||||||
await fs.writeFileSync(secretFile, value);
|
fs.writeFileSync(secretFile, value);
|
||||||
|
|
||||||
return `id=${key},src=${secretFile}`;
|
return `id=${key},src=${secretFile}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLocalOrTarExporter(outputs: string[]): Boolean {
|
export function isLocalOrTarExporter(outputs: string[]): boolean {
|
||||||
for (let output of csvparse(outputs.join(`\n`), {
|
const records = parse(outputs.join(`\n`), {
|
||||||
delimiter: ',',
|
delimiter: ',',
|
||||||
trim: true,
|
trim: true,
|
||||||
columns: false,
|
columns: false,
|
||||||
relaxColumnCount: true
|
relaxColumnCount: true
|
||||||
})) {
|
});
|
||||||
|
for (const record of records) {
|
||||||
// Local if no type is defined
|
// Local if no type is defined
|
||||||
// https://github.com/docker/buildx/blob/d2bf42f8b4784d83fde17acb3ed84703ddc2156b/build/output.go#L29-L43
|
// https://github.com/docker/buildx/blob/d2bf42f8b4784d83fde17acb3ed84703ddc2156b/build/output.go#L29-L43
|
||||||
if (output.length == 1 && !output[0].startsWith('type=')) {
|
if (record.length == 1 && !record[0].startsWith('type=')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (let [key, value] of output.map(chunk => chunk.split('=').map(item => item.trim()))) {
|
for (const [key, value] of record.map(chunk => chunk.split('=').map(item => item.trim()))) {
|
||||||
if (key == 'type' && (value == 'local' || value == 'tar')) {
|
if (key == 'type' && (value == 'local' || value == 'tar')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -53,8 +113,8 @@ export function isLocalOrTarExporter(outputs: string[]): Boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasGitAuthToken(secrets: string[]): Boolean {
|
export function hasGitAuthToken(secrets: string[]): boolean {
|
||||||
for (let secret of secrets) {
|
for (const secret of secrets) {
|
||||||
if (secret.startsWith('GIT_AUTH_TOKEN=')) {
|
if (secret.startsWith('GIT_AUTH_TOKEN=')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -62,28 +122,161 @@ export function hasGitAuthToken(secrets: string[]): Boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isAvailable(): Promise<Boolean> {
|
export async function isAvailable(standalone?: boolean): Promise<boolean> {
|
||||||
return await exec.exec(`docker`, ['buildx'], true).then(res => {
|
const cmd = getCommand([], standalone);
|
||||||
if (res.stderr != '' && !res.success) {
|
return await exec
|
||||||
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return res.exitCode == 0;
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
.catch(error => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function satisfiesBuildKitVersion(builderName: string, range: string, standalone?: boolean): Promise<boolean> {
|
||||||
|
const builderInspect = await inspect(builderName, standalone);
|
||||||
|
for (const node of builderInspect.nodes) {
|
||||||
|
if (!node.buildkit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return res.success;
|
// BuildKit version reported by moby is in the format of `v0.11.0-moby`
|
||||||
});
|
if (builderInspect.driver == 'docker' && !node.buildkit.endsWith('-moby')) {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
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);
|
const version = node.buildkit.replace(/-moby$/, '');
|
||||||
});
|
if (!semver.satisfies(version, range)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parseVersion(stdout: string): Promise<string> {
|
async function inspect(name: string, standalone?: boolean): Promise<Builder> {
|
||||||
const matches = /\sv?([0-9.]+)/.exec(stdout);
|
const cmd = getCommand(['inspect', name], standalone);
|
||||||
if (!matches) {
|
return await exec
|
||||||
throw new Error(`Cannot parse Buildx version`);
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
}
|
ignoreReturnCode: true,
|
||||||
return semver.clean(matches[1]);
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr.trim());
|
||||||
|
}
|
||||||
|
return parseInspect(res.stdout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parseInspect(data: string): Promise<Builder> {
|
||||||
|
const builder: Builder = {
|
||||||
|
nodes: []
|
||||||
|
};
|
||||||
|
let node: Node = {};
|
||||||
|
for (const line of data.trim().split(`\n`)) {
|
||||||
|
const [key, ...rest] = line.split(':');
|
||||||
|
const value = rest.map(v => v.trim()).join(':');
|
||||||
|
if (key.length == 0 || value.length == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (key.toLowerCase()) {
|
||||||
|
case 'name': {
|
||||||
|
if (builder.name == undefined) {
|
||||||
|
builder.name = value;
|
||||||
|
} else {
|
||||||
|
if (Object.keys(node).length > 0) {
|
||||||
|
builder.nodes.push(node);
|
||||||
|
node = {};
|
||||||
|
}
|
||||||
|
node.name = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'driver': {
|
||||||
|
builder.driver = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'endpoint': {
|
||||||
|
node.endpoint = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'driver options': {
|
||||||
|
node['driver-opts'] = (value.match(/(\w+)="([^"]*)"/g) || []).map(v => v.replace(/^(.*)="(.*)"$/g, '$1=$2'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'status': {
|
||||||
|
node.status = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'flags': {
|
||||||
|
node['buildkitd-flags'] = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'buildkit': {
|
||||||
|
node.buildkit = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'platforms': {
|
||||||
|
let platforms: Array<string> = [];
|
||||||
|
// if a preferred platform is being set then use only these
|
||||||
|
// https://docs.docker.com/engine/reference/commandline/buildx_inspect/#get-information-about-a-builder-instance
|
||||||
|
if (value.includes('*')) {
|
||||||
|
for (const platform of value.split(', ')) {
|
||||||
|
if (platform.includes('*')) {
|
||||||
|
platforms.push(platform.replace('*', ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// otherwise set all platforms available
|
||||||
|
platforms = value.split(', ');
|
||||||
|
}
|
||||||
|
node.platforms = platforms.join(',');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.keys(node).length > 0) {
|
||||||
|
builder.nodes.push(node);
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVersion(standalone?: boolean): Promise<string> {
|
||||||
|
const cmd = getCommand(['version'], standalone);
|
||||||
|
return await exec
|
||||||
|
.getExecOutput(cmd.command, cmd.args, {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr.trim());
|
||||||
|
}
|
||||||
|
return parseVersion(res.stdout.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseVersion(stdout: string): string {
|
||||||
|
const matches = /\sv?([0-9a-f]{7}|[0-9.]+)/.exec(stdout);
|
||||||
|
if (!matches) {
|
||||||
|
throw new Error(`Cannot parse buildx version`);
|
||||||
|
}
|
||||||
|
return matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function satisfies(version: string, range: string): boolean {
|
||||||
|
return semver.satisfies(version, range) || /^[0-9a-f]{7}$/.exec(version) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCommand(args: Array<string>, standalone?: boolean) {
|
||||||
|
return {
|
||||||
|
command: standalone ? 'buildx' : 'docker',
|
||||||
|
args: standalone ? args : ['buildx', ...args]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
315
src/context.ts
315
src/context.ts
@ -1,44 +1,58 @@
|
|||||||
import csvparse from 'csv-parse/lib/sync';
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
import * as buildx from './buildx';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as github from '@actions/github';
|
import * as github from '@actions/github';
|
||||||
|
import {parse} from 'csv-parse/sync';
|
||||||
import * as buildx from './buildx';
|
import * as handlebars from 'handlebars';
|
||||||
|
|
||||||
let _defaultContext, _tmpDir: string;
|
let _defaultContext, _tmpDir: string;
|
||||||
|
|
||||||
export interface Inputs {
|
export interface Inputs {
|
||||||
context: string;
|
addHosts: string[];
|
||||||
file: string;
|
|
||||||
buildArgs: string[];
|
|
||||||
labels: string[];
|
|
||||||
tags: string[];
|
|
||||||
pull: boolean;
|
|
||||||
target: string;
|
|
||||||
allow: string[];
|
allow: string[];
|
||||||
noCache: boolean;
|
attests: string[];
|
||||||
|
buildArgs: string[];
|
||||||
|
buildContexts: string[];
|
||||||
builder: string;
|
builder: string;
|
||||||
platforms: string[];
|
|
||||||
load: boolean;
|
|
||||||
push: boolean;
|
|
||||||
outputs: string[];
|
|
||||||
cacheFrom: string[];
|
cacheFrom: string[];
|
||||||
cacheTo: string[];
|
cacheTo: string[];
|
||||||
|
cgroupParent: string;
|
||||||
|
context: string;
|
||||||
|
file: string;
|
||||||
|
labels: string[];
|
||||||
|
load: boolean;
|
||||||
|
network: string;
|
||||||
|
noCache: boolean;
|
||||||
|
noCacheFilters: string[];
|
||||||
|
outputs: string[];
|
||||||
|
platforms: string[];
|
||||||
|
provenance: string;
|
||||||
|
pull: boolean;
|
||||||
|
push: boolean;
|
||||||
|
sbom: string;
|
||||||
secrets: string[];
|
secrets: string[];
|
||||||
githubToken: string;
|
secretFiles: string[];
|
||||||
|
shmSize: string;
|
||||||
ssh: string[];
|
ssh: string[];
|
||||||
|
tags: string[];
|
||||||
|
target: string;
|
||||||
|
ulimit: string[];
|
||||||
|
githubToken: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defaultContext(): string {
|
export function defaultContext(): string {
|
||||||
if (!_defaultContext) {
|
if (!_defaultContext) {
|
||||||
_defaultContext = `https://github.com/${github.context.repo.owner}/${
|
let ref = github.context.ref;
|
||||||
github.context.repo.repo
|
if (github.context.sha && ref && !ref.startsWith('refs/')) {
|
||||||
}.git#${github.context?.ref?.replace(/^refs\//, '')}`;
|
ref = `refs/heads/${github.context.ref}`;
|
||||||
|
}
|
||||||
|
if (github.context.sha && !ref.startsWith(`refs/pull/`)) {
|
||||||
|
ref = github.context.sha;
|
||||||
|
}
|
||||||
|
_defaultContext = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}.git#${ref}`;
|
||||||
}
|
}
|
||||||
return _defaultContext;
|
return _defaultContext;
|
||||||
}
|
}
|
||||||
@ -54,66 +68,75 @@ export function tmpNameSync(options?: tmp.TmpNameOptions): string {
|
|||||||
return tmp.tmpNameSync(options);
|
return tmp.tmpNameSync(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function provenanceBuilderID(): string {
|
||||||
|
return `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}`;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getInputs(defaultContext: string): Promise<Inputs> {
|
export async function getInputs(defaultContext: string): Promise<Inputs> {
|
||||||
return {
|
return {
|
||||||
context: core.getInput('context') || defaultContext,
|
addHosts: await getInputList('add-hosts'),
|
||||||
file: core.getInput('file') || 'Dockerfile',
|
|
||||||
buildArgs: await getInputList('build-args', true),
|
|
||||||
labels: await getInputList('labels', true),
|
|
||||||
tags: await getInputList('tags'),
|
|
||||||
pull: /true/i.test(core.getInput('pull')),
|
|
||||||
target: core.getInput('target'),
|
|
||||||
allow: await getInputList('allow'),
|
allow: await getInputList('allow'),
|
||||||
noCache: /true/i.test(core.getInput('no-cache')),
|
attests: await getInputList('attests', true),
|
||||||
|
buildArgs: await getInputList('build-args', true),
|
||||||
|
buildContexts: await getInputList('build-contexts', true),
|
||||||
builder: core.getInput('builder'),
|
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),
|
cacheFrom: await getInputList('cache-from', true),
|
||||||
cacheTo: await getInputList('cache-to', true),
|
cacheTo: await getInputList('cache-to', true),
|
||||||
|
cgroupParent: core.getInput('cgroup-parent'),
|
||||||
|
context: core.getInput('context') || defaultContext,
|
||||||
|
file: core.getInput('file'),
|
||||||
|
labels: await getInputList('labels', true),
|
||||||
|
load: core.getBooleanInput('load'),
|
||||||
|
network: core.getInput('network'),
|
||||||
|
noCache: core.getBooleanInput('no-cache'),
|
||||||
|
noCacheFilters: await getInputList('no-cache-filters'),
|
||||||
|
outputs: await getInputList('outputs', true),
|
||||||
|
platforms: await getInputList('platforms'),
|
||||||
|
provenance: getProvenanceInput('provenance'),
|
||||||
|
pull: core.getBooleanInput('pull'),
|
||||||
|
push: core.getBooleanInput('push'),
|
||||||
|
sbom: core.getInput('sbom'),
|
||||||
secrets: await getInputList('secrets', true),
|
secrets: await getInputList('secrets', true),
|
||||||
githubToken: core.getInput('github-token'),
|
secretFiles: await getInputList('secret-files', true),
|
||||||
ssh: await getInputList('ssh')
|
shmSize: core.getInput('shm-size'),
|
||||||
|
ssh: await getInputList('ssh'),
|
||||||
|
tags: await getInputList('tags'),
|
||||||
|
target: core.getInput('target'),
|
||||||
|
ulimit: await getInputList('ulimit', true),
|
||||||
|
githubToken: core.getInput('github-token')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> {
|
export async function getArgs(inputs: Inputs, defaultContext: string, buildxVersion: string, standalone?: boolean): Promise<Array<string>> {
|
||||||
let args: Array<string> = ['buildx'];
|
const context = handlebars.compile(inputs.context)({defaultContext});
|
||||||
args.push.apply(args, await getBuildArgs(inputs, defaultContext, buildxVersion));
|
// prettier-ignore
|
||||||
args.push.apply(args, await getCommonArgs(inputs));
|
return [
|
||||||
args.push(inputs.context);
|
...await getBuildArgs(inputs, defaultContext, context, buildxVersion, standalone),
|
||||||
return args;
|
...await getCommonArgs(inputs, buildxVersion),
|
||||||
|
context
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> {
|
async function getBuildArgs(inputs: Inputs, defaultContext: string, context: string, buildxVersion: string, standalone?: boolean): Promise<Array<string>> {
|
||||||
let args: Array<string> = ['build'];
|
const args: Array<string> = ['build'];
|
||||||
await asyncForEach(inputs.buildArgs, async buildArg => {
|
await asyncForEach(inputs.addHosts, async addHost => {
|
||||||
args.push('--build-arg', buildArg);
|
args.push('--add-host', addHost);
|
||||||
});
|
});
|
||||||
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) {
|
if (inputs.allow.length > 0) {
|
||||||
args.push('--allow', inputs.allow.join(','));
|
args.push('--allow', inputs.allow.join(','));
|
||||||
}
|
}
|
||||||
if (inputs.platforms.length > 0) {
|
if (buildx.satisfies(buildxVersion, '>=0.10.0')) {
|
||||||
args.push('--platform', inputs.platforms.join(','));
|
await asyncForEach(inputs.attests, async attest => {
|
||||||
|
args.push('--attest', attest);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
await asyncForEach(inputs.outputs, async output => {
|
await asyncForEach(inputs.buildArgs, async buildArg => {
|
||||||
args.push('--output', output);
|
args.push('--build-arg', buildArg);
|
||||||
});
|
});
|
||||||
if (
|
if (buildx.satisfies(buildxVersion, '>=0.8.0')) {
|
||||||
!buildx.isLocalOrTarExporter(inputs.outputs) &&
|
await asyncForEach(inputs.buildContexts, async buildContext => {
|
||||||
(inputs.platforms.length == 0 || semver.satisfies(buildxVersion, '>=0.4.2'))
|
args.push('--build-context', buildContext);
|
||||||
) {
|
});
|
||||||
args.push('--iidfile', await buildx.getImageIDFile());
|
|
||||||
}
|
}
|
||||||
await asyncForEach(inputs.cacheFrom, async cacheFrom => {
|
await asyncForEach(inputs.cacheFrom, async cacheFrom => {
|
||||||
args.push('--cache-from', cacheFrom);
|
args.push('--cache-from', cacheFrom);
|
||||||
@ -121,39 +144,99 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
|
|||||||
await asyncForEach(inputs.cacheTo, async cacheTo => {
|
await asyncForEach(inputs.cacheTo, async cacheTo => {
|
||||||
args.push('--cache-to', cacheTo);
|
args.push('--cache-to', cacheTo);
|
||||||
});
|
});
|
||||||
|
if (inputs.cgroupParent) {
|
||||||
|
args.push('--cgroup-parent', inputs.cgroupParent);
|
||||||
|
}
|
||||||
|
if (inputs.file) {
|
||||||
|
args.push('--file', inputs.file);
|
||||||
|
}
|
||||||
|
if (!buildx.isLocalOrTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || buildx.satisfies(buildxVersion, '>=0.4.2'))) {
|
||||||
|
args.push('--iidfile', await buildx.getImageIDFile());
|
||||||
|
}
|
||||||
|
await asyncForEach(inputs.labels, async label => {
|
||||||
|
args.push('--label', label);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.noCacheFilters, async noCacheFilter => {
|
||||||
|
args.push('--no-cache-filter', noCacheFilter);
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.outputs, async output => {
|
||||||
|
args.push('--output', output);
|
||||||
|
});
|
||||||
|
if (inputs.platforms.length > 0) {
|
||||||
|
args.push('--platform', inputs.platforms.join(','));
|
||||||
|
}
|
||||||
|
if (buildx.satisfies(buildxVersion, '>=0.10.0')) {
|
||||||
|
if (inputs.provenance) {
|
||||||
|
args.push('--provenance', inputs.provenance);
|
||||||
|
} else if ((await buildx.satisfiesBuildKitVersion(inputs.builder, '>=0.11.0', standalone)) && !hasDockerExport(inputs)) {
|
||||||
|
// If provenance not specified but BuildKit version compatible for
|
||||||
|
// attestation, disable provenance anyway. Also needs to make sure user
|
||||||
|
// doesn't want to explicitly load the image to docker.
|
||||||
|
// While this action successfully pushes OCI compliant images to
|
||||||
|
// well-known registries, some runtimes (e.g. Google Cloud Run and AWS
|
||||||
|
// Lambda) are not able to pull resulting image from their own registry...
|
||||||
|
// See also https://github.com/docker/buildx/issues/1533
|
||||||
|
args.push('--provenance', 'false');
|
||||||
|
}
|
||||||
|
if (inputs.sbom) {
|
||||||
|
args.push('--sbom', inputs.sbom);
|
||||||
|
}
|
||||||
|
}
|
||||||
await asyncForEach(inputs.secrets, async secret => {
|
await asyncForEach(inputs.secrets, async secret => {
|
||||||
try {
|
try {
|
||||||
args.push('--secret', await buildx.getSecret(secret));
|
args.push('--secret', await buildx.getSecretString(secret));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.warning(err.message);
|
core.warning(err.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) {
|
await asyncForEach(inputs.secretFiles, async secretFile => {
|
||||||
args.push('--secret', await buildx.getSecret(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
|
try {
|
||||||
|
args.push('--secret', await buildx.getSecretFile(secretFile));
|
||||||
|
} catch (err) {
|
||||||
|
core.warning(err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && context.startsWith(defaultContext)) {
|
||||||
|
args.push('--secret', await buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
|
||||||
|
}
|
||||||
|
if (inputs.shmSize) {
|
||||||
|
args.push('--shm-size', inputs.shmSize);
|
||||||
}
|
}
|
||||||
await asyncForEach(inputs.ssh, async ssh => {
|
await asyncForEach(inputs.ssh, async ssh => {
|
||||||
args.push('--ssh', ssh);
|
args.push('--ssh', ssh);
|
||||||
});
|
});
|
||||||
if (inputs.file) {
|
await asyncForEach(inputs.tags, async tag => {
|
||||||
args.push('--file', inputs.file);
|
args.push('--tag', tag);
|
||||||
|
});
|
||||||
|
if (inputs.target) {
|
||||||
|
args.push('--target', inputs.target);
|
||||||
}
|
}
|
||||||
|
await asyncForEach(inputs.ulimit, async ulimit => {
|
||||||
|
args.push('--ulimit', ulimit);
|
||||||
|
});
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCommonArgs(inputs: Inputs): Promise<Array<string>> {
|
async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||||
let args: Array<string> = [];
|
const args: Array<string> = [];
|
||||||
if (inputs.noCache) {
|
|
||||||
args.push('--no-cache');
|
|
||||||
}
|
|
||||||
if (inputs.builder) {
|
if (inputs.builder) {
|
||||||
args.push('--builder', inputs.builder);
|
args.push('--builder', inputs.builder);
|
||||||
}
|
}
|
||||||
if (inputs.pull) {
|
|
||||||
args.push('--pull');
|
|
||||||
}
|
|
||||||
if (inputs.load) {
|
if (inputs.load) {
|
||||||
args.push('--load');
|
args.push('--load');
|
||||||
}
|
}
|
||||||
|
if (buildx.satisfies(buildxVersion, '>=0.6.0')) {
|
||||||
|
args.push('--metadata-file', await buildx.getMetadataFile());
|
||||||
|
}
|
||||||
|
if (inputs.network) {
|
||||||
|
args.push('--network', inputs.network);
|
||||||
|
}
|
||||||
|
if (inputs.noCache) {
|
||||||
|
args.push('--no-cache');
|
||||||
|
}
|
||||||
|
if (inputs.pull) {
|
||||||
|
args.push('--pull');
|
||||||
|
}
|
||||||
if (inputs.push) {
|
if (inputs.push) {
|
||||||
args.push('--push');
|
args.push('--push');
|
||||||
}
|
}
|
||||||
@ -161,26 +244,29 @@ async function getCommonArgs(inputs: Inputs): Promise<Array<string>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
|
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
|
||||||
let res: Array<string> = [];
|
const res: Array<string> = [];
|
||||||
|
|
||||||
const items = core.getInput(name);
|
const items = core.getInput(name);
|
||||||
if (items == '') {
|
if (items == '') {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let output of (await csvparse(items, {
|
const records = await parse(items, {
|
||||||
columns: false,
|
columns: false,
|
||||||
|
relaxQuotes: true,
|
||||||
relaxColumnCount: true,
|
relaxColumnCount: true,
|
||||||
skipLinesWithEmptyValues: true
|
skipEmptyLines: true
|
||||||
})) as Array<string[]>) {
|
});
|
||||||
if (output.length == 1) {
|
|
||||||
res.push(output[0]);
|
for (const record of records as Array<string[]>) {
|
||||||
|
if (record.length == 1) {
|
||||||
|
res.push(record[0]);
|
||||||
continue;
|
continue;
|
||||||
} else if (!ignoreComma) {
|
} else if (!ignoreComma) {
|
||||||
res.push(...output);
|
res.push(...record);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
res.push(output.join(','));
|
res.push(record.join(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.filter(item => item).map(pat => pat.trim());
|
return res.filter(item => item).map(pat => pat.trim());
|
||||||
@ -191,3 +277,64 @@ export const asyncForEach = async (array, callback) => {
|
|||||||
await callback(array[index], index, array);
|
await callback(array[index], index, array);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getProvenanceInput(name: string): string {
|
||||||
|
const input = core.getInput(name);
|
||||||
|
if (!input) {
|
||||||
|
// if input is not set, default values will be set later.
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
const builderID = provenanceBuilderID();
|
||||||
|
try {
|
||||||
|
return core.getBooleanInput(name) ? `builder-id=${builderID}` : 'false';
|
||||||
|
} catch (err) {
|
||||||
|
// not a valid boolean, so we assume it's a string
|
||||||
|
return getProvenanceAttrs(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProvenanceAttrs(input: string): string {
|
||||||
|
const builderID = provenanceBuilderID();
|
||||||
|
// parse attributes from input
|
||||||
|
const fields = parse(input, {
|
||||||
|
relaxColumnCount: true,
|
||||||
|
skipEmptyLines: true
|
||||||
|
})[0];
|
||||||
|
// check if builder-id attribute exists in the input
|
||||||
|
for (const field of fields) {
|
||||||
|
const parts = field
|
||||||
|
.toString()
|
||||||
|
.split(/(?<=^[^=]+?)=/)
|
||||||
|
.map(item => item.trim());
|
||||||
|
if (parts[0] == 'builder-id') {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if not add builder-id attribute
|
||||||
|
return `${input},builder-id=${builderID}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasDockerExport(inputs: Inputs): boolean {
|
||||||
|
if (inputs.load) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (const output of inputs.outputs) {
|
||||||
|
const fields = parse(output, {
|
||||||
|
relaxColumnCount: true,
|
||||||
|
skipEmptyLines: true
|
||||||
|
})[0];
|
||||||
|
for (const field of fields) {
|
||||||
|
const parts = field
|
||||||
|
.toString()
|
||||||
|
.split(/(?<=^[^=]+?)=/)
|
||||||
|
.map(item => item.trim());
|
||||||
|
if (parts.length != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (parts[0] == 'type' && parts[1] == 'docker') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,19 @@
|
|||||||
import * as exec from './exec';
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
export async function isDaemonRunning(): Promise<boolean> {
|
export async function isAvailable(): Promise<boolean> {
|
||||||
return await exec.exec(`docker`, ['version', '--format', '{{.Server.Os}}'], true).then(res => {
|
return await exec
|
||||||
return !res.stdout.includes(' ') && res.success;
|
.getExecOutput('docker', undefined, {
|
||||||
});
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return res.exitCode == 0;
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
.catch(error => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
34
src/exec.ts
34
src/exec.ts
@ -1,34 +0,0 @@
|
|||||||
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()
|
|
||||||
};
|
|
||||||
};
|
|
9
src/github.ts
Normal file
9
src/github.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import jwt_decode, {JwtPayload} from 'jwt-decode';
|
||||||
|
|
||||||
|
interface Jwt extends JwtPayload {
|
||||||
|
ac?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parseRuntimeToken = (token: string): Jwt => {
|
||||||
|
return jwt_decode<Jwt>(token);
|
||||||
|
};
|
99
src/main.ts
99
src/main.ts
@ -1,41 +1,89 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
|
||||||
import * as buildx from './buildx';
|
import * as buildx from './buildx';
|
||||||
import * as context from './context';
|
import * as context from './context';
|
||||||
import * as exec from './exec';
|
import * as docker from './docker';
|
||||||
|
import * as github from './github';
|
||||||
import * as stateHelper from './state-helper';
|
import * as stateHelper from './state-helper';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (os.platform() !== 'linux') {
|
|
||||||
throw new Error(`Only supported on linux platform`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(await buildx.isAvailable())) {
|
|
||||||
throw new Error(`Buildx is required. See https://github.com/docker/setup-buildx-action to set up buildx.`);
|
|
||||||
}
|
|
||||||
stateHelper.setTmpDir(context.tmpDir());
|
|
||||||
|
|
||||||
const buildxVersion = await buildx.getVersion();
|
|
||||||
core.info(`📣 Buildx version: ${buildxVersion}`);
|
|
||||||
|
|
||||||
const defContext = context.defaultContext();
|
const defContext = context.defaultContext();
|
||||||
let inputs: context.Inputs = await context.getInputs(defContext);
|
const inputs: context.Inputs = await context.getInputs(defContext);
|
||||||
|
|
||||||
core.info(`🏃 Starting build...`);
|
// standalone if docker cli not available
|
||||||
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
|
const standalone = !(await docker.isAvailable());
|
||||||
await exec.exec('docker', args).then(res => {
|
|
||||||
if (res.stderr != '' && !res.success) {
|
await core.group(`GitHub Actions runtime token access controls`, async () => {
|
||||||
throw new Error(`buildx call failed with: ${res.stderr.match(/(.*)\s*$/)![0]}`);
|
const actionsRuntimeToken = process.env['ACTIONS_RUNTIME_TOKEN'];
|
||||||
|
if (actionsRuntimeToken) {
|
||||||
|
core.info(JSON.stringify(JSON.parse(github.parseRuntimeToken(actionsRuntimeToken).ac as string), undefined, 2));
|
||||||
|
} else {
|
||||||
|
core.info(`ACTIONS_RUNTIME_TOKEN not set`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
core.startGroup(`Docker info`);
|
||||||
|
if (standalone) {
|
||||||
|
core.info(`Docker info skipped in standalone mode`);
|
||||||
|
} else {
|
||||||
|
await exec.exec('docker', ['version'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
await exec.exec('docker', ['info'], {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
core.endGroup();
|
||||||
|
|
||||||
|
if (!(await buildx.isAvailable(standalone))) {
|
||||||
|
core.setFailed(`Docker 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(standalone);
|
||||||
|
await core.group(`Buildx version`, async () => {
|
||||||
|
const versionCmd = buildx.getCommand(['version'], standalone);
|
||||||
|
await exec.exec(versionCmd.command, versionCmd.args, {
|
||||||
|
failOnStdErr: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion, standalone);
|
||||||
|
const buildCmd = buildx.getCommand(args, standalone);
|
||||||
|
await exec
|
||||||
|
.getExecOutput(buildCmd.command, buildCmd.args, {
|
||||||
|
ignoreReturnCode: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const imageID = await buildx.getImageID();
|
const imageID = await buildx.getImageID();
|
||||||
|
const metadata = await buildx.getMetadata();
|
||||||
|
const digest = await buildx.getDigest(metadata);
|
||||||
|
|
||||||
if (imageID) {
|
if (imageID) {
|
||||||
core.info('🛒 Extracting digest...');
|
await core.group(`ImageID`, async () => {
|
||||||
core.info(`${imageID}`);
|
core.info(imageID);
|
||||||
core.setOutput('digest', imageID);
|
core.setOutput('imageid', imageID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (digest) {
|
||||||
|
await core.group(`Digest`, async () => {
|
||||||
|
core.info(digest);
|
||||||
|
core.setOutput('digest', digest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (metadata) {
|
||||||
|
await core.group(`Metadata`, async () => {
|
||||||
|
core.info(metadata);
|
||||||
|
core.setOutput('metadata', metadata);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
@ -44,8 +92,9 @@ async function run(): Promise<void> {
|
|||||||
|
|
||||||
async function cleanup(): Promise<void> {
|
async function cleanup(): Promise<void> {
|
||||||
if (stateHelper.tmpDir.length > 0) {
|
if (stateHelper.tmpDir.length > 0) {
|
||||||
core.info(`🚿 Removing temp folder ${stateHelper.tmpDir}`);
|
core.startGroup(`Removing temp folder ${stateHelper.tmpDir}`);
|
||||||
fs.rmdirSync(stateHelper.tmpDir, {recursive: true});
|
fs.rmSync(stateHelper.tmpDir, {recursive: true});
|
||||||
|
core.endGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
|
||||||
RUN echo "Hello world!"
|
RUN echo "Hello world!"
|
||||||
|
3
test/addhost.Dockerfile
Normal file
3
test/addhost.Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM busybox
|
||||||
|
RUN cat /etc/hosts
|
3
test/buildcontext.Dockerfile
Normal file
3
test/buildcontext.Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM alpine
|
||||||
|
RUN cat /etc/*release
|
3
test/cgroup.Dockerfile
Normal file
3
test/cgroup.Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM alpine
|
||||||
|
RUN cat /proc/self/cgroup
|
16
test/go/Dockerfile
Normal file
16
test/go/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
FROM golang:1.19-alpine AS base
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
RUN apk add --no-cache file git
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
FROM base as build
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download -x
|
||||||
|
COPY . .
|
||||||
|
RUN go build -ldflags "-s -w" -o /usr/bin/app .
|
||||||
|
|
||||||
|
FROM scratch AS binary
|
||||||
|
COPY --from=build /usr/bin/app /bin/app
|
||||||
|
|
||||||
|
FROM alpine:3.17 AS image
|
||||||
|
COPY --from=build /usr/bin/app /bin/app
|
19
test/go/go.mod
Normal file
19
test/go/go.mod
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
module github.com/docker/build-push-action/test/go
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require github.com/labstack/echo/v4 v4.9.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
|
github.com/labstack/gommon v0.4.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
|
||||||
|
)
|
38
test/go/go.sum
Normal file
38
test/go/go.sum
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
|
||||||
|
github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
|
||||||
|
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||||
|
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||||
|
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||||
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||||
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
|
||||||
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||||
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
31
test/go/main.go
Normal file
31
test/go/main.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/labstack/echo/v4/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
e := echo.New()
|
||||||
|
|
||||||
|
e.Use(middleware.Logger())
|
||||||
|
e.Use(middleware.Recover())
|
||||||
|
|
||||||
|
e.GET("/", func(c echo.Context) error {
|
||||||
|
return c.HTML(http.StatusOK, "Hello World")
|
||||||
|
})
|
||||||
|
|
||||||
|
e.GET("/ping", func(c echo.Context) error {
|
||||||
|
return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"})
|
||||||
|
})
|
||||||
|
|
||||||
|
httpPort := os.Getenv("HTTP_PORT")
|
||||||
|
if httpPort == "" {
|
||||||
|
httpPort = "8080"
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Logger.Fatal(e.Start(":" + httpPort))
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG BUILDPLATFORM
|
ARG BUILDPLATFORM
|
||||||
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
|
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
|
||||||
|
|
||||||
RUN apk --update --no-cache add \
|
RUN apk --update --no-cache add \
|
||||||
shadow \
|
shadow \
|
||||||
sudo \
|
sudo \
|
||||||
@ -17,6 +16,5 @@ RUN sudo chown buildx. /log
|
|||||||
USER root
|
USER root
|
||||||
|
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
|
||||||
COPY --from=build /log /log
|
COPY --from=build /log /log
|
||||||
RUN ls -al /log
|
RUN ls -al /log
|
@ -1,3 +1,4 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
FROM --platform=$BUILDPLATFORM golang:alpine AS build
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
9
test/nocachefilter.Dockerfile
Normal file
9
test/nocachefilter.Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM busybox AS base
|
||||||
|
RUN echo "Hello world!" > /hello
|
||||||
|
|
||||||
|
FROM alpine AS build
|
||||||
|
COPY --from=base /hello /hello
|
||||||
|
RUN uname -a
|
||||||
|
|
||||||
|
FROM build
|
4
test/secret.Dockerfile
Normal file
4
test/secret.Dockerfile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM busybox
|
||||||
|
RUN --mount=type=secret,id=MYSECRET \
|
||||||
|
echo "MYSECRET=$(cat /run/secrets/MYSECRET)"
|
3
test/shmsize.Dockerfile
Normal file
3
test/shmsize.Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM busybox
|
||||||
|
RUN mount | grep /dev/shm
|
3
test/ulimit.Dockerfile
Normal file
3
test/ulimit.Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM busybox
|
||||||
|
RUN ulimit -a
|
@ -2,20 +2,18 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"lib": [
|
|
||||||
"es6",
|
|
||||||
"dom"
|
|
||||||
],
|
|
||||||
"newLine": "lf",
|
"newLine": "lf",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"esModuleInterop": true,
|
"useUnknownInCatchVariables": false,
|
||||||
"sourceMap": true
|
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"**/*.test.ts"
|
"**/*.test.ts",
|
||||||
|
"jest.config.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user