mirror of
https://github.com/docker/build-push-action.git
synced 2025-06-15 15:47:12 +02:00
Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
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
|
### Troubleshooting
|
||||||
|
|
||||||
Before sumbitting a bug report please read the [Troubleshooting doc](https://github.com/docker/build-push-action/blob/master/TROUBLESHOOTING.md).
|
Before submitting a bug report please read the [Troubleshooting doc](https://github.com/docker/build-push-action/blob/master/TROUBLESHOOTING.md).
|
||||||
|
|
||||||
### Behaviour
|
### Behaviour
|
||||||
|
|
||||||
|
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@ -5,8 +5,8 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
labels:
|
labels:
|
||||||
- ":game_die: dependencies"
|
- "dependencies"
|
||||||
- ":robot: bot"
|
- "bot"
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
@ -14,5 +14,5 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-type: "production"
|
- dependency-type: "production"
|
||||||
labels:
|
labels:
|
||||||
- ":game_die: dependencies"
|
- "dependencies"
|
||||||
- ":robot: bot"
|
- "bot"
|
||||||
|
88
.github/workflows/ci.yml
vendored
88
.github/workflows/ci.yml
vendored
@ -70,9 +70,6 @@ jobs:
|
|||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest
|
name: Check digest
|
||||||
run: |
|
run: |
|
||||||
@ -133,9 +130,6 @@ jobs:
|
|||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest
|
name: Check digest
|
||||||
run: |
|
run: |
|
||||||
@ -191,9 +185,6 @@ jobs:
|
|||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest
|
name: Check digest
|
||||||
run: |
|
run: |
|
||||||
@ -392,9 +383,6 @@ jobs:
|
|||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest
|
name: Check digest
|
||||||
run: |
|
run: |
|
||||||
@ -447,9 +435,6 @@ jobs:
|
|||||||
name: Inspect (1)
|
name: Inspect (1)
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:latest
|
docker buildx imagetools inspect localhost:5000/name/app:latest
|
||||||
-
|
|
||||||
name: Image digest (1)
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest (1)
|
name: Check digest (1)
|
||||||
run: |
|
run: |
|
||||||
@ -480,9 +465,6 @@ jobs:
|
|||||||
name: Inspect (2)
|
name: Inspect (2)
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:latest
|
docker buildx imagetools inspect localhost:5000/name/app:latest
|
||||||
-
|
|
||||||
name: Image digest (2)
|
|
||||||
run: echo ${{ steps.docker_build2.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest (2)
|
name: Check digest (2)
|
||||||
run: |
|
run: |
|
||||||
@ -503,7 +485,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
uses: crazy-max/ghaction-dump-context@v1
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
|
||||||
github-cache-first:
|
local-cache-first:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
digest: ${{ steps.docker_build.outputs.digest }}
|
digest: ${{ steps.docker_build.outputs.digest }}
|
||||||
@ -531,7 +513,7 @@ jobs:
|
|||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: /tmp/.buildx-cache
|
path: /tmp/.buildx-cache
|
||||||
key: ${{ runner.os }}-buildx-ghcache-${{ github.sha }}
|
key: ${{ runner.os }}-buildx-local-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-buildx-ghcache-
|
${{ runner.os }}-buildx-ghcache-
|
||||||
-
|
-
|
||||||
@ -557,9 +539,6 @@ jobs:
|
|||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest
|
name: Check digest
|
||||||
run: |
|
run: |
|
||||||
@ -572,9 +551,9 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
uses: crazy-max/ghaction-dump-context@v1
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
|
||||||
github-cache-hit:
|
local-cache-hit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: github-cache-first
|
needs: local-cache-first
|
||||||
services:
|
services:
|
||||||
registry:
|
registry:
|
||||||
image: registry:2
|
image: registry:2
|
||||||
@ -600,7 +579,7 @@ jobs:
|
|||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: /tmp/.buildx-cache
|
path: /tmp/.buildx-cache
|
||||||
key: ${{ runner.os }}-buildx-ghcache-${{ github.sha }}
|
key: ${{ runner.os }}-buildx-local-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-buildx-ghcache-
|
${{ runner.os }}-buildx-ghcache-
|
||||||
-
|
-
|
||||||
@ -622,9 +601,6 @@ jobs:
|
|||||||
name: Inspect
|
name: Inspect
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
docker buildx imagetools inspect localhost:5000/name/app:1.0.0
|
||||||
-
|
|
||||||
name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
-
|
-
|
||||||
name: Check digest
|
name: Check digest
|
||||||
run: |
|
run: |
|
||||||
@ -635,8 +611,8 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: Compare digests
|
name: Compare digests
|
||||||
run: |
|
run: |
|
||||||
echo Compare "${{ needs.github-cache-first.outputs.digest }}" with "${{ steps.docker_build.outputs.digest }}"
|
echo Compare "${{ needs.local-cache-first.outputs.digest }}" with "${{ steps.docker_build.outputs.digest }}"
|
||||||
if [ "${{ needs.github-cache-first.outputs.digest }}" != "${{ steps.docker_build.outputs.digest }}" ]; then
|
if [ "${{ needs.local-cache-first.outputs.digest }}" != "${{ steps.docker_build.outputs.digest }}" ]; then
|
||||||
echo "::error::Digests should be identical"
|
echo "::error::Digests should be identical"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -647,3 +623,53 @@ jobs:
|
|||||||
name: Dump context
|
name: Dump context
|
||||||
if: always()
|
if: always()
|
||||||
uses: crazy-max/ghaction-dump-context@v1
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
|
||||||
|
github-cache:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
buildx_version:
|
||||||
|
- ""
|
||||||
|
- latest
|
||||||
|
services:
|
||||||
|
registry:
|
||||||
|
image: registry:2
|
||||||
|
ports:
|
||||||
|
- 5000:5000
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
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
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
||||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -27,6 +27,6 @@ jobs:
|
|||||||
targets: test
|
targets: test
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
file: ./coverage/clover.xml
|
file: ./coverage/clover.xml
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 240,
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
|
19
README.md
19
README.md
@ -33,8 +33,6 @@ ___
|
|||||||
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
||||||
* [Copy between registries](docs/advanced/copy-between-registries.md)
|
* [Copy between registries](docs/advanced/copy-between-registries.md)
|
||||||
* [Cache](docs/advanced/cache.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)
|
* [Local registry](docs/advanced/local-registry.md)
|
||||||
* [Export image to Docker](docs/advanced/export-docker.md)
|
* [Export image to Docker](docs/advanced/export-docker.md)
|
||||||
* [Share built image between jobs](docs/advanced/share-image-jobs.md)
|
* [Share built image between jobs](docs/advanced/share-image-jobs.md)
|
||||||
@ -53,7 +51,7 @@ By default, this action uses the [Git context](#git-context) so you don't need t
|
|||||||
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)
|
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>`.
|
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
|
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
|
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
|
[`context` input](#inputs) alongside the [`actions/checkout`](https://github.com/actions/checkout/) action to remove
|
||||||
this restriction.
|
this restriction.
|
||||||
@ -100,9 +98,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
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)
|
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)
|
||||||
@ -121,9 +116,6 @@ a [secret](docs/advanced/secrets.md) named `GIT_AUTH_TOKEN` to be able to authen
|
|||||||
GIT_AUTH_TOKEN=${{ secrets.MYTOKEN }}
|
GIT_AUTH_TOKEN=${{ secrets.MYTOKEN }}
|
||||||
```
|
```
|
||||||
|
|
||||||
> :warning: Subdir for Git context is not yet supported ([moby/buildkit#1684](https://github.com/moby/buildkit/issues/1684))
|
|
||||||
> but you can use the [path context](#path-context) in the meantime. More info on [Docker docs website](https://docs.docker.com/engine/reference/commandline/build/#git-repositories).
|
|
||||||
|
|
||||||
### Path context
|
### Path context
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@ -170,8 +162,6 @@ jobs:
|
|||||||
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
||||||
* [Copy between registries](docs/advanced/copy-between-registries.md)
|
* [Copy between registries](docs/advanced/copy-between-registries.md)
|
||||||
* [Cache](docs/advanced/cache.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)
|
* [Local registry](docs/advanced/local-registry.md)
|
||||||
* [Export image to Docker](docs/advanced/export-docker.md)
|
* [Export image to Docker](docs/advanced/export-docker.md)
|
||||||
* [Share built image between jobs](docs/advanced/share-image-jobs.md)
|
* [Share built image between jobs](docs/advanced/share-image-jobs.md)
|
||||||
@ -223,9 +213,10 @@ Following inputs can be used as `step.with` keys
|
|||||||
|
|
||||||
Following outputs are available
|
Following outputs are available
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|---------------|---------|---------------------------------------|
|
|-------------------|---------|---------------------------------------|
|
||||||
| `digest` | String | Image content-addressable identifier also called a digest |
|
| `digest` | String | Image content-addressable identifier also called a digest |
|
||||||
|
| `metadata` | JSON | Build result metadata |
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
||||||
* [BuildKit container logs](#buildkit-container-logs)
|
* [BuildKit container logs](#buildkit-container-logs)
|
||||||
* [With containerd](#with-containerd)
|
* [With containerd](#with-containerd)
|
||||||
|
* [`repository name must be lowercase`](#repository-name-must-be-lowercase)
|
||||||
|
|
||||||
## Cannot push to a registry
|
## 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`
|
* `failed commit on ref "manifest-sha256:...": unexpected status: 401 Unauthorized`
|
||||||
* `unexpected response: 401 Unauthorized`
|
* `unexpected response: 401 Unauthorized`
|
||||||
|
|
||||||
These issues are not directly related to this action but are rather linked to [buildx](https://github.com/docker/buildx),
|
These issues are not directly related to this action but are rather linked to
|
||||||
[buildkit](https://github.com/moby/buildkit), [containerd](https://github.com/containerd/containerd) or the registry
|
[buildx](https://github.com/docker/buildx), [buildkit](https://github.com/moby/buildkit),
|
||||||
on which you're pushing your image. The quality of error message depends on the registry and are usually not very informative.
|
[containerd](https://github.com/containerd/containerd) or the registry on which
|
||||||
|
you're pushing your image. The quality of error message depends on the registry
|
||||||
|
and are usually not very informative.
|
||||||
|
|
||||||
### BuildKit container logs
|
### BuildKit container logs
|
||||||
|
|
||||||
@ -25,8 +28,9 @@ action step and attach BuildKit container logs to your issue.
|
|||||||
|
|
||||||
### With containerd
|
### With containerd
|
||||||
|
|
||||||
Next you can test pushing with [containerd action](https://github.com/crazy-max/ghaction-setup-containerd) using the
|
Next you can test pushing with [containerd action](https://github.com/crazy-max/ghaction-setup-containerd)
|
||||||
following workflow. If it works then open an issue on [buildkit](https://github.com/moby/buildkit) repository.
|
using the following workflow. If it works then open an issue on [buildkit](https://github.com/moby/buildkit)
|
||||||
|
repository.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: containerd
|
name: containerd
|
||||||
@ -69,3 +73,47 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo ctr --debug i push --user "${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" docker.io/user/app:latest
|
sudo ctr --debug i push --user "${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}" docker.io/user/app:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `repository name must be lowercase`
|
||||||
|
|
||||||
|
You may encounter this issue if you're using `github.repository` as a repo slug
|
||||||
|
in your tag:
|
||||||
|
|
||||||
|
```
|
||||||
|
#6 exporting to image
|
||||||
|
#6 exporting layers
|
||||||
|
#6 exporting layers 1.2s done
|
||||||
|
#6 exporting manifest sha256:b47f7dfb97b89ccd5de553af3c8cd94c4795884cbe5693e93946b1d95a7b1d12 0.0s done
|
||||||
|
#6 exporting config sha256:995e93fab8196893192f08a38deea6769dc4d98f86cf705eccc24ec96a3e271c 0.0s done
|
||||||
|
#6 ERROR: invalid reference format: repository name must be lowercase
|
||||||
|
------
|
||||||
|
> exporting to image:
|
||||||
|
------
|
||||||
|
error: failed to solve: invalid reference format: repository name must be lowercase
|
||||||
|
```
|
||||||
|
|
||||||
|
or a cache reference:
|
||||||
|
|
||||||
|
```
|
||||||
|
#10 importing cache manifest from ghcr.io/My-Org/repo:main
|
||||||
|
#10 ERROR: invalid reference format: repository name must be lowercase
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this issue you can use our [metadata action](https://github.com/docker/metadata-action)
|
||||||
|
to generate sanitized tags, or a dedicated step to sanitize the slug:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Sanitize repo slug
|
||||||
|
uses: actions/github-script@v4
|
||||||
|
id: repo_slug
|
||||||
|
with:
|
||||||
|
result-encoding: string
|
||||||
|
script: return `ghcr.io/${github.repository.toLowerCase()}`
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.repo_slug.outputs.result }}:latest
|
||||||
|
```
|
||||||
|
40
UPGRADE.md
40
UPGRADE.md
@ -101,25 +101,17 @@ steps:
|
|||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
-
|
-
|
||||||
name: Prepare
|
name: Docker meta
|
||||||
id: prep
|
id: meta
|
||||||
run: |
|
uses: docker/metadata-action@v3
|
||||||
DOCKER_IMAGE=myorg/myrepository
|
with:
|
||||||
VERSION=edge
|
images: |
|
||||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
myorg/myrepository
|
||||||
VERSION=${GITHUB_REF#refs/tags/}
|
tags: |
|
||||||
elif [[ $GITHUB_REF == refs/heads/* ]]; then
|
type=ref,event=branch
|
||||||
VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g')
|
type=ref,event=pr
|
||||||
elif [[ $GITHUB_REF == refs/pull/* ]]; then
|
type=semver,pattern={{version}}
|
||||||
VERSION=pr-${{ github.event.number }}
|
type=sha
|
||||||
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
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
@ -136,12 +128,6 @@ steps:
|
|||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.prep.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: |
|
labels: ${{ steps.meta.outputs.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 * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
import * as buildx from '../src/buildx';
|
import * as buildx from '../src/buildx';
|
||||||
import * as context from '../src/context';
|
import * as context from '../src/context';
|
||||||
import * as docker from '../src/docker';
|
|
||||||
|
|
||||||
const tmpNameSync = path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
const tmpNameSync = path.join('/tmp/.docker-build-push-jest', '.tmpname-jest').split(path.sep).join(path.posix.sep);
|
||||||
const digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
const digest = 'sha256:bfb45ab72e46908183546477a08f8867fc40cebadd00af54b071b097aed127a9';
|
||||||
|
const metadata = `{
|
||||||
|
"containerimage.config.digest": "sha256:059b68a595b22564a1cbc167af369349fdc2ecc1f7bc092c2235cbf601a795fd",
|
||||||
|
"containerimage.digest": "sha256:b09b9482c72371486bb2c1d2c2a2633ed1d0b8389e12c8d52b9e052725c0c83c"
|
||||||
|
}`;
|
||||||
|
|
||||||
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
|
||||||
const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep);
|
const tmpDir = path.join('/tmp/.docker-build-push-jest').split(path.sep).join(path.posix.sep);
|
||||||
@ -32,6 +36,17 @@ describe('getImageID', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getMetadata', () => {
|
||||||
|
it('matches', async () => {
|
||||||
|
const metadataFile = await buildx.getMetadataFile();
|
||||||
|
console.log(`metadataFile: ${metadataFile}`);
|
||||||
|
await fs.writeFileSync(metadataFile, metadata);
|
||||||
|
const expected = await buildx.getMetadata();
|
||||||
|
console.log(`metadata: ${expected}`);
|
||||||
|
expect(expected).toEqual(metadata);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('isLocalOrTarExporter', () => {
|
describe('isLocalOrTarExporter', () => {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
test.each([
|
test.each([
|
||||||
@ -92,9 +107,26 @@ describe('isLocalOrTarExporter', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isAvailable', () => {
|
||||||
|
const execSpy: jest.SpyInstance = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
buildx.isAvailable();
|
||||||
|
|
||||||
|
expect(execSpy).toHaveBeenCalledWith(`docker`, ['buildx'], {
|
||||||
|
silent: true,
|
||||||
|
ignoreReturnCode: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getVersion', () => {
|
describe('getVersion', () => {
|
||||||
async function isDaemonRunning() {
|
async function isDaemonRunning() {
|
||||||
return await docker.isDaemonRunning();
|
return await exec
|
||||||
|
.getExecOutput(`docker`, ['version', '--format', '{{.Server.Os}}'], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
return !res.stdout.includes(' ') && res.exitCode == 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(isDaemonRunning() ? it : it.skip)(
|
(isDaemonRunning() ? it : it.skip)(
|
||||||
'valid',
|
'valid',
|
||||||
@ -111,9 +143,20 @@ describe('parseVersion', () => {
|
|||||||
test.each([
|
test.each([
|
||||||
['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
['github.com/docker/buildx 0.4.1+azure bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||||
['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
['github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c', '0.4.1'],
|
||||||
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2']
|
['github.com/docker/buildx v0.4.2 fb7b670b764764dc4716df3eba07ffdae4cc47b2', '0.4.2'],
|
||||||
|
['github.com/docker/buildx f117971 f11797113e5a9b86bd976329c5dbb8a8bfdfadfa', 'f117971']
|
||||||
])('given %p', async (stdout, expected) => {
|
])('given %p', async (stdout, expected) => {
|
||||||
expect(await buildx.parseVersion(stdout)).toEqual(expected);
|
expect(buildx.parseVersion(stdout)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('satisfies', () => {
|
||||||
|
test.each([
|
||||||
|
['0.4.1', '>=0.3.2', true],
|
||||||
|
['bda4882a65349ca359216b135896bddc1d92461c', '>0.1.0', false],
|
||||||
|
['f117971', '>0.6.0', true]
|
||||||
|
])('given %p', async (version, range, expected) => {
|
||||||
|
expect(buildx.satisfies(version, range)).toBe(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -125,13 +168,7 @@ describe('getSecret', () => {
|
|||||||
['aaaaaaaa', false, '', '', true],
|
['aaaaaaaa', false, '', '', true],
|
||||||
['aaaaaaaa=', false, '', '', true],
|
['aaaaaaaa=', false, '', '', true],
|
||||||
['=bbbbbbb', 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]
|
[`notfound=secret`, true, '', '', true]
|
||||||
])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => {
|
])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => {
|
||||||
try {
|
try {
|
||||||
|
@ -143,6 +143,10 @@ describe('getArgs', () => {
|
|||||||
'0.4.1',
|
'0.4.1',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -155,6 +159,10 @@ describe('getArgs', () => {
|
|||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['build-args', 'MY_ARG=val1,val2,val3\nARG=val'],
|
['build-args', 'MY_ARG=val1,val2,val3\nARG=val'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -169,6 +177,10 @@ describe('getArgs', () => {
|
|||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['tags', 'name/app:7.4, name/app:latest'],
|
['tags', 'name/app:7.4, name/app:latest'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -184,7 +196,11 @@ describe('getArgs', () => {
|
|||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['labels', 'org.opencontainers.image.title=buildkit\norg.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit'],
|
['labels', 'org.opencontainers.image.title=buildkit\norg.opencontainers.image.description=concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit'],
|
||||||
['outputs', 'type=local,dest=./release-out']
|
['outputs', 'type=local,dest=./release-out'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -199,7 +215,11 @@ describe('getArgs', () => {
|
|||||||
'0.4.1',
|
'0.4.1',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['platforms', 'linux/amd64,linux/arm64']
|
['platforms', 'linux/amd64,linux/arm64'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -211,7 +231,11 @@ describe('getArgs', () => {
|
|||||||
[
|
[
|
||||||
'0.4.1',
|
'0.4.1',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.']
|
['context', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -225,6 +249,10 @@ describe('getArgs', () => {
|
|||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -238,7 +266,11 @@ describe('getArgs', () => {
|
|||||||
'0.4.2',
|
'0.4.2',
|
||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['github-token', 'abcdefghijklmno0123456789'],
|
['github-token', 'abcdefghijklmno0123456789'],
|
||||||
['outputs', '.']
|
['outputs', '.'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'false'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -257,7 +289,10 @@ describe('getArgs', () => {
|
|||||||
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
['secrets', 'GIT_AUTH_TOKEN=abcdefghijklmno=0123456789'],
|
||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -288,7 +323,10 @@ bbbb
|
|||||||
ccc"`],
|
ccc"`],
|
||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -322,7 +360,10 @@ bbbb
|
|||||||
ccc`],
|
ccc`],
|
||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -348,7 +389,10 @@ ccc`],
|
|||||||
['file', './test/Dockerfile'],
|
['file', './test/Dockerfile'],
|
||||||
['builder', 'builder-git-context-2'],
|
['builder', 'builder-git-context-2'],
|
||||||
['network', 'host'],
|
['network', 'host'],
|
||||||
['push', 'true']
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false']
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
'buildx',
|
'buildx',
|
||||||
@ -367,7 +411,11 @@ ccc`],
|
|||||||
new Map<string, string>([
|
new Map<string, string>([
|
||||||
['context', '.'],
|
['context', '.'],
|
||||||
['labels', 'org.opencontainers.image.title=filter_results_top_n\norg.opencontainers.image.description=Reference implementation of operation "filter results (top-n)"'],
|
['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',
|
'buildx',
|
||||||
@ -377,7 +425,30 @@ ccc`],
|
|||||||
'--output', 'type=local,dest=./release-out',
|
'--output', 'type=local,dest=./release-out',
|
||||||
'.'
|
'.'
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
'0.6.0',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', '.'],
|
||||||
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
|
['file', './test/Dockerfile'],
|
||||||
|
['network', 'host'],
|
||||||
|
['load', 'false'],
|
||||||
|
['no-cache', 'false'],
|
||||||
|
['push', 'true'],
|
||||||
|
['pull', 'false']
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'buildx',
|
||||||
|
'build',
|
||||||
|
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
|
||||||
|
'--metadata-file', '/tmp/.docker-build-push-jest/metadata-file',
|
||||||
|
'--file', './test/Dockerfile',
|
||||||
|
'--network', 'host',
|
||||||
|
'--push',
|
||||||
|
'.'
|
||||||
|
]
|
||||||
|
],
|
||||||
])(
|
])(
|
||||||
'given %p with %p as inputs, returns %p',
|
'given %p with %p as inputs, returns %p',
|
||||||
async (buildxVersion: string, inputs: Map<string, any>, expected: Array<string>) => {
|
async (buildxVersion: string, inputs: Map<string, any>, expected: Array<string>) => {
|
||||||
@ -517,13 +588,7 @@ FOO=bar`
|
|||||||
);
|
);
|
||||||
const res = await context.getInputList('secrets', true);
|
const res = await context.getInputList('secrets', true);
|
||||||
console.log(res);
|
console.log(res);
|
||||||
expect(res).toEqual([
|
expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']);
|
||||||
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
|
|
||||||
'MYSECRET=aaaaaaaa',
|
|
||||||
'bbbbbbb',
|
|
||||||
'ccccccccc',
|
|
||||||
'FOO=bar'
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('large multiline values', async () => {
|
it('large multiline values', async () => {
|
||||||
@ -592,7 +657,7 @@ describe('setOutput', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
|
// See: https://github.com/actions/toolkit/blob/a1b068ec31a042ff1e10a522d8fdf0b8869d53ca/packages/core/src/core.ts#L89
|
||||||
function getInputName(name: string): string {
|
function getInputName(name: string): string {
|
||||||
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
|
return `INPUT_${name.replace(/ /g, '_').toUpperCase()}`;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,8 @@ inputs:
|
|||||||
outputs:
|
outputs:
|
||||||
digest:
|
digest:
|
||||||
description: 'Image content-addressable identifier also called a digest'
|
description: 'Image content-addressable identifier also called a digest'
|
||||||
|
metadata:
|
||||||
|
description: 'Build result metadata'
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
|
3
codecov.yml
Normal file
3
codecov.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
comment: false
|
||||||
|
github_checks:
|
||||||
|
annotations: false
|
24234
dist/index.js
generated
vendored
24234
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
@ -1,13 +1,18 @@
|
|||||||
# Cache
|
# Cache
|
||||||
|
|
||||||
|
* [Inline cache](#inline-cache)
|
||||||
* [Registry cache](#registry-cache)
|
* [Registry cache](#registry-cache)
|
||||||
* [GitHub cache](#github-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 case 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
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
@ -44,16 +49,104 @@ jobs:
|
|||||||
cache-to: type=inline
|
cache-to: type=inline
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Registry cache
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
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.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
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
|
## 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:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
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.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
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).
|
> :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).
|
> 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.
|
You can also leverage [GitHub cache](https://docs.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows)
|
||||||
> More info: https://github.com/docker/buildx/pull/535
|
using [actions/cache](https://github.com/actions/cache) and [`type=local` cache exporter](https://github.com/moby/buildkit#local-directory-1)
|
||||||
|
with this action:
|
||||||
You can leverage [GitHub cache](https://docs.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows)
|
|
||||||
using [actions/cache](https://github.com/actions/cache) with this action:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
@ -95,7 +188,7 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
tags: user/app:latest
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
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
|
# Temp fix
|
||||||
# https://github.com/docker/build-push-action/issues/252
|
# https://github.com/docker/build-push-action/issues/252
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
# syntax=docker/dockerfile:1.2
|
# syntax=docker/dockerfile:1.2
|
||||||
ARG NODE_VERSION
|
ARG NODE_VERSION
|
||||||
|
ARG DOCKER_VERSION=20.10.7
|
||||||
|
ARG BUILDX_VERSION=0.6.0
|
||||||
|
|
||||||
|
FROM docker:${DOCKER_VERSION} as docker
|
||||||
|
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||||
|
|
||||||
FROM node:${NODE_VERSION}-alpine AS base
|
FROM node:${NODE_VERSION}-alpine AS base
|
||||||
RUN apk add --no-cache git
|
RUN apk add --no-cache git
|
||||||
@ -15,8 +20,8 @@ ENV RUNNER_TEMP=/tmp/github_runner
|
|||||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
||||||
RUN --mount=type=bind,target=.,rw \
|
RUN --mount=type=bind,target=.,rw \
|
||||||
--mount=type=cache,target=/src/node_modules \
|
--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=docker,source=/usr/local/bin/docker,target=/usr/bin/docker \
|
||||||
--mount=type=bind,from=crazymax/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
|
yarn run test --coverageDirectory=/tmp/coverage
|
||||||
|
|
||||||
FROM scratch AS test-coverage
|
FROM scratch AS test-coverage
|
||||||
|
26
package.json
26
package.json
@ -28,26 +28,26 @@
|
|||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.3.0",
|
"@actions/core": "^1.5.0",
|
||||||
"@actions/exec": "^1.0.4",
|
"@actions/exec": "^1.1.0",
|
||||||
"@actions/github": "^5.0.0",
|
"@actions/github": "^5.0.0",
|
||||||
"csv-parse": "^4.15.4",
|
"csv-parse": "^4.16.0",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"tmp": "^0.2.1"
|
"tmp": "^0.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/csv-parse": "^1.2.2",
|
"@types/csv-parse": "^1.2.2",
|
||||||
"@types/jest": "^26.0.3",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/node": "^14.0.14",
|
"@types/node": "^14.17.4",
|
||||||
"@types/tmp": "^0.2.0",
|
"@types/tmp": "^0.2.0",
|
||||||
"@vercel/ncc": "^0.23.0",
|
"@vercel/ncc": "^0.28.6",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.6.0",
|
||||||
"jest": "^26.1.0",
|
"jest": "^26.6.3",
|
||||||
"jest-circus": "^26.1.0",
|
"jest-circus": "^26.6.3",
|
||||||
"jest-runtime": "^26.1.0",
|
"jest-runtime": "^26.6.3",
|
||||||
"prettier": "^2.0.5",
|
"prettier": "^2.3.1",
|
||||||
"ts-jest": "^26.1.1",
|
"ts-jest": "^26.5.6",
|
||||||
"typescript": "^3.9.5",
|
"typescript": "^4.3.4",
|
||||||
"typescript-formatter": "^7.2.2"
|
"typescript-formatter": "^7.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ import csvparse from 'csv-parse/lib/sync';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
import * as context from './context';
|
import * as context from './context';
|
||||||
import * as exec from './exec';
|
|
||||||
|
|
||||||
export async function getImageIDFile(): Promise<string> {
|
export async function getImageIDFile(): Promise<string> {
|
||||||
return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
|
return path.join(context.tmpDir(), 'iidfile').split(path.sep).join(path.posix.sep);
|
||||||
@ -18,6 +18,18 @@ export async function getImageID(): Promise<string | undefined> {
|
|||||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return fs.readFileSync(metadataFile, {encoding: 'utf-8'});
|
||||||
|
}
|
||||||
|
|
||||||
export async function getSecretString(kvp: string): Promise<string> {
|
export async function getSecretString(kvp: string): Promise<string> {
|
||||||
return getSecret(kvp, false);
|
return getSecret(kvp, false);
|
||||||
}
|
}
|
||||||
@ -80,27 +92,41 @@ export function hasGitAuthToken(secrets: string[]): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function isAvailable(): Promise<Boolean> {
|
export async function isAvailable(): Promise<Boolean> {
|
||||||
return await exec.exec(`docker`, ['buildx'], true).then(res => {
|
return await exec
|
||||||
if (res.stderr != '' && !res.success) {
|
.getExecOutput('docker', ['buildx'], {
|
||||||
return false;
|
ignoreReturnCode: true,
|
||||||
}
|
silent: true
|
||||||
return res.success;
|
})
|
||||||
});
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return res.exitCode == 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getVersion(): Promise<string> {
|
export async function getVersion(): Promise<string> {
|
||||||
return await exec.exec(`docker`, ['buildx', 'version'], true).then(res => {
|
return await exec
|
||||||
if (res.stderr != '' && !res.success) {
|
.getExecOutput('docker', ['buildx', 'version'], {
|
||||||
throw new Error(res.stderr);
|
ignoreReturnCode: true,
|
||||||
}
|
silent: true
|
||||||
return parseVersion(res.stdout);
|
})
|
||||||
});
|
.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> {
|
export function parseVersion(stdout: string): string {
|
||||||
const matches = /\sv?([0-9.]+)/.exec(stdout);
|
const matches = /\sv?([0-9a-f]{7}|[0-9.]+)/.exec(stdout);
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
throw new Error(`Cannot parse buildx version`);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import csvparse from 'csv-parse/lib/sync';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
|
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
@ -46,9 +45,7 @@ export function defaultContext(): string {
|
|||||||
if (github.context.sha && !ref.startsWith(`refs/pull/`)) {
|
if (github.context.sha && !ref.startsWith(`refs/pull/`)) {
|
||||||
ref = github.context.sha;
|
ref = github.context.sha;
|
||||||
}
|
}
|
||||||
_defaultContext = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${
|
_defaultContext = `${process.env.GITHUB_SERVER_URL || 'https://github.com'}/${github.context.repo.owner}/${github.context.repo.repo}.git#${ref}`;
|
||||||
github.context.repo.repo
|
|
||||||
}.git#${ref}`;
|
|
||||||
}
|
}
|
||||||
return _defaultContext;
|
return _defaultContext;
|
||||||
}
|
}
|
||||||
@ -74,13 +71,13 @@ export async function getInputs(defaultContext: string): Promise<Inputs> {
|
|||||||
context: core.getInput('context') || defaultContext,
|
context: core.getInput('context') || defaultContext,
|
||||||
file: core.getInput('file'),
|
file: core.getInput('file'),
|
||||||
labels: await getInputList('labels', true),
|
labels: await getInputList('labels', true),
|
||||||
load: /true/i.test(core.getInput('load')),
|
load: core.getBooleanInput('load'),
|
||||||
network: core.getInput('network'),
|
network: core.getInput('network'),
|
||||||
noCache: /true/i.test(core.getInput('no-cache')),
|
noCache: core.getBooleanInput('no-cache'),
|
||||||
outputs: await getInputList('outputs', true),
|
outputs: await getInputList('outputs', true),
|
||||||
platforms: await getInputList('platforms'),
|
platforms: await getInputList('platforms'),
|
||||||
pull: /true/i.test(core.getInput('pull')),
|
pull: core.getBooleanInput('pull'),
|
||||||
push: /true/i.test(core.getInput('push')),
|
push: core.getBooleanInput('push'),
|
||||||
secrets: await getInputList('secrets', true),
|
secrets: await getInputList('secrets', true),
|
||||||
secretFiles: await getInputList('secret-files', true),
|
secretFiles: await getInputList('secret-files', true),
|
||||||
ssh: await getInputList('ssh'),
|
ssh: await getInputList('ssh'),
|
||||||
@ -121,12 +118,12 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
|
|||||||
await asyncForEach(inputs.outputs, async output => {
|
await asyncForEach(inputs.outputs, async output => {
|
||||||
args.push('--output', output);
|
args.push('--output', output);
|
||||||
});
|
});
|
||||||
if (
|
if (!buildx.isLocalOrTarExporter(inputs.outputs) && (inputs.platforms.length == 0 || buildx.satisfies(buildxVersion, '>=0.4.2'))) {
|
||||||
!buildx.isLocalOrTarExporter(inputs.outputs) &&
|
|
||||||
(inputs.platforms.length == 0 || semver.satisfies(buildxVersion, '>=0.4.2'))
|
|
||||||
) {
|
|
||||||
args.push('--iidfile', await buildx.getImageIDFile());
|
args.push('--iidfile', await buildx.getImageIDFile());
|
||||||
}
|
}
|
||||||
|
if (buildx.satisfies(buildxVersion, '>=0.6.0')) {
|
||||||
|
args.push('--metadata-file', await buildx.getMetadataFile());
|
||||||
|
}
|
||||||
await asyncForEach(inputs.cacheFrom, async cacheFrom => {
|
await asyncForEach(inputs.cacheFrom, async cacheFrom => {
|
||||||
args.push('--cache-from', cacheFrom);
|
args.push('--cache-from', cacheFrom);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import * as exec from './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;
|
|
||||||
});
|
|
||||||
}
|
|
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()
|
|
||||||
};
|
|
||||||
};
|
|
33
src/main.ts
33
src/main.ts
@ -1,9 +1,9 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as buildx from './buildx';
|
import * as buildx from './buildx';
|
||||||
import * as context from './context';
|
import * as context from './context';
|
||||||
import * as exec from './exec';
|
|
||||||
import * as stateHelper from './state-helper';
|
import * as stateHelper from './state-helper';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@ -23,19 +23,28 @@ async function run(): Promise<void> {
|
|||||||
let inputs: context.Inputs = await context.getInputs(defContext);
|
let inputs: context.Inputs = await context.getInputs(defContext);
|
||||||
|
|
||||||
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
|
const args: string[] = await context.getArgs(inputs, defContext, buildxVersion);
|
||||||
await exec.exec('docker', args).then(res => {
|
await exec
|
||||||
if (res.stderr != '' && !res.success) {
|
.getExecOutput('docker', args, {
|
||||||
throw new Error(`buildx call failed with: ${res.stderr.match(/(.*)\s*$/)![0]}`);
|
ignoreReturnCode: true
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(`buildx failed with: ${res.stderr.match(/(.*)\s*$/)![0].trim()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await core.group(`Setting outputs`, async () => {
|
||||||
|
const imageID = await buildx.getImageID();
|
||||||
|
const metadata = await buildx.getMetadata();
|
||||||
|
if (imageID) {
|
||||||
|
core.info(`digest=${imageID}`);
|
||||||
|
context.setOutput('digest', imageID);
|
||||||
|
}
|
||||||
|
if (metadata) {
|
||||||
|
core.info(`metadata=${metadata}`);
|
||||||
|
context.setOutput('metadata', metadata);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const imageID = await buildx.getImageID();
|
|
||||||
if (imageID) {
|
|
||||||
core.startGroup(`Extracting digest`);
|
|
||||||
core.info(`${imageID}`);
|
|
||||||
context.setOutput('digest', imageID);
|
|
||||||
core.endGroup();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user