l7r7
l7r7

Reputation: 1338

Add a tag to a Docker image if there's a git tag using GitHub Action

I'm using GitHub Actions to build a docker image using the build-push-action. I'd like to add tags to the image before pushing it to the docker registry:

I have something along the lines of:

- name: Build and push
  id: docker_build
  uses: docker/build-push-action@v2
  with:
    context: .
    push: true
    tags:
      - user/image:latest

It would be easy to always add more tags, but I want to add it only if there's a git tag. Is there a way to do that?

Upvotes: 17

Views: 43329

Answers (4)

Carter
Carter

Reputation: 1294

I was not able to use the above answers because they are triggered upon adding a tag, whereas I wanted it to be triggered by pushing to master.

In my case, I would:

  1. Use an action to update the tags upon on a push to master. https://github.com/mathieudutour/github-tag-action
  2. And in a separate step, deploy:
- name: Checkout
  uses: actions/checkout@v2
  with:
    fetch-depth: 0 # Without this, this action won't be able to find any or the correct tags.

- name: 'Get tag'
  id: tag
  uses: 'WyriHaximus/github-action-get-previous-tag@8a0e045f02c0a3a04e1452df58b90fc7e555e950'

- name: Set correct environment
  run: |
    TAG=${{ steps.tag.outputs.tag }}
    echo "TAG=$TAG" >> "$GITHUB_ENV"

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v1

- name: Retrieve metadata
  id: metadata
  uses: docker/metadata-action@e5622373a38e60fb6d795a4421e56882f2d7a681
  env:
    ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
  with:
    images: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}
    tags: |
      type=semver,pattern={{major}}.{{minor}}.{{patch}},value=${{ env.TAG }}
      type=semver,pattern={{major}}.{{minor}},value=${{ env.TAG }}
      type=semver,pattern={{major}},value=${{ env.TAG }}

- name: Build and push
  id: docker
  uses: docker/build-push-action@v2
  with:
    push: true
    tags: ${{ steps.metadata.outputs.tags }}

Upvotes: 3

Kevin Condon
Kevin Condon

Reputation: 1738

There's a docker/metadata-action that does this. Make sure to set up the push tags trigger along with whatever other triggers you might need. The action docs have a lot more details about what tags it applies for each event trigger type. See also https://docs.github.com/en/actions/publishing-packages/publishing-docker-images for even more info on the general topic of Docker image publishing.

name: Tag Docker Image with Git

on:
  push:
    tags: [ v* ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Log into the Container registry
      uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Extract metadata for the Docker image
      id: meta
      uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

    - name: Build and push the Docker image
      uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

Upvotes: 22

ITChap
ITChap

Reputation: 4752

Maybe something like this:


- name: Build and push
  id: gen_tags
  run: |
    if [[ $GITHUB_REF == 'refs/tags/'* ]]; then
      TAGS='["user/image:latest","user/image:'${GITHUB_REF/refs\/tags\//}'"]'
    else
      TAGS='["user/image:latest"]'
    fi
    echo '::set-output name=tags::'$TAGS

- name: Build and push
  id: docker_build
  uses: docker/build-push-action@v2
  needs: gen_tags
  with:
    context: .
    push: true
    tags: ${{ fromJson(steps.gen_tags.outputs.tags) }}

The first step generates the list of tags and the second build/push. if $GITHUB_REF starts by refs/tags/ it is a tag and as such we generate a json list with both docker tags. Else, we use a list that contains only the latest tag. Since we can only pass strings around, we have to output the json as a string and then parse it in the second step using fromJson. I am sorry for the ugly escaping (you might actually have issues there and have to try few different solutions), but it's a bit tricky to do without making the script more complex.

Upvotes: 2

l7r7
l7r7

Reputation: 1338

I found a solution using a dedicated action. I create the tags in a separate step and add it afterwards. The relevant parts of the CI config look like this:

- name: Docker meta
  id: docker_meta
  uses: crazy-max/ghaction-docker-meta@v1
  with:
    images: l7r7/sample
    tag-custom: latest
    tag-semver: |
      {{raw}}
- name: Build and push
  id: docker_build
  uses: docker/build-push-action@v2
  with:
    context: .
    push: false
    tags: ${{ steps.docker_meta.outputs.tags }}
    labels: ${{ steps.docker_meta.outputs.labels }}

To be precise, it's not exactly what I was asking for, because it will add a tag containing the branch name as well. But that's ok for me. I can live with that.

A full working example can be found here.

Upvotes: 8

Related Questions