name: build
on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
  schedule:
    - cron: "0 2 * * *"

env:
  UV_NO_SYNC: true

jobs:
  static-analysis:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - uses: pre-commit/action@v3.0.1
        with:
          extra_args: --all-files

  compatibility-tests:
    runs-on: ubuntu-latest
    continue-on-error: true
    strategy:
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
          - "3.12"
        pydantic-version:
          - "2.5.2"
        motor-version:
          - "3.1.1"
          - "3.2.0"
          - "3.3.2"

    steps:
      - uses: actions/checkout@v6
      - name: Mongo Service
        run: bash mongodb-cluster/run.sh
        env:
          MODE: standalone
          VERSION: "4.4"
      - name: "Set up Python ${{ matrix.python-version }}"
        uses: actions/setup-python@v6
        with:
          python-version: "${{ matrix.python-version }}"
      - name: Setup uv
        uses: astral-sh/setup-uv@v7
        with:
          enable-cache: true
          cache-dependency-glob: |
            pyproject.toml
            uv.lock
      - name: Install dependencies
        run: |
          uv sync --locked --no-dev --extra test
          uv pip install "pymongo<4.9" "pydantic==${{ matrix.pydantic-version }}" "motor==${{ matrix.motor-version }}"

      - name: Run compatibility checks.
        run: |
          uv run python -c "import motor; print(motor.version)" 1>&2
          uv run python -c "import pydantic; print(pydantic.VERSION)" 1>&2
          uv run python -m pytest -q -rs

  tests:
    runs-on: ubuntu-latest
    continue-on-error: true
    strategy:
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
          - "3.12"
        mongo-version:
          - "4.4"
          - "5"
          - "6"
        mongo-mode:
          - standalone
        connection-string:
          - mongodb://localhost:27017/
        include:
          - python-version: "3.12"
            mongo-version: 4.0
            mongo-mode: replicaSet
            connection-string: mongodb://172.16.17.11:27017,172.16.17.12:27017,172.16.17.13:27017/?replicaSet=mongodb-action-replica-set
          - python-version: "3.12"
            mongo-version: 4.2
            mongo-mode: sharded
            connection-string: mongodb://172.16.17.10:27017/?retryWrites=false

    steps:
      - uses: actions/checkout@v6
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
      - name: Setup uv
        uses: astral-sh/setup-uv@v7
        with:
          enable-cache: true
          cache-dependency-glob: |
            pyproject.toml
            uv.lock
      - name: Mongo Service
        run: bash mongodb-cluster/run.sh
        env:
          MODE: ${{ matrix.mongo-mode }}
          VERSION: ${{ matrix.mongo-version }}
      - name: Install dependencies
        run: |
          uv sync --locked --no-dev --extra test
          uv pip install flit
      - name: Run all tests
        run: |
          set -e
          uv run coverage run -m pytest -v
          uv run coverage report -m
          uv run coverage xml
        env:
          TEST_MONGO_URI: ${{ matrix.connection-string }}
          TEST_MONGO_MODE: ${{ matrix.mongo-mode }}

      - uses: codecov/codecov-action@v5
        if: github.event_name != 'schedule' # Don't report coverage for nightly builds
        with:
          flags: tests-${{ matrix.python-version }}-${{ matrix.mongo-version }}-${{ matrix.mongo-mode }}
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}

  integrated-realworld-test:
    runs-on: ubuntu-latest
    env:
      UV_SYSTEM_PYTHON: true
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v6
        with:
          path: odmantic-current
      - name: Setup uv
        uses: astral-sh/setup-uv@v7
        with:
          enable-cache: true
          cache-dependency-glob: |
            pyproject.toml
            uv.lock
      - uses: actions/checkout@v6
        with:
          repository: art049/fastapi-odmantic-realworld-example
          submodules: recursive
          path: fastapi-odmantic-realworld-example
      - name: Set up Python 3.12
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Install poetry and flit
        run: |
          uv pip install poetry
          uv pip install flit
      - name: Mongo Service
        run: bash odmantic-current/mongodb-cluster/run.sh
      - name: Install dependencies (w/o ODMantic)
        working-directory: fastapi-odmantic-realworld-example
        run: |
          echo "$(grep -v 'odmantic =' ./pyproject.toml)" > pyproject.toml
          poetry lock
          poetry install --no-root
      - name: Install current ODMantic version
        working-directory: fastapi-odmantic-realworld-example
        run: poetry run pip install ../odmantic-current/
      - name: Start the FastAPI server
        working-directory: fastapi-odmantic-realworld-example
        run: |
          ./scripts/start.sh &
          # Wait for the server
          while ! curl "http://localhost:8000/health" > /dev/null 2>&1
          do
            sleep 1;
          done
          echo "Server ready."
        env:
          MONGO_URI: "mongodb://localhost:27017/"
      - name: Run realworld backend tests
        working-directory: fastapi-odmantic-realworld-example
        run: ./realworld/api/run-api-tests.sh
        env:
          APIURL: http://localhost:8000

  all-ci-checks:
    needs:
      - static-analysis
      - compatibility-tests
      - tests
      - integrated-realworld-test
    runs-on: ubuntu-latest
    steps:
      - run: echo "All CI checks passed."
