name: tests

on:
  push:
    branches: [main]
    paths-ignore:
      - 'docs/**'
  pull_request:
    paths-ignore:
      - 'docs/**'

env:
  HF_HOME: .cache/huggingface

permissions: {}

jobs:
  check_code_quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0
        with:
          persist-credentials: false
      - name: Set up Python
        uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c  # v6.0.0
        with:
          python-version: "3.11"
          cache: "pip"
          cache-dependency-path: "setup.py"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install .[dev]
      - name: Check quality
        run: |
          make quality

  tests:
    needs: check_code_quality
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13"]
        os: ["ubuntu-latest", "macos-13", "windows-latest"]
        exclude:
          - os: macos-13
            python-version: "3.13"
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0
        with:
          persist-credentials: false
      - name: Model cache
        uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809  # v4.2.4
        with:
          # Avoid caching HF_HOME/modules and Python cache files to prevent interoperability
          # issues and potential cache poisioning. We also avoid lock files to prevent runs
          # avoiding re-download because they see a lock file.
          path: |
            ${{ env.HF_HOME }}/hub/**
            !${{ env.HF_HOME }}/**/*.pyc
          key: model-cache-${{ github.run_id }}
          restore-keys: model-cache-
          enableCrossOsArchive: true
      - name: Dump cache content
        # TODO: remove this step after 2025-02-15
        if: matrix.os != 'windows-latest'
        run: |
          SHASUM=sha256sum
          [ -f "$(which shasum)" ] && SHASUM=shasum
          find "${{ env.HF_HOME }}/hub" -type f -exec "$SHASUM" {} \; > cache_content_initial || true
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c  # v6.0.0
        with:
          python-version: ${{ matrix.python-version }}
          cache: "pip"
          cache-dependency-path: "setup.py"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install setuptools
          # cpu version of pytorch
          pip install -e .[test]
      - name: Test with pytest
        # MacOS tests are currently too flaky and will fail almost each time. Thus, continue (green checkmark) even if
        # they fail, but add a notice so that the failure is not completely silent
        continue-on-error: ${{ matrix.os == 'macos-13' }}
        shell: bash
        env:
          HF_TOKEN: ${{ secrets.HF_TOKEN }}
          TRANSFORMERS_IS_CI: 1
        run: |
          set +e
          make test
          status=$?
          # Post a notice only if this is macOS AND tests failed
          if [ "$status" -ne 0 ] && [ "${{ matrix.os }}" = "macos-13" ]; then
            {
              echo "## ⚠️ macOS tests failed"
              echo ""
              echo "- OS: ${{ matrix.os }}"
              echo "- Python: ${{ matrix.python-version }}"
              echo ""
              echo "Check the logs from this step for details."
            } >> "$GITHUB_STEP_SUMMARY"
          fi
          # Return the real status. On macOS this won't fail the job because of continue-on-error.
          exit $status
      - name: Dump cache content and diff
        # This is just debug info so that we can monitor if the model cache diverges substantially
        # over time and what the diverging model is.
        # TODO: remove after 2025-02-15
        if: matrix.os != 'windows-latest'
        run: |
          SHASUM=sha256sum
          [ -f "$(which shasum)" ] && SHASUM=shasum
          find "${{ env.HF_HOME }}/hub" -type f -exec "$SHASUM" {} \; > cache_content_after || true
          diff -udp cache_content_initial cache_content_after || true
      - name: Delete old model cache entries
        run: |
          # make sure that cache cleaning doesn't break the pipeline
          python scripts/ci_clean_cache.py -d || true
      - name: Update model cache
        uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809  # v4.2.4
        # Only let one runner (preferably the one that covers most tests) update the model cache
        # after *every* run. This way we make sure that our cache is never outdated and we don't
        # have to keep track of hashes.
        if: always() && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.10'
        with:
          path: |
            ${{ env.HF_HOME }}/hub/**
            !${{ env.HF_HOME }}/**/*.pyc
          key: model-cache-${{ github.run_id }}
