# ============================================================================= # Python CI Pipeline # Runs: lint (ruff), type check (mypy), test (pytest), coverage upload # ============================================================================= name: Python CI on: push: branches: [main] paths: - "**.py" - "requirements*.txt" - "pyproject.toml" - ".github/workflows/ci-python.yaml" pull_request: branches: [main] paths: - "**.py" - "requirements*.txt" - "pyproject.toml" - ".github/workflows/ci-python.yaml" permissions: contents: read env: PYTHON_VERSION: "3.12" jobs: # --------------------------------------------------------------------------- # Lint with Ruff # --------------------------------------------------------------------------- lint: name: Lint runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install ruff run: pip install ruff - name: Ruff check (lint) run: ruff check . - name: Ruff format (formatting) run: ruff format --check . # --------------------------------------------------------------------------- # Type check with mypy # --------------------------------------------------------------------------- type-check: name: Type Check runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Cache pip dependencies uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('requirements*.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Install dependencies run: | pip install --upgrade pip pip install -r requirements.txt pip install mypy - name: Run mypy run: mypy src/ --ignore-missing-imports # --------------------------------------------------------------------------- # Test with pytest # --------------------------------------------------------------------------- test: name: Test runs-on: ubuntu-latest timeout-minutes: 15 # Uncomment to add a PostgreSQL service for integration tests. # services: # postgres: # image: postgres:17-alpine # env: # POSTGRES_USER: test # POSTGRES_PASSWORD: test # POSTGRES_DB: test_db # ports: # - 5432:5432 # options: >- # --health-cmd pg_isready # --health-interval 10s # --health-timeout 5s # --health-retries 5 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Cache pip dependencies uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('requirements*.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Install dependencies run: | pip install --upgrade pip pip install -r requirements.txt pip install -r requirements-dev.txt - name: Run tests with coverage run: | pytest \ --cov=src \ --cov-report=xml:coverage.xml \ --cov-report=term-missing \ --junitxml=junit.xml \ -v env: PYTHONPATH: ${{ github.workspace }} # DATABASE_URL: postgresql://test:test@localhost:5432/test_db - name: Upload coverage report if: always() uses: actions/upload-artifact@v4 with: name: coverage-report path: coverage.xml retention-days: 7 - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: test-results path: junit.xml retention-days: 7 # Uncomment to upload coverage to Codecov. # - name: Upload to Codecov # if: github.event_name == 'push' && github.ref == 'refs/heads/main' # uses: codecov/codecov-action@v4 # with: # files: coverage.xml # token: ${{ secrets.CODECOV_TOKEN }}