# Based on https://docs.docker.com/build/ci/github-actions/multi-platform/#with-bake (https://github.com/docker/build-push-action/issues/671#issuecomment-1609106171)
# with example from here https://github.com/crazy-max/docker-linguist/blob/master/.github/workflows/build.yml that uses caching
#
# may have to use this to enable pushing to multiple registries? https://github.com/docker/build-push-action/discussions/1067#discussioncomment-8677682

name: build

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

on:
  push:
    branches:
      - 'master'
    tags:
      - '*.*.*'
    paths-ignore:
      - 'README.md'
      - '.github/**'
      - 'flatpak/**'

env:
  DOCKERHUB_SLUG: foxxmd/multi-scrobbler
  GHCR_SLUG: ghcr.io/foxxmd/multi-scrobbler

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.platforms.outputs.matrix }}
    steps:
      -
        name: Checkout
        uses: actions/checkout@v4

      - name: Set short git commit SHA
        id: appvars
        # https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7
        # short sha available under env.COMMIT_SHORT_SHA
        run: |
          calculatedSha=$(git rev-parse --short HEAD)
          branchName=$(git rev-parse --abbrev-ref HEAD)
          echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
          echo "COMMIT_BRANCH=$branchName" >> $GITHUB_ENV

      - name: Get App Version
        id: appversion
        env:
          # use release instead of tags once version is correctly parsed
          #APP_VERSION: ${{ github.event.release.tag_name }}

          # https://github.com/actions/runner/issues/409#issuecomment-752775072
          # https://stackoverflow.com/a/69919067/1469797
          APP_VERSION: ${{ contains(github.ref, 'refs/tags/') && github.ref_name || format('{0}-{1}', env.COMMIT_BRANCH, env.COMMIT_SHORT_SHA ) }}
        run: |
          echo appversion=$APP_VERSION >>${GITHUB_OUTPUT}

      -
        name: Create matrix
        id: platforms
        run: |
          echo "matrix=$(docker buildx bake --file ./docker-bake.hcl image-all --print | jq -cr '.target."image-all".platforms')" >>${GITHUB_OUTPUT}
      -
        name: Show matrix
        run: |
          echo ${{ steps.platforms.outputs.matrix }}
      -
        name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: |
            ${{ env.DOCKERHUB_SLUG }}
            ${{ env.GHCR_SLUG }}
          tags: |
            type=edge

            # maybe re-enable branch-named tags in the futures
            #type=ref,event=branch,enable=${{ !endsWith(github.ref, 'master') }}
            
            # tag non-prelease as latest -- has a higher priority than regular tag so it shows first in registries
            type=match,pattern=\d.\d.\d$,priority=901
            
            # tag all semver (include pre-release)
            type=semver,pattern={{version}}
          labels: |
            org.opencontainers.image.title=Multi-Scrobbler
            org.opencontainers.image.description=Scrobble from many sources to many clients
            org.opencontainers.image.vendor=FoxxMD
      -
        name: Rename meta bake definition file
        run: |
          mv "${{ steps.meta.outputs.bake-file }}" "/tmp/bake-meta.json"
      -
        name: Upload meta bake definition
        uses: actions/upload-artifact@v3
        with:
          name: bake-meta
          path: /tmp/bake-meta.json
          if-no-files-found: error
          retention-days: 1

  build:
    runs-on: ubuntu-latest
    needs:
      - prepare
    strategy:
      fail-fast: false
      matrix:
        platform: ${{ fromJson(needs.prepare.outputs.matrix) }}
    steps:
      -
        name: Prepare
        run: |
          platform=${{ matrix.platform }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
      -
        name: Checkout
        uses: actions/checkout@v4
      -
        name: Test App Version Transfer
        run: |
          echo "App Version in Build ${{ needs.prepare.appversion.outputs.appversion }}"
      -
        name: Download meta bake definition
        uses: actions/download-artifact@v3
        with:
          name: bake-meta
          path: /tmp
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
        with:
          buildkitd-flags: "--debug"
      -
        name: Login to DockerHub
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      -
        name: Login to GHCR
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      -
        name: Build
        id: bake
        uses: docker/bake-action@v5
        with:
          files: |
            ./.github/act/docker-bake.hcl
            /tmp/bake-meta.json
          targets: image
          set: |
            *.args.APP_BUILD_VERSION=${{ needs.prepare.appversion.outputs.appversion }}
            *.tags=
            *.platform=${{ matrix.platform }}
            *.cache-from=type=gha,scope=build-${{ env.PLATFORM_PAIR }}
            *.cache-to=type=gha,scope=build-${{ env.PLATFORM_PAIR }}
            *.output=type=image,"name=${{ env.DOCKERHUB_SLUG }},${{ env.GHCR_SLUG }}",push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
      -
        name: Export digest
        run: |
          mkdir -p /tmp/digests
          digest="${{ fromJSON(steps.bake.outputs.metadata).image['containerimage.digest'] }}"
          touch "/tmp/digests/${digest#sha256:}"
      -
        name: Upload digest
        uses: actions/upload-artifact@v3
        with:
          name: digests-${{ env.PLATFORM_PAIR }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  merge:
    runs-on: ubuntu-latest
    if: github.event_name != 'pull_request'
    needs:
      - build
    steps:
      -
        name: Download meta bake definition
        uses: actions/download-artifact@v3
        with:
          name: bake-meta
          path: /tmp
      -
        name: Download digests
        uses: actions/download-artifact@v3
        with:
          path: /tmp/digests
          pattern: digests-*
          merge-multiple: true
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      -
        name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      -
        name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      -
        name: Create manifest list and push
        working-directory: /tmp/digests
        run: |
          docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("${{ env.DOCKERHUB_SLUG }}")) | "-t " + .) | join(" ")' /tmp/bake-meta.json) \
            $(printf '${{ env.DOCKERHUB_SLUG }}@sha256:%s ' *)
          docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map(select(startswith("${{ env.GHCR_SLUG }}")) | "-t " + .) | join(" ")' /tmp/bake-meta.json) \
            $(printf '${{ env.GHCR_SLUG }}@sha256:%s ' *)
      -
        name: Inspect image
        run: |
          tag=$(jq -r '.target."docker-metadata-action".args.DOCKER_META_VERSION' /tmp/bake-meta.json)
          docker buildx imagetools inspect ${{ env.DOCKERHUB_SLUG }}:${tag}
          docker buildx imagetools inspect ${{ env.GHCR_SLUG }}:${tag}
