# Copyright 2022 Google LLC
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

# A workflow to publish the official docker image.
name: Publish to Docker Hub

on:
  # Runs when called from another workflow.
  workflow_call:
    inputs:
      tag:
        required: true
        type: string
      latest:
        required: true
        type: boolean
    secrets:
      DOCKERHUB_CI_USERNAME:
        required: true
      DOCKERHUB_CI_TOKEN:
        required: true
      DOCKERHUB_PACKAGE_NAME:
        required: true

  # Runs when triggered manually by a maintainer.
  workflow_dispatch:
    inputs:
      tag:
        description: The tag to build from and to push to.
        required: true
        type: string
      latest:
        description: If true, push to the "latest" tag.
        required: true
        type: boolean

jobs:
  # Following multiarch GitHub Actions guide from
  # https://docs.docker.com/build/ci/github-actions/multi-platform/
  publish_docker_hub:
    strategy:
      fail-fast: false
      matrix:
        include:
          - docker_arch: amd64
            runs_on: ubuntu-latest

          - docker_arch: arm64
            runs_on: ubuntu-24.04-arm

    name: Build image for ${{ matrix.docker_arch }}
    runs-on: ${{ matrix.runs_on }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.tag }}
          submodules: recursive
          fetch-tags: true
          persist-credentials: false

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_CI_USERNAME }}
          password: ${{ secrets.DOCKERHUB_CI_TOKEN }}

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

      - name: Build and push by digest
        id: build
        uses: docker/build-push-action@v6
        with:
          # Important: use actions/checkout source, which has the right tags!
          # Without context: ., this action will try to fetch git source
          # itself, and it will be unable to determine the correct version
          # number.
          context: .
          platforms: linux/${{ matrix.docker_arch }}
          #FIXME: labels: ${{ steps.meta.outputs.labels }}
          tags: ${{ secrets.DOCKERHUB_PACKAGE_NAME }}
          outputs: type=image,push-by-digest=true,name-canonical=true,push=true

      - name: Export digest
        run: |
          mkdir -p ${{ runner.temp }}/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "${{ runner.temp }}/digests/${digest#sha256:}"

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

  # We do this as separate build and merge steps, rather than the one-step
  # docker/build-push-action with multiple platforms, because that one-step
  # method uses emulation that is _painfully_ slow.  We can build for arm64
  # natively in parallel with x64 in about 1/6 the time of using emulation to
  # do it on a single runner.  The cost is just this longer workflow.
  publish_docker_hub_multiarch:
    name: Publish to Docker Hub (multiarch)
    needs: publish_docker_hub
    runs-on: ubuntu-latest
    steps:
      - name: Download digests
        uses: actions/download-artifact@v4
        with:
          path: ${{ runner.temp }}/digests
          pattern: digests-*
          merge-multiple: true

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_CI_USERNAME }}
          password: ${{ secrets.DOCKERHUB_CI_TOKEN }}

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

      - name: Merge multiarch and push to tag
        working-directory: ${{ runner.temp }}/digests
        run: |
          # Get digests from file names in this folder
          formatted_digests=$(printf '${{ secrets.DOCKERHUB_PACKAGE_NAME }}@sha256:%s ' *)
          docker buildx imagetools create \
              --tag ${{ secrets.DOCKERHUB_PACKAGE_NAME }}:${{ inputs.tag }} \
              $formatted_digests

      - name: Inspect image
        run: |
          docker buildx imagetools inspect ${{ secrets.DOCKERHUB_PACKAGE_NAME }}:${{ inputs.tag }}

      - name: Tag multiarch as "latest"
        if: ${{ inputs.latest }}
        run: |
          # Push out an alias to the tagged multiarch version we already pushed.
          docker buildx imagetools create \
              --tag ${{ secrets.DOCKERHUB_PACKAGE_NAME }}:latest \
              ${{ secrets.DOCKERHUB_PACKAGE_NAME }}:${{ inputs.tag }}
