name: build multi-arch images

on:
  # Upstream podman 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 Podman build
    env:
      PODMAN_QUAY_REGISTRY: quay.io/podman
      CONTAINERS_QUAY_REGISTRY: quay.io/containers
      # list of architectures for build
      PLATFORMS: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64

    # build several images (upstream, testing, stable) in parallel
    strategy:
      matrix:
        # Builds are located under contrib/podmanimage/<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 Podman
        uses: docker/build-push-action@v2
        with:
          context: contrib/podmanimage/${{ matrix.source }}
          file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: localhost:5000/podman/${{ matrix.source }}

      # Simple verification that container works + grab version number
      - name: amd64 container sniff test
        id: sniff_test
        run: |
          VERSION_OUTPUT="$(docker run localhost:5000/podman/${{ matrix.source }} \
                            podman --storage-driver=vfs version)"
          echo "$VERSION_OUTPUT"
          VERSION=$(grep -Em1 '^Version: ' <<<"$VERSION_OUTPUT" | awk '{print $2}')
          test -n "$VERSION"
          echo "::set-output name=version::${VERSION}"

      # Generate image FQINs, labels, check whether to push
      - name: Generate image information
        id: image_info
        run: |
          VERSION='v${{ steps.sniff_test.outputs.version }}'
          # workaround vim syntax-hilighting bug: '
          if [[ "${{ matrix.source }}" == 'stable' ]]; then
            # quay.io/podman/stable:vX.X.X
            ALLTAGS=$(skopeo list-tags \
                      docker://$PODMAN_QUAY_REGISTRY/stable | \
                      jq -r '.Tags[]')
            PUSH="false"
            if ! fgrep -qx "$VERSION" <<<"$ALLTAGS"; then
                PUSH="true"
            fi

            FQIN="$PODMAN_QUAY_REGISTRY/stable:$VERSION"
            # Only push if version tag does not exist
            if [[ "$PUSH" == "true" ]]; then
              echo "Will push $FQIN"
              echo "::set-output name=podman_push::true"
              echo "::set-output name=podman_fqin::${FQIN}"
            else
              echo "Not pushing, $FQIN already exists."
            fi

            # quay.io/containers/podman:vX.X.X
            unset ALLTAGS
            ALLTAGS=$(skopeo list-tags \
                      docker://$CONTAINERS_QUAY_REGISTRY/podman | \
                      jq -r '.Tags[]')
            PUSH="false"
            if ! fgrep -qx "$VERSION" <<<"$ALLTAGS"; then
                PUSH="true"
            fi

            FQIN="$CONTAINERS_QUAY_REGISTRY/podman:$VERSION"
            # Only push if version tag does not exist
            if [[ "$PUSH" == "true" ]]; then
              echo "Will push $FQIN"
              echo "::set-output name=containers_push::true"
              echo "::set-output name=containers_fqin::$FQIN"
            else
              echo "Not pushing, $FQIN already exists."
            fi
          elif [[ "${{ matrix.source }}" == 'testing' ]]; then
            P_FQIN="$PODMAN_QUAY_REGISTRY/testing:master"
            echo "Will push $P_FQIN"
            echo "::set-output name=podman_fqin::${P_FQIN}"
            echo '::set-output name=podman_push::true'
          elif [[ "${{ matrix.source }}" == 'upstream' ]]; then
            P_FQIN="$PODMAN_QUAY_REGISTRY/upstream:master"
            C_FQIN="$CONTAINERS_QUAY_REGISTRY/podman:master"
            echo "Will push $P_FQIN and $C_FQIN"
            echo "::set-output name=podman_fqin::${P_FQIN}"
            echo "::set-output name=containers_fqin::${C_FQIN}"
            # Always push 'master' tag
            echo '::set-output name=podman_push::true'
            echo '::set-output name=containers_push::true'
          else
            echo "::error ::Unknown matrix value ${{ matrix.source }}"
            exit 1
          fi

      - 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.
          # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#multiline-strings
          cat << EOF | tee -a $GITHUB_ENV
          LABELS<<DELIMITER
          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)
          DELIMITER
          EOF

      # Separate steps to login and push for podman and containers quay
      # repositories are required, because 2 sets of credentials are used and `docker
      # login` as well as `podman login` do not support having 2 different
      # credential sets for 1 registry.
      # At the same time reuse of non-shell steps is not supported by Github Actions
      # via anchors or composite actions

      # Push to 'podman' Quay repo for stable, testing. and upstream
      - name: Login to 'podman' Quay registry
        uses: docker/login-action@v1
        if: ${{ steps.image_info.outputs.podman_push == 'true' }}
        with:
          registry: ${{ env.PODMAN_QUAY_REGISTRY }}
          # N/B: Secrets are not passed to workflows that are triggered
          #      by a pull request from a fork
          username: ${{ secrets.PODMAN_QUAY_USERNAME }}
          password: ${{ secrets.PODMAN_QUAY_PASSWORD }}

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

      # Push to 'containers' Quay repo only stable podman
      - name: Login to 'containers' Quay registry
        if: ${{ steps.image_info.outputs.containers_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 'containers' Quay
        if: ${{ steps.image_info.outputs.containers_push == 'true' }}
        uses: docker/build-push-action@v2
        with:
          cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }}
          cache-to: type=inline
          context: contrib/podmanimage/${{ matrix.source }}
          file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
          platforms: ${{ env.PLATFORMS }}
          push: true
          tags: ${{ steps.image_info.outputs.containers_fqin }}
          labels: |
            ${{ env.LABELS }}