name: Build and Push Docker Images

permissions:
  pull-requests: write
  contents: read

on:
  push:
    branches:
      - main
    tags:
      - 'v*.*.*'
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.22
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Cache npm dependencies
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-
      - name: Install frontend dependencies
        run: npm install
        working-directory: web-app
      - name: Build frontend
        run: npm run build && cp -r dist/ ../dist/
        working-directory: web-app
      - name: Run frontend tests
        run: npm test
        working-directory: web-app
      - name: Install mupdf
        run: sudo apt-get install -y mupdf
      - name: Set library path
        run: echo "/usr/lib" | sudo tee -a /etc/ld.so.conf.d/mupdf.conf && sudo ldconfig
      - name: Install dependencies
        run: go mod download
      - name: Run Go tests
        run: go test ./...
  build-amd64:
    runs-on: ubuntu-latest
    needs: test
    outputs:
      digest: ${{ steps.build_amd64.outputs.digest }}
      image_tag: ${{ steps.set_image_tag.outputs.image_tag }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Set Docker tags
        id: set_tags
        run: |
          if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then
            echo "TAGS=icereed/paperless-gpt:pr-${GITHUB_SHA}-amd64" >> $GITHUB_ENV
          elif [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
            VERSION=${GITHUB_REF#refs/tags/}
            echo "TAGS=icereed/paperless-gpt:${VERSION}-amd64" >> $GITHUB_ENV
          else
            echo "TAGS=icereed/paperless-gpt:unreleased-amd64" >> $GITHUB_ENV
          fi
      - name: Build and push AMD64 image
        id: build_amd64
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64
          push: true
          cache-from: type=gha
          cache-to: type=gha,mode=max
          tags: ${{ env.TAGS }}
          build-args: |
            VERSION=${{ github.ref_type == 'tag' && github.ref_name || github.sha }}
            COMMIT=${{ github.sha }}
            BUILD_DATE=${{ github.event.repository.pushed_at }}
      - name: Set image tag output
        id: set_image_tag
        run: echo "image_tag=${TAGS}" >> $GITHUB_OUTPUT
      - name: Export digest for amd64
        run: |
          mkdir -p ${{ runner.temp }}/digests
          echo "${{ steps.build_amd64.outputs.digest }}" | sed 's/^sha256://g' > ${{ runner.temp }}/digests/digest-amd64.txt
      - name: Upload amd64 digest
        uses: actions/upload-artifact@v4
        with:
          name: digest-amd64
          path: ${{ runner.temp }}/digests/digest-amd64.txt

  build-arm64:
    runs-on: ubuntu-24.04-arm
    needs: test
    outputs:
      digest: ${{ steps.build_arm64.outputs.digest }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Log in to Docker Hub
        if: ${{ github.event_name != 'pull_request' }}
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Set Docker tags
        id: set_tags
        run: |
          if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
            VERSION=${GITHUB_REF#refs/tags/}
            echo "TAGS=icereed/paperless-gpt:${VERSION}-arm64" >> $GITHUB_ENV
          else
            echo "TAGS=icereed/paperless-gpt:unreleased-arm64" >> $GITHUB_ENV
          fi
      - name: Build and push ARM64 image
        id: build_arm64
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/arm64
          push: ${{ github.event_name != 'pull_request' }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          tags: ${{ env.TAGS }}
          build-args: |
            VERSION=${{ github.ref_type == 'tag' && github.ref_name || github.sha }}
            COMMIT=${{ github.sha }}
            BUILD_DATE=${{ github.event.repository.pushed_at }}
      - name: Export digest for arm64
        run: |
          mkdir -p ${{ runner.temp }}/digests
          echo "${{ steps.build_arm64.outputs.digest }}" | sed 's/^sha256://g' > ${{ runner.temp }}/digests/digest-arm64.txt
      - name: Upload arm64 digest
        uses: actions/upload-artifact@v4
        with:
          name: digest-arm64
          path: ${{ runner.temp }}/digests/digest-arm64.txt

  merge-manifests:
    needs: [build-amd64, build-arm64]
    runs-on: ubuntu-latest
    if: github.event_name != 'pull_request'
    env:
      DOCKERHUB_REPO: icereed/paperless-gpt
    steps:
      - name: Download amd64 digest
        uses: actions/download-artifact@v4
        with:
          name: digest-amd64
          path: ${{ runner.temp }}/digests
      - name: Download arm64 digest
        uses: actions/download-artifact@v4
        with:
          name: digest-arm64
          path: ${{ runner.temp }}/digests
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Determine version/tag
        id: get_version
        run: |
          if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
            VERSION=${GITHUB_REF#refs/tags/}
            echo "VERSION=${VERSION}" >> $GITHUB_ENV
          else
            echo "VERSION=unreleased" >> $GITHUB_ENV
          fi
      - name: Create and push manifest list
        run: |
          AMD64_DIGEST=$(cat ${{ runner.temp }}/digests/digest-amd64.txt)
          ARM64_DIGEST=$(cat ${{ runner.temp }}/digests/digest-arm64.txt)
          # Create manifest with the single-arch image digests
          docker buildx imagetools create -t ${DOCKERHUB_REPO}:${VERSION} \
            ${DOCKERHUB_REPO}@sha256:${AMD64_DIGEST} ${DOCKERHUB_REPO}@sha256:${ARM64_DIGEST}
          # Also push "latest" tag when on a tag
          if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
            docker buildx imagetools create -t ${DOCKERHUB_REPO}:latest \
              ${DOCKERHUB_REPO}@sha256:${AMD64_DIGEST} ${DOCKERHUB_REPO}@sha256:${ARM64_DIGEST}
          fi
      - name: Inspect manifest
        run: |
          docker buildx imagetools inspect ${DOCKERHUB_REPO}:${VERSION}
          if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
            docker buildx imagetools inspect ${DOCKERHUB_REPO}:latest
          fi

  e2e-tests:
    name: E2E Tests
    needs: build-amd64
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./web-app
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set PAPERLESS_GPT_IMAGE
        run: |
          if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
            IMAGE="icereed/paperless-gpt:pr-${GITHUB_SHA}-amd64"
          elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then
            IMAGE="icereed/paperless-gpt:${GITHUB_REF_NAME}-amd64"
          else
            IMAGE="icereed/paperless-gpt:unreleased-amd64"
          fi
          echo "PAPERLESS_GPT_IMAGE=${IMAGE}" >> $GITHUB_ENV
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: './web-app/package-lock.json'
      - name: Install dependencies
        run: npm ci
      - name: Install Playwright browsers
        run: npx playwright install chromium --with-deps
      - name: Run Playwright tests
        run: npm run test:e2e
        env:
          CI: true
          DEBUG: testcontainers:containers
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          PAPERLESS_GPT_IMAGE: ${{ env.PAPERLESS_GPT_IMAGE }}
      - name: Upload Playwright Report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: web-app/playwright-report/
          retention-days: 30
      - name: Upload test screenshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: web-app/test-results/
          retention-days: 30