mirror of
https://github.com/docker/build-push-action.git
synced 2025-06-12 14:17:12 +02:00
Compare commits
166 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
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"
|
||||
]
|
||||
}
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -5,7 +5,7 @@ about: Create a report to help us improve
|
||||
|
||||
### 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
|
||||
|
||||
|
BIN
.github/build-push-action.png
vendored
BIN
.github/build-push-action.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 19 KiB |
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@ -5,8 +5,8 @@ updates:
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- ":game_die: dependencies"
|
||||
- ":robot: bot"
|
||||
- "dependencies"
|
||||
- "bot"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
@ -14,5 +14,5 @@ updates:
|
||||
allow:
|
||||
- dependency-type: "production"
|
||||
labels:
|
||||
- ":game_die: dependencies"
|
||||
- ":robot: bot"
|
||||
- "dependencies"
|
||||
- "bot"
|
||||
|
431
.github/workflows/ci.yml
vendored
431
.github/workflows/ci.yml
vendored
@ -4,10 +4,10 @@ on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 'master'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- 'master'
|
||||
|
||||
jobs:
|
||||
minimal:
|
||||
@ -15,21 +15,17 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: action
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: ./action
|
||||
with:
|
||||
file: ./test/Dockerfile
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
git-context:
|
||||
runs-on: ubuntu-latest
|
||||
@ -41,16 +37,16 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: action
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
version: latest
|
||||
driver-opts: network=host
|
||||
@ -70,9 +66,6 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest
|
||||
run: |
|
||||
@ -80,10 +73,6 @@ jobs:
|
||||
echo "::error::Digest should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
git-context-secret:
|
||||
runs-on: ubuntu-latest
|
||||
@ -95,16 +84,16 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: action
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: network=host
|
||||
-
|
||||
@ -133,9 +122,6 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest
|
||||
run: |
|
||||
@ -143,10 +129,6 @@ jobs:
|
||||
echo "::error::Digest should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
path-context:
|
||||
runs-on: ubuntu-latest
|
||||
@ -164,14 +146,14 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
version: ${{ matrix.buildx-version }}
|
||||
driver-opts: network=host
|
||||
@ -191,9 +173,6 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest
|
||||
run: |
|
||||
@ -201,17 +180,13 @@ jobs:
|
||||
echo "::error::Digest should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
error:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Stop docker
|
||||
run: |
|
||||
@ -232,23 +207,19 @@ jobs:
|
||||
echo "::error::Should have failed"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
error-buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
id: docker_build
|
||||
@ -268,10 +239,6 @@ jobs:
|
||||
echo "::error::Should have failed"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
docker-driver:
|
||||
runs-on: ubuntu-latest
|
||||
@ -283,7 +250,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Build
|
||||
id: docker_build
|
||||
@ -293,17 +260,13 @@ jobs:
|
||||
file: ./test/Dockerfile
|
||||
push: true
|
||||
tags: localhost:5000/name/app:latest
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
export-docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
@ -316,20 +279,16 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker image inspect myimage:latest
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
network:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: List networks
|
||||
run: docker network ls
|
||||
@ -340,10 +299,130 @@ jobs:
|
||||
context: ./test
|
||||
tags: name/app:latest
|
||||
network: host
|
||||
|
||||
shm-size:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:master
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/shmsize.Dockerfile
|
||||
tags: name/app:latest
|
||||
shm-size: 2g
|
||||
|
||||
ulimit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:master
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/ulimit.Dockerfile
|
||||
tags: name/app:latest
|
||||
ulimit: |
|
||||
nofile=1024:1024
|
||||
nproc=3
|
||||
|
||||
cgroup-parent:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:master
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/cgroup.Dockerfile
|
||||
tags: name/app:latest
|
||||
cgroup-parent: foo
|
||||
|
||||
add-hosts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/addhost.Dockerfile
|
||||
tags: name/app:latest
|
||||
add-hosts: |
|
||||
docker:10.180.0.1
|
||||
foo:10.0.0.1
|
||||
|
||||
build-contexts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/buildcontext.Dockerfile
|
||||
build-contexts: |
|
||||
alpine=docker-image://debian:stable-slim
|
||||
tags: name/app:latest
|
||||
|
||||
no-cache-filters:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/nocachefilter.Dockerfile
|
||||
no-cache-filters: build
|
||||
tags: name/app:latest
|
||||
cache-from: type=gha,scope=nocachefilter
|
||||
cache-to: type=gha,scope=nocachefilter,mode=max
|
||||
|
||||
multi:
|
||||
runs-on: ubuntu-latest
|
||||
@ -364,14 +443,14 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
version: ${{ matrix.buildx-version }}
|
||||
driver-opts: network=host
|
||||
@ -392,9 +471,6 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest
|
||||
run: |
|
||||
@ -402,10 +478,93 @@ jobs:
|
||||
echo "::error::Digest should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
digest:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_IMAGE: localhost:5000/name/app
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
driver:
|
||||
- docker
|
||||
- docker-container
|
||||
load:
|
||||
- true
|
||||
- false
|
||||
push:
|
||||
- true
|
||||
- false
|
||||
exclude:
|
||||
- driver: docker
|
||||
load: true
|
||||
push: true
|
||||
- driver: docker-container
|
||||
load: true
|
||||
push: true
|
||||
- driver: docker
|
||||
load: false
|
||||
push: false
|
||||
- driver: docker-container
|
||||
load: false
|
||||
push: false
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
steps:
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver: ${{ matrix.driver }}
|
||||
driver-opts: |
|
||||
network=host
|
||||
-
|
||||
name: Build
|
||||
id: docker_build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
load: ${{ matrix.load }}
|
||||
push: ${{ matrix.push }}
|
||||
tags: ${{ env.DOCKER_IMAGE }}:latest
|
||||
platforms: ${{ matrix.platforms }}
|
||||
-
|
||||
name: Docker images
|
||||
run: |
|
||||
docker image ls --no-trunc
|
||||
-
|
||||
name: Check digest
|
||||
if: ${{ matrix.push }}
|
||||
run: |
|
||||
if [ -z "${{ steps.docker_build.outputs.digest }}" ]; then
|
||||
echo "::error::Digest should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Check manifest
|
||||
if: ${{ matrix.push }}
|
||||
run: |
|
||||
set -x
|
||||
docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}@${{ steps.docker_build.outputs.digest }} --format '{{json .}}'
|
||||
-
|
||||
name: Check image ID
|
||||
run: |
|
||||
if [ -z "${{ steps.docker_build.outputs.imageid }}" ]; then
|
||||
echo "::error::Image ID should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Inspect image
|
||||
if: ${{ matrix.load }}
|
||||
run: |
|
||||
set -x
|
||||
docker image inspect ${{ steps.docker_build.outputs.imageid }}
|
||||
|
||||
registry-cache:
|
||||
runs-on: ubuntu-latest
|
||||
@ -417,14 +576,14 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: |
|
||||
network=host
|
||||
@ -447,9 +606,6 @@ jobs:
|
||||
name: Inspect (1)
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:latest
|
||||
-
|
||||
name: Image digest (1)
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest (1)
|
||||
run: |
|
||||
@ -480,9 +636,6 @@ jobs:
|
||||
name: Inspect (2)
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:latest
|
||||
-
|
||||
name: Image digest (2)
|
||||
run: echo ${{ steps.docker_build2.outputs.digest }}
|
||||
-
|
||||
name: Check digest (2)
|
||||
run: |
|
||||
@ -498,12 +651,8 @@ jobs:
|
||||
echo "::error::Digests should be identical"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
github-cache-first:
|
||||
local-cache-first:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
digest: ${{ steps.docker_build.outputs.digest }}
|
||||
@ -515,23 +664,23 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: |
|
||||
network=host
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-ghcache-${{ github.sha }}
|
||||
key: ${{ runner.os }}-buildx-local-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-ghcache-
|
||||
-
|
||||
@ -557,9 +706,6 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest
|
||||
run: |
|
||||
@ -567,14 +713,10 @@ jobs:
|
||||
echo "::error::Digest should not be empty"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
|
||||
github-cache-hit:
|
||||
local-cache-hit:
|
||||
runs-on: ubuntu-latest
|
||||
needs: github-cache-first
|
||||
needs: local-cache-first
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
@ -583,24 +725,24 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: |
|
||||
network=host
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-ghcache-${{ github.sha }}
|
||||
key: ${{ runner.os }}-buildx-local-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-ghcache-
|
||||
-
|
||||
@ -622,9 +764,6 @@ jobs:
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
-
|
||||
name: Check digest
|
||||
run: |
|
||||
@ -635,15 +774,77 @@ jobs:
|
||||
-
|
||||
name: Compare digests
|
||||
run: |
|
||||
echo Compare "${{ needs.github-cache-first.outputs.digest }}" with "${{ steps.docker_build.outputs.digest }}"
|
||||
if [ "${{ needs.github-cache-first.outputs.digest }}" != "${{ steps.docker_build.outputs.digest }}" ]; then
|
||||
echo Compare "${{ needs.local-cache-first.outputs.digest }}" with "${{ steps.docker_build.outputs.digest }}"
|
||||
if [ "${{ needs.local-cache-first.outputs.digest }}" != "${{ steps.docker_build.outputs.digest }}" ]; then
|
||||
echo "::error::Digests should be identical"
|
||||
exit 1
|
||||
fi
|
||||
-
|
||||
name: Cache hit
|
||||
run: echo ${{ steps.cache.outputs.cache-hit }}
|
||||
|
||||
github-cache:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
buildx_version:
|
||||
- ""
|
||||
- latest
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
steps:
|
||||
-
|
||||
name: Dump context
|
||||
if: always()
|
||||
uses: crazy-max/ghaction-dump-context@v1
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
version: ${{ matrix.buildx_version }}
|
||||
driver-opts: |
|
||||
network=host
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build and push
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/multi.Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
localhost:5000/name/app:latest
|
||||
localhost:5000/name/app:1.0.0
|
||||
cache-from: type=gha,scope=ci-${{ matrix.buildx_version }}
|
||||
cache-to: type=gha,scope=ci-${{ matrix.buildx_version }}
|
||||
-
|
||||
name: Inspect
|
||||
run: |
|
||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||
|
||||
standalone:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Uninstall moby cli
|
||||
run: |
|
||||
sudo apt-get purge -y moby-cli moby-buildx
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: ./
|
||||
with:
|
||||
context: ./test
|
||||
file: ./test/Dockerfile
|
||||
|
19
.github/workflows/e2e.yml
vendored
19
.github/workflows/e2e.yml
vendored
@ -3,10 +3,10 @@ name: e2e
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # everyday at 10am
|
||||
- cron: '0 10 * * *'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 'master'
|
||||
tags:
|
||||
- v*
|
||||
|
||||
@ -52,26 +52,31 @@ jobs:
|
||||
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:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ matrix.slug }}
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ matrix.registry }}
|
||||
username: ${{ secrets[matrix.username_secret] }}
|
||||
|
10
.github/workflows/example.yml
vendored
10
.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
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * 0' # everyday sunday at 10am
|
||||
- cron: '0 10 * * 0'
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
@ -25,11 +25,11 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.DOCKER_IMAGE }}
|
||||
tags: |
|
||||
@ -42,7 +42,7 @@ jobs:
|
||||
type=sha
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: network=host
|
||||
-
|
||||
|
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@ -14,19 +14,19 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Validate
|
||||
uses: docker/bake-action@v1
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: validate
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v1
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: test
|
||||
-
|
||||
name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage/clover.xml
|
||||
|
38
.github/workflows/virtual-env.yml
vendored
38
.github/workflows/virtual-env.yml
vendored
@ -3,7 +3,17 @@ name: virtual-env
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # everyday at 10am
|
||||
- cron: '0 10 * * *'
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
paths:
|
||||
- '.github/workflows/virtual-env.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
paths:
|
||||
- '.github/workflows/virtual-env.yml'
|
||||
|
||||
jobs:
|
||||
os:
|
||||
@ -13,25 +23,49 @@ jobs:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- ubuntu-22.04
|
||||
- ubuntu-20.04
|
||||
- ubuntu-18.04
|
||||
- ubuntu-16.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()
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"printWidth": 240,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
|
154
README.md
154
README.md
@ -4,15 +4,6 @@
|
||||
[](https://github.com/docker/build-push-action/actions?workflow=test)
|
||||
[](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'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) with many [usage examples](#advanced-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
|
||||
|
||||
GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx) with full support of the
|
||||
@ -33,11 +24,10 @@ ___
|
||||
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
||||
* [Copy between registries](docs/advanced/copy-between-registries.md)
|
||||
* [Cache](docs/advanced/cache.md)
|
||||
* [Registry cache](docs/advanced/cache.md#registry-cache)
|
||||
* [GitHub cache](docs/advanced/cache.md#github-cache)
|
||||
* [Local registry](docs/advanced/local-registry.md)
|
||||
* [Export image to Docker](docs/advanced/export-docker.md)
|
||||
* [Share built image between jobs](docs/advanced/share-image-jobs.md)
|
||||
* [Test your image before pushing it](docs/advanced/test-before-push.md)
|
||||
* [Handle tags and labels](docs/advanced/tags-labels.md)
|
||||
* [Update DockerHub repo description](docs/advanced/dockerhub-desc.md)
|
||||
* [Customizing](#customizing)
|
||||
@ -48,17 +38,7 @@ ___
|
||||
|
||||
## Usage
|
||||
|
||||
By default, this action uses the [Git context](#git-context) so you don't need to use the
|
||||
[`actions/checkout`](https://github.com/actions/checkout/) action to checkout the repository because this will be
|
||||
done directly by buildkit. The git reference will be based on the [event that triggered your workflow](https://docs.github.com/en/actions/reference/events-that-trigger-workflows)
|
||||
and will result in the following context: `https://github.com/<owner>/<repo>.git#<ref>`.
|
||||
|
||||
Be careful because **any file mutation in the steps that precede the build step will be ignored** since
|
||||
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.
|
||||
|
||||
In the examples below we are using 3 other actions:
|
||||
In the examples below we are also using 3 other actions:
|
||||
|
||||
* [`setup-buildx`](https://github.com/docker/setup-buildx-action) action will create and boot a builder using by
|
||||
default the `docker-container` [builder driver](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#driver).
|
||||
@ -69,13 +49,20 @@ to add emulation support with QEMU to be able to build against more platforms.
|
||||
|
||||
### Git context
|
||||
|
||||
By default, this action uses the [Git context](#git-context) so you don't need
|
||||
to use the [`actions/checkout`](https://github.com/actions/checkout/) action to
|
||||
check out the repository because 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/reference/events-that-trigger-workflows)
|
||||
and will result in the following context: `https://github.com/<owner>/<repo>.git#<ref>`.
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -83,37 +70,55 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
-
|
||||
name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
```
|
||||
|
||||
Building from the current repository automatically uses the [GitHub Token](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token)
|
||||
so it does not need to be passed. If you want to authenticate against another private repository, you have to use
|
||||
a [secret](docs/advanced/secrets.md) named `GIT_AUTH_TOKEN` to be able to authenticate against it with buildx:
|
||||
Be careful because **any file mutation in the steps that precede the build step
|
||||
will be ignored, including processing of the `.dockerignore` file** since
|
||||
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
|
||||
-
|
||||
name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: "{{defaultContext}}:mysubdir"
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
```
|
||||
> :warning: Subdirectory for Git context is not yet available for the buildx [`docker` driver](https://github.com/docker/buildx/blob/master/docs/reference/buildx_create.md#driver).
|
||||
|
||||
Building from the current repository automatically uses the [GitHub Token](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token)
|
||||
so it does not need to be passed. If you want to authenticate against another
|
||||
private repository, you have to use a [secret](docs/advanced/secrets.md) named
|
||||
`GIT_AUTH_TOKEN` to be able to authenticate against it with buildx:
|
||||
|
||||
```yaml
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
@ -121,9 +126,6 @@ a [secret](docs/advanced/secrets.md) named `GIT_AUTH_TOKEN` to be able to authen
|
||||
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 on [Docker docs website](https://docs.docker.com/engine/reference/commandline/build/#git-repositories).
|
||||
|
||||
### Path context
|
||||
|
||||
```yaml
|
||||
@ -132,7 +134,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -140,22 +142,22 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@ -170,11 +172,10 @@ jobs:
|
||||
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
||||
* [Copy between registries](docs/advanced/copy-between-registries.md)
|
||||
* [Cache](docs/advanced/cache.md)
|
||||
* [Registry cache](docs/advanced/cache.md#registry-cache)
|
||||
* [GitHub cache](docs/advanced/cache.md#github-cache)
|
||||
* [Local registry](docs/advanced/local-registry.md)
|
||||
* [Export image to Docker](docs/advanced/export-docker.md)
|
||||
* [Share built image between jobs](docs/advanced/share-image-jobs.md)
|
||||
* [Test your image before pushing it](docs/advanced/test-before-push.md)
|
||||
* [Handle tags and labels](docs/advanced/tags-labels.md)
|
||||
* [Update DockerHub repo description](docs/advanced/dockerhub-desc.md)
|
||||
|
||||
@ -196,36 +197,45 @@ Following inputs can be used as `step.with` keys
|
||||
> tags: name/app:latest,name/app:1.0.0
|
||||
> ```
|
||||
|
||||
| Name | Type | Description |
|
||||
|---------------------|----------|------------------------------------|
|
||||
| `allow` | List/CSV | List of [extra privileged entitlement](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#allow) (eg. `network.host,security.insecure`) |
|
||||
| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) |
|
||||
| `build-args` | List | List of build-time variables |
|
||||
| `cache-from` | List | List of [external cache sources](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#cache-from) (eg. `type=local,src=path/to/dir`) |
|
||||
| `cache-to` | List | List of [cache export destinations](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#cache-to) (eg. `type=local,dest=path/to/dir`) |
|
||||
| `context` | String | Build's context is the set of files located in the specified [`PATH` or `URL`](https://docs.docker.com/engine/reference/commandline/build/) (default [Git context](#git-context)) |
|
||||
| `file` | String | Path to the Dockerfile. (default `{context}/Dockerfile`) |
|
||||
| `labels` | List | List of metadata for an image |
|
||||
| `load` | Bool | [Load](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#load) is a shorthand for `--output=type=docker` (default `false`) |
|
||||
| `network` | String | Set the networking mode for the `RUN` instructions during build |
|
||||
| `no-cache` | Bool | Do not use cache when building the image (default `false`) |
|
||||
| `outputs` | List | List of [output destinations](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#output) (format: `type=local,dest=path`) |
|
||||
| `platforms` | List/CSV | List of [target platforms](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#platform) for build |
|
||||
| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) |
|
||||
| `push` | Bool | [Push](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#push) is a shorthand for `--output=type=registry` (default `false`) |
|
||||
| `secrets` | List | List of secrets to expose to the build (eg. `key=string`, `GIT_AUTH_TOKEN=mytoken`) |
|
||||
| `secret-files` | List | List of secret files to expose to the build (eg. `key=filename`, `MY_SECRET=./secret.txt`) |
|
||||
| `ssh` | List | List of SSH agent socket or keys to expose to the build |
|
||||
| `tags` | List/CSV | List of tags |
|
||||
| `target` | String | Sets the target stage to build |
|
||||
| Name | Type | Description |
|
||||
|--------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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`) |
|
||||
| `allow` | List/CSV | List of [extra privileged entitlement](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#allow) (e.g., `network.host,security.insecure`) |
|
||||
| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) |
|
||||
| `build-args` | List | List of [build-time variables](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#build-arg) |
|
||||
| `build-contexts` | List | List of additional [build contexts](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#build-context) (e.g., `name=path`) |
|
||||
| `cache-from` | List | List of [external cache sources](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#cache-from) (e.g., `type=local,src=path/to/dir`) |
|
||||
| `cache-to` | List | List of [cache export destinations](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#cache-to) (e.g., `type=local,dest=path/to/dir`) |
|
||||
| `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 |
|
||||
| `context` | String | Build's context is the set of files located in the specified [`PATH` or `URL`](https://docs.docker.com/engine/reference/commandline/build/) (default [Git context](#git-context)) |
|
||||
| `file` | String | Path to the Dockerfile. (default `{context}/Dockerfile`) |
|
||||
| `labels` | List | List of metadata for an image |
|
||||
| `load` | Bool | [Load](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#load) is a shorthand for `--output=type=docker` (default `false`) |
|
||||
| `network` | String | Set the networking mode for the `RUN` instructions during build |
|
||||
| `no-cache` | Bool | Do not use cache when building the image (default `false`) |
|
||||
| `no-cache-filters` | List/CSV | Do not cache specified stages |
|
||||
| `outputs` | List | List of [output destinations](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#output) (format: `type=local,dest=path`) |
|
||||
| `platforms` | List/CSV | List of [target platforms](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#platform) for build |
|
||||
| `pull` | Bool | Always attempt to pull all referenced images (default `false`) |
|
||||
| `push` | Bool | [Push](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#push) is a shorthand for `--output=type=registry` (default `false`) |
|
||||
| `secrets` | List | List of [secrets](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#secret) to expose to the build (e.g., `key=string`, `GIT_AUTH_TOKEN=mytoken`) |
|
||||
| `secret-files` | List | List of [secret files](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#secret) to expose to the build (e.g., `key=filename`, `MY_SECRET=./secret.txt`) |
|
||||
| `shm-size` | String | Size of [`/dev/shm`](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#-size-of-devshm---shm-size) (e.g., `2g`) |
|
||||
| `ssh` | List | List of [SSH agent socket or keys](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#ssh) to expose to the build |
|
||||
| `tags` | List/CSV | List of tags |
|
||||
| `target` | String | Sets the target stage to build |
|
||||
| `ulimit` | List | [Ulimit](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#-set-ulimits---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 }}`) |
|
||||
|
||||
### outputs
|
||||
|
||||
Following outputs are available
|
||||
|
||||
| Name | Type | Description |
|
||||
|---------------|---------|---------------------------------------|
|
||||
| `digest` | String | Image content-addressable identifier also called a digest |
|
||||
| Name | Type | Description |
|
||||
|------------|---------|-----------------------------------------|
|
||||
| `imageid` | String | Image ID |
|
||||
| `digest` | String | Image digest |
|
||||
| `metadata` | JSON | Build result metadata |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
||||
* [BuildKit container logs](#buildkit-container-logs)
|
||||
* [With containerd](#with-containerd)
|
||||
* [`repository name must be lowercase`](#repository-name-must-be-lowercase)
|
||||
|
||||
## Cannot push to a registry
|
||||
|
||||
@ -14,9 +15,11 @@ While pushing to a registry, you may encounter these kinds of issues:
|
||||
* `failed commit on ref "manifest-sha256:...": unexpected status: 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),
|
||||
[buildkit](https://github.com/moby/buildkit), [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.
|
||||
These issues are not directly related to this action but are rather linked to
|
||||
[buildx](https://github.com/docker/buildx), [buildkit](https://github.com/moby/buildkit),
|
||||
[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.
|
||||
|
||||
### BuildKit container logs
|
||||
|
||||
@ -25,8 +28,9 @@ action step and attach BuildKit container logs to your issue.
|
||||
|
||||
### With containerd
|
||||
|
||||
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.
|
||||
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
|
||||
name: containerd
|
||||
@ -40,21 +44,21 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Set up containerd
|
||||
uses: crazy-max/ghaction-setup-containerd@v1
|
||||
uses: crazy-max/ghaction-setup-containerd@v2
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@ -69,3 +73,65 @@ jobs:
|
||||
run: |
|
||||
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
|
||||
```
|
||||
|
147
UPGRADE.md
147
UPGRADE.md
@ -1,147 +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` input to support multi-platform builds
|
||||
* Add `allow` input
|
||||
* Add `load` input
|
||||
* Add `outputs` input
|
||||
* Add `cache-from` input (`cache_froms` removed)
|
||||
* Add `cache-to` 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: .
|
||||
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: .
|
||||
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 to handle tags and labels](docs/advanced/tags-labels.md) based on GitHub
|
||||
> actions events and Git metadata.
|
@ -1,13 +1,17 @@
|
||||
import {describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
|
||||
import * as exec from '@actions/exec';
|
||||
import * as buildx from '../src/buildx';
|
||||
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 digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||
const imageID = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||
const metadata = `{
|
||||
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
||||
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
||||
}`;
|
||||
|
||||
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||
const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep);
|
||||
@ -24,96 +28,92 @@ jest.spyOn(context, 'tmpNameSync').mockImplementation((): string => {
|
||||
describe('getImageID', () => {
|
||||
it('matches', async () => {
|
||||
const imageIDFile = await buildx.getImageIDFile();
|
||||
console.log(`imageIDFile: ${imageIDFile}`);
|
||||
await fs.writeFileSync(imageIDFile, digest);
|
||||
const imageID = await buildx.getImageID();
|
||||
console.log(`imageID: ${imageID}`);
|
||||
expect(imageID).toEqual(digest);
|
||||
await fs.writeFileSync(imageIDFile, imageID);
|
||||
const expected = await buildx.getImageID();
|
||||
expect(expected).toEqual(imageID);
|
||||
});
|
||||
});
|
||||
|
||||
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', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
[
|
||||
'type=registry,ref=user/app',
|
||||
],
|
||||
false
|
||||
],
|
||||
[
|
||||
[
|
||||
'type=docker',
|
||||
],
|
||||
false
|
||||
],
|
||||
[
|
||||
[
|
||||
'type=local,dest=./release-out'
|
||||
],
|
||||
true
|
||||
],
|
||||
[
|
||||
[
|
||||
'type=tar,dest=/tmp/image.tar'
|
||||
],
|
||||
true
|
||||
],
|
||||
[
|
||||
[
|
||||
'type=docker',
|
||||
'type=tar,dest=/tmp/image.tar'
|
||||
],
|
||||
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);
|
||||
}
|
||||
);
|
||||
[['type=registry,ref=user/app'], false],
|
||||
[['type=docker'], false],
|
||||
[['type=local,dest=./release-out'], true],
|
||||
[['type=tar,dest=/tmp/image.tar'], true],
|
||||
[['type=docker', 'type=tar,dest=/tmp/image.tar'], 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('isAvailable', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
buildx.isAvailable();
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAvailable standalone', () => {
|
||||
const execSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
buildx.isAvailable(true);
|
||||
|
||||
// eslint-disable-next-line jest/no-standalone-expect
|
||||
expect(execSpy).toHaveBeenCalledWith(`buildx`, [], {
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVersion', () => {
|
||||
async function isDaemonRunning() {
|
||||
return await docker.isDaemonRunning();
|
||||
}
|
||||
(isDaemonRunning() ? it : it.skip)(
|
||||
'valid',
|
||||
async () => {
|
||||
const version = await buildx.getVersion();
|
||||
console.log(`version: ${version}`);
|
||||
expect(semver.valid(version)).not.toBeNull();
|
||||
},
|
||||
100000
|
||||
);
|
||||
it('valid', async () => {
|
||||
const version = await buildx.getVersion();
|
||||
expect(semver.valid(version)).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseVersion', () => {
|
||||
test.each([
|
||||
['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||
['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2']
|
||||
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'],
|
||||
['github.com/docker/buildx f117971 f11797113e5a9b86bd976329c5dbb8a8bfdfadfa', 'f117971']
|
||||
])('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);
|
||||
});
|
||||
});
|
||||
|
||||
@ -125,13 +125,7 @@ describe('getSecret', () => {
|
||||
['aaaaaaaa', false, '', '', true],
|
||||
['aaaaaaaa=', false, '', '', true],
|
||||
['=bbbbbbb', false, '', '', true],
|
||||
[
|
||||
`foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`,
|
||||
true,
|
||||
'foo',
|
||||
'bar',
|
||||
false
|
||||
],
|
||||
[`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 {
|
||||
@ -142,12 +136,11 @@ describe('getSecret', () => {
|
||||
secret = await buildx.getSecretString(kvp);
|
||||
}
|
||||
expect(true).toBe(!invalid);
|
||||
console.log(`secret: ${secret}`);
|
||||
expect(secret).toEqual(`id=${exKey},src=${tmpNameSync}`);
|
||||
const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8');
|
||||
console.log(`secretValue: ${secretValue}`);
|
||||
expect(secretValue).toEqual(exValue);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(true).toBe(invalid);
|
||||
}
|
||||
});
|
||||
|
@ -1,3 +1,4 @@
|
||||
import {beforeEach, describe, expect, it, jest, test} from '@jest/globals';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
@ -140,24 +141,32 @@ describe('getArgs', () => {
|
||||
// prettier-ignore
|
||||
test.each([
|
||||
[
|
||||
0,
|
||||
'0.4.1',
|
||||
new Map<string, string>([
|
||||
['context', '.'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'.'
|
||||
]
|
||||
],
|
||||
[
|
||||
1,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['build-args', 'MY_ARG=val1,val2,val3\nARG=val'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--build-arg', 'MY_ARG=val1,val2,val3',
|
||||
'--build-arg', 'ARG=val',
|
||||
@ -166,28 +175,36 @@ describe('getArgs', () => {
|
||||
]
|
||||
],
|
||||
[
|
||||
2,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['tags', 'name/app:7.4, name/app:latest'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'--tag', 'name/app:7.4',
|
||||
'--tag', 'name/app:latest',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'https://github.com/docker/build-push-action.git#refs/heads/test-jest'
|
||||
]
|
||||
],
|
||||
[
|
||||
3,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['context', '.'],
|
||||
['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',
|
||||
'--label', 'org.opencontainers.image.title=buildkit',
|
||||
'--label', 'org.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit',
|
||||
@ -196,38 +213,50 @@ describe('getArgs', () => {
|
||||
]
|
||||
],
|
||||
[
|
||||
4,
|
||||
'0.4.1',
|
||||
new Map<string, string>([
|
||||
['context', '.'],
|
||||
['platforms', 'linux/amd64,linux/arm64']
|
||||
['platforms', 'linux/amd64,linux/arm64'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--platform', 'linux/amd64,linux/arm64',
|
||||
'.'
|
||||
]
|
||||
],
|
||||
[
|
||||
5,
|
||||
'0.4.1',
|
||||
new Map<string, string>([
|
||||
['context', '.']
|
||||
['context', '.'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'.'
|
||||
]
|
||||
],
|
||||
[
|
||||
6,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['context', '.'],
|
||||
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||
@ -235,13 +264,17 @@ describe('getArgs', () => {
|
||||
]
|
||||
],
|
||||
[
|
||||
7,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['github-token', 'abcdefghijklmno0123456789'],
|
||||
['outputs', '.']
|
||||
['outputs', '.'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--output', '.',
|
||||
'--secret', 'id=GIT_AUTH_TOKEN,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||
@ -249,6 +282,7 @@ describe('getArgs', () => {
|
||||
]
|
||||
],
|
||||
[
|
||||
8,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||
@ -257,21 +291,24 @@ describe('getArgs', () => {
|
||||
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
||||
['file', './test/Dockerfile'],
|
||||
['builder', 'builder-git-context-2'],
|
||||
['push', 'true']
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'true'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'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',
|
||||
'--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',
|
||||
'--push',
|
||||
'https://github.com/docker/build-push-action.git#refs/heads/master'
|
||||
]
|
||||
],
|
||||
[
|
||||
9,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||
@ -288,24 +325,27 @@ bbbb
|
||||
ccc"`],
|
||||
['file', './test/Dockerfile'],
|
||||
['builder', 'builder-git-context-2'],
|
||||
['push', 'true']
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'true'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--platform', 'linux/amd64,linux/arm64',
|
||||
'--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',
|
||||
'--secret', 'id=MYSECRET,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',
|
||||
'--file', './test/Dockerfile',
|
||||
'--builder', 'builder-git-context-2',
|
||||
'--push',
|
||||
'https://github.com/docker/build-push-action.git#refs/heads/master'
|
||||
]
|
||||
],
|
||||
[
|
||||
10,
|
||||
'0.4.2',
|
||||
new Map<string, string>([
|
||||
['context', 'https://github.com/docker/build-push-action.git#refs/heads/master'],
|
||||
@ -322,24 +362,27 @@ bbbb
|
||||
ccc`],
|
||||
['file', './test/Dockerfile'],
|
||||
['builder', 'builder-git-context-2'],
|
||||
['push', 'true']
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'true'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--platform', 'linux/amd64,linux/arm64',
|
||||
'--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',
|
||||
'--secret', 'id=MYSECRET,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',
|
||||
'--file', './test/Dockerfile',
|
||||
'--builder', 'builder-git-context-2',
|
||||
'--push',
|
||||
'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'],
|
||||
@ -348,14 +391,16 @@ ccc`],
|
||||
['file', './test/Dockerfile'],
|
||||
['builder', 'builder-git-context-2'],
|
||||
['network', 'host'],
|
||||
['push', 'true']
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'true'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'build',
|
||||
'--file', './test/Dockerfile',
|
||||
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||
'--secret', 'id=MY_SECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
|
||||
'--file', './test/Dockerfile',
|
||||
'--builder', 'builder-git-context-2',
|
||||
'--network', 'host',
|
||||
'--push',
|
||||
@ -363,32 +408,107 @@ ccc`],
|
||||
]
|
||||
],
|
||||
[
|
||||
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']
|
||||
['outputs', 'type=local,dest=./release-out'],
|
||||
['load', 'false'],
|
||||
['no-cache', 'false'],
|
||||
['push', 'false'],
|
||||
['pull', 'false'],
|
||||
]),
|
||||
[
|
||||
'buildx',
|
||||
'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'
|
||||
]
|
||||
],
|
||||
])(
|
||||
'given %p with %p as inputs, returns %p',
|
||||
async (buildxVersion: string, inputs: Map<string, any>, expected: Array<string>) => {
|
||||
await inputs.forEach((value: string, name: string) => {
|
||||
'[%d] given %p with %p as inputs, returns %p',
|
||||
async (num: number, buildxVersion: string, inputs: Map<string, string>, expected: Array<string>) => {
|
||||
inputs.forEach((value: string, name: string) => {
|
||||
setInput(name, value);
|
||||
});
|
||||
const defContext = context.defaultContext();
|
||||
const inp = await context.getInputs(defContext);
|
||||
console.log(inp);
|
||||
const res = await context.getArgs(inp, defContext, buildxVersion);
|
||||
console.log(res);
|
||||
expect(res).toEqual(expected);
|
||||
}
|
||||
);
|
||||
@ -398,63 +518,54 @@ describe('getInputList', () => {
|
||||
it('single line correctly', async () => {
|
||||
await setInput('foo', 'bar');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar']);
|
||||
});
|
||||
|
||||
it('multiline correctly', async () => {
|
||||
setInput('foo', 'bar\nbaz');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('empty lines correctly', async () => {
|
||||
setInput('foo', 'bar\n\nbaz');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('comma correctly', async () => {
|
||||
setInput('foo', 'bar,baz');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('empty result correctly', async () => {
|
||||
setInput('foo', 'bar,baz,');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('different new lines correctly', async () => {
|
||||
setInput('foo', 'bar\r\nbaz');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar', 'baz']);
|
||||
});
|
||||
|
||||
it('different new lines and comma correctly', async () => {
|
||||
setInput('foo', 'bar\r\nbaz,bat');
|
||||
const res = await context.getInputList('foo');
|
||||
console.log(res);
|
||||
expect(res).toEqual(['bar', 'baz', 'bat']);
|
||||
});
|
||||
|
||||
it('multiline and ignoring comma correctly', async () => {
|
||||
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
|
||||
const res = await context.getInputList('cache-from', true);
|
||||
console.log(res);
|
||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||
});
|
||||
|
||||
it('different new lines and ignoring comma correctly', async () => {
|
||||
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
|
||||
const res = await context.getInputList('cache-from', true);
|
||||
console.log(res);
|
||||
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
|
||||
});
|
||||
|
||||
@ -468,7 +579,6 @@ ccccccccc"
|
||||
FOO=bar`
|
||||
);
|
||||
const res = await context.getInputList('secrets', true);
|
||||
console.log(res);
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
@ -492,7 +602,6 @@ bbbb
|
||||
ccc"`
|
||||
);
|
||||
const res = await context.getInputList('secrets', true);
|
||||
console.log(res);
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
@ -516,14 +625,7 @@ ccccccccc
|
||||
FOO=bar`
|
||||
);
|
||||
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 () => {
|
||||
@ -533,7 +635,6 @@ FOO=bar`
|
||||
FOO=bar`
|
||||
);
|
||||
const res = await context.getInputList('secrets', true);
|
||||
console.log(res);
|
||||
expect(res).toEqual([`GPG_KEY=${pgp}`, 'FOO=bar']);
|
||||
});
|
||||
|
||||
@ -547,11 +648,10 @@ ccccccccc"
|
||||
FOO=bar`
|
||||
);
|
||||
const res = await context.getInputList('secrets', true);
|
||||
console.log(res);
|
||||
expect(res).toEqual([
|
||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
||||
`MYSECRET=aaaaaaaa
|
||||
bbbb\"bbb
|
||||
bbbb"bbb
|
||||
ccccccccc`,
|
||||
'FOO=bar'
|
||||
]);
|
||||
@ -573,26 +673,29 @@ describe('asyncForEach', () => {
|
||||
|
||||
describe('setOutput', () => {
|
||||
beforeEach(() => {
|
||||
process.stdout.write = jest.fn();
|
||||
process.stdout.write = jest.fn() as typeof process.stdout.write;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('setOutput produces the correct command', () => {
|
||||
context.setOutput('some output', 'some value');
|
||||
assertWriteCalls([`::set-output name=some output::some value${os.EOL}`]);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('setOutput handles bools', () => {
|
||||
context.setOutput('some output', false);
|
||||
assertWriteCalls([`::set-output name=some output::false${os.EOL}`]);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('setOutput handles numbers', () => {
|
||||
context.setOutput('some output', 1.01);
|
||||
assertWriteCalls([`::set-output name=some output::1.01${os.EOL}`]);
|
||||
});
|
||||
});
|
||||
|
||||
// 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 {
|
||||
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
|
||||
});
|
||||
});
|
||||
});
|
38
action.yml
38
action.yml
@ -7,20 +7,29 @@ branding:
|
||||
color: 'blue'
|
||||
|
||||
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 (eg. network.host,security.insecure)"
|
||||
description: "List of extra privileged entitlement (e.g., network.host,security.insecure)"
|
||||
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:
|
||||
description: "Builder instance"
|
||||
required: false
|
||||
cache-from:
|
||||
description: "List of external cache sources for buildx (eg. user/app:cache, type=local,src=path/to/dir)"
|
||||
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 (eg. user/app:cache, type=local,dest=path/to/dir)"
|
||||
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:
|
||||
description: "Build's context is the set of files located in the specified PATH or URL"
|
||||
@ -42,6 +51,9 @@ inputs:
|
||||
description: "Do not use cache when building the image"
|
||||
required: 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
|
||||
@ -49,7 +61,7 @@ inputs:
|
||||
description: "List of target platforms for build"
|
||||
required: false
|
||||
pull:
|
||||
description: "Always attempt to pull a newer version of the image"
|
||||
description: "Always attempt to pull all referenced images"
|
||||
required: false
|
||||
default: 'false'
|
||||
push:
|
||||
@ -57,10 +69,13 @@ inputs:
|
||||
required: false
|
||||
default: 'false'
|
||||
secrets:
|
||||
description: "List of secrets to expose to the build (eg. key=string, 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 (eg. key=filename, MY_SECRET=./secret.txt)"
|
||||
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"
|
||||
@ -71,16 +86,23 @@ inputs:
|
||||
target:
|
||||
description: "Sets the target stage to build"
|
||||
required: false
|
||||
ulimit:
|
||||
description: "Ulimit options (e.g., nofile=1024:1024)"
|
||||
required: false
|
||||
github-token:
|
||||
description: "GitHub Token used to authenticate against a repository for Git context"
|
||||
default: ${{ github.token }}
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
imageid:
|
||||
description: 'Image ID'
|
||||
digest:
|
||||
description: 'Image content-addressable identifier also called a digest'
|
||||
description: 'Image digest'
|
||||
metadata:
|
||||
description: 'Build result metadata'
|
||||
|
||||
runs:
|
||||
using: 'node12'
|
||||
using: 'node16'
|
||||
main: '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
|
78
dev.Dockerfile
Normal file
78
dev.Dockerfile
Normal file
@ -0,0 +1,78 @@
|
||||
# syntax=docker/dockerfile:1.4
|
||||
|
||||
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
|
||||
ENV RUNNER_TEMP=/tmp/github_runner
|
||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
--mount=type=bind,from=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
||||
--mount=type=bind,from=buildx,source=/buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
||||
yarn run test --coverageDirectory=/tmp/coverage
|
||||
|
||||
FROM scratch AS test-coverage
|
||||
COPY --from=test /tmp/coverage /
|
16962
dist/index.js
generated
vendored
16962
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
1045
dist/licenses.txt
generated
vendored
Normal file
1045
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
@ -1,13 +1,3 @@
|
||||
variable "NODE_VERSION" {
|
||||
default = "12"
|
||||
}
|
||||
|
||||
target "node-version" {
|
||||
args = {
|
||||
NODE_VERSION = NODE_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
group "default" {
|
||||
targets = ["build"]
|
||||
}
|
||||
@ -17,51 +7,47 @@ group "pre-checkin" {
|
||||
}
|
||||
|
||||
group "validate" {
|
||||
targets = ["format-validate", "build-validate", "vendor-validate"]
|
||||
targets = ["lint", "build-validate", "vendor-validate"]
|
||||
}
|
||||
|
||||
target "build" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "build-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "build-validate" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "build-validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "format" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "format-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "format-validate" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/build.Dockerfile"
|
||||
target = "format-validate"
|
||||
target "lint" {
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "lint"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "vendor-update" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/vendor.Dockerfile"
|
||||
target = "update"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "vendor-update"
|
||||
output = ["."]
|
||||
}
|
||||
|
||||
target "vendor-validate" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/vendor.Dockerfile"
|
||||
target = "validate"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "vendor-validate"
|
||||
output = ["type=cacheonly"]
|
||||
}
|
||||
|
||||
target "test" {
|
||||
inherits = ["node-version"]
|
||||
dockerfile = "./hack/test.Dockerfile"
|
||||
dockerfile = "dev.Dockerfile"
|
||||
target = "test-coverage"
|
||||
output = ["./coverage"]
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
# Cache
|
||||
|
||||
* [Inline cache](#inline-cache)
|
||||
* [Registry cache](#registry-cache)
|
||||
* [GitHub cache](#github-cache)
|
||||
* [Cache backend API](#cache-backend-api)
|
||||
* [Local cache](#local-cache)
|
||||
|
||||
> More info about buildx cache: https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#cache-from
|
||||
> More info about cache on [BuildKit](https://github.com/moby/buildkit#export-cache) and [Buildx](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#cache-from) repositories.
|
||||
|
||||
## Registry cache
|
||||
## Inline cache
|
||||
|
||||
You can import/export cache from a cache manifest or (special) image configuration on the registry.
|
||||
In most cases you want to use the [`type=inline` cache exporter](https://github.com/moby/buildkit#inline-push-image-and-cache-together).
|
||||
However, note that the `inline` cache exporter only supports `min` cache mode. To enable `max` cache mode, push the
|
||||
image and the cache separately by using the `registry` cache exporter as shown in the [next example](#registry-cache).
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
@ -15,7 +20,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -23,19 +28,19 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@ -44,16 +49,10 @@ jobs:
|
||||
cache-to: type=inline
|
||||
```
|
||||
|
||||
## GitHub cache
|
||||
## Registry cache
|
||||
|
||||
> :warning: At the moment caches are copied over the existing cache so it [keeps growing](https://github.com/docker/build-push-action/issues/252).
|
||||
> The `Move cache` step is used as a temporary fix (see https://github.com/moby/buildkit/issues/1896).
|
||||
|
||||
> :rocket: There is a new cache backend using GitHub cache being developed that will lighten your workflow.
|
||||
> More info: https://github.com/docker/buildx/pull/535
|
||||
|
||||
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:
|
||||
You can import/export cache from a cache manifest or (special) image configuration on the registry with the
|
||||
[`type=registry` cache exporter](https://github.com/moby/buildkit/tree/master#registry-push-image-and-cache-separately).
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
@ -61,7 +60,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -69,13 +68,107 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
cache-from: type=registry,ref=user/app:buildcache
|
||||
cache-to: type=registry,ref=user/app:buildcache,mode=max
|
||||
```
|
||||
|
||||
## GitHub cache
|
||||
|
||||
### Cache backend API
|
||||
|
||||
> :test_tube: This cache exporter is considered EXPERIMENTAL until further notice. Please provide feedback on
|
||||
> [BuildKit repository](https://github.com/moby/buildkit) if you encounter any issues.
|
||||
|
||||
Since [buildx 0.6.0](https://github.com/docker/buildx/releases/tag/v0.6.0) and [BuildKit 0.9.0](https://github.com/moby/buildkit/releases/tag/v0.9.0),
|
||||
you can use the [`type=gha` cache exporter](https://github.com/moby/buildkit/tree/master#github-actions-cache-experimental).
|
||||
|
||||
GitHub Actions cache exporter backend uses the [GitHub Cache API](https://github.com/tonistiigi/go-actions-cache/blob/master/api.md)
|
||||
to fetch and upload cache blobs. That's why this type of cache should be exclusively used in a GitHub Action workflow
|
||||
as the `url` (`$ACTIONS_CACHE_URL`) and `token` (`$ACTIONS_RUNTIME_TOKEN`) attributes are populated when a workflow
|
||||
is started.
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
```
|
||||
|
||||
### Local cache
|
||||
|
||||
> :warning: At the moment caches are copied over the existing cache so it [keeps growing](https://github.com/docker/build-push-action/issues/252).
|
||||
> The `Move cache` step is used as a temporary fix (see https://github.com/moby/buildkit/issues/1896).
|
||||
|
||||
You can also 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) and [`type=local` cache exporter](https://github.com/moby/buildkit#local-directory-1)
|
||||
with this action:
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
@ -83,19 +176,19 @@ jobs:
|
||||
${{ runner.os }}-buildx-
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
|
||||
-
|
||||
# Temp fix
|
||||
# https://github.com/docker/build-push-action/issues/252
|
||||
|
@ -12,7 +12,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -20,36 +20,36 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- # quay and ghcr logins for pushing image after testing
|
||||
name: Login to Quay Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.QUAY_USERNAME }}
|
||||
password: ${{ secrets.QUAY_TOKEN }}
|
||||
-
|
||||
name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@ -62,7 +62,7 @@ jobs:
|
||||
run: make tests
|
||||
- # copy multiplatform image from dockerhub to quay and ghcr
|
||||
name: Push Image to multiple registries
|
||||
uses: akhilerm/tag-push-action@v1.0.0
|
||||
uses: akhilerm/tag-push-action@v2.0.0
|
||||
with:
|
||||
src: docker.io/user/app:1.0.0
|
||||
dst: |
|
||||
|
@ -10,7 +10,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -18,22 +18,22 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
@ -9,7 +9,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -17,13 +17,13 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
load: true
|
||||
|
@ -6,7 +6,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -14,12 +14,12 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
id: builder1
|
||||
-
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
id: builder2
|
||||
-
|
||||
name: Builder 1 name
|
||||
@ -29,14 +29,14 @@ jobs:
|
||||
run: echo ${{ steps.builder2.outputs.name }}
|
||||
-
|
||||
name: Build against builder1
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
builder: ${{ steps.builder1.outputs.name }}
|
||||
context: .
|
||||
target: mytarget1
|
||||
-
|
||||
name: Build against builder2
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
builder: ${{ steps.builder2.outputs.name }}
|
||||
context: .
|
||||
|
@ -8,7 +8,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -21,18 +21,18 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: network=host
|
||||
-
|
||||
name: Build and push to local registry
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
@ -12,7 +12,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -20,22 +20,22 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
@ -14,7 +14,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -22,29 +22,29 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
@ -22,7 +22,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -30,16 +30,16 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
@ -11,7 +11,7 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -19,20 +19,20 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build and export
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
tags: myimage:latest
|
||||
outputs: type=docker,dest=/tmp/myimage.tar
|
||||
-
|
||||
name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: myimage
|
||||
path: /tmp/myimage.tar
|
||||
@ -43,10 +43,10 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Download artifact
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: myimage
|
||||
path: /tmp
|
||||
|
@ -1,7 +1,6 @@
|
||||
# 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)
|
||||
If you 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 metadata action](https://github.com/docker/metadata-action)
|
||||
to handle tags and labels based on GitHub actions events and Git metadata.
|
||||
|
||||
@ -10,7 +9,7 @@ name: ci
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # everyday at 10am
|
||||
- cron: '0 10 * * *'
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
@ -18,7 +17,7 @@ on:
|
||||
- 'v*.*.*'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
@ -26,11 +25,11 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: |
|
||||
@ -47,28 +46,28 @@ jobs:
|
||||
type=sha
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Login to GHCR
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
|
64
docs/advanced/test-before-push.md
Normal file
64
docs/advanced/test-before-push.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Test your image before pushing it
|
||||
|
||||
In some cases, you might want to validate that the image works as expected
|
||||
before pushing it.
|
||||
|
||||
The workflow below will be composed of several steps to achieve this:
|
||||
* Build and export the image to Docker
|
||||
* Test your image
|
||||
* Multi-platform build and push the image
|
||||
|
||||
```yaml
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
env:
|
||||
TEST_TAG: user/myapp:test
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and export to Docker
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
load: true
|
||||
tags: ${{ env.TEST_TAG }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
docker run --rm ${{ env.TEST_TAG }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: user/app:latest
|
||||
```
|
||||
|
||||
> :bulb: Build time will not be increased with this workflow because internal
|
||||
> cache for `linux/amd64` will be used from previous step on `Build and push`
|
||||
> step so only `linux/arm64` will be actually built.
|
@ -1,42 +0,0 @@
|
||||
# syntax=docker/dockerfile:1.2
|
||||
ARG NODE_VERSION
|
||||
|
||||
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
|
||||
|
||||
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 \
|
||||
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
|
||||
|
||||
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 format-validate
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn run format-check \
|
@ -1,23 +0,0 @@
|
||||
# syntax=docker/dockerfile:1.2
|
||||
ARG NODE_VERSION
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine AS base
|
||||
RUN apk add --no-cache git
|
||||
WORKDIR /src
|
||||
|
||||
FROM base AS deps
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn install
|
||||
|
||||
FROM deps AS test
|
||||
ENV RUNNER_TEMP=/tmp/github_runner
|
||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
--mount=type=bind,from=crazymax/docker,source=/usr/libexec/docker/cli-plugins/docker-buildx,target=/usr/libexec/docker/cli-plugins/docker-buildx \
|
||||
--mount=type=bind,from=crazymax/docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
||||
yarn run test --coverageDirectory=/tmp/coverage
|
||||
|
||||
FROM scratch AS test-coverage
|
||||
COPY --from=test /tmp/coverage /
|
@ -1,23 +0,0 @@
|
||||
# syntax=docker/dockerfile:1.2
|
||||
ARG NODE_VERSION
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine AS base
|
||||
RUN apk add --no-cache git
|
||||
WORKDIR /src
|
||||
|
||||
FROM base AS vendored
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=cache,target=/src/node_modules \
|
||||
yarn install && mkdir /out && cp yarn.lock /out
|
||||
|
||||
FROM scratch AS update
|
||||
COPY --from=vendored /out /
|
||||
|
||||
FROM vendored AS validate
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
git add -A && cp -rf /out/* .; \
|
||||
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
|
@ -1,12 +1,13 @@
|
||||
module.exports = {
|
||||
clearMocks: false,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
setupFiles: ["dotenv/config"],
|
||||
testEnvironment: 'node',
|
||||
setupFiles: ['dotenv/config'],
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: false
|
||||
}
|
||||
moduleNameMapper: {
|
||||
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
|
||||
},
|
||||
verbose: true
|
||||
};
|
47
package.json
47
package.json
@ -3,11 +3,11 @@
|
||||
"description": "Build and push Docker images",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc && ncc build",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
|
||||
"lint": "eslint src/**/*.ts __tests__/**/*.ts",
|
||||
"format": "eslint --fix src/**/*.ts __tests__/**/*.ts",
|
||||
"test": "jest --coverage",
|
||||
"pre-checkin": "yarn run format && yarn run build"
|
||||
"all": "yarn run build && yarn run format && yarn test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -28,26 +28,31 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.3.0",
|
||||
"@actions/exec": "^1.0.4",
|
||||
"@actions/github": "^5.0.0",
|
||||
"csv-parse": "^4.15.4",
|
||||
"semver": "^7.3.5",
|
||||
"@actions/core": "^1.9.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.0.3",
|
||||
"csv-parse": "^5.3.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"semver": "^7.3.7",
|
||||
"tmp": "^0.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/csv-parse": "^1.2.2",
|
||||
"@types/jest": "^26.0.3",
|
||||
"@types/node": "^14.0.14",
|
||||
"@types/tmp": "^0.2.0",
|
||||
"@vercel/ncc": "^0.23.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"jest": "^26.1.0",
|
||||
"jest-circus": "^26.1.0",
|
||||
"jest-runtime": "^26.1.0",
|
||||
"prettier": "^2.0.5",
|
||||
"ts-jest": "^26.1.1",
|
||||
"typescript": "^3.9.5",
|
||||
"typescript-formatter": "^7.2.2"
|
||||
"@types/node": "^16.11.26",
|
||||
"@types/semver": "^7.3.9",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"@vercel/ncc": "^0.33.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^27.2.5",
|
||||
"prettier": "^2.3.1",
|
||||
"ts-jest": "^27.1.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.4.4"
|
||||
}
|
||||
}
|
||||
|
107
src/buildx.ts
107
src/buildx.ts
@ -1,10 +1,10 @@
|
||||
import csvparse from 'csv-parse/lib/sync';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as semver from 'semver';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
import * as context from './context';
|
||||
import * as exec from './exec';
|
||||
|
||||
export async function getImageIDFile(): Promise<string> {
|
||||
return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
|
||||
@ -15,7 +15,34 @@ export async function getImageID(): Promise<string | undefined> {
|
||||
if (!fs.existsSync(iidFile)) {
|
||||
return undefined;
|
||||
}
|
||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'}).trim();
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -49,19 +76,20 @@ export async function getSecret(kvp: string, file: boolean): Promise<string> {
|
||||
return `id=${key},src=${secretFile}`;
|
||||
}
|
||||
|
||||
export function isLocalOrTarExporter(outputs: string[]): Boolean {
|
||||
for (let output of csvparse(outputs.join(`\n`), {
|
||||
export function isLocalOrTarExporter(outputs: string[]): boolean {
|
||||
const records = parse(outputs.join(`\n`), {
|
||||
delimiter: ',',
|
||||
trim: true,
|
||||
columns: false,
|
||||
relaxColumnCount: true
|
||||
})) {
|
||||
});
|
||||
for (const record of records) {
|
||||
// Local if no type is defined
|
||||
// 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;
|
||||
}
|
||||
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')) {
|
||||
return true;
|
||||
}
|
||||
@ -70,8 +98,8 @@ export function isLocalOrTarExporter(outputs: string[]): Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasGitAuthToken(secrets: string[]): Boolean {
|
||||
for (let secret of secrets) {
|
||||
export function hasGitAuthToken(secrets: string[]): boolean {
|
||||
for (const secret of secrets) {
|
||||
if (secret.startsWith('GIT_AUTH_TOKEN=')) {
|
||||
return true;
|
||||
}
|
||||
@ -79,28 +107,55 @@ export function hasGitAuthToken(secrets: string[]): Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function isAvailable(): Promise<Boolean> {
|
||||
return await exec.exec(`docker`, ['buildx'], true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
export async function isAvailable(standalone?: boolean): Promise<boolean> {
|
||||
const cmd = getCommand([], standalone);
|
||||
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;
|
||||
}
|
||||
return res.success;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getVersion(): Promise<string> {
|
||||
return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(res.stderr);
|
||||
}
|
||||
return parseVersion(res.stdout);
|
||||
});
|
||||
export async function 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 async function parseVersion(stdout: string): Promise<string> {
|
||||
const matches = /\sv?([0-9.]+)/.exec(stdout);
|
||||
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 semver.clean(matches[1]);
|
||||
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]
|
||||
};
|
||||
}
|
||||
|
145
src/context.ts
145
src/context.ts
@ -1,8 +1,7 @@
|
||||
import csvparse from 'csv-parse/lib/sync';
|
||||
import {parse} from 'csv-parse/sync';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
import * as tmp from 'tmp';
|
||||
|
||||
import * as core from '@actions/core';
|
||||
@ -10,30 +9,37 @@ import {issueCommand} from '@actions/core/lib/command';
|
||||
import * as github from '@actions/github';
|
||||
|
||||
import * as buildx from './buildx';
|
||||
import * as handlebars from 'handlebars';
|
||||
|
||||
let _defaultContext, _tmpDir: string;
|
||||
|
||||
export interface Inputs {
|
||||
addHosts: string[];
|
||||
allow: string[];
|
||||
buildArgs: string[];
|
||||
buildContexts: string[];
|
||||
builder: string;
|
||||
cacheFrom: string[];
|
||||
cacheTo: string[];
|
||||
cgroupParent: string;
|
||||
context: string;
|
||||
file: string;
|
||||
labels: string[];
|
||||
load: boolean;
|
||||
network: string;
|
||||
noCache: boolean;
|
||||
noCacheFilters: string[];
|
||||
outputs: string[];
|
||||
platforms: string[];
|
||||
pull: boolean;
|
||||
push: boolean;
|
||||
secrets: string[];
|
||||
secretFiles: string[];
|
||||
shmSize: string;
|
||||
ssh: string[];
|
||||
tags: string[];
|
||||
target: string;
|
||||
ulimit: string[];
|
||||
githubToken: string;
|
||||
}
|
||||
|
||||
@ -46,9 +52,7 @@ export function defaultContext(): string {
|
||||
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}`;
|
||||
_defaultContext = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}.git#${ref}`;
|
||||
}
|
||||
return _defaultContext;
|
||||
}
|
||||
@ -66,66 +70,60 @@ export function tmpNameSync(options?: tmp.TmpNameOptions): string {
|
||||
|
||||
export async function getInputs(defaultContext: string): Promise<Inputs> {
|
||||
return {
|
||||
addHosts: await getInputList('add-hosts'),
|
||||
allow: await getInputList('allow'),
|
||||
buildArgs: await getInputList('build-args', true),
|
||||
buildContexts: await getInputList('build-contexts', true),
|
||||
builder: core.getInput('builder'),
|
||||
cacheFrom: await getInputList('cache-from', 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: /true/i.test(core.getInput('load')),
|
||||
load: core.getBooleanInput('load'),
|
||||
network: core.getInput('network'),
|
||||
noCache: /true/i.test(core.getInput('no-cache')),
|
||||
noCache: core.getBooleanInput('no-cache'),
|
||||
noCacheFilters: await getInputList('no-cache-filters'),
|
||||
outputs: await getInputList('outputs', true),
|
||||
platforms: await getInputList('platforms'),
|
||||
pull: /true/i.test(core.getInput('pull')),
|
||||
push: /true/i.test(core.getInput('push')),
|
||||
pull: core.getBooleanInput('pull'),
|
||||
push: core.getBooleanInput('push'),
|
||||
secrets: await getInputList('secrets', true),
|
||||
secretFiles: await getInputList('secret-files', true),
|
||||
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>> {
|
||||
let args: Array<string> = ['buildx'];
|
||||
args.push.apply(args, await getBuildArgs(inputs, defaultContext, buildxVersion));
|
||||
args.push.apply(args, await getCommonArgs(inputs));
|
||||
args.push(inputs.context);
|
||||
return args;
|
||||
// prettier-ignore
|
||||
return [
|
||||
...await getBuildArgs(inputs, defaultContext, buildxVersion),
|
||||
...await getCommonArgs(inputs, buildxVersion),
|
||||
handlebars.compile(inputs.context)({defaultContext})
|
||||
];
|
||||
}
|
||||
|
||||
async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersion: string): Promise<Array<string>> {
|
||||
let args: Array<string> = ['build'];
|
||||
await asyncForEach(inputs.buildArgs, async buildArg => {
|
||||
args.push('--build-arg', buildArg);
|
||||
const args: Array<string> = ['build'];
|
||||
await asyncForEach(inputs.addHosts, async addHost => {
|
||||
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) {
|
||||
args.push('--allow', inputs.allow.join(','));
|
||||
}
|
||||
if (inputs.platforms.length > 0) {
|
||||
args.push('--platform', inputs.platforms.join(','));
|
||||
}
|
||||
await asyncForEach(inputs.outputs, async output => {
|
||||
args.push('--output', output);
|
||||
await asyncForEach(inputs.buildArgs, async buildArg => {
|
||||
args.push('--build-arg', buildArg);
|
||||
});
|
||||
if (
|
||||
!buildx.isLocalOrTarExporter(inputs.outputs) &&
|
||||
(inputs.platforms.length == 0 || semver.satisfies(buildxVersion, '>=0.4.2'))
|
||||
) {
|
||||
args.push('--iidfile', await buildx.getImageIDFile());
|
||||
if (buildx.satisfies(buildxVersion, '>=0.8.0')) {
|
||||
await asyncForEach(inputs.buildContexts, async buildContext => {
|
||||
args.push('--build-context', buildContext);
|
||||
});
|
||||
}
|
||||
await asyncForEach(inputs.cacheFrom, async cacheFrom => {
|
||||
args.push('--cache-from', cacheFrom);
|
||||
@ -133,6 +131,27 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
|
||||
await asyncForEach(inputs.cacheTo, async 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(','));
|
||||
}
|
||||
await asyncForEach(inputs.secrets, async secret => {
|
||||
try {
|
||||
args.push('--secret', await buildx.getSecretString(secret));
|
||||
@ -150,32 +169,44 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
|
||||
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == 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 => {
|
||||
args.push('--ssh', ssh);
|
||||
});
|
||||
if (inputs.file) {
|
||||
args.push('--file', inputs.file);
|
||||
await asyncForEach(inputs.tags, async tag => {
|
||||
args.push('--tag', tag);
|
||||
});
|
||||
if (inputs.target) {
|
||||
args.push('--target', inputs.target);
|
||||
}
|
||||
await asyncForEach(inputs.ulimit, async ulimit => {
|
||||
args.push('--ulimit', ulimit);
|
||||
});
|
||||
return args;
|
||||
}
|
||||
|
||||
async function getCommonArgs(inputs: Inputs): Promise<Array<string>> {
|
||||
let args: Array<string> = [];
|
||||
if (inputs.noCache) {
|
||||
args.push('--no-cache');
|
||||
}
|
||||
async function getCommonArgs(inputs: Inputs, buildxVersion: string): Promise<Array<string>> {
|
||||
const args: Array<string> = [];
|
||||
if (inputs.builder) {
|
||||
args.push('--builder', inputs.builder);
|
||||
}
|
||||
if (inputs.pull) {
|
||||
args.push('--pull');
|
||||
}
|
||||
if (inputs.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) {
|
||||
args.push('--push');
|
||||
}
|
||||
@ -183,27 +214,29 @@ async function getCommonArgs(inputs: Inputs): Promise<Array<string>> {
|
||||
}
|
||||
|
||||
export async function getInputList(name: string, ignoreComma?: boolean): Promise<string[]> {
|
||||
let res: Array<string> = [];
|
||||
const res: Array<string> = [];
|
||||
|
||||
const items = core.getInput(name);
|
||||
if (items == '') {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (let output of (await csvparse(items, {
|
||||
const records = await parse(items, {
|
||||
columns: false,
|
||||
relax: true,
|
||||
relaxQuotes: true,
|
||||
relaxColumnCount: true,
|
||||
skipLinesWithEmptyValues: true
|
||||
})) as Array<string[]>) {
|
||||
if (output.length == 1) {
|
||||
res.push(output[0]);
|
||||
skipEmptyLines: true
|
||||
});
|
||||
|
||||
for (const record of records as Array<string[]>) {
|
||||
if (record.length == 1) {
|
||||
res.push(record[0]);
|
||||
continue;
|
||||
} else if (!ignoreComma) {
|
||||
res.push(...output);
|
||||
res.push(...record);
|
||||
continue;
|
||||
}
|
||||
res.push(output.join(','));
|
||||
res.push(record.join(','));
|
||||
}
|
||||
|
||||
return res.filter(item => item).map(pat => pat.trim());
|
||||
@ -216,6 +249,6 @@ export const asyncForEach = async (array, callback) => {
|
||||
};
|
||||
|
||||
// FIXME: Temp fix https://github.com/actions/toolkit/issues/777
|
||||
export function setOutput(name: string, value: any): void {
|
||||
export function setOutput(name: string, value: unknown): void {
|
||||
issueCommand('set-output', {name}, value);
|
||||
}
|
||||
|
@ -1,7 +1,19 @@
|
||||
import * as exec from './exec';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
export async function isDaemonRunning(): Promise<boolean> {
|
||||
return await exec.exec(`docker`, ['version', '--format', '{{.Server.Os}}'], true).then(res => {
|
||||
return !res.stdout.includes(' ') && res.success;
|
||||
});
|
||||
export async function isAvailable(): Promise<boolean> {
|
||||
return await exec
|
||||
.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()
|
||||
};
|
||||
};
|
73
src/main.ts
73
src/main.ts
@ -1,40 +1,79 @@
|
||||
import * as fs from 'fs';
|
||||
import * as buildx from './buildx';
|
||||
import * as context from './context';
|
||||
import * as exec from './exec';
|
||||
import * as docker from './docker';
|
||||
import * as stateHelper from './state-helper';
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
const defContext = context.defaultContext();
|
||||
const inputs: context.Inputs = await context.getInputs(defContext);
|
||||
|
||||
// standalone if docker cli not available
|
||||
const standalone = !(await docker.isAvailable());
|
||||
|
||||
core.startGroup(`Docker info`);
|
||||
await exec.exec('docker', ['version']);
|
||||
await exec.exec('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())) {
|
||||
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();
|
||||
const defContext = context.defaultContext();
|
||||
let inputs: context.Inputs = await context.getInputs(defContext);
|
||||
|
||||
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
|
||||
await exec.exec('docker', args).then(res => {
|
||||
if (res.stderr != '' && !res.success) {
|
||||
throw new Error(`buildx call failed with: ${res.stderr.match(/(.*)\s*$/)![0]}`);
|
||||
}
|
||||
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);
|
||||
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 metadata = await buildx.getMetadata();
|
||||
const digest = await buildx.getDigest(metadata);
|
||||
|
||||
if (imageID) {
|
||||
core.startGroup(`Extracting digest`);
|
||||
core.info(`${imageID}`);
|
||||
context.setOutput('digest', imageID);
|
||||
core.endGroup();
|
||||
await core.group(`ImageID`, async () => {
|
||||
core.info(imageID);
|
||||
context.setOutput('imageid', imageID);
|
||||
});
|
||||
}
|
||||
if (digest) {
|
||||
await core.group(`Digest`, async () => {
|
||||
core.info(digest);
|
||||
context.setOutput('digest', digest);
|
||||
});
|
||||
}
|
||||
if (metadata) {
|
||||
await core.group(`Metadata`, async () => {
|
||||
core.info(metadata);
|
||||
context.setOutput('metadata', metadata);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
|
2
test/addhost.Dockerfile
Normal file
2
test/addhost.Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
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-upstream:master
|
||||
FROM alpine
|
||||
RUN cat /etc/*release
|
2
test/cgroup.Dockerfile
Normal file
2
test/cgroup.Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
FROM alpine
|
||||
RUN cat /proc/self/cgroup
|
8
test/nocachefilter.Dockerfile
Normal file
8
test/nocachefilter.Dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
FROM busybox AS base
|
||||
RUN echo "Hello world!" > /hello
|
||||
|
||||
FROM alpine AS build
|
||||
COPY --from=base /hello /hello
|
||||
RUN uname -a
|
||||
|
||||
FROM build
|
2
test/shmsize.Dockerfile
Normal file
2
test/shmsize.Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
FROM busybox
|
||||
RUN mount | grep /dev/shm
|
2
test/ulimit.Dockerfile
Normal file
2
test/ulimit.Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
FROM busybox
|
||||
RUN ulimit -a
|
@ -2,20 +2,18 @@
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"newLine": "lf",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true
|
||||
"useUnknownInCatchVariables": false,
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.test.ts"
|
||||
"**/*.test.ts",
|
||||
"jest.config.ts"
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user