docker / docker/metadata-action

when using labels across multiple tags, the label is only applied to 1 of the tags (at random)

Open
#534 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

kind/upstream status/needs-more-info
Dominant language
TypeScript
Stars
1.1k
Forks
160
Avg merge
4d 17h
Merged PRs (30d)
12

Description

Contributing guidelines
I've found a bug, and:
  • The documentation does not mention anything about my problem
  • There are no open or closed issues that are related to my problem
Description

Using this code:

        - name: Set container metadata (for releases, 183d expiry)
          id: meta-release
          if: ${{ env.REF_NAME_SHORT != 'next' }}
          uses: docker/metadata-action@v5
          with:
            images: ${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}
            tags: |
              type=raw,value=${{ env.REF_NAME }}
              type=raw,value=${{ env.REF_NAME }}-${{ env.SHORT_SHA }}
              type=raw,value=${{ env.REF_NAME_SHORT }}
              type=raw,value=${{ env.REF_NAME_SHORT }}-${{ env.SHORT_SHA }}
            labels: |
              quay.expires-after=183d

in this workflow:

https://github.com/redhat-developer/rhdh/blob/main/.github/workflows/next-build-image.yaml#L194-L206

when pushing a tag to the repo results in 4 correctly created tags, but ONLY ONE of them has the quay.expires-after=183d label applied; the other 3 have no tag expiration set.

You can see the created tags here https://quay.io/repository/rhdh-community/rhdh?tab=tags

Image

Related downstream issue (in case this is a configuration problem or I've done something wrong): https://issues.redhat.com/browse/RHIDP-8270

Expected behaviour

all tags in a given push should get the same labels applied, not just whichever one is found first in the hashmap/array

Actual behaviour

only 1 of 4 tags has the correct expiration date set

Repository URL

https://github.com/redhat-developer/rhdh/actions/workflows/next-build-image.yaml

Workflow run URL

https://github.com/redhat-developer/rhdh/actions/runs/16476194526/job/46583106978

YAML workflow
name: Build Next and Tag Image

on:
  # workflow_dispatch so that it can be triggered manually if needed
  workflow_dispatch:
  schedule:
    # run at 3:18 UTC every day
    - cron: "18 3 * * *"

  # in addition to building multi-arch :next images daily,
  # also build multi-arch images for any x.y or x.y.z tag pushed to the repo
  push:
    tags:
      - '[0-9]+.[0-9]+.[0-9]+'
      - '[0-9]+.[0-9]+'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  REGISTRY: quay.io
  REGISTRY_IMAGE: rhdh-community/rhdh

jobs:
  build-image:
    name: Build Image
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-24.04-arm
          - ubuntu-24.04
    runs-on: ${{ matrix.os }}
    timeout-minutes: 720 # Set to 12 hours instead of default 360 = 6hrs
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Prepare
        run: |
          if [ "${{ matrix.os }}" == "ubuntu-24.04" ]; then
            platform="linux/amd64"
          elif [ "${{ matrix.os }}" == "ubuntu-24.04-arm" ]; then
            platform="linux/arm64"
          else
            echo "Unknown platform"
            exit 1
          fi

          ref_name=${{ github.ref_name }}
          if [ "$ref_name" == "main" ]; then
            ref_name="next"
          fi
          # from 1.6.1 => 1.6
          ref_name_short="${ref_name%.*}"
          if [[ $ref_name_short == "1" ]]; then
            ref_name_short="${ref_name}"
          fi
          echo "REF_NAME=$ref_name" >> $GITHUB_ENV
          echo "REF_NAME_SHORT=${ref_name_short}" >> $GITHUB_ENV
          echo "PLATFORM=$platform" >> $GITHUB_ENV
          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
          echo "PLATFORM_ARCH=${platform#*/}" >> $GITHUB_ENV

      - name: Get the last commit short SHA
        uses: ./.github/actions/get-sha

      - name: Build and Push with Buildx (for :next builds, 14d expiry)
        uses: ./.github/actions/docker-build
        id: build-next
        if: ${{ env.REF_NAME_SHORT == 'next' }}
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.QUAY_USERNAME }}
          password: ${{ secrets.QUAY_TOKEN }}
          imageName: ${{ env.REGISTRY_IMAGE }}
          imageTags: |
            type=raw,value=${{ env.REF_NAME }}-${{ env.PLATFORM_ARCH }}
            type=raw,value=${{ env.REF_NAME }}-${{ env.SHORT_SHA }}-${{ env.PLATFORM_ARCH }}
          imageLabels: quay.expires-after=14d
          push: true
          platform: ${{ env.PLATFORM }}

      - name: Build and Push with Buildx (for releases, 183d expiry)
        uses: ./.github/actions/docker-build
        id: build-release
        if: ${{ env.REF_NAME_SHORT != 'next' }}
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.QUAY_USERNAME }}
          password: ${{ secrets.QUAY_TOKEN }}
          imageName: ${{ env.REGISTRY_IMAGE }}
          imageTags: |
            type=raw,value=${{ env.REF_NAME }}-${{ env.PLATFORM_ARCH }}
            type=raw,value=${{ env.REF_NAME }}-${{ env.SHORT_SHA }}-${{ env.PLATFORM_ARCH }}
          imageLabels: quay.expires-after=183d
          push: true
          platform: ${{ env.PLATFORM }}

      - name: Export digest (for :next builds)
        id: export-digest-next
        if: ${{ env.REF_NAME_SHORT == 'next' }}
        run: |
          mkdir -p /tmp/digests
          digest="${{ steps.build-next.outputs.digest }}"
          touch "/tmp/digests/${digest#sha256:}"

      - name: Export digest (for releases)
        id: export-digest-release
        if: ${{ env.REF_NAME_SHORT != 'next' }}
        run: |
          mkdir -p /tmp/digests
          digest="${{ steps.build-release.outputs.digest }}"
          touch "/tmp/digests/${digest#sha256:}"

      - name: Upload digest
        uses: actions/upload-artifact@v4
        with:
          name: digests-${{ env.PLATFORM_PAIR }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  merge:
      runs-on: ubuntu-latest
      needs:
        - build-image
      steps:
        - name: Prepare
          run: |
            ref_name=${{ github.ref_name }}
            if [ "$ref_name" == "main" ]; then
              ref_name="next"
            fi
            # from 1.6.1 => 1.6
            ref_name_short="${ref_name%.*}"
            if [[ $ref_name_short == "1" ]]; then
              ref_name_short="${ref_name}"
            fi
            echo "REF_NAME=$ref_name" >> $GITHUB_ENV
            echo "REF_NAME_SHORT=${ref_name_short}" >> $GITHUB_ENV

        - name: Checkout
          uses: actions/checkout@v4
          with:
            fetch-depth: 0

        - name: Download digests
          uses: actions/download-artifact@v4
          with:
            path: /tmp/digests
            pattern: digests-*
            merge-multiple: true

        - name: Get the last commit short SHA
          uses: ./.github/actions/get-sha

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

        - name: Set container metadata (for :next builds, 14d expiry)
          id: meta-next
          if: ${{ env.REF_NAME_SHORT == 'next'}}
          uses: docker/metadata-action@v5
          with:
            images: ${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}
            tags: |
              type=raw,value=${{ env.REF_NAME }}
              type=raw,value=${{ env.REF_NAME }}-${{ env.SHORT_SHA }}
            labels: |
              quay.expires-after=14d

        - name: Set container metadata (for releases, 183d expiry)
          id: meta-release
          if: ${{ env.REF_NAME_SHORT != 'next' }}
          uses: docker/metadata-action@v5
          with:
            images: ${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}
            tags: |
              type=raw,value=${{ env.REF_NAME }}
              type=raw,value=${{ env.REF_NAME }}-${{ env.SHORT_SHA }}
              type=raw,value=${{ env.REF_NAME_SHORT }}
              type=raw,value=${{ env.REF_NAME_SHORT }}-${{ env.SHORT_SHA }}
            labels: |
              quay.expires-after=183d

        - name: Login to Docker Hub
          uses: docker/login-action@v3
          with:
            registry: ${{ env.REGISTRY }}
            username: ${{ secrets.QUAY_USERNAME }}
            password: ${{ secrets.QUAY_TOKEN }}

        - name: Create manifest list and push
          working-directory: /tmp/digests
          run: |
            docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
              $(printf '${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)

        - name: Inspect image (for :next builds)
          id: inspect-next
          if: ${{ env.REF_NAME_SHORT == 'next'}}
          run: |
            docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ steps.meta-next.outputs.version }}

        - name: Inspect image (for releases)
          id: inspect-release
          if: ${{ env.REF_NAME_SHORT != 'next'}}
          run: |
            docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ steps.meta-release.outputs.version }}
Workflow logs

Problem occurs in the merge step but I've attached all three logs in case you want them

2_merge.txt
1_Build Image (ubuntu-24.04-arm).txt
0_Build Image (ubuntu-24.04).txt

BuildKit logs

Additional info

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the merge job in the linked next-build-image.yaml workflow, especially the metadata-action step and the following docker buildx imagetools create command. Review the attached merge log and the generated DOCKER_METADATA_OUTPUT_JSON to trace how labels relate to the four tags. Done means every tag created by the merge step receives quay.expires-after=183d.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, github-actions, typescript
Domain
ci-cd, devops
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.