name: Build Docker images

on:
  release:
    types: [published]
  workflow_dispatch:

permissions:
  contents: read

env:
  DOCKERHUB_IMAGE: docker.io/3proxy/3proxy
  GHCR_IMAGE: ghcr.io/3proxy/3proxy

jobs:
  build:
    name: ${{ matrix.image }} ${{ matrix.platform }}
    permissions:
      contents: read
      packages: write
    runs-on: ${{ matrix.runner }}
    strategy:
      fail-fast: false
      matrix:
        image: [full, busybox, minimal]
        platform: [linux/amd64, linux/arm64, linux/arm/v7]
        include:
          - platform: linux/amd64
            runner: ubuntu-latest
          - platform: linux/arm64
            runner: ubuntu-24.04-arm
          - platform: linux/arm/v7
            runner: ubuntu-24.04-arm
    steps:
      - name: Checkout
        uses: actions/checkout@v7

      - name: Platform name
        id: platform
        run: echo "pair=$(echo '${{ matrix.platform }}' | tr / -)" >> "$GITHUB_OUTPUT"

      - name: Set up QEMU
        if: matrix.platform == 'linux/arm/v7'
        uses: docker/setup-qemu-action@v4

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

      - name: Login to GHCR
        uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push by digest
        id: build
        uses: docker/build-push-action@v7
        with:
          context: .
          file: Dockerfile.${{ matrix.image }}
          platforms: ${{ matrix.platform }}
          provenance: false
          sbom: false
          outputs: type=image,name=${{ env.GHCR_IMAGE }},push-by-digest=true,name-canonical=true,push=true

      - name: Export digest
        env:
          DIGEST: ${{ steps.build.outputs.digest }}
        run: |
          mkdir -p /tmp/digests
          touch "/tmp/digests/${DIGEST#sha256:}"

      - name: Upload digest
        uses: actions/upload-artifact@v7
        with:
          name: digests-${{ matrix.image }}-${{ steps.platform.outputs.pair }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  publish:
    name: Publish ${{ matrix.image }}
    permissions:
      contents: read
      packages: write
      id-token: write
      attestations: write
    runs-on: ubuntu-latest
    needs: build
    strategy:
      fail-fast: false
      matrix:
        include:
          - image: full
            suffix: ''
            floating: latest
          - image: busybox
            suffix: .busybox
            floating: busybox
          - image: minimal
            suffix: .minimal
            floating: minimal
    steps:
      - name: Download digests
        uses: actions/download-artifact@v7
        with:
          path: /tmp/digests
          pattern: digests-${{ matrix.image }}-*
          merge-multiple: true

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

      - name: Install cosign
        uses: sigstore/cosign-installer@v3
        with:
          cosign-release: v2.4.3

      - name: Login to Docker Hub
        uses: docker/login-action@v4
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GHCR
        uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Determine tags
        id: tags
        env:
          RELEASE_TAG: ${{ github.event.release.tag_name }}
          SUFFIX: ${{ matrix.suffix }}
          FLOATING: ${{ matrix.floating }}
        run: |
          if [[ "$RELEASE_TAG" != "" ]]; then
            RELEASE="${RELEASE_TAG#v}"
            echo "versioned=${RELEASE}${SUFFIX}" >> "$GITHUB_OUTPUT"
            echo "moving=${FLOATING}" >> "$GITHUB_OUTPUT"
          else
            DATETIME=$(date +%d%m%y%H%M%S)
            BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | tr "/" "-")
            echo "versioned=${DATETIME}-${BRANCH}${SUFFIX}" >> "$GITHUB_OUTPUT"
            echo "moving=${BRANCH}${SUFFIX}" >> "$GITHUB_OUTPUT"
          fi

      - name: Create manifest list and push
        working-directory: /tmp/digests
        env:
          VERSIONED: ${{ steps.tags.outputs.versioned }}
          MOVING: ${{ steps.tags.outputs.moving }}
        run: |
          docker buildx imagetools create \
            -t "${DOCKERHUB_IMAGE}:${VERSIONED}" \
            -t "${DOCKERHUB_IMAGE}:${MOVING}" \
            -t "${GHCR_IMAGE}:${VERSIONED}" \
            -t "${GHCR_IMAGE}:${MOVING}" \
            $(printf "${GHCR_IMAGE}@sha256:%s " *)

      - name: Get pushed digest
        id: digest
        env:
          VERSIONED: ${{ steps.tags.outputs.versioned }}
        run: |
          DIGEST=$(docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${VERSIONED}" \
            --format '{{json .Manifest}}' | jq -r .digest)
          echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"

      - name: Attest Docker Hub image
        uses: actions/attest-build-provenance@v2
        with:
          subject-name: ${{ env.DOCKERHUB_IMAGE }}
          subject-digest: ${{ steps.digest.outputs.digest }}
          push-to-registry: false

      - name: Attest GHCR image
        uses: actions/attest-build-provenance@v2
        with:
          subject-name: ${{ env.GHCR_IMAGE }}
          subject-digest: ${{ steps.digest.outputs.digest }}
          push-to-registry: false

      - name: Sign images
        env:
          DIGEST: ${{ steps.digest.outputs.digest }}
        run: |
          cosign sign --yes "${DOCKERHUB_IMAGE}@${DIGEST}"
          cosign sign --yes "${GHCR_IMAGE}@${DIGEST}"

