name: Reusable Container Build Workflow

on:
  workflow_call:
    inputs:
      # Which suffix to look for with the Dockerfile. Can be dev or prod
      build_type:
        required: true
        type: string
      # For example 'alpha', for pre-release or weekly builds
      tag:
        required: false
        type: string
      # Is this a final release? Then we set this to true, so the 'latest' tag is updated
      tag_latest:
        required: false
        type: boolean
      # The container image dragonflydb/dragonfly
      image:
        required: true
        type: string
      # ghcr.io / hub.docker.com / quay.io / you name it
      registry:
        required: true
        type: string
      # Username used to login to the registry
      registry_username:
        required: true
        type: string
      # Do we have to fetch release assets? Then set this to true.
      # Not required for build_type == dev, as they entirely build from source
      # But for build_type == prod, as they're based on the release assets
      fetch_release:
        required: false
        type: boolean
      # Which version are we fetching? Should be identical to the release version.
      # For example v0.12.0
      release_version:
        required: false
        type: string
    secrets:
      # Password used to login to the registry
      registry_password:
        required: true
      # Github Personal Access Token used to fetch assets from a release
      GH_TOKEN:
        required: false

jobs:
  container-build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - flavor: alpine
            dockerfile: tools/packaging/Dockerfile.alpine
            tag_main: false
          - flavor: ubuntu
            dockerfile: tools/packaging/Dockerfile.ubuntu
            tag_main: true
    steps:
      - name: checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 1
          submodules: true

      - if: inputs.fetch_release
        name: Fetch release asset
        uses: dsaltares/fetch-gh-release-asset@1.1.0
        with:
          version: "tags/${{ inputs.release_version }}"
          regex: true
          file: "dragonfly-.*\\.tar\\.gz"
          target: 'releases/'
          token: ${{ secrets.GH_TOKEN }}

      - if: inputs.fetch_release
        name: Extract artifacts
        run: |
          echo "Event prerelease ${{ github.event.release.prerelease }}"
          echo "Input prerelease ${{ github.event.inputs.PRERELEASE }}"
          ls -l
          ls -l releases
          for f in releases/*.tar.gz; do tar xvfz $f -C releases; done
          rm releases/*.tar.gz

      - name: Set up QEMU
        id: qemu
        uses: docker/setup-qemu-action@v2
        with:
          platforms: arm64,amd64

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ inputs.registry }}
          username: ${{ inputs.registry_username }}
          password: ${{ secrets.registry_password }}

      - name: Docker meta
        id: metadata
        uses: docker/metadata-action@v4
        with:
          images: |
            ${{ inputs.image }}
          tags: |
            # will set tag 'latest' for ubuntu build on production push
            # inputs.tag_latest will be true on when triggered by docker-release.yml
            # matrix.tag_main will only be true for ubuntu flavor
            type=raw,value=latest,enable=${{ matrix.tag_main && inputs.tag_latest }}

            # set a tag like 'alpine' or 'ubuntu', if we're setting 'latest' during this build as well
            type=raw,value=${{ matrix.flavor }},enable=${{ inputs.tag_latest }}

            # will set tag like 'alpha' for ubuntu build, if inputs.tag is not empty
            # but will set the non-flavored tag only, if matrix.tag_main is true
            type=raw,value=${{ inputs.tag }},enable=${{ inputs.tag != 'false' && matrix.tag_main }}

            # will set tag like 'alpha-(ubuntu|alpine)', if inputs.tag is not empty
            type=raw,value=${{ inputs.tag }}-${{ matrix.flavor }},enable=${{ inputs.tag != 'false' }}

            # will set tag like 'v0.12.0' for ubuntu build, if inputs.release_version is not empty
            # but will set the non-flavored tag only, if matrix.tag_main is true
            type=raw,value=${{ inputs.release_version }},enable=${{ matrix.tag_main && inputs.release_version != '' }}

            # will set tag like 'v0.12.0-(ubuntu|alpine)', if inputs.release_version is not empty
            type=raw,value=${{ inputs.release_version }}-${{ matrix.flavor }},enable=${{ inputs.release_version != '' }}

      #  build is broken based on platforms as load: true is not supported with multi-platform builds
      - if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
        name: Build release image for amd64
        uses: docker/build-push-action@v3
        with:
          context: .
          platforms: linux/amd64
          build-args: |
            QEMU_CPU=max,pauth-impdef=on
          push: false
          tags: |
            ${{ steps.metadata.outputs.tags }}
          labels: ${{ steps.metadata.outputs.labels }}
          file: ${{ matrix.dockerfile }}-${{ inputs.build_type }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          # only load AMD64 image for testing
          load: true

      - if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
        name: Build release image for arm64
        uses: docker/build-push-action@v3
        with:
            context: .
            platforms: linux/arm64
            build-args: |
              QEMU_CPU=max,pauth-impdef=on
            push: false
            tags: |
              ${{ steps.metadata.outputs.tags }}
            labels: ${{ steps.metadata.outputs.labels }}
            file: ${{ matrix.dockerfile }}-${{ inputs.build_type }}
            cache-from: type=gha
            cache-to: type=gha,mode=max

      - if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
        name: Test Docker run
        run: |
          # docker run with port-forwarding
          # install redis-tools
          sudo apt-get install redis-tools -y
          tag="${{ steps.metadata.outputs.tags }}"
          # use the first tag if multiple tags are provided
          if [[ $(echo "${tag}" | wc -l) -gt 1 ]]; then
            echo "Multiple tags provided, using the first one"
            tag=$(echo "${tag}" | head -n 1)
          fi
          echo "Testing ${tag}"
          docker run -d -p 6379:6379 ${tag}
          sleep 5
          # ping with redis-cli and expect PONG
          if [[ $(redis-cli -h localhost ping) != "PONG" ]]; then
            echo "Redis ping failed"
            exit 1
          else
            echo "Redis ping succeeded"
            exit 0
          fi

      - if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
        name: Push release image
        uses: docker/build-push-action@v3
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          build-args: |
            QEMU_CPU=max,pauth-impdef=on
          tags: |
            ${{ steps.metadata.outputs.tags }}
          labels: ${{ steps.metadata.outputs.labels }}
          file: ${{ matrix.dockerfile }}-${{ inputs.build_type }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
