GitHub Action to extract metadata (tags, labels) from Git reference and GitHub events for Docker
Go to file
CrazyMax b2391d37b4
Merge pull request #193 from crazy-max/images-opts
attribute to enable/disable images
2022-04-28 13:19:16 +02:00
.github backward compatibility with old images format 2022-04-28 09:08:29 +02:00
__tests__ backward compatibility with old images format 2022-04-28 09:08:29 +02:00
dist backward compatibility with old images format 2022-04-28 09:08:29 +02:00
src backward compatibility with old images format 2022-04-28 09:08:29 +02:00
test Rename bake target 2021-05-10 15:54:35 +02:00
.dockerignore Enhance workflow (#51) 2021-03-29 13:18:19 +02:00
.editorconfig Initial commit 2020-10-25 02:25:23 +01:00
.eslintrc.json chore: update dev dependencies and workflow 2022-03-22 21:09:00 +01:00
.gitattributes base_ref global expression 2021-10-22 13:14:53 +02:00
.gitignore Initial commit 2020-10-25 02:25:23 +01:00
.prettierrc.json Initial commit 2020-10-25 02:25:23 +01:00
action.yml Add json output to action.yml 2022-03-07 08:25:24 +01:00
codecov.yml PEP 440 support 2021-07-06 13:56:55 +02:00
dev.Dockerfile chore: update dev dependencies and workflow 2022-03-22 21:09:00 +01:00
docker-bake.hcl chore: update dev dependencies and workflow 2022-03-22 21:09:00 +01:00
jest.config.ts Fix csv-parse implementation since major update 2022-04-25 13:35:08 +02:00
LICENSE Move to Docker org 2021-05-08 01:41:46 +02:00
package.json Bump csv-parse from 4.16.3 to 5.0.4 2022-04-25 11:06:07 +00:00
README.md backward compatibility with old images format 2022-04-28 09:08:29 +02:00
tsconfig.json chore: update dev dependencies and workflow 2022-03-22 21:09:00 +01:00
UPGRADE.md v3 upgrade notes 2021-05-10 16:03:37 +02:00
yarn.lock Bump csv-parse from 4.16.3 to 5.0.4 2022-04-25 11:06:07 +00:00

GitHub release GitHub marketplace Test workflow Codecov

About

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.

Screenshot


Usage

Basic

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

Semver

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

Bake definition

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": "860c1904a1ce19322e91ac35af1ab07466440c37",
        "org.opencontainers.image.licenses": "MIT"
      },
      "args": {
        "DOCKER_META_IMAGES": "name/app",
        "DOCKER_META_VERSION": "1.2.3"
      }
    }
  }
}

Customizing

inputs

Following inputs can be used as step.with keys

List type is a newline-delimited string

labels: |
  org.opencontainers.image.title=MyCustomTitle
  org.opencontainers.image.description=Another description
  org.opencontainers.image.vendor=MyCompany  
Name Type Description
images List 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)

outputs

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

images input

images defines a list of Docker images to use as base name for tags:

images: |
  name/foo
  ghcr.io/name/bar
  # or
  name=name/foo
  name=ghcr.io/name/bar  

Extended attributes and default values:

images: |
  name=,enable=true  
  • name=<string> image base name
  • enable=<true|false> enable this entry (default true)

flavor input

flavor defines a global behavior for tags:

flavor: |
  latest=auto
  prefix=
  suffix=  
  • latest=<auto|true|false>: Handle latest tag (default auto)
  • prefix=<string>,onlatest=<true|false>: A global prefix for each generated tag and optionally for latest
  • suffix=<string>,onlatest=<true|false>: A global suffix for each generated tag and optionally for latest

tags input

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 (default true)
  • priority=<number> priority to manage the order of tags
  • prefix=<string> add prefix
  • suffix=<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  

type=schedule

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:

Pattern Output
nightly nightly
{{date 'YYYYMMDD'}} 20210326

Extended attributes and default values:

tags: |
  type=schedule,enable=true,priority=1000,prefix=,suffix=,pattern=nightly  

type=semver

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 tag
  • version ; shorthand for {{major}}.{{minor}}.{{patch}} (can include pre-release)
  • major ; major version identifier
  • minor ; minor version identifier
  • patch ; 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}} v2.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}} (or {{raw}} if specified) 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=  

type=pep440

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 tag
  • version ; cleaned version
  • major ; major version identifier
  • minor ; minor version identifier
  • patch ; 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
v1.2.3rc2 {{raw}} v1.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}} (or {{raw}} if specified) 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=  

type=match

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=  

type=edge

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  

type=ref

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  

type=raw

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=  

type=sha

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  

Notes

Latest tag

latest tag is handled through the flavor input. It will be generated by default (auto mode) for:

For conditionally tagging with latest for a specific branch name, e.g. if your default branch name is not master, use type=raw with a boolean expression:

tags: |
  # set latest tag for master branch
  type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}  

You can also use the {{is_default_branch}} global expression to conditionally tag with latest for the default branch:

tags: |
  # set latest tag for default branch
  type=raw,value=latest,enable={{is_default_branch}}  

Global expressions

The following Handlebars' template expressions for prefix, suffix, value and enable attributes are available:

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}}  

{{branch}}

Returns the branch name that triggered the workflow run. Will be empty if not a branch reference:

Event Ref Output
pull_request refs/pull/2/merge
push refs/heads/master master
push refs/heads/my/branch my-branch
push tag refs/tags/v1.2.3

{{tag}}

Returns the tag name that triggered the workflow run. Will be empty if not a tag reference:

Event Ref Output
pull_request refs/pull/2/merge
push refs/heads/master
push refs/heads/my/branch
push tag refs/tags/v1.2.3 v1.2.3

{{sha}}

Returns the short commit SHA that triggered the workflow run (e.g., 90dd603).

{{base_ref}}

Returns the base ref or target branch of the pull request that triggered the workflow run. Will be empty for a branch reference:

Event Ref Output
pull_request refs/pull/2/merge master
push refs/heads/master
push refs/heads/my/branch
push tag* refs/tags/v1.2.3 master

*base_ref is available in the push payload but doesn't always seem to return the expected branch when the push tag event occurs. It's also not documented in GitHub docs. We keep it for backward compatibility, but it's not recommended relying on it. More context in #192.

{{is_default_branch}}

Returns true if the branch that triggered the workflow run is the default one, otherwise false.

{{date '<format>'}}

Returns the current date rendered by its moment format.

Expression Output example
{{date 'YYYYMMDD'}} 20200110
{{date 'dddd, MMMM Do YYYY, h:mm:ss a'}} Friday, January 10th 2020, 3:25:50 pm

Major version zero

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.') }}  

JSON output object

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'] }}            

Overwrite labels

If some 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            

Keep up-to-date with GitHub Dependabot

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"