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