From 19c387e0ea9da5df7755ee5c15d1cb345a541d53 Mon Sep 17 00:00:00 2001 From: Pietro Delsante Date: Thu, 16 Jul 2026 10:52:13 +0200 Subject: [PATCH] CI: support parallel coverage in reusable python workflow Allow projects to run the Django test suite in parallel under coverage: - drop `-a` from `coverage run` (append is incompatible with coverage parallel mode, concurrency=multiprocessing / parallel=true); - add a guarded `coverage combine` step before the coverage report so the per-process .coverage.* files produced by parallel workers are merged. Both changes are no-ops for projects that don't use parallel coverage (single coverage run needs no append; combine is skipped when there are no .coverage.* files). Applied to workflows/_python.yml and its hard-linked .github/ self-test copy. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/_python.yml | 18 +++++++++++++++++- workflows/_python.yml | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.github/workflows/_python.yml b/.github/workflows/_python.yml index 4d0a4a5..52082e2 100644 --- a/.github/workflows/_python.yml +++ b/.github/workflows/_python.yml @@ -513,7 +513,11 @@ jobs: CMD="coverage run --rcfile=${{ inputs.coverage_config_path }}" if [[ -n '${{ inputs.django_settings_module }}' ]]; then - CMD="${CMD} -a manage.py test" + # No '-a' (append): it is incompatible with coverage parallel + # mode (concurrency=multiprocessing / parallel=true) used by + # projects that run the Django test suite with --parallel. + # A single coverage run does not need append anyway. + CMD="${CMD} manage.py test" # manage manual tags if [[ -n '${{ inputs.tags_for_manual_tests }}' ]]; then for tag in ${{ inputs.tags_for_manual_tests }}; do @@ -543,6 +547,18 @@ jobs: env: ${{ secrets }} shell: bash + - name: Combine coverage data + if: inputs.use_coverage && inputs.upload_coverage + run: | + # When coverage runs in parallel mode (concurrency=multiprocessing), + # each worker process writes its own .coverage.* file; merge them + # before reporting. No-op for projects not using parallel coverage. + if ls .coverage.* >/dev/null 2>&1; then + coverage combine + fi + working-directory: ${{ inputs.working_directory }} + shell: bash + - name: Create coverage output if: inputs.use_coverage && inputs.upload_coverage id: coverage-output diff --git a/workflows/_python.yml b/workflows/_python.yml index 4d0a4a5..52082e2 100644 --- a/workflows/_python.yml +++ b/workflows/_python.yml @@ -513,7 +513,11 @@ jobs: CMD="coverage run --rcfile=${{ inputs.coverage_config_path }}" if [[ -n '${{ inputs.django_settings_module }}' ]]; then - CMD="${CMD} -a manage.py test" + # No '-a' (append): it is incompatible with coverage parallel + # mode (concurrency=multiprocessing / parallel=true) used by + # projects that run the Django test suite with --parallel. + # A single coverage run does not need append anyway. + CMD="${CMD} manage.py test" # manage manual tags if [[ -n '${{ inputs.tags_for_manual_tests }}' ]]; then for tag in ${{ inputs.tags_for_manual_tests }}; do @@ -543,6 +547,18 @@ jobs: env: ${{ secrets }} shell: bash + - name: Combine coverage data + if: inputs.use_coverage && inputs.upload_coverage + run: | + # When coverage runs in parallel mode (concurrency=multiprocessing), + # each worker process writes its own .coverage.* file; merge them + # before reporting. No-op for projects not using parallel coverage. + if ls .coverage.* >/dev/null 2>&1; then + coverage combine + fi + working-directory: ${{ inputs.working_directory }} + shell: bash + - name: Create coverage output if: inputs.use_coverage && inputs.upload_coverage id: coverage-output