name: Docker

on:
  workflow_dispatch:
  push:
    branches: [main]
  pull_request:
  release:
    types: [published]

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

permissions: {}

jobs:
  pre-job:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      should_run_server: ${{ steps.found_paths.outputs.server == 'true' || steps.should_force.outputs.should_force == 'true' }}
      should_run_ml: ${{ steps.found_paths.outputs.machine-learning == 'true' || steps.should_force.outputs.should_force == 'true' }}
    steps:
      - name: Checkout code
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false
      - id: found_paths
        uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
        with:
          filters: |
            server:
              - 'server/**'
              - 'openapi/**'
              - 'web/**'
              - 'i18n/**'
            machine-learning:
              - 'machine-learning/**'
            workflow:
              - '.github/workflows/docker.yml'
              - '.github/workflows/multi-runner-build.yml'
              - '.github/actions/image-build'

      - name: Check if we should force jobs to run
        id: should_force
        run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' }}" >> "$GITHUB_OUTPUT"

  retag_ml:
    name: Re-Tag ML
    needs: pre-job
    permissions:
      contents: read
      packages: write
    if: ${{ needs.pre-job.outputs.should_run_ml == 'false' && !github.event.pull_request.head.repo.fork }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        suffix: ['', '-cuda', '-rocm', '-openvino', '-armnn', '-rknn']
    steps:
      - name: Login to GitHub Container Registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Re-tag image
        env:
          REGISTRY_NAME: 'ghcr.io'
          REPOSITORY: ${{ github.repository_owner }}/immich-machine-learning
          TAG_OLD: main${{ matrix.suffix }}
          TAG_PR: ${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }}
          TAG_COMMIT: commit-${{ github.event_name != 'pull_request' && github.sha || github.event.pull_request.head.sha }}${{ matrix.suffix }}
        run: |
          docker buildx imagetools create -t "${REGISTRY_NAME}/${REPOSITORY}:${TAG_PR}" "${REGISTRY_NAME}/${REPOSITORY}:${TAG_OLD}"
          docker buildx imagetools create -t "${REGISTRY_NAME}/${REPOSITORY}:${TAG_COMMIT}" "${REGISTRY_NAME}/${REPOSITORY}:${TAG_OLD}"

  retag_server:
    name: Re-Tag Server
    needs: pre-job
    permissions:
      contents: read
      packages: write
    if: ${{ needs.pre-job.outputs.should_run_server == 'false' && !github.event.pull_request.head.repo.fork }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        suffix: ['']
    steps:
      - name: Login to GitHub Container Registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Re-tag image
        env:
          REGISTRY_NAME: 'ghcr.io'
          REPOSITORY: ${{ github.repository_owner }}/immich-server
          TAG_OLD: main${{ matrix.suffix }}
          TAG_PR: ${{ github.event.number == 0 && github.ref_name || format('pr-{0}', github.event.number) }}${{ matrix.suffix }}
          TAG_COMMIT: commit-${{ github.event_name != 'pull_request' && github.sha || github.event.pull_request.head.sha }}${{ matrix.suffix }}
        run: |
          docker buildx imagetools create -t "${REGISTRY_NAME}/${REPOSITORY}:${TAG_PR}" "${REGISTRY_NAME}/${REPOSITORY}:${TAG_OLD}"
          docker buildx imagetools create -t "${REGISTRY_NAME}/${REPOSITORY}:${TAG_COMMIT}" "${REGISTRY_NAME}/${REPOSITORY}:${TAG_OLD}"

  machine-learning:
    name: Build and Push ML
    needs: pre-job
    if: ${{ needs.pre-job.outputs.should_run_ml == 'true' }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - device: cpu
            tag-suffix: ''
          - device: cuda
            tag-suffix: '-cuda'
            platforms: linux/amd64
          - device: openvino
            tag-suffix: '-openvino'
            platforms: linux/amd64
          - device: armnn
            tag-suffix: '-armnn'
            platforms: linux/arm64
          - device: rknn
            tag-suffix: '-rknn'
            platforms: linux/arm64
          - device: rocm
            tag-suffix: '-rocm'
            platforms: linux/amd64
            runner-mapping: '{"linux/amd64": "mich"}'
    uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@094bfb927b8cd75b343abaac27b3241be0fccfe9 # multi-runner-build-workflow-0.1.0
    permissions:
      contents: read
      actions: read
      packages: write
    secrets:
      DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
      DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
    with:
      image: immich-machine-learning
      context: machine-learning
      dockerfile: machine-learning/Dockerfile
      platforms: ${{ matrix.platforms }}
      runner-mapping: ${{ matrix.runner-mapping }}
      tag-suffix: ${{ matrix.tag-suffix }}
      dockerhub-push: ${{ github.event_name == 'release' }}
      build-args: |
        DEVICE=${{ matrix.device }}

  server:
    name: Build and Push Server
    needs: pre-job
    if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
    uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@094bfb927b8cd75b343abaac27b3241be0fccfe9 # multi-runner-build-workflow-0.1.0
    permissions:
      contents: read
      actions: read
      packages: write
    secrets:
      DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
      DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
    with:
      image: immich-server
      context: .
      dockerfile: server/Dockerfile
      dockerhub-push: ${{ github.event_name == 'release' }}
      build-args: |
        DEVICE=cpu

  success-check-server:
    name: Docker Build & Push Server Success
    needs: [server, retag_server]
    permissions: {}
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Any jobs failed?
        if: ${{ contains(needs.*.result, 'failure') }}
        run: exit 1
      - name: All jobs passed or skipped
        if: ${{ !(contains(needs.*.result, 'failure')) }}
        # zizmor: ignore[template-injection]
        run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"

  success-check-ml:
    name: Docker Build & Push ML Success
    needs: [machine-learning, retag_ml]
    permissions: {}
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Any jobs failed?
        if: ${{ contains(needs.*.result, 'failure') }}
        run: exit 1
      - name: All jobs passed or skipped
        if: ${{ !(contains(needs.*.result, 'failure')) }}
        # zizmor: ignore[template-injection]
        run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
