name: Tests And Linting

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-python@v6
        with:
          python-version: "3.13"

      - name: Install uv
        uses: astral-sh/setup-uv@v7
        with:
          version: "0.5.4"
          enable-cache: true

      - name: Instal dependencies
        run: uv sync --all-groups

      - uses: j178/prek-action@v1

  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
        pydantic-version: ["1.10", "2.0"]
        sqla-version: ["1.4", "2"]
        exclude:
          - pydantic-version: "1.10"
            sqla-version: "1.4"
          - python-version: "3.14"
            pydantic-version: "1.10"
    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Set up python ${{ matrix.python-version }}
        id: checkout-python
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}

      - name: Create cache file
        run: echo '${{ matrix.pydantic-version }}-${{ matrix.sqla-version }}' > ./matrix-file.txt

      - name: Set up python ${{ matrix.python-version }}
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install uv
        uses: astral-sh/setup-uv@v7
        with:
          version: "0.5.4"
          enable-cache: true
          cache-dependency-glob: |
            uv.lock
            matrix-file.txt

      - name: Install pydantic
        if: matrix.pydantic-version == '1.10'
        run: uv add --group pydantic "pydantic[email]==1.10.17"

      - name: Pin hypothesis for pydantic 1.10
        if: matrix.pydantic-version == '1.10'
        run: uv add --group test "hypothesis==6.135.20"

      - name: Install SQLAlchemy
        if: matrix.sqla-version == '1.4'
        run: uv add --group sqlalchemy "sqlalchemy[asyncio]==1.4.49"

      - name: Sync
        run: uv sync --all-extras

      - name: Test
        if: matrix.python-version != '3.13' || matrix.pydantic-version != '2.0' || matrix.sqla-version != '2'
        run: uv run pytest tests

      - name: Test with Coverage
        if: matrix.python-version == '3.13' && matrix.pydantic-version == '2.0' && matrix.sqla-version == '2'
        run: uv run pytest tests docs/examples --cov=. --cov-report=xml

      - uses: actions/upload-artifact@v6
        if: matrix.python-version == '3.13' && matrix.pydantic-version == '2.0' && matrix.sqla-version == '2'
        with:
          name: coverage-data
          path: coverage.xml

  build-docs:
    needs:
      - validate
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.13"

      - name: Install uv
        uses: astral-sh/setup-uv@v7
        with:
          version: "0.5.4"
          enable-cache: true

      - name: Install dependencies
        run: uv sync --all-extras

      - name: Build docs
        run: uv run make docs

      - name: Save PR number
        env:
          PR_NUMBER: ${{ github.event.number }}
        run: echo $PR_NUMBER > .pr_number

      - name: Upload artifact
        uses: actions/upload-artifact@v6
        with:
          name: docs-preview
          include-hidden-files: true
          path: |
            docs/_build/html
            .pr_number

  codeql:
    needs:
      - test
      - validate
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Initialize CodeQL With Dependencies
        if: github.event_name == 'push' && github.ref_name == 'main'
        uses: github/codeql-action/init@v4

      - name: Initialize CodeQL Without Dependencies
        if: github.event_name == 'pull_request'
        uses: github/codeql-action/init@v4
        with:
          setup-python-dependencies: false

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v4

  upload-test-coverage:
    runs-on: ubuntu-latest
    needs:
      - test
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: "3.13"

      - name: Download Artifacts
        uses: actions/download-artifact@v7
        with:
          name: coverage-data

      - name: Fix coverage file name
        run: sed -i "s/home\/runner\/work\/polyfactory\/polyfactory/github\/workspace/g" coverage.xml

      - name: Upload coverage reports to Codecov
        uses: codecov/codecov-action@v5
        with:
          files: coverage.xml
          token: ${{ secrets.CODECOV_TOKEN }}

  test_success:
    needs: test
    if: always()
    runs-on: ubuntu-latest
    permissions: {}
    steps:
      - name: Report success or fail
        run: |
          echo "test workflow exited with ${{ needs.test.result }}"
          exit ${{ needs.test.result == 'success' && '0' || '1' }}
