GitHub Action to extract metadata from Git reference and GitHub events. This action is particularly useful if used with Docker Build Push action to tag and label Docker images.
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: name/app
-
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
uses: docker/build-push-action@v2
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Event | Ref | Docker Tags |
---|---|---|
pull_request |
refs/pull/2/merge |
pr-2 |
push |
refs/heads/master |
master |
push |
refs/heads/releases/v1 |
releases-v1 |
push tag |
refs/tags/v1.2.3 |
v1.2.3 , latest |
push tag |
refs/tags/v2.0.8-beta.67 |
v2.0.8-beta.67 , latest |
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: name/app
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
-
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
uses: docker/build-push-action@v2
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Event | Ref | Docker Tags |
---|---|---|
pull_request |
refs/pull/2/merge |
pr-2 |
push |
refs/heads/master |
master |
push |
refs/heads/releases/v1 |
releases-v1 |
push tag |
refs/tags/v1.2.3 |
1.2.3 , 1.2 , latest |
push tag |
refs/tags/v2.0.8-beta.67 |
2.0.8-beta.67 |
This action also handles a bake definition file that can be used with the
Docker Bake action. You just have to declare an empty target named
docker-metadata-action
and inherit from it.
// docker-bake.hcl
target "docker-metadata-action" {}
target "build" {
inherits = ["docker-metadata-action"]
context = "./"
dockerfile = "Dockerfile"
platforms = [
"linux/amd64",
"linux/arm/v6",
"linux/arm/v7",
"linux/arm64",
"linux/386"
]
}
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: name/app
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
-
name: Build
uses: docker/bake-action@v1
with:
files: |
./docker-bake.hcl
${{ steps.meta.outputs.bake-file }}
targets: build
Content of ${{ steps.meta.outputs.bake-file }}
file will look like this with refs/tags/v1.2.3
ref:
{
"target": {
"docker-metadata-action": {
"tags": [
"name/app:1.2.3",
"name/app:1.2",
"name/app:sha-90dd603",
"name/app:latest"
],
"labels": {
"org.opencontainers.image.title": "Hello-World",
"org.opencontainers.image.description": "This your first repo!",
"org.opencontainers.image.url": "https://github.com/octocat/Hello-World",
"org.opencontainers.image.source": "https://github.com/octocat/Hello-World",
"org.opencontainers.image.version": "1.2.3",
"org.opencontainers.image.created": "2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision": "90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses": "MIT"
},
"args": {
"DOCKER_META_IMAGES": "name/app",
"DOCKER_META_VERSION": "1.2.3"
}
}
}
}
Following inputs can be used as step.with
keys
List
type is a newline-delimited stringlabels: | org.opencontainers.image.title=MyCustomTitle org.opencontainers.image.description=Another description org.opencontainers.image.vendor=MyCompany
CSV
type is a comma-delimited stringimages: name/app,ghcr.io/name/app
Name | Type | Description |
---|---|---|
images |
List/CSV | List of Docker images to use as base name for tags |
tags |
List | List of tags as key-value pair attributes |
flavor |
List | Flavor to apply |
labels |
List | List of custom labels |
sep-tags |
String | Separator to use for tags output (default \n ) |
sep-labels |
String | Separator to use for labels output (default \n ) |
bake-target |
String | Bake target name (default docker-metadata-action ) |
Following outputs are available
Name | Type | Description |
---|---|---|
version |
String | Docker image version |
tags |
String | Docker tags |
labels |
String | Docker labels |
json |
String | JSON output of tags and labels |
bake-file |
File | Bake definition file path |
flavor
defines a global behavior for tags
:
flavor: |
latest=auto
prefix=
suffix=
latest=<auto|true|false>
: Handle latest tag (defaultauto
)prefix=<string>,onlatest=<true|false>
: A global prefix for each generated tag and optionally forlatest
suffix=<string>,onlatest=<true|false>
: A global suffix for each generated tag and optionally forlatest
tags
is the core input of this action as everything related to it will reflect the output metadata. This one is in
the form of a key-value pair list in CSV format to remove limitations intrinsically linked to GitHub Actions
(only string format is handled in the input fields). Here is an example:
tags: |
type=schedule
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=ref,event=branch
type=ref,event=pr
type=sha
Each entry is defined by a type
, which are:
And global attributes:
enable=<true|false>
enable this entry (defaulttrue
)priority=<number>
priority to manage the order of tagsprefix=<string>
add prefixsuffix=<string>
add suffix
Default entries if tags
input is empty:
tags: |
type=schedule
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
tags: |
# minimal
type=schedule
# default
type=schedule,pattern=nightly
# handlebars
type=schedule,pattern={{date 'YYYYMMDD'}}
Will be used on schedule event.
pattern
is a specially crafted attribute to support Handlebars template with
the following expressions:
date 'format'
; render date by its moment format
Pattern | Output |
---|---|
nightly |
nightly |
{{date 'YYYYMMDD'}} |
20210326 |
Extended attributes and default values:
tags: |
type=schedule,enable=true,priority=1000,prefix=,suffix=,pattern=nightly
tags: |
# minimal
type=semver,pattern={{version}}
# use custom value instead of git tag
type=semver,pattern={{version}},value=v1.0.0
Will be used on a push tag event
and requires a valid semver Git tag, but you can also use a custom value through value
attribute.
pattern
attribute supports Handlebars template with the following expressions:
raw
; the actual tagversion
; shorthand for{{major}}.{{minor}}.{{patch}}
(can include pre-release)major
; major version identifierminor
; minor version identifierpatch
; patch version identifier
Git tag | Pattern | Output |
---|---|---|
v1.2.3 |
{{raw}} |
v1.2.3 |
v1.2.3 |
{{version}} |
1.2.3 |
v1.2.3 |
{{major}}.{{minor}} |
1.2 |
v1.2.3 |
v{{major}} |
v1 |
v1.2.3 |
{{minor}} |
2 |
v1.2.3 |
{{patch}} |
3 |
v2.0.8-beta.67 |
{{raw}} |
2.0.8-beta.67 * |
v2.0.8-beta.67 |
{{version}} |
2.0.8-beta.67 |
v2.0.8-beta.67 |
{{major}}.{{minor}} |
2.0.8-beta.67 * |
*Pre-release (rc, beta, alpha) will only extend
{{version}}
as tag because they are updated frequently, and contain many breaking changes that are (by the author's design) not yet fit for public consumption.
Extended attributes and default values:
tags: |
type=semver,enable=true,priority=900,prefix=,suffix=,pattern=,value=
tags: |
# minimal
type=pep440,pattern={{version}}
# use custom value instead of git tag
type=pep440,pattern={{version}},value=1.0.0
Will be used on a push tag event
and requires a Git tag that conforms to PEP 440, but you can also use a
custom value through value
attribute.
pattern
attribute supports Handlebars template with the following expressions:
raw
; the actual tagversion
; cleaned versionmajor
; major version identifierminor
; minor version identifierpatch
; patch version identifier
Git tag | Pattern | Output |
---|---|---|
1.2.3 |
{{raw}} |
1.2.3 |
1.2.3 |
{{version}} |
1.2.3 |
v1.2.3 |
{{version}} |
1.2.3 |
1.2.3 |
{{major}}.{{minor}} |
1.2 |
1.2.3 |
v{{major}} |
v1 |
1.2.3rc2 |
{{raw}} |
1.2.3rc2 * |
1.2.3rc2 |
{{version}} |
1.2.3rc2 |
1.2.3rc2 |
{{major}}.{{minor}} |
1.2.3rc2 * |
1.2.3post1 |
{{major}}.{{minor}} |
1.2.3.post1 * |
1.2.3beta2 |
{{major}}.{{minor}} |
1.2.3b2 * |
1.0dev4 |
{{major}}.{{minor}} |
1.0.dev4 * |
*dev/pre/post release will only extend
{{version}}
as tag because they are updated frequently, and contain many breaking changes that are (by the author's design) not yet fit for public consumption.
Extended attributes and default values:
tags: |
type=pep440,enable=true,priority=900,prefix=,suffix=,pattern=,value=
tags: |
# minimal
type=match,pattern=\d.\d.\d
# define match group
type=match,pattern=v(.*),group=1
# use custom value instead of git tag
type=match,pattern=v(.*),group=1,value=v1.0.0
Can create a regular expression for matching Git tag with a pattern and capturing group. Will be used on a
push tag event but you can also use
a custom value through value
attribute.
Git tag | Pattern | Group | Output |
---|---|---|---|
v1.2.3 |
\d.\d.\d |
0 |
1.2.3 |
v2.0.8-beta.67 |
v(.*) |
1 |
2.0.8-beta.67 |
v2.0.8-beta.67 |
v(\d.\d) |
1 |
2.0 |
20200110-RC2 |
\d+ |
0 |
20200110 |
p1/v1.2.3 |
p1-v(\d.\d.\d) |
1 |
1.2.3 |
Extended attributes and default values:
tags: |
type=match,enable=true,priority=800,prefix=,suffix=,pattern=,group=0,value=
tags: |
# minimal
type=edge
# define default branch
type=edge,branch=main
An edge
tag reflects the last commit of the active branch on your Git repository. I usually prefer to use edge
as a Docker tag for a better distinction or common pattern. This is also used by official images
like Alpine.
Extended attributes and default values:
tags: |
type=edge,enable=true,priority=700,prefix=,suffix=,branch=$repo.default_branch
tags: |
# branch event
type=ref,event=branch
# tag event
type=ref,event=tag
# pull request event
type=ref,event=pr
This type handles Git ref (or reference) for the following events:
branch
; eg.refs/heads/master
tag
; eg.refs/tags/v1.0.0
pr
; eg.refs/pull/318/merge
Event | Ref | Output |
---|---|---|
pull_request |
refs/pull/2/merge |
pr-2 |
push |
refs/heads/master |
master |
push |
refs/heads/my/branch |
my-branch |
push tag |
refs/tags/v1.2.3 |
v1.2.3 |
push tag |
refs/tags/v2.0.8-beta.67 |
v2.0.8-beta.67 |
Extended attributes and default values:
tags: |
# branch event
type=ref,enable=true,priority=600,prefix=,suffix=,event=branch
# tag event
type=ref,enable=true,priority=600,prefix=,suffix=,event=tag
# pull request event
type=ref,enable=true,priority=600,prefix=pr-,suffix=,event=pr
tags: |
type=raw,value=foo
type=raw,value=bar
# or
type=raw,foo
type=raw,bar
# or
foo
bar
Output custom tags according to your needs.
Extended attributes and default values:
tags: |
type=raw,enable=true,priority=200,prefix=,suffix=,value=
tags: |
# minimal (short sha)
type=sha
# full length sha
type=sha,format=long
Output Git short commit (or long if specified) as Docker tag like sha-ad132f5
.
Extended attributes and default values:
tags: |
type=sha,enable=true,priority=100,prefix=sha-,suffix=,format=short
latest
tag is handled through the flavor
input. It will be generated by default (auto
mode) for:
The following Handlebars template expressions for prefix
, suffix
and value
attributes are available:
Expression | Output |
---|---|
{{branch}} |
master |
{{tag}} |
v1.2.3 |
{{sha}} |
90dd603 |
{{base_ref}} |
master |
{{date 'YYYYMMDD'}} |
20210326 |
tags: |
# dynamically set the branch name as a prefix
type=sha,prefix={{branch}}-
# dynamically set the branch name and sha as a custom tag
type=raw,value=mytag-{{branch}}-{{sha}}
Major version zero (0.y.z
) is for initial development and may change at any time. This means the public API
should not be considered stable.
In this case, Docker tag 0
should not be generated if you're using type=semver
with {{major}}
pattern. You can manage this behavior like this:
# refs/tags/v0.1.2
tags: |
# output 0.1.2
type=semver,pattern={{version}}
# output 0.1
type=semver,pattern={{major}}.{{minor}}
# disabled if major zero
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
The json
output is a JSON object composed of the generated tags and labels so that you can reuse them further in your
workflow using the fromJSON
function:
-
name: Docker meta
uses: docker/metadata-action@v3
id: meta
with:
images: name/app
-
name: Build and push
uses: docker/build-push-action@v2
with:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
If some of the OCI Image Format Specification labels generated are not suitable, you can overwrite them like this:
-
name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: name/app
labels: |
maintainer=CrazyMax
org.opencontainers.image.title=MyCustomTitle
org.opencontainers.image.description=Another description
org.opencontainers.image.vendor=MyCompany
Since Dependabot
has native GitHub Actions support,
to enable it on your GitHub repo all you need to do is add the .github/dependabot.yml
file:
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"