---

# Please see contrib/<reponame>image/README.md for details on the intentions
# of this workflow.
#
# BIG FAT WARNING:  This workflow is duplicated across containers/skopeo,
#                   containers/buildah, and containers/podman.  ANY AND
#                   ALL CHANGES MADE HERE MUST BE MANUALLY DUPLICATED
#                   TO THE OTHER REPOS.

name: build multi-arch images

on:
  # Upstream tends to be very active, with many merges per day.
  # Only run this daily via cron schedule, or manually, not by branch push.
  schedule:
    - cron:  '0 8 * * *'
  # allows to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  multi:
    name: multi-arch image build
    env:
      REPONAME: skopeo  # No easy way to parse this out of $GITHUB_REPOSITORY
      # Server/namespace value used to format FQIN
      REPONAME_QUAY_REGISTRY: quay.io/skopeo
      CONTAINERS_QUAY_REGISTRY: quay.io/containers
      # list of architectures for build
      PLATFORMS: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64
      # Command to execute in container to obtain project version number
      VERSION_CMD: "--version"  # skopeo is the entrypoint

    # build several images (upstream, testing, stable) in parallel
    strategy:
      # By default, failure of one matrix item cancels all others
      fail-fast: false
      matrix:
        # Builds are located under contrib/<reponame>image/<source> directory
        source:
          - upstream
          - testing
          - stable
    runs-on: ubuntu-latest
    # internal registry caches build for inspection before push
    services:
      registry:
        image: quay.io/libpod/registry:2
        ports:
          - 5000:5000
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
        with:
          driver-opts: network=host
          install: true

      - name: Build and locally push image
        uses: docker/build-push-action@v2
        with:
          context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
          file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}

      # Simple verification that stable images work, and
      # also grab version number use in forming the FQIN.
      - name: amd64 container sniff test
        if: matrix.source == 'stable'
        id: sniff_test
        run: |
          podman pull --tls-verify=false \
                            localhost:5000/$REPONAME/${{ matrix.source }}
          VERSION_OUTPUT=$(podman run \
                           localhost:5000/$REPONAME/${{ matrix.source }} \
                           $VERSION_CMD)
          echo "$VERSION_OUTPUT"
          VERSION=$(awk -r -e "/^${REPONAME} version /"'{print $3}' <<<"$VERSION_OUTPUT")
          test -n "$VERSION"
          echo "::set-output name=version::$VERSION"

      - name: Generate image FQIN(s) to push
        id: reponame_reg
        run: |
          if [[ "${{ matrix.source }}" == 'stable' ]]; then
            # The command version in image just built
            VERSION='v${{ steps.sniff_test.outputs.version }}'
            # workaround vim syntax-highlight bug: '
            # Push both new|updated version-tag and latest-tag FQINs
            FQIN="$REPONAME_QUAY_REGISTRY/stable:$VERSION,$REPONAME_QUAY_REGISTRY/stable:latest"
          elif [[ "${{ matrix.source }}" == 'testing' ]]; then
            # Assume some contents changed, always push latest testing.
            FQIN="$REPONAME_QUAY_REGISTRY/testing:latest"
          elif [[ "${{ matrix.source }}" == 'upstream' ]]; then
            # Assume some contents changed, always push latest upstream.
            FQIN="$REPONAME_QUAY_REGISTRY/upstream:latest"
          else
            echo "::error::Unknown matrix item '${{ matrix.source }}'"
            exit 1
          fi
          echo "::warning::Pushing $FQIN"
          echo "::set-output name=fqin::${FQIN}"
          echo '::set-output name=push::true'

      # This is substantially similar to the above logic,
      # but only handles $CONTAINERS_QUAY_REGISTRY for
      # the stable "latest" and named-version tagged images.
      - name: Generate containers reg. image FQIN(s)
        if: matrix.source == 'stable'
        id: containers_reg
        run: |
          VERSION='v${{ steps.sniff_test.outputs.version }}'
          # workaround vim syntax-highlight bug: '
          # Push both new|updated version-tag and latest-tag FQINs
          FQIN="$CONTAINERS_QUAY_REGISTRY/$REPONAME:$VERSION,$CONTAINERS_QUAY_REGISTRY/$REPONAME:latest"
          echo "::warning::Pushing $FQIN"
          echo "::set-output name=fqin::${FQIN}"
          echo '::set-output name=push::true'

      - name: Define LABELS multi-line env. var. value
        run: |
          # This is a really hacky/strange workflow idiom, required
          # for setting multi-line $LABELS value for consumption in
          # a future step.  There is literally no cleaner way to do this :<
          # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#multiline-strings
          function set_labels() {
            echo 'LABELS<<DELIMITER' >> "$GITHUB_ENV"
            for line; do
                echo "$line" | tee -a "$GITHUB_ENV"
            done
            echo "DELIMITER" >> "$GITHUB_ENV"
          }

          declare -a lines
          lines=(\
            "org.opencontainers.image.source=https://github.com/${GITHUB_REPOSITORY}.git"
            "org.opencontainers.image.revision=${GITHUB_SHA}"
            "org.opencontainers.image.created=$(date -u --iso-8601=seconds)"
          )

          # Only the 'stable' matrix source obtains $VERSION
          if [[ "${{ matrix.source }}" == "stable" ]]; then
            lines+=(\
              "org.opencontainers.image.version=${{ steps.sniff_test.outputs.version }}"
            )
          fi

          set_labels "${lines[@]}"

      # Separate steps to login and push for $REPONAME_QUAY_REGISTRY and
      # $CONTAINERS_QUAY_REGISTRY are required, because 2 sets of credentials
      # are used and namespaced within the registry.  At the same time, reuse
      # of non-shell steps is not supported by Github Actions nor are YAML
      # anchors/aliases, nor composite actions.

      # Push to $REPONAME_QUAY_REGISTRY for stable, testing. and upstream
      - name: Login to ${{ env.REPONAME_QUAY_REGISTRY }}
        uses: docker/login-action@v1
        if: steps.reponame_reg.outputs.push == 'true'
        with:
          registry: ${{ env.REPONAME_QUAY_REGISTRY }}
          # N/B: Secrets are not passed to workflows that are triggered
          #      by a pull request from a fork
          username: ${{ secrets.REPONAME_QUAY_USERNAME }}
          password: ${{ secrets.REPONAME_QUAY_PASSWORD }}

      - name: Push images to ${{ steps.reponame_reg.outputs.fqin }}
        uses: docker/build-push-action@v2
        if: steps.reponame_reg.outputs.push == 'true'
        with:
          cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
          cache-to: type=inline
          context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
          file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: ${{ steps.reponame_reg.outputs.fqin }}
          labels: |
            ${{ env.LABELS }}

      # Push to $CONTAINERS_QUAY_REGISTRY only stable
      - name: Login to ${{ env.CONTAINERS_QUAY_REGISTRY }}
        if: steps.containers_reg.outputs.push == 'true'
        uses: docker/login-action@v1
        with:
          registry: ${{ env.CONTAINERS_QUAY_REGISTRY}}
          username: ${{ secrets.CONTAINERS_QUAY_USERNAME }}
          password: ${{ secrets.CONTAINERS_QUAY_PASSWORD }}

      - name: Push images to ${{ steps.containers_reg.outputs.fqin }}
        if: steps.containers_reg.outputs.push == 'true'
        uses: docker/build-push-action@v2
        with:
          cache-from: type=registry,ref=localhost:5000/${{ env.REPONAME }}/${{ matrix.source }}
          cache-to: type=inline
          context: contrib/${{ env.REPONAME }}image/${{ matrix.source }}
          file: ./contrib/${{ env.REPONAME }}image/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: ${{ steps.containers_reg.outputs.fqin }}
          labels: |
            ${{ env.LABELS }}
