Python CI
Complete Python project continuous integration workflow, including multi-version matrix, pip cache, lint, test and coverage.
name: Python CI
on:
push:
branches:
- main
- 'feature/**'
paths:
- 'src/**'
- 'tests/**'
- 'pyproject.toml'
- 'setup.py'
- 'requirements*.txt'
pull_request:
branches:
- main
concurrency:
max: 1
exceed-action: QUEUE
permissions:
repository: read
jobs:
lint:
name: Code Quality Check
runs-on: {ubuntu-24,x64,slim}
steps:
- name: Checkout code
uses: checkout
- name: Setup Python
uses: setup-python
with:
python-version: '3.12'
cache: 'pip'
- name: Install lint tools
run: pip install flake8 black isort mypy
- name: Flake8 Check
run: flake8 src/ --max-line-length=120 --statistics
- name: Black Format Check
run: black --check --diff src/
- name: isort Import Sort Check
run: isort --check-only --diff src/
- name: mypy Type Check
run: mypy src/ --ignore-missing-imports
test:
name: Python ${{ matrix.python-version }} Test
runs-on: {ubuntu-24,x64,small}
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
fail-fast: false
max-parallel: 3
steps:
- name: Checkout code
uses: checkout
- name: Setup Python ${{ matrix.python-version }}
uses: setup-python
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Unit Test + Coverage
run: |
pytest tests/ \
--cov=src \
--cov-report=term-missing \
--cov-report=xml:coverage.xml \
--junitxml=test-results.xml \
-v
- name: Test Results Summary
if: ${{ always }}
run: |
echo "## Python Test Results - Python ${{ matrix.python-version }}" >> $ATOMGIT_STEP_SUMMARY
echo "Status: ${{ job.status }}" >> $ATOMGIT_STEP_SUMMARY
- name: Upload Coverage Report
if: ${{ always }}
uses: upload-artifact
with:
name: coverage-py${{ matrix.python-version }}
path: |
coverage.xml
test-results.xml
retention-days: 7
build:
name: Build Package
needs: [lint, test]
runs-on: {ubuntu-24,x64,small}
if: ${{ atomgit.ref == 'refs/heads/main' }}
steps:
- name: Checkout code
uses: checkout
- name: Setup Python
uses: setup-python
with:
python-version: '3.12'
- name: Install build tools
run: pip install build twine
- name: Build Python package
run: python -m build
- name: Upload artifact
uses: upload-artifact
with:
name: python-package
path: dist/
retention-days: 7