name: Docker image Build and Push

on:
  workflow_call:
    inputs:
      image:
        description: 'Docker image name'
        required: true
        type: string
      dockerfile:
        description: 'Path to the Dockerfile'
        required: true
        type: string
      artifact_prefix:
        description: 'Prefix for the artifact name'
        required: true
        type: string
      commit_sha:
        description: 'Commit SHA to checkout'
        required: true
        type: string
      tags:
        description: 'Space-separated list of tags to apply to the image (e.g., "latest v2.0.0")'
        required: true
        type: string
      push:
        description: 'Push image to ghcr.io'
        required: false
        type: boolean
        default: true
      platforms:
        description: 'A JSON array of platforms to build for.'
        required: false
        type: string
        default: '["linux/amd64", "linux/arm64"]'
      version:
        description: 'DD_VERSION to pass as build argument to Dockerfile'
        required: false
        type: string
        default: ''

jobs:
  build-images:
    runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || 'ubuntu-24.04-arm' }}
    strategy:
      matrix:
        platform: ${{ fromJSON(inputs.platforms) }}
    steps:
      - name: Prepare
        run: |
          platform=${{ matrix.platform }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV"

      - name: Checkout
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
        with:
          ref: ${{ inputs.commit_sha }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Login to Docker
        shell: bash
        # It's not possible to use a `dd-octo-sts` token here because GitHub Packages
        # only supports PATs for authentication.
        # https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-to-the-container-registry
        run: docker login -u publisher -p ${{ secrets.GITHUB_TOKEN }} ghcr.io

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
        with:
          images: ${{ inputs.image }}

      - name: Build and push by digest
        id: build
        if: inputs.push == true
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: ${{ inputs.dockerfile }}
          platforms: ${{ matrix.platform }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            DD_VERSION=${{ inputs.version }}
            COMMIT_SHA=${{ inputs.commit_sha }}
          # This builds a Docker image and uploads it using a unique fingerprint, without a name
          outputs: type=image,name=${{ inputs.image }},push-by-digest=true,name-canonical=true,push=true

      - name: Generate tags
        if: inputs.push == false
        id: tags
        run: |
          TAGS=""
          # shellcheck disable=SC2086
          for tag in ${{ inputs.tags }}; do
            if [ -n "$tag" ]; then
              TAGS="$TAGS,${{ inputs.image }}:$tag"
            fi
          done
          echo "list=${TAGS:1}" >> "$GITHUB_OUTPUT"

      - name: Build and export
        id: build-export
        if: inputs.push == false
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: ${{ inputs.dockerfile }}
          platforms: ${{ matrix.platform }}
          labels: ${{ steps.meta.outputs.labels }}
          tags: ${{ steps.tags.outputs.list }}
          build-args: |
            DD_VERSION=${{ inputs.version }}
            COMMIT_SHA=${{ inputs.commit_sha }}
          outputs: type=docker,dest=/tmp/${{ inputs.artifact_prefix }}-${{ env.PLATFORM_PAIR }}.tar
          push: false

      - name: Export digest
        if: inputs.push == true
        run: |
          mkdir -p /tmp/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "/tmp/digests/${digest#sha256:}"

      - name: Upload digest
        if: inputs.push == true
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
        with:
          name: digests-${{ inputs.artifact_prefix }}-${{ env.PLATFORM_PAIR }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

      - name: Upload image artifact
        if: inputs.push == false
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
        with:
          name: ${{ inputs.artifact_prefix }}-${{ env.PLATFORM_PAIR }}
          path: /tmp/${{ inputs.artifact_prefix }}-${{ env.PLATFORM_PAIR }}.tar
          if-no-files-found: error
          retention-days: 1

  publish-images:
    if: inputs.push == true
    runs-on: ubuntu-latest
    needs: [build-images]
    steps:
      - name: Download digests
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
        with:
          path: /tmp/digests
          pattern: digests-${{ inputs.artifact_prefix }}-*
          merge-multiple: true

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Login to Docker
        shell: bash
        run: docker login -u publisher -p ${{ secrets.GITHUB_TOKEN }} ghcr.io

      - name: Create manifest list and push
        working-directory: /tmp/digests
        run: |
          TAG_FLAGS=""
          # shellcheck disable=SC2086
          for tag in ${{ inputs.tags }}; do
            if [ -n "$tag" ]; then
              TAG_FLAGS="$TAG_FLAGS -t ${{ inputs.image }}:$tag"
            fi
          done
          # shellcheck disable=SC2046,SC2086
          docker buildx imagetools create $TAG_FLAGS \
            $(printf '${{ inputs.image }}@sha256:%s ' *)
