name: Test on: push: branches: - master pull_request: types: - opened - synchronize schedule: # cron every week on monday - cron: "0 0 * * 1" permissions: {} env: UV_NO_SYNC: true INLINE_SNAPSHOT_DEFAULT_FLAGS: review jobs: changes: runs-on: ubuntu-latest # Required permissions permissions: pull-requests: read # Set job outputs to values from filter step outputs: src: ${{ steps.filter.outputs.src }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false # For pull requests it's not necessary to checkout the code but for the main branch it is - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 id: filter with: filters: | src: - .github/workflows/test.yml - docs_src/** - fastapi/** - scripts/** - tests/** - .python-version - pyproject.toml - uv.lock test: needs: - changes if: needs.changes.outputs.src == 'true' || github.ref == 'refs/heads/master' strategy: matrix: os: [ windows-latest, macos-latest ] python-version: [ "3.14", "3.14t" ] deprecated-tests: [ "no-deprecation" ] uv-resolution: - highest starlette-src: - starlette-pypi - starlette-git include: - os: macos-latest python-version: "3.10" coverage: coverage uv-resolution: lowest-direct deprecated-tests: "no-deprecation" - os: windows-latest python-version: "3.12" coverage: coverage uv-resolution: lowest-direct deprecated-tests: "no-deprecation" - os: ubuntu-latest python-version: "3.13" coverage: coverage uv-resolution: highest deprecated-tests: "no-deprecation" - os: ubuntu-latest python-version: "3.13" uv-resolution: highest codspeed: codspeed deprecated-tests: "no-deprecation" - os: ubuntu-latest python-version: "3.14" coverage: coverage uv-resolution: highest starlette-src: starlette-git deprecated-tests: "test-deprecation" - os: ubuntu-latest python-version: "3.14t" coverage: coverage uv-resolution: highest deprecated-tests: "no-deprecation" fail-fast: false runs-on: ${{ matrix.os }} env: UV_PYTHON: ${{ matrix.python-version }} UV_RESOLUTION: ${{ matrix.uv-resolution }} STARLETTE_SRC: ${{ matrix.starlette-src }} steps: - name: Dump GitHub context env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: ${{ matrix.python-version }} - name: Setup uv uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: "0.11.4" enable-cache: true cache-dependency-glob: | pyproject.toml uv.lock - name: Install Dependencies run: uv sync --no-dev --group tests --extra all - name: Ensure that we have the lowest supported Pydantic version if: matrix.uv-resolution == 'lowest-direct' run: uv pip install "pydantic==2.9.0" - name: Install Starlette from source if: matrix.starlette-src == 'starlette-git' run: uv pip install "git+https://github.com/Kludex/starlette@main" - name: Install deprecated libraries just for testing if: matrix.deprecated-tests == 'test-deprecation' run: uv pip install orjson ujson - name: Reinstall SQLAlchemy without Cython extensions if: matrix.python-version == '3.14t' && matrix.os == 'ubuntu-latest' run: "DISABLE_SQLALCHEMY_CEXT=1 uv pip install --force-reinstall --no-binary :all: sqlalchemy" - run: mkdir coverage - name: Test run: uv run --no-sync bash scripts/test-cov.sh env: COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.deprecated-tests}} CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.deprecated-tests}} # Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow - name: Store coverage files if: matrix.coverage == 'coverage' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.deprecated-tests}}-${{ hashFiles('**/coverage/.coverage.*') }} path: coverage include-hidden-files: true benchmark: needs: - changes if: needs.changes.outputs.src == 'true' || github.ref == 'refs/heads/master' runs-on: ubuntu-latest env: UV_PYTHON: "3.13" UV_RESOLUTION: highest steps: - name: Dump GitHub context env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.13" - name: Setup uv uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: "0.11.4" enable-cache: true cache-dependency-glob: | pyproject.toml uv.lock - name: Install Dependencies run: uv sync --no-dev --group tests --extra all - name: CodSpeed benchmarks uses: CodSpeedHQ/action@1c8ae4843586d3ba879736b7f6b7b0c990757fab # v4.12.1 with: mode: simulation run: uv run --no-sync pytest tests/benchmarks --codspeed coverage-combine: needs: - test runs-on: ubuntu-latest steps: - name: Dump GitHub context env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version-file: ".python-version" - name: Setup uv uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: "0.11.4" enable-cache: true cache-dependency-glob: | pyproject.toml uv.lock - name: Install Dependencies run: uv sync --locked --no-dev --group tests --extra all - name: Get coverage files uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-* path: coverage merge-multiple: true - run: ls -la coverage - run: uv run coverage combine coverage - run: uv run coverage html --title "Coverage for ${{ github.sha }}" - name: Store coverage HTML uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage-html path: htmlcov include-hidden-files: true - run: uv run coverage report --fail-under=100 # https://github.com/marketplace/actions/alls-green#why check: # This job does nothing and is only used for the branch protection if: always() needs: - coverage-combine - benchmark runs-on: ubuntu-latest steps: - name: Dump GitHub context env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} allowed-skips: coverage-combine,test,benchmark