mirror of
https://github.com/docker/build-push-action.git
synced 2025-06-14 07:07:12 +02:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
9379083e42 | |||
a63b18dea2 | |||
af867d4937 | |||
33eec1587d | |||
3db4797dd2 | |||
659fcba376 | |||
080cadd33e | |||
dc4c1fca8b | |||
b280b0485b | |||
b87564a5cc | |||
d2bc6a5d16 | |||
e5f26cdae4 | |||
616efcd405 | |||
0539e1a717 | |||
636b4540ec | |||
af932bfb2e | |||
2db03de115 | |||
4643aec7c4 |
111
.github/labels.yml
vendored
111
.github/labels.yml
vendored
@ -1,111 +0,0 @@
|
|||||||
## more info https://github.com/crazy-max/ghaction-github-labeler
|
|
||||||
- # automerge
|
|
||||||
name: ":bell: automerge"
|
|
||||||
color: "8f4fbc"
|
|
||||||
description: ""
|
|
||||||
- # bot
|
|
||||||
name: ":robot: bot"
|
|
||||||
color: "69cde9"
|
|
||||||
description: ""
|
|
||||||
- # bug
|
|
||||||
name: ":bug: bug"
|
|
||||||
color: "b60205"
|
|
||||||
description: ""
|
|
||||||
- # dependencies
|
|
||||||
name: ":game_die: dependencies"
|
|
||||||
color: "0366d6"
|
|
||||||
description: ""
|
|
||||||
from_name: "dependencies"
|
|
||||||
- # documentation
|
|
||||||
name: ":memo: documentation"
|
|
||||||
color: "c5def5"
|
|
||||||
description: ""
|
|
||||||
- # duplicate
|
|
||||||
name: ":busts_in_silhouette: duplicate"
|
|
||||||
color: "cccccc"
|
|
||||||
description: ""
|
|
||||||
- # enhancement
|
|
||||||
name: ":sparkles: enhancement"
|
|
||||||
color: "0054ca"
|
|
||||||
description: ""
|
|
||||||
- # feature request
|
|
||||||
name: ":bulb: feature request"
|
|
||||||
color: "0e8a16"
|
|
||||||
description: ""
|
|
||||||
- # feedback
|
|
||||||
name: ":mega: feedback"
|
|
||||||
color: "03a9f4"
|
|
||||||
description: ""
|
|
||||||
- # future maybe
|
|
||||||
name: ":rocket: future maybe"
|
|
||||||
color: "fef2c0"
|
|
||||||
description: ""
|
|
||||||
- # good first issue
|
|
||||||
name: ":hatching_chick: good first issue"
|
|
||||||
color: "7057ff"
|
|
||||||
description: ""
|
|
||||||
- # help wanted
|
|
||||||
name: ":pray: help wanted"
|
|
||||||
color: "4caf50"
|
|
||||||
description: ""
|
|
||||||
- # hold
|
|
||||||
name: ":hand: hold"
|
|
||||||
color: "24292f"
|
|
||||||
description: ""
|
|
||||||
- # invalid
|
|
||||||
name: ":no_entry_sign: invalid"
|
|
||||||
color: "e6e6e6"
|
|
||||||
description: ""
|
|
||||||
- # maybe bug
|
|
||||||
name: ":interrobang: maybe bug"
|
|
||||||
color: "ff5722"
|
|
||||||
description: ""
|
|
||||||
- # needs more info
|
|
||||||
name: ":thinking: needs more info"
|
|
||||||
color: "795548"
|
|
||||||
description: ""
|
|
||||||
- # question
|
|
||||||
name: ":question: question"
|
|
||||||
color: "3f51b5"
|
|
||||||
description: ""
|
|
||||||
- # upstream
|
|
||||||
name: ":eyes: upstream"
|
|
||||||
color: "fbca04"
|
|
||||||
description: ""
|
|
||||||
- # wontfix
|
|
||||||
name: ":coffin: wontfix"
|
|
||||||
color: "ffffff"
|
|
||||||
description: ""
|
|
||||||
|
|
||||||
- # registry-aws-ecr
|
|
||||||
name: "registry-aws-ecr"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-azure-acr
|
|
||||||
name: "registry-azure-acr"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-dockerhub
|
|
||||||
name: "registry-dockerhub"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-github
|
|
||||||
name: "registry-github"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-google-gar
|
|
||||||
name: "registry-google-gar"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-google-gcr
|
|
||||||
name: "registry-google-gcr"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-nexus
|
|
||||||
name: "registry-nexus"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
||||||
- # registry-quay
|
|
||||||
name: "registry-quay"
|
|
||||||
color: "84858A"
|
|
||||||
description: ""
|
|
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@ -244,12 +244,6 @@ jobs:
|
|||||||
|
|
||||||
docker-driver:
|
docker-driver:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
push:
|
|
||||||
- true
|
|
||||||
- false
|
|
||||||
services:
|
services:
|
||||||
registry:
|
registry:
|
||||||
image: registry:2
|
image: registry:2
|
||||||
@ -262,24 +256,12 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: Build
|
name: Build
|
||||||
id: docker_build
|
id: docker_build
|
||||||
continue-on-error: ${{ matrix.push }}
|
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
context: ./test
|
context: ./test
|
||||||
file: ./test/Dockerfile
|
file: ./test/Dockerfile
|
||||||
push: ${{ matrix.push }}
|
push: true
|
||||||
tags: localhost:5000/name/app:latest
|
tags: localhost:5000/name/app:latest
|
||||||
-
|
|
||||||
name: Check
|
|
||||||
run: |
|
|
||||||
echo "${{ toJson(steps.docker_build) }}"
|
|
||||||
if [ "${{ matrix.push }}" = "false" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
if [ "${{ steps.docker_build.outcome }}" != "failure" ] || [ "${{ steps.docker_build.conclusion }}" != "success" ]; then
|
|
||||||
echo "::error::Should have failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
-
|
-
|
||||||
name: Dump context
|
name: Dump context
|
||||||
if: always()
|
if: always()
|
||||||
|
20
.github/workflows/labels.yml
vendored
20
.github/workflows/labels.yml
vendored
@ -1,20 +0,0 @@
|
|||||||
name: labels
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
paths:
|
|
||||||
- '.github/labels.yml'
|
|
||||||
- '.github/workflows/labels.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
labeler:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Run Labeler
|
|
||||||
uses: crazy-max/ghaction-github-labeler@v3
|
|
38
.github/workflows/virtual-env.yml
vendored
Normal file
38
.github/workflows/virtual-env.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: virtual-env
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 10 * * *' # everyday at 10am
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
os:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- ubuntu-20.04
|
||||||
|
- ubuntu-18.04
|
||||||
|
- ubuntu-16.04
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: List install packages
|
||||||
|
run: apt list --installed
|
||||||
|
-
|
||||||
|
name: Docker info
|
||||||
|
run: docker info
|
||||||
|
-
|
||||||
|
name: Docker version
|
||||||
|
run: docker version
|
||||||
|
-
|
||||||
|
name: buildx version
|
||||||
|
run: docker buildx version
|
||||||
|
-
|
||||||
|
name: containerd version
|
||||||
|
run: containerd --version
|
||||||
|
-
|
||||||
|
name: Dump context
|
||||||
|
if: always()
|
||||||
|
uses: crazy-max/ghaction-dump-context@v1
|
@ -1,4 +1,4 @@
|
|||||||
#syntax=docker/dockerfile:1.1-experimental
|
#syntax=docker/dockerfile:1.2
|
||||||
|
|
||||||
FROM node:12 AS deps
|
FROM node:12 AS deps
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
@ -23,7 +23,7 @@ FROM deps AS test
|
|||||||
COPY --from=docker /usr/local/bin/docker /usr/bin/
|
COPY --from=docker /usr/local/bin/docker /usr/bin/
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG BUILDX_VERSION=v0.4.2
|
ARG BUILDX_VERSION=v0.5.1
|
||||||
ENV RUNNER_TEMP=/tmp/github_runner
|
ENV RUNNER_TEMP=/tmp/github_runner
|
||||||
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
|
||||||
RUN mkdir -p /usr/local/lib/docker/cli-plugins && \
|
RUN mkdir -p /usr/local/lib/docker/cli-plugins && \
|
||||||
|
557
README.md
557
README.md
@ -6,18 +6,18 @@
|
|||||||
|
|
||||||
## Upgrade from v1
|
## Upgrade from v1
|
||||||
|
|
||||||
`v2` of this action includes significant updates and now uses Docker [Buildx](https://github.com/docker/buildx). It
|
`v2` of this action includes significant updates and now uses Docker [Buildx](https://github.com/docker/buildx). It's
|
||||||
works with 3 new actions ([login](https://github.com/docker/login-action), [setup-buildx](https://github.com/docker/setup-buildx-action)
|
also rewritten as a [typescript-action](https://github.com/actions/typescript-action/) to be as close as possible
|
||||||
and [setup-qemu](https://github.com/docker/setup-qemu-action)) that we have created. It's also rewritten as a
|
of the [GitHub Runner](https://github.com/actions/virtual-environments) during its execution.
|
||||||
[typescript-action](https://github.com/actions/typescript-action/) to be as close as possible of the
|
|
||||||
[GitHub Runner](https://github.com/actions/virtual-environments) during its execution.
|
|
||||||
|
|
||||||
[Upgrade notes](UPGRADE.md) and many [usage examples](#usage) have been added to handle most use cases but `v1` is
|
[Upgrade notes](UPGRADE.md) with many [usage examples](#advanced-usage) have been added to handle most use cases but
|
||||||
still available through [`releases/v1` branch](https://github.com/docker/build-push-action/tree/releases/v1).
|
`v1` is still available through [`releases/v1` branch](https://github.com/docker/build-push-action/tree/releases/v1).
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx).
|
GitHub Action to build and push Docker images with [Buildx](https://github.com/docker/buildx) with full support of the
|
||||||
|
features provided by [Moby BuildKit](https://github.com/moby/buildkit) builder toolkit. This includes multi-platform
|
||||||
|
build, secrets, remote cache, etc. and different builder deployment/namespacing options.
|
||||||
|
|
||||||
> :bulb: See also:
|
> :bulb: See also:
|
||||||
> * [login](https://github.com/docker/login-action) action
|
> * [login](https://github.com/docker/login-action) action
|
||||||
@ -31,46 +31,58 @@ ___
|
|||||||
* [Usage](#usage)
|
* [Usage](#usage)
|
||||||
* [Git context](#git-context)
|
* [Git context](#git-context)
|
||||||
* [Path context](#path-context)
|
* [Path context](#path-context)
|
||||||
* [Isolated builders](#isolated-builders)
|
|
||||||
* [Multi-platform image](#multi-platform-image)
|
|
||||||
* [Advanced usage](#advanced-usage)
|
* [Advanced usage](#advanced-usage)
|
||||||
* [Push to multi-registries](#push-to-multi-registries)
|
* [Multi-platform image](docs/advanced/multi-platform.md)
|
||||||
* [Cache to registry](#cache-to-registry)
|
* [Secrets](docs/advanced/secrets.md)
|
||||||
* [Local registry](#local-registry)
|
* [Isolated builders](docs/advanced/isolated-builders.md)
|
||||||
* [Export image to Docker](#export-image-to-docker)
|
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
||||||
* [Leverage GitHub cache](#leverage-github-cache)
|
* [Cache](docs/advanced/cache.md)
|
||||||
* [Handle tags and labels](#handle-tags-and-labels)
|
* [Registry cache](docs/advanced/cache.md#registry-cache)
|
||||||
* [Update DockerHub repo description](#update-dockerhub-repo-description)
|
* [GitHub cache](docs/advanced/cache.md#github-cache)
|
||||||
|
* [Local registry](docs/advanced/local-registry.md)
|
||||||
|
* [Export image to Docker](docs/advanced/export-docker.md)
|
||||||
|
* [Handle tags and labels](docs/advanced/tags-labels.md)
|
||||||
|
* [Update DockerHub repo description](docs/advanced/dockerhub-desc.md)
|
||||||
* [Customizing](#customizing)
|
* [Customizing](#customizing)
|
||||||
* [inputs](#inputs)
|
* [inputs](#inputs)
|
||||||
* [outputs](#outputs)
|
* [outputs](#outputs)
|
||||||
* [Notes](#notes)
|
|
||||||
* [Multi-line secret value](#multi-line-secret-value)
|
|
||||||
* [Troubleshooting](#troubleshooting)
|
* [Troubleshooting](#troubleshooting)
|
||||||
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
|
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
|
||||||
* [Limitation](#limitation)
|
* [Limitation](#limitation)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
This action uses our [setup-buildx](https://github.com/docker/setup-buildx-action) action that extends the
|
By default, this action uses the [Git context](#git-context) so you don't need to use the
|
||||||
`docker build` command named [buildx](https://github.com/docker/buildx) with the full support of the features
|
[`actions/checkout`](https://github.com/actions/checkout/) action to checkout the repository because this will be
|
||||||
provided by [Moby BuildKit](https://github.com/moby/buildkit) builder toolkit. This includes multi-arch build,
|
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)
|
||||||
build-secrets, remote cache, etc. and different builder deployment/namespacing options.
|
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:
|
||||||
|
|
||||||
|
* [`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#--driver-driver). This is
|
||||||
|
**not required but recommended** using it to be able to build multi-platform images, export cache, etc.
|
||||||
|
* [`setup-qemu`](https://github.com/docker/setup-qemu-action) action can be useful if you want
|
||||||
|
to add emulation support with QEMU to be able to build against more platforms.
|
||||||
|
* [`login`](https://github.com/docker/setup-qemu-action) action will take care to log in against a Docker registry.
|
||||||
|
|
||||||
### Git context
|
### Git context
|
||||||
|
|
||||||
The default behavior of this action is to use the Git context invoked by your workflow.
|
|
||||||
(eg. `https://github.com/<owner>/<repo>.git#<ref>`)
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
main:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
@ -92,17 +104,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
tags: user/app:latest
|
||||||
build-args: |
|
|
||||||
arg1=value1
|
|
||||||
arg2=value2
|
|
||||||
-
|
-
|
||||||
name: Image digest
|
name: Image digest
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
```
|
```
|
||||||
|
|
||||||
Building from current repository automatically uses the [GitHub Token](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token)
|
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)
|
||||||
as provided by `secrets` so it does not need to be passed. But if you want to authenticate against another private
|
so it does not need to be passed. If you want to authenticate against another private repository, you have to use
|
||||||
repository, you have to use a secret named `GIT_AUTH_TOKEN` to be able to authenticate against it with buildx:
|
a [secret](docs/advanced/secrets.md) named `GIT_AUTH_TOKEN` to be able to authenticate against it with buildx:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
-
|
-
|
||||||
@ -117,23 +126,20 @@ repository, you have to use a secret named `GIT_AUTH_TOKEN` to be able to authen
|
|||||||
```
|
```
|
||||||
|
|
||||||
> :warning: Subdir for Git context is not yet supported ([moby/buildkit#1684](https://github.com/moby/buildkit/issues/1684))
|
> :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.
|
> 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).
|
||||||
|
|
||||||
> More info: https://docs.docker.com/engine/reference/commandline/build/#git-repositories
|
|
||||||
|
|
||||||
### Path context
|
### Path context
|
||||||
|
|
||||||
You can also use the `PATH` context alongside the [`actions/checkout`](https://github.com/actions/checkout/) action.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: ci
|
name: ci
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
path-context:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
@ -156,435 +162,23 @@ jobs:
|
|||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/386
|
|
||||||
push: true
|
push: true
|
||||||
tags: user/app:latest
|
tags: user/app:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Isolated builders
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
multi-builders:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
id: builder1
|
|
||||||
-
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
id: builder2
|
|
||||||
-
|
|
||||||
name: Builder 1 name
|
|
||||||
run: echo ${{ steps.builder1.outputs.name }}
|
|
||||||
-
|
|
||||||
name: Builder 2 name
|
|
||||||
run: echo ${{ steps.builder2.outputs.name }}
|
|
||||||
-
|
|
||||||
name: Build against builder1
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
builder: ${{ steps.builder1.outputs.name }}
|
|
||||||
target: mytarget1
|
|
||||||
-
|
|
||||||
name: Build against builder2
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
builder: ${{ steps.builder2.outputs.name }}
|
|
||||||
target: mytarget2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multi-platform image
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
multi:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
user/app:latest
|
|
||||||
user/app:1.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced usage
|
## Advanced usage
|
||||||
|
|
||||||
### Push to multi-registries
|
* [Multi-platform image](docs/advanced/multi-platform.md)
|
||||||
|
* [Secrets](docs/advanced/secrets.md)
|
||||||
The following workflow will connect you to [DockerHub](https://github.com/docker/login-action#dockerhub)
|
* [Isolated builders](docs/advanced/isolated-builders.md)
|
||||||
and [GitHub Container Registry](https://github.com/docker/login-action#github-container-registry) and push the
|
* [Push to multi-registries](docs/advanced/push-multi-registries.md)
|
||||||
image to these registries.
|
* [Cache](docs/advanced/cache.md)
|
||||||
|
* [Registry cache](docs/advanced/cache.md#registry-cache)
|
||||||
<details>
|
* [GitHub cache](docs/advanced/cache.md#github-cache)
|
||||||
<summary><b>Show workflow</b></summary>
|
* [Local registry](docs/advanced/local-registry.md)
|
||||||
|
* [Export image to Docker](docs/advanced/export-docker.md)
|
||||||
```yaml
|
* [Handle tags and labels](docs/advanced/tags-labels.md)
|
||||||
name: ci
|
* [Update DockerHub repo description](docs/advanced/dockerhub-desc.md)
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
multi-registries:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.CR_PAT }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
user/app:latest
|
|
||||||
user/app:1.0.0
|
|
||||||
ghcr.io/user/app:latest
|
|
||||||
ghcr.io/user/app:1.0.0
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Cache to registry
|
|
||||||
|
|
||||||
You can import/export cache from a cache manifest or (special) image configuration on the registry.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
registry-cache:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: user/app:latest
|
|
||||||
cache-from: type=registry,ref=user/app:latest
|
|
||||||
cache-to: type=inline
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Local registry
|
|
||||||
|
|
||||||
For testing purposes you may need to create a [local registry](https://hub.docker.com/_/registry) to push images into:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
local-registry:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
registry:
|
|
||||||
image: registry:2
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
with:
|
|
||||||
driver-opts: network=host
|
|
||||||
-
|
|
||||||
name: Build and push to local registry
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: localhost:5000/name/app:latest
|
|
||||||
-
|
|
||||||
name: Inspect
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools inspect localhost:5000/name/app:latest
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Export image to Docker
|
|
||||||
|
|
||||||
You may want your build result to be available in the Docker client through `docker images` to be able to use it
|
|
||||||
in another step of your workflow:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
export-docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
load: true
|
|
||||||
tags: myimage:latest
|
|
||||||
-
|
|
||||||
name: Inspect
|
|
||||||
run: |
|
|
||||||
docker image inspect myimage:latest
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Leverage GitHub cache
|
|
||||||
|
|
||||||
You can leverage [GitHub cache](https://docs.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows)
|
|
||||||
using [actions/cache](https://github.com/actions/cache) with this action:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
github-cache:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Cache Docker layers
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: /tmp/.buildx-cache
|
|
||||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-buildx-
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: user/app:latest
|
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
|
||||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
> If you want to [export layers for all stages](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue),
|
|
||||||
> you have to specify `mode=max` attribute in `cache-to`.
|
|
||||||
|
|
||||||
### Handle tags and labels
|
|
||||||
|
|
||||||
If you come from [`v1`](https://github.com/docker/build-push-action/tree/releases/v1#readme) and want an
|
|
||||||
"automatic" tag management and [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
|
|
||||||
for labels, you can do it in a dedicated step. The following workflow will use the [Docker meta action](https://github.com/crazy-max/ghaction-docker-meta)
|
|
||||||
to handle tags and labels based on GitHub actions events and Git metadata.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 10 * * *' # everyday at 10am
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
tags:
|
|
||||||
- 'v*.*.*'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Docker meta
|
|
||||||
id: docker_meta
|
|
||||||
uses: crazy-max/ghaction-docker-meta@v1
|
|
||||||
with:
|
|
||||||
images: name/app # list of Docker images to use as base name for tags
|
|
||||||
tag-sha: true # add git short SHA as Docker tag
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/386
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Update DockerHub repo description
|
|
||||||
|
|
||||||
You can update the [DockerHub repository description](https://docs.docker.com/docker-hub/repos/) using
|
|
||||||
a third-party action called [DockerHub Description](https://github.com/peter-evans/dockerhub-description)
|
|
||||||
with this action:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Show workflow</b></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: ci
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
tags: user/app:latest
|
|
||||||
-
|
|
||||||
name: Update repo description
|
|
||||||
uses: peter-evans/dockerhub-description@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
||||||
repository: user/app
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Customizing
|
## Customizing
|
||||||
|
|
||||||
@ -622,7 +216,8 @@ Following inputs can be used as `step.with` keys
|
|||||||
| `outputs` | List | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) |
|
| `outputs` | List | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) |
|
||||||
| `cache-from` | List | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) |
|
| `cache-from` | List | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) |
|
||||||
| `cache-to` | List | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) |
|
| `cache-to` | List | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) |
|
||||||
| `secrets` | List | List of secrets to expose to the build (eg. `key=value`, `GIT_AUTH_TOKEN=mytoken`) |
|
| `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 |
|
| `ssh` | List | List of SSH agent socket or keys to expose to the build |
|
||||||
|
|
||||||
### outputs
|
### outputs
|
||||||
@ -633,38 +228,6 @@ Following outputs are available
|
|||||||
|---------------|---------|---------------------------------------|
|
|---------------|---------|---------------------------------------|
|
||||||
| `digest` | String | Image content-addressable identifier also called a digest |
|
| `digest` | String | Image content-addressable identifier also called a digest |
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
### Multi-line secret value
|
|
||||||
|
|
||||||
To handle multi-line value for a secret, you will need to place the key-value pair between quotes:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
secrets: |
|
|
||||||
"MYSECRET=${{ secrets.GPG_KEY }}"
|
|
||||||
GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
|
||||||
"MYSECRET=aaaaaaaa
|
|
||||||
bbbbbbb
|
|
||||||
ccccccccc"
|
|
||||||
FOO=bar
|
|
||||||
"EMPTYLINE=aaaa
|
|
||||||
|
|
||||||
bbbb
|
|
||||||
ccc"
|
|
||||||
"JSON_SECRET={""key1"":""value1"",""key2"":""value2""}"
|
|
||||||
```
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|--------------------|--------------------------------------------------|
|
|
||||||
| `MYSECRET` | `***********************` |
|
|
||||||
| `GIT_AUTH_TOKEN` | `abcdefghi,jklmno=0123456789` |
|
|
||||||
| `MYSECRET` | `aaaaaaaa\nbbbbbbb\nccccccccc` |
|
|
||||||
| `FOO` | `bar` |
|
|
||||||
| `EMPTYLINE` | `aaaa\n\nbbbb\nccc` |
|
|
||||||
| `JSON_SECRET` | `{"key1":"value1","key2":"value2"}` |
|
|
||||||
|
|
||||||
> Note: all quote signs need to be doubled for escaping.
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
See [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
|
See [TROUBLESHOOTING.md](TROUBLESHOOTING.md)
|
||||||
|
@ -1,113 +1,7 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
* [`auto-push is currently not implemented for docker driver`](#auto-push-is-currently-not-implemented-for-docker-driver)
|
|
||||||
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
* [Cannot push to a registry](#cannot-push-to-a-registry)
|
||||||
|
|
||||||
## `auto-push is currently not implemented for docker driver`
|
|
||||||
|
|
||||||
If you're using the default builder (which uses the docker driver) without using our `setup-buildx-action`, you may
|
|
||||||
encounter this error message if you try to push your image:
|
|
||||||
|
|
||||||
```
|
|
||||||
Run docker/build-push-action@v2
|
|
||||||
📣 Buildx version: 0.4.2
|
|
||||||
🏃 Starting build...
|
|
||||||
/usr/bin/docker buildx build --tag localhost:5000/name/app:latest --iidfile /tmp/docker-build-push-eYl8PB/iidfile --file ./test/Dockerfile --push ./test
|
|
||||||
auto-push is currently not implemented for docker driver
|
|
||||||
Error: buildx call failed with: auto-push is currently not implemented for docker driver
|
|
||||||
```
|
|
||||||
|
|
||||||
While waiting for an implementation to be done on buildx/buildkit, you have the following possibilities
|
|
||||||
to solve this atm:
|
|
||||||
|
|
||||||
### With `docker-container` driver and `setup-buildx`
|
|
||||||
|
|
||||||
> Recommended solution
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ env.USER }}
|
|
||||||
password: ${{ secrets.PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
tags: ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
push: true
|
|
||||||
```
|
|
||||||
|
|
||||||
### With `docker` driver
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Login
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ env.USER }}
|
|
||||||
password: ${{ secrets.PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
tags: ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
load: true
|
|
||||||
-
|
|
||||||
name: Push
|
|
||||||
run: docker push ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### With `docker` driver and `setup-buildx`
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
with:
|
|
||||||
driver: docker
|
|
||||||
-
|
|
||||||
name: Login
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ env.USER }}
|
|
||||||
password: ${{ secrets.PASSWORD }}
|
|
||||||
-
|
|
||||||
name: Build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
tags: ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
load: true
|
|
||||||
-
|
|
||||||
name: Push
|
|
||||||
run: docker push ${{ env.REGISTRY }}/myapp:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cannot push to a registry
|
## Cannot push to a registry
|
||||||
|
|
||||||
While pushing to a registry, you may encounter these kinds of issues:
|
While pushing to a registry, you may encounter these kinds of issues:
|
||||||
@ -165,8 +59,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
platforms: linux/amd64,linux/arm64
|
||||||
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
|
||||||
tags: docker.io/user/app:latest
|
tags: docker.io/user/app:latest
|
||||||
outputs: type=oci,dest=/tmp/image.tar
|
outputs: type=oci,dest=/tmp/image.tar
|
||||||
-
|
-
|
||||||
|
@ -63,7 +63,6 @@ steps:
|
|||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
|
||||||
pull: true
|
pull: true
|
||||||
push: true
|
push: true
|
||||||
build-args: |
|
build-args: |
|
||||||
@ -136,7 +135,6 @@ steps:
|
|||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.prep.outputs.tags }}
|
tags: ${{ steps.prep.outputs.tags }}
|
||||||
labels: |
|
labels: |
|
||||||
@ -145,5 +143,5 @@ steps:
|
|||||||
org.opencontainers.image.revision=${{ github.sha }}
|
org.opencontainers.image.revision=${{ github.sha }}
|
||||||
```
|
```
|
||||||
|
|
||||||
> You can also use the [Docker meta action](https://github.com/crazy-max/ghaction-docker-meta) to handle tags and
|
> You can also use the [Docker meta action to handle tags and labels](docs/advanced/tags-labels.md) based on GitHub
|
||||||
> labels based on GitHub actions events and Git metadata. A workflow example is available in the [README](README.md#handle-tags-and-labels).
|
> actions events and Git metadata.
|
||||||
|
@ -119,21 +119,34 @@ describe('parseVersion', () => {
|
|||||||
|
|
||||||
describe('getSecret', () => {
|
describe('getSecret', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['A_SECRET=abcdef0123456789', 'A_SECRET', 'abcdef0123456789', false],
|
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', false],
|
||||||
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false],
|
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false],
|
||||||
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false],
|
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', false, 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false],
|
||||||
['aaaaaaaa', '', '', true],
|
['aaaaaaaa', false, '', '', true],
|
||||||
['aaaaaaaa=', '', '', true],
|
['aaaaaaaa=', false, '', '', true],
|
||||||
['=bbbbbbb', '', '', true]
|
['=bbbbbbb', false, '', '', true],
|
||||||
])('given %p key and %p secret', async (kvp, key, secret, invalid) => {
|
[
|
||||||
|
`foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`,
|
||||||
|
true,
|
||||||
|
'foo',
|
||||||
|
'bar',
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[`notfound=secret`, true, '', '', true]
|
||||||
|
])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => {
|
||||||
try {
|
try {
|
||||||
const secretArgs = await buildx.getSecret(kvp);
|
let secret: string;
|
||||||
|
if (file) {
|
||||||
|
secret = await buildx.getSecretFile(kvp);
|
||||||
|
} else {
|
||||||
|
secret = await buildx.getSecretString(kvp);
|
||||||
|
}
|
||||||
expect(true).toBe(!invalid);
|
expect(true).toBe(!invalid);
|
||||||
console.log(`secretArgs: ${secretArgs}`);
|
console.log(`secret: ${secret}`);
|
||||||
expect(secretArgs).toEqual(`id=${key},src=${tmpNameSync}`);
|
expect(secret).toEqual(`id=${exKey},src=${tmpNameSync}`);
|
||||||
const secretContent = await fs.readFileSync(tmpNameSync, 'utf-8');
|
const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8');
|
||||||
console.log(`secretValue: ${secretContent}`);
|
console.log(`secretValue: ${secretValue}`);
|
||||||
expect(secretContent).toEqual(secret);
|
expect(secretValue).toEqual(exValue);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
expect(true).toBe(invalid);
|
expect(true).toBe(invalid);
|
||||||
}
|
}
|
||||||
|
@ -337,6 +337,27 @@ ccc`],
|
|||||||
'--push',
|
'--push',
|
||||||
'https://github.com/docker/build-push-action.git#heads/master'
|
'https://github.com/docker/build-push-action.git#heads/master'
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'0.5.1',
|
||||||
|
new Map<string, string>([
|
||||||
|
['context', 'https://github.com/docker/build-push-action.git#heads/master'],
|
||||||
|
['tag', 'localhost:5000/name/app:latest'],
|
||||||
|
['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`],
|
||||||
|
['file', './test/Dockerfile'],
|
||||||
|
['builder', 'builder-git-context-2'],
|
||||||
|
['push', 'true']
|
||||||
|
]),
|
||||||
|
[
|
||||||
|
'buildx',
|
||||||
|
'build',
|
||||||
|
'--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',
|
||||||
|
'--push',
|
||||||
|
'https://github.com/docker/build-push-action.git#heads/master'
|
||||||
|
]
|
||||||
]
|
]
|
||||||
])(
|
])(
|
||||||
'given %p with %p as inputs, returns %p',
|
'given %p with %p as inputs, returns %p',
|
||||||
|
1
__tests__/fixtures/secret.txt
Normal file
1
__tests__/fixtures/secret.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
bar
|
11
action.yml
11
action.yml
@ -60,15 +60,18 @@ inputs:
|
|||||||
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 (eg. user/app:cache, type=local,dest=path/to/dir)"
|
||||||
required: false
|
required: false
|
||||||
secrets:
|
secrets:
|
||||||
description: "List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)"
|
description: "List of secrets to expose to the build (eg. 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)"
|
||||||
|
required: false
|
||||||
|
ssh:
|
||||||
|
description: "List of SSH agent socket or keys to expose to the build"
|
||||||
required: false
|
required: false
|
||||||
github-token:
|
github-token:
|
||||||
description: "GitHub Token used to authenticate against a repository for Git context"
|
description: "GitHub Token used to authenticate against a repository for Git context"
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
required: false
|
required: false
|
||||||
ssh:
|
|
||||||
description: "List of SSH agent socket or keys to expose to the build"
|
|
||||||
required: false
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
digest:
|
digest:
|
||||||
|
138
dist/index.js
generated
vendored
138
dist/index.js
generated
vendored
@ -4581,7 +4581,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.parseVersion = exports.getVersion = exports.isAvailable = exports.hasGitAuthToken = exports.isLocalOrTarExporter = exports.getSecret = exports.getImageID = exports.getImageIDFile = void 0;
|
exports.parseVersion = exports.getVersion = exports.isAvailable = exports.hasGitAuthToken = exports.isLocalOrTarExporter = exports.getSecret = exports.getSecretFile = exports.getSecretString = exports.getImageID = exports.getImageIDFile = void 0;
|
||||||
const sync_1 = __importDefault(__webpack_require__(750));
|
const sync_1 = __importDefault(__webpack_require__(750));
|
||||||
const fs_1 = __importDefault(__webpack_require__(747));
|
const fs_1 = __importDefault(__webpack_require__(747));
|
||||||
const path_1 = __importDefault(__webpack_require__(622));
|
const path_1 = __importDefault(__webpack_require__(622));
|
||||||
@ -4604,18 +4604,36 @@ function getImageID() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getImageID = getImageID;
|
exports.getImageID = getImageID;
|
||||||
function getSecret(kvp) {
|
function getSecretString(kvp) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
return getSecret(kvp, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getSecretString = getSecretString;
|
||||||
|
function getSecretFile(kvp) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
return getSecret(kvp, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getSecretFile = getSecretFile;
|
||||||
|
function getSecret(kvp, file) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const delimiterIndex = kvp.indexOf('=');
|
const delimiterIndex = kvp.indexOf('=');
|
||||||
const key = kvp.substring(0, delimiterIndex);
|
const key = kvp.substring(0, delimiterIndex);
|
||||||
const value = kvp.substring(delimiterIndex + 1);
|
let value = kvp.substring(delimiterIndex + 1);
|
||||||
if (key.length == 0 || value.length == 0) {
|
if (key.length == 0 || value.length == 0) {
|
||||||
throw new Error(`${kvp} is not a valid secret`);
|
throw new Error(`${kvp} is not a valid secret`);
|
||||||
}
|
}
|
||||||
|
if (file) {
|
||||||
|
if (!fs_1.default.existsSync(value)) {
|
||||||
|
throw new Error(`secret file ${value} not found`);
|
||||||
|
}
|
||||||
|
value = fs_1.default.readFileSync(value, { encoding: 'utf-8' });
|
||||||
|
}
|
||||||
const secretFile = context.tmpNameSync({
|
const secretFile = context.tmpNameSync({
|
||||||
tmpdir: context.tmpDir()
|
tmpdir: context.tmpDir()
|
||||||
});
|
});
|
||||||
yield fs_1.default.writeFileSync(secretFile, value);
|
fs_1.default.writeFileSync(secretFile, value);
|
||||||
return `id=${key},src=${secretFile}`;
|
return `id=${key},src=${secretFile}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -11668,10 +11686,14 @@ additional information.
|
|||||||
const { Transform } = __webpack_require__(413)
|
const { Transform } = __webpack_require__(413)
|
||||||
const ResizeableBuffer = __webpack_require__(942)
|
const ResizeableBuffer = __webpack_require__(942)
|
||||||
|
|
||||||
|
// white space characters
|
||||||
|
// https://en.wikipedia.org/wiki/Whitespace_character
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes#Types
|
||||||
|
// \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff
|
||||||
const tab = 9
|
const tab = 9
|
||||||
const nl = 10
|
const nl = 10 // \n, 0x0A in hexadecimal, 10 in decimal
|
||||||
const np = 12
|
const np = 12
|
||||||
const cr = 13
|
const cr = 13 // \r, 0x0D in hexadécimal, 13 in decimal
|
||||||
const space = 32
|
const space = 32
|
||||||
const boms = {
|
const boms = {
|
||||||
// Note, the following are equals:
|
// Note, the following are equals:
|
||||||
@ -11860,6 +11882,27 @@ class Parser extends Transform {
|
|||||||
throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`)
|
throw new Error(`Invalid Option: from_line must be an integer, got ${JSON.stringify(opts.from_line)}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Normalize options `ignore_last_delimiters`
|
||||||
|
if(options.ignore_last_delimiters === undefined || options.ignore_last_delimiters === null){
|
||||||
|
options.ignore_last_delimiters = false
|
||||||
|
}else if(typeof options.ignore_last_delimiters === 'number'){
|
||||||
|
options.ignore_last_delimiters = Math.floor(options.ignore_last_delimiters)
|
||||||
|
if(options.ignore_last_delimiters === 0){
|
||||||
|
options.ignore_last_delimiters = false
|
||||||
|
}
|
||||||
|
}else if(typeof options.ignore_last_delimiters !== 'boolean'){
|
||||||
|
throw new CsvError('CSV_INVALID_OPTION_IGNORE_LAST_DELIMITERS', [
|
||||||
|
'Invalid option `ignore_last_delimiters`:',
|
||||||
|
'the value must be a boolean value or an integer,',
|
||||||
|
`got ${JSON.stringify(options.ignore_last_delimiters)}`
|
||||||
|
], options)
|
||||||
|
}
|
||||||
|
if(options.ignore_last_delimiters === true && options.columns === false){
|
||||||
|
throw new CsvError('CSV_IGNORE_LAST_DELIMITERS_REQUIRES_COLUMNS', [
|
||||||
|
'The option `ignore_last_delimiters`',
|
||||||
|
'requires the activation of the `columns` option'
|
||||||
|
], options)
|
||||||
|
}
|
||||||
// Normalize option `info`
|
// Normalize option `info`
|
||||||
if(options.info === undefined || options.info === null || options.info === false){
|
if(options.info === undefined || options.info === null || options.info === false){
|
||||||
options.info = false
|
options.info = false
|
||||||
@ -12177,7 +12220,7 @@ class Parser extends Transform {
|
|||||||
}
|
}
|
||||||
// Auto discovery of record_delimiter, unix, mac and windows supported
|
// Auto discovery of record_delimiter, unix, mac and windows supported
|
||||||
if(this.state.quoting === false && record_delimiter.length === 0){
|
if(this.state.quoting === false && record_delimiter.length === 0){
|
||||||
const record_delimiterCount = this.__autoDiscoverRowDelimiter(buf, pos)
|
const record_delimiterCount = this.__autoDiscoverRecordDelimiter(buf, pos)
|
||||||
if(record_delimiterCount){
|
if(record_delimiterCount){
|
||||||
record_delimiter = this.options.record_delimiter
|
record_delimiter = this.options.record_delimiter
|
||||||
}
|
}
|
||||||
@ -12218,12 +12261,12 @@ class Parser extends Transform {
|
|||||||
const isNextChrTrimable = rtrim && this.__isCharTrimable(nextChr)
|
const isNextChrTrimable = rtrim && this.__isCharTrimable(nextChr)
|
||||||
const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr)
|
const isNextChrComment = comment !== null && this.__compareBytes(comment, buf, pos+quote.length, nextChr)
|
||||||
const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr)
|
const isNextChrDelimiter = this.__isDelimiter(buf, pos+quote.length, nextChr)
|
||||||
const isNextChrRowDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRowDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length)
|
const isNextChrRecordDelimiter = record_delimiter.length === 0 ? this.__autoDiscoverRecordDelimiter(buf, pos+quote.length) : this.__isRecordDelimiter(nextChr, buf, pos+quote.length)
|
||||||
// Escape a quote
|
// Escape a quote
|
||||||
// Treat next char as a regular character
|
// Treat next char as a regular character
|
||||||
if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){
|
if(escape !== null && this.__isEscape(buf, pos, chr) && this.__isQuote(buf, pos + escape.length)){
|
||||||
pos += escape.length - 1
|
pos += escape.length - 1
|
||||||
}else if(!nextChr || isNextChrDelimiter || isNextChrRowDelimiter || isNextChrComment || isNextChrTrimable){
|
}else if(!nextChr || isNextChrDelimiter || isNextChrRecordDelimiter || isNextChrComment || isNextChrTrimable){
|
||||||
this.state.quoting = false
|
this.state.quoting = false
|
||||||
this.state.wasQuoting = true
|
this.state.wasQuoting = true
|
||||||
pos += quote.length - 1
|
pos += quote.length - 1
|
||||||
@ -12234,7 +12277,7 @@ class Parser extends Transform {
|
|||||||
'Invalid Closing Quote:',
|
'Invalid Closing Quote:',
|
||||||
`got "${String.fromCharCode(nextChr)}"`,
|
`got "${String.fromCharCode(nextChr)}"`,
|
||||||
`at line ${this.info.lines}`,
|
`at line ${this.info.lines}`,
|
||||||
'instead of delimiter, row delimiter, trimable character',
|
'instead of delimiter, record delimiter, trimable character',
|
||||||
'(if activated) or comment',
|
'(if activated) or comment',
|
||||||
], this.options, this.__context())
|
], this.options, this.__context())
|
||||||
)
|
)
|
||||||
@ -12275,25 +12318,24 @@ class Parser extends Transform {
|
|||||||
this.info.comment_lines++
|
this.info.comment_lines++
|
||||||
// Skip full comment line
|
// Skip full comment line
|
||||||
}else{
|
}else{
|
||||||
|
// Activate records emition if above from_line
|
||||||
|
if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0) >= from_line){
|
||||||
|
this.state.enabled = true
|
||||||
|
this.__resetField()
|
||||||
|
this.__resetRecord()
|
||||||
|
pos += recordDelimiterLength - 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
// Skip if line is empty and skip_empty_lines activated
|
// Skip if line is empty and skip_empty_lines activated
|
||||||
if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){
|
if(skip_empty_lines === true && this.state.wasQuoting === false && this.state.record.length === 0 && this.state.field.length === 0){
|
||||||
this.info.empty_lines++
|
this.info.empty_lines++
|
||||||
pos += recordDelimiterLength - 1
|
pos += recordDelimiterLength - 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Activate records emition if above from_line
|
const errField = this.__onField()
|
||||||
if(this.state.enabled === false && this.info.lines + (this.state.wasRowDelimiter === true ? 1: 0 ) >= from_line){
|
if(errField !== undefined) return errField
|
||||||
this.state.enabled = true
|
const errRecord = this.__onRecord()
|
||||||
this.__resetField()
|
if(errRecord !== undefined) return errRecord
|
||||||
this.__resetRow()
|
|
||||||
pos += recordDelimiterLength - 1
|
|
||||||
continue
|
|
||||||
}else{
|
|
||||||
const errField = this.__onField()
|
|
||||||
if(errField !== undefined) return errField
|
|
||||||
const errRecord = this.__onRow()
|
|
||||||
if(errRecord !== undefined) return errRecord
|
|
||||||
}
|
|
||||||
if(to !== -1 && this.info.records >= to){
|
if(to !== -1 && this.info.records >= to){
|
||||||
this.state.stop = true
|
this.state.stop = true
|
||||||
this.push(null)
|
this.push(null)
|
||||||
@ -12366,7 +12408,7 @@ class Parser extends Transform {
|
|||||||
if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){
|
if(this.state.wasQuoting === true || this.state.record.length !== 0 || this.state.field.length !== 0){
|
||||||
const errField = this.__onField()
|
const errField = this.__onField()
|
||||||
if(errField !== undefined) return errField
|
if(errField !== undefined) return errField
|
||||||
const errRecord = this.__onRow()
|
const errRecord = this.__onRecord()
|
||||||
if(errRecord !== undefined) return errRecord
|
if(errRecord !== undefined) return errRecord
|
||||||
}else if(this.state.wasRowDelimiter === true){
|
}else if(this.state.wasRowDelimiter === true){
|
||||||
this.info.empty_lines++
|
this.info.empty_lines++
|
||||||
@ -12382,21 +12424,17 @@ class Parser extends Transform {
|
|||||||
this.state.wasRowDelimiter = false
|
this.state.wasRowDelimiter = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Helper to test if a character is a space or a line delimiter
|
__onRecord(){
|
||||||
__isCharTrimable(chr){
|
|
||||||
return chr === space || chr === tab || chr === cr || chr === nl || chr === np
|
|
||||||
}
|
|
||||||
__onRow(){
|
|
||||||
const {columns, columns_duplicates_to_array, encoding, info, from, relax_column_count, relax_column_count_less, relax_column_count_more, raw, skip_lines_with_empty_values} = this.options
|
const {columns, columns_duplicates_to_array, encoding, info, from, relax_column_count, relax_column_count_less, relax_column_count_more, raw, skip_lines_with_empty_values} = this.options
|
||||||
const {enabled, record} = this.state
|
const {enabled, record} = this.state
|
||||||
if(enabled === false){
|
if(enabled === false){
|
||||||
return this.__resetRow()
|
return this.__resetRecord()
|
||||||
}
|
}
|
||||||
// Convert the first line into column names
|
// Convert the first line into column names
|
||||||
const recordLength = record.length
|
const recordLength = record.length
|
||||||
if(columns === true){
|
if(columns === true){
|
||||||
if(isRecordEmpty(record)){
|
if(isRecordEmpty(record)){
|
||||||
this.__resetRow()
|
this.__resetRecord()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return this.__firstLineToColumns(record)
|
return this.__firstLineToColumns(record)
|
||||||
@ -12438,12 +12476,12 @@ class Parser extends Transform {
|
|||||||
}
|
}
|
||||||
if(skip_lines_with_empty_values === true){
|
if(skip_lines_with_empty_values === true){
|
||||||
if(isRecordEmpty(record)){
|
if(isRecordEmpty(record)){
|
||||||
this.__resetRow()
|
this.__resetRecord()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.state.recordHasError === true){
|
if(this.state.recordHasError === true){
|
||||||
this.__resetRow()
|
this.__resetRecord()
|
||||||
this.state.recordHasError = false
|
this.state.recordHasError = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -12517,7 +12555,7 @@ class Parser extends Transform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.__resetRow()
|
this.__resetRecord()
|
||||||
}
|
}
|
||||||
__firstLineToColumns(record){
|
__firstLineToColumns(record){
|
||||||
const {firstLineToHeaders} = this.state
|
const {firstLineToHeaders} = this.state
|
||||||
@ -12537,13 +12575,13 @@ class Parser extends Transform {
|
|||||||
const normalizedHeaders = normalizeColumnsArray(headers)
|
const normalizedHeaders = normalizeColumnsArray(headers)
|
||||||
this.state.expectedRecordLength = normalizedHeaders.length
|
this.state.expectedRecordLength = normalizedHeaders.length
|
||||||
this.options.columns = normalizedHeaders
|
this.options.columns = normalizedHeaders
|
||||||
this.__resetRow()
|
this.__resetRecord()
|
||||||
return
|
return
|
||||||
}catch(err){
|
}catch(err){
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__resetRow(){
|
__resetRecord(){
|
||||||
if(this.options.raw === true){
|
if(this.options.raw === true){
|
||||||
this.state.rawBuffer.reset()
|
this.state.rawBuffer.reset()
|
||||||
}
|
}
|
||||||
@ -12616,6 +12654,10 @@ class Parser extends Transform {
|
|||||||
}
|
}
|
||||||
return [undefined, field]
|
return [undefined, field]
|
||||||
}
|
}
|
||||||
|
// Helper to test if a character is a space or a line delimiter
|
||||||
|
__isCharTrimable(chr){
|
||||||
|
return chr === space || chr === tab || chr === cr || chr === nl || chr === np
|
||||||
|
}
|
||||||
// Keep it in case we implement the `cast_int` option
|
// Keep it in case we implement the `cast_int` option
|
||||||
// __isInt(value){
|
// __isInt(value){
|
||||||
// // return Number.isInteger(parseInt(value))
|
// // return Number.isInteger(parseInt(value))
|
||||||
@ -12642,14 +12684,19 @@ class Parser extends Transform {
|
|||||||
needMoreDataSize,
|
needMoreDataSize,
|
||||||
// Skip if the remaining buffer smaller than record delimiter
|
// Skip if the remaining buffer smaller than record delimiter
|
||||||
recordDelimiterMaxLength,
|
recordDelimiterMaxLength,
|
||||||
// Skip if the remaining buffer can be row delimiter following the closing quote
|
// Skip if the remaining buffer can be record delimiter following the closing quote
|
||||||
// 1 is for quote.length
|
// 1 is for quote.length
|
||||||
quoting ? (quote.length + recordDelimiterMaxLength) : 0,
|
quoting ? (quote.length + recordDelimiterMaxLength) : 0,
|
||||||
)
|
)
|
||||||
return numOfCharLeft < requiredLength
|
return numOfCharLeft < requiredLength
|
||||||
}
|
}
|
||||||
__isDelimiter(buf, pos, chr){
|
__isDelimiter(buf, pos, chr){
|
||||||
const {delimiter} = this.options
|
const {delimiter, ignore_last_delimiters} = this.options
|
||||||
|
if(ignore_last_delimiters === true && this.state.record.length === this.options.columns.length - 1){
|
||||||
|
return 0
|
||||||
|
}else if(ignore_last_delimiters !== false && typeof ignore_last_delimiters === 'number' && this.state.record.length === ignore_last_delimiters - 1){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
loop1: for(let i = 0; i < delimiter.length; i++){
|
loop1: for(let i = 0; i < delimiter.length; i++){
|
||||||
const del = delimiter[i]
|
const del = delimiter[i]
|
||||||
if(del[0] === chr){
|
if(del[0] === chr){
|
||||||
@ -12704,7 +12751,7 @@ class Parser extends Transform {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
__autoDiscoverRowDelimiter(buf, pos){
|
__autoDiscoverRecordDelimiter(buf, pos){
|
||||||
const {encoding} = this.options
|
const {encoding} = this.options
|
||||||
const chr = buf[pos]
|
const chr = buf[pos]
|
||||||
if(chr === cr){
|
if(chr === cr){
|
||||||
@ -13003,6 +13050,7 @@ function getInputs(defaultContext) {
|
|||||||
cacheFrom: yield getInputList('cache-from', true),
|
cacheFrom: yield getInputList('cache-from', true),
|
||||||
cacheTo: yield getInputList('cache-to', true),
|
cacheTo: yield getInputList('cache-to', true),
|
||||||
secrets: yield getInputList('secrets', true),
|
secrets: yield getInputList('secrets', true),
|
||||||
|
secretFiles: yield getInputList('secret-files', true),
|
||||||
githubToken: core.getInput('github-token'),
|
githubToken: core.getInput('github-token'),
|
||||||
ssh: yield getInputList('ssh')
|
ssh: yield getInputList('ssh')
|
||||||
};
|
};
|
||||||
@ -13055,14 +13103,22 @@ function getBuildArgs(inputs, defaultContext, buildxVersion) {
|
|||||||
}));
|
}));
|
||||||
yield exports.asyncForEach(inputs.secrets, (secret) => __awaiter(this, void 0, void 0, function* () {
|
yield exports.asyncForEach(inputs.secrets, (secret) => __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
args.push('--secret', yield buildx.getSecret(secret));
|
args.push('--secret', yield buildx.getSecretString(secret));
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
core.warning(err.message);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
yield exports.asyncForEach(inputs.secretFiles, (secretFile) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
args.push('--secret', yield buildx.getSecretFile(secretFile));
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
core.warning(err.message);
|
core.warning(err.message);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) {
|
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) {
|
||||||
args.push('--secret', yield buildx.getSecret(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
|
args.push('--secret', yield buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
|
||||||
}
|
}
|
||||||
yield exports.asyncForEach(inputs.ssh, (ssh) => __awaiter(this, void 0, void 0, function* () {
|
yield exports.asyncForEach(inputs.ssh, (ssh) => __awaiter(this, void 0, void 0, function* () {
|
||||||
args.push('--ssh', ssh);
|
args.push('--ssh', ssh);
|
||||||
|
107
docs/advanced/cache.md
Normal file
107
docs/advanced/cache.md
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# Cache
|
||||||
|
|
||||||
|
* [Registry cache](#registry-cache)
|
||||||
|
* [GitHub cache](#github-cache)
|
||||||
|
|
||||||
|
> More info about buildx cache: https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue
|
||||||
|
|
||||||
|
## Registry cache
|
||||||
|
|
||||||
|
You can import/export cache from a cache manifest or (special) image configuration on the registry.
|
||||||
|
|
||||||
|
```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:latest
|
||||||
|
cache-to: type=inline
|
||||||
|
```
|
||||||
|
|
||||||
|
## GitHub 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:
|
||||||
|
|
||||||
|
```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: Cache Docker layers
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache
|
||||||
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||||
|
-
|
||||||
|
# Temp fix
|
||||||
|
# https://github.com/docker/build-push-action/issues/252
|
||||||
|
# https://github.com/moby/buildkit/issues/1896
|
||||||
|
name: Move cache
|
||||||
|
run: |
|
||||||
|
rm -rf /tmp/.buildx-cache
|
||||||
|
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||||
|
```
|
48
docs/advanced/dockerhub-desc.md
Normal file
48
docs/advanced/dockerhub-desc.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Update DockerHub repo description
|
||||||
|
|
||||||
|
You can update the [DockerHub repository description](https://docs.docker.com/docker-hub/repos/) using
|
||||||
|
a third party action called [DockerHub Description](https://github.com/peter-evans/dockerhub-description)
|
||||||
|
with this action:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
-
|
||||||
|
name: Update repo description
|
||||||
|
uses: peter-evans/dockerhub-description@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||||
|
repository: user/app
|
||||||
|
```
|
35
docs/advanced/export-docker.md
Normal file
35
docs/advanced/export-docker.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Export image to Docker
|
||||||
|
|
||||||
|
You may want your build result to be available in the Docker client through `docker images` to be able to use it
|
||||||
|
in another step of your workflow:
|
||||||
|
|
||||||
|
```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: Build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
load: true
|
||||||
|
tags: myimage:latest
|
||||||
|
-
|
||||||
|
name: Inspect
|
||||||
|
run: |
|
||||||
|
docker image inspect myimage:latest
|
||||||
|
```
|
44
docs/advanced/isolated-builders.md
Normal file
44
docs/advanced/isolated-builders.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Isolated builders
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
id: builder1
|
||||||
|
-
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
id: builder2
|
||||||
|
-
|
||||||
|
name: Builder 1 name
|
||||||
|
run: echo ${{ steps.builder1.outputs.name }}
|
||||||
|
-
|
||||||
|
name: Builder 2 name
|
||||||
|
run: echo ${{ steps.builder2.outputs.name }}
|
||||||
|
-
|
||||||
|
name: Build against builder1
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.builder1.outputs.name }}
|
||||||
|
context: .
|
||||||
|
target: mytarget1
|
||||||
|
-
|
||||||
|
name: Build against builder2
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
builder: ${{ steps.builder2.outputs.name }}
|
||||||
|
context: .
|
||||||
|
target: mytarget2
|
||||||
|
```
|
44
docs/advanced/local-registry.md
Normal file
44
docs/advanced/local-registry.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Local registry
|
||||||
|
|
||||||
|
For testing purposes you may need to create a [local registry](https://hub.docker.com/_/registry) to push images into:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-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:
|
||||||
|
driver-opts: network=host
|
||||||
|
-
|
||||||
|
name: Build and push to local registry
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: localhost:5000/name/app:latest
|
||||||
|
-
|
||||||
|
name: Inspect
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect localhost:5000/name/app:latest
|
||||||
|
```
|
44
docs/advanced/multi-platform.md
Normal file
44
docs/advanced/multi-platform.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Multi-platform image
|
||||||
|
|
||||||
|
You can build multi-platform images using the [`platforms` input](../../README.md#inputs) as described below.
|
||||||
|
|
||||||
|
> :bulb: List of available platforms will be displayed and available through our [setup-buildx](https://github.com/docker/setup-buildx-action#about) action.
|
||||||
|
|
||||||
|
> :bulb: If you want support for more platforms, you can use QEMU with our [setup-qemu](https://github.com/docker/setup-qemu-action) action.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
||||||
|
```
|
57
docs/advanced/push-multi-registries.md
Normal file
57
docs/advanced/push-multi-registries.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Push to multi-registries
|
||||||
|
|
||||||
|
* [Docker Hub and GHCR](#docker-hub-and-ghcr)
|
||||||
|
|
||||||
|
## Docker Hub and GHCR
|
||||||
|
|
||||||
|
The following workflow will connect you to [DockerHub](https://github.com/docker/login-action#dockerhub)
|
||||||
|
and [GitHub Container Registry](https://github.com/docker/login-action#github-container-registry) and push the
|
||||||
|
image to these registries.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.CR_PAT }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
user/app:latest
|
||||||
|
user/app:1.0.0
|
||||||
|
ghcr.io/user/app:latest
|
||||||
|
ghcr.io/user/app:1.0.0
|
||||||
|
```
|
84
docs/advanced/secrets.md
Normal file
84
docs/advanced/secrets.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# Secrets
|
||||||
|
|
||||||
|
In the following example we will expose and use the [GITHUB_TOKEN secret](https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret)
|
||||||
|
as provided by GitHub in your workflow.
|
||||||
|
|
||||||
|
First let's create our `Dockerfile` to use our secret:
|
||||||
|
|
||||||
|
```Dockerfile
|
||||||
|
#syntax=docker/dockerfile:1.2
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
RUN --mount=type=secret,id=github_token \
|
||||||
|
cat /run/secrets/github_token
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see we have named our secret `github_token`. Here is the workflow you can use to expose this secret using
|
||||||
|
the [`secrets` input](../../README.md#inputs):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: user/app:latest
|
||||||
|
secrets: |
|
||||||
|
"github_token=${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
```
|
||||||
|
|
||||||
|
> :bulb: You can also expose a secret file to the build with [`secret-files`](../../README.md#inputs) input:
|
||||||
|
> ```yaml
|
||||||
|
> secret-files: |
|
||||||
|
> "MY_SECRET=./secret.txt"
|
||||||
|
> ```
|
||||||
|
|
||||||
|
If you're using [GitHub secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) and need to handle
|
||||||
|
multi-line value, you will need to place the key-value pair between quotes:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
secrets: |
|
||||||
|
"MYSECRET=${{ secrets.GPG_KEY }}"
|
||||||
|
GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
|
||||||
|
"MYSECRET=aaaaaaaa
|
||||||
|
bbbbbbb
|
||||||
|
ccccccccc"
|
||||||
|
FOO=bar
|
||||||
|
"EMPTYLINE=aaaa
|
||||||
|
|
||||||
|
bbbb
|
||||||
|
ccc"
|
||||||
|
"JSON_SECRET={""key1"":""value1"",""key2"":""value2""}"
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Value |
|
||||||
|
|--------------------|--------------------------------------------------|
|
||||||
|
| `MYSECRET` | `***********************` |
|
||||||
|
| `GIT_AUTH_TOKEN` | `abcdefghi,jklmno=0123456789` |
|
||||||
|
| `MYSECRET` | `aaaaaaaa\nbbbbbbb\nccccccccc` |
|
||||||
|
| `FOO` | `bar` |
|
||||||
|
| `EMPTYLINE` | `aaaa\n\nbbbb\nccc` |
|
||||||
|
| `JSON_SECRET` | `{"key1":"value1","key2":"value2"}` |
|
||||||
|
|
||||||
|
> :bulb: All quote signs need to be doubled for escaping.
|
70
docs/advanced/tags-labels.md
Normal file
70
docs/advanced/tags-labels.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# Handle tags and labels
|
||||||
|
|
||||||
|
If you come from [`v1`](https://github.com/docker/build-push-action/tree/releases/v1#readme) and want an
|
||||||
|
"automatic" tag management and [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
|
||||||
|
for labels, you can do it in a dedicated step. The following workflow will use the [Docker meta action](https://github.com/crazy-max/ghaction-docker-meta)
|
||||||
|
to handle tags and labels based on GitHub actions events and Git metadata.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 10 * * *' # everyday at 10am
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Docker meta
|
||||||
|
id: docker_meta
|
||||||
|
uses: crazy-max/ghaction-docker-meta@v1
|
||||||
|
with:
|
||||||
|
# list of Docker images to use as base name for tags
|
||||||
|
images: |
|
||||||
|
name/app
|
||||||
|
ghcr.io/username/app
|
||||||
|
# add git short SHA as Docker tag
|
||||||
|
tag-sha: true
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Login to GHCR
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ secrets.GHCR_USERNAME }}
|
||||||
|
password: ${{ secrets.GHCR_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||||
|
```
|
@ -31,7 +31,7 @@
|
|||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/exec": "^1.0.4",
|
"@actions/exec": "^1.0.4",
|
||||||
"@actions/github": "^4.0.0",
|
"@actions/github": "^4.0.0",
|
||||||
"csv-parse": "^4.14.2",
|
"csv-parse": "^4.15.1",
|
||||||
"semver": "^7.3.4",
|
"semver": "^7.3.4",
|
||||||
"tmp": "^0.2.1"
|
"tmp": "^0.2.1"
|
||||||
},
|
},
|
||||||
|
@ -18,17 +18,34 @@ export async function getImageID(): Promise<string | undefined> {
|
|||||||
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSecret(kvp: string): Promise<string> {
|
export async function getSecretString(kvp: string): Promise<string> {
|
||||||
|
return getSecret(kvp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSecretFile(kvp: string): Promise<string> {
|
||||||
|
return getSecret(kvp, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSecret(kvp: string, file: boolean): Promise<string> {
|
||||||
const delimiterIndex = kvp.indexOf('=');
|
const delimiterIndex = kvp.indexOf('=');
|
||||||
const key = kvp.substring(0, delimiterIndex);
|
const key = kvp.substring(0, delimiterIndex);
|
||||||
const value = kvp.substring(delimiterIndex + 1);
|
let value = kvp.substring(delimiterIndex + 1);
|
||||||
if (key.length == 0 || value.length == 0) {
|
if (key.length == 0 || value.length == 0) {
|
||||||
throw new Error(`${kvp} is not a valid secret`);
|
throw new Error(`${kvp} is not a valid secret`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
if (!fs.existsSync(value)) {
|
||||||
|
throw new Error(`secret file ${value} not found`);
|
||||||
|
}
|
||||||
|
value = fs.readFileSync(value, {encoding: 'utf-8'});
|
||||||
|
}
|
||||||
|
|
||||||
const secretFile = context.tmpNameSync({
|
const secretFile = context.tmpNameSync({
|
||||||
tmpdir: context.tmpDir()
|
tmpdir: context.tmpDir()
|
||||||
});
|
});
|
||||||
await fs.writeFileSync(secretFile, value);
|
fs.writeFileSync(secretFile, value);
|
||||||
|
|
||||||
return `id=${key},src=${secretFile}`;
|
return `id=${key},src=${secretFile}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ export interface Inputs {
|
|||||||
cacheFrom: string[];
|
cacheFrom: string[];
|
||||||
cacheTo: string[];
|
cacheTo: string[];
|
||||||
secrets: string[];
|
secrets: string[];
|
||||||
|
secretFiles: string[];
|
||||||
githubToken: string;
|
githubToken: string;
|
||||||
ssh: string[];
|
ssh: string[];
|
||||||
}
|
}
|
||||||
@ -73,6 +74,7 @@ export async function getInputs(defaultContext: string): Promise<Inputs> {
|
|||||||
cacheFrom: await getInputList('cache-from', true),
|
cacheFrom: await getInputList('cache-from', true),
|
||||||
cacheTo: await getInputList('cache-to', true),
|
cacheTo: await getInputList('cache-to', true),
|
||||||
secrets: await getInputList('secrets', true),
|
secrets: await getInputList('secrets', true),
|
||||||
|
secretFiles: await getInputList('secret-files', true),
|
||||||
githubToken: core.getInput('github-token'),
|
githubToken: core.getInput('github-token'),
|
||||||
ssh: await getInputList('ssh')
|
ssh: await getInputList('ssh')
|
||||||
};
|
};
|
||||||
@ -123,13 +125,20 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
|
|||||||
});
|
});
|
||||||
await asyncForEach(inputs.secrets, async secret => {
|
await asyncForEach(inputs.secrets, async secret => {
|
||||||
try {
|
try {
|
||||||
args.push('--secret', await buildx.getSecret(secret));
|
args.push('--secret', await buildx.getSecretString(secret));
|
||||||
|
} catch (err) {
|
||||||
|
core.warning(err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await asyncForEach(inputs.secretFiles, async secretFile => {
|
||||||
|
try {
|
||||||
|
args.push('--secret', await buildx.getSecretFile(secretFile));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.warning(err.message);
|
core.warning(err.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) {
|
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) {
|
||||||
args.push('--secret', await buildx.getSecret(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
|
args.push('--secret', await buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
|
||||||
}
|
}
|
||||||
await asyncForEach(inputs.ssh, async ssh => {
|
await asyncForEach(inputs.ssh, async ssh => {
|
||||||
args.push('--ssh', ssh);
|
args.push('--ssh', ssh);
|
||||||
|
@ -1236,10 +1236,10 @@ cssstyle@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
cssom "~0.3.6"
|
cssom "~0.3.6"
|
||||||
|
|
||||||
csv-parse@*, csv-parse@^4.14.2:
|
csv-parse@*, csv-parse@^4.15.1:
|
||||||
version "4.14.2"
|
version "4.15.1"
|
||||||
resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-4.14.2.tgz#c1329cff95a99b8773a92c4e62f8bff114b34726"
|
resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-4.15.1.tgz#fc5a0a1b24eaa6d4c24892daa387c46f7f92f8d2"
|
||||||
integrity sha512-YE2xlTKtM035/94llhgsp9qFQxGi47EkQJ1pZ+mLT/98GpIsbjkMGAb7Rmu9hNxVfYFOLf10hP+rPVqnoccLgw==
|
integrity sha512-TXIvRtNp0fqMJbk3yPR35bQIDzMH4khDwduElzE7Fl1wgnl25mnWYLSLqd/wS5GsDoX1rWtysivEYMNsz5jKwQ==
|
||||||
|
|
||||||
dashdash@^1.12.0:
|
dashdash@^1.12.0:
|
||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
|
Reference in New Issue
Block a user