Test against the versions you support
If your README says 'works on Python 3.10–3.12', CI should prove it on every PR. Without it, the support claim is a lie waiting to be discovered.
The basic pattern: a matrix over the dimension(s) you support. Example dimensions:
- Language version (Python 3.10, 3.11, 3.12, 3.13).
- OS (ubuntu-latest, macos-latest, windows-latest).
- Database driver (postgres 14, 15, 16).
- Framework version (Django 4.2, 5.0).
Each matrix cell is its own job, runs in parallel, with its own logs. The job name in the UI is templated (e.g., test (python-3.12, ubuntu-latest)).
Cost discipline
A naive 4×3 matrix is 12 runs per PR. Cost grows fast. Two compromises:
- Full matrix on main, smoke matrix on PR. PRs only test the lowest and highest version on Linux. Main runs the full matrix.
- Cancel slow OSes when Linux fails. Use job-level
fail-fast: trueto abort the whole matrix on the first failure.