diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a577b387..8a789bc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,13 +65,17 @@ jobs: sarif_file: zizmor.sarif category: zizmor - - name: Report coverage + - name: Prepare coverage file for upload if: contains(matrix.name, 'coverage') - uses: codecov/codecov-action@v5 + run: mv .coverage coverage.${TOXENV} + + - name: Upload temporary coverage artifact + if: contains(matrix.name, 'coverage') + uses: actions/upload-artifact@v4 with: - fail_ci_if_error: true - files: ./coverage.xml - token: ${{ secrets.CODECOV_TOKEN }} + name: coverage-artifact-${{ matrix.name }} + path: coverage.${{ matrix.name }} + retention-days: 1 strategy: fail-fast: false @@ -151,11 +155,85 @@ jobs: python: 'pypy3.9' allow_failure: false + report-coverage: + name: Report Combined Coverage + runs-on: ubuntu-24.04 + needs: test + if: always() + permissions: + contents: read + actions: write + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Install coverage tool + run: python -m pip install coverage[toml] + + - name: Download all coverage artifacts + uses: actions/download-artifact@v4 + with: + path: downloaded-coverage-artifacts + pattern: coverage-artifact-* + + - name: Combine coverage reports + run: | + mkdir combined_coverage_data + find downloaded-coverage-artifacts -type f -name 'coverage.*' -exec cp {} combined_coverage_data/ \; + coverage combine combined_coverage_data/* + coverage xml + coverage html + coverage report --show-missing --format=markdown >> $GITHUB_STEP_SUMMARY + + - name: Determine retention days + id: determine-retention-days + run: | + if [ "${GITHUB_REF}" = "refs/heads/main" ] || [[ "${GITHUB_REF}" == refs/tags/* ]]; then + echo "retention_days=90" >> $GITHUB_OUTPUT + else + echo "retention_days=3" >> $GITHUB_OUTPUT + fi + env: + GITHUB_REF: ${{ github.ref }} + + - name: Upload combined .coverage file + uses: actions/upload-artifact@v4 + with: + name: coverage-file + path: .coverage + retention-days: ${{ steps.determine-retention-days.outputs.retention_days }} + include-hidden-files: true + + - name: Upload HTML coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage-html-report + path: htmlcov + retention-days: ${{ steps.determine-retention-days.outputs.retention_days }} + + - name: Delete temporary coverage artifacts from run + uses: geekyeggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b # 5.1.0 + with: + name: coverage-artifact-* + + - name: Report coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: ./coverage.xml + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + verbose: true + check: # This job does nothing and is only used for the branch protection if: always() needs: - - test + - report-coverage runs-on: ubuntu-24.04 diff --git a/pyproject.toml b/pyproject.toml index 36cdfe32..29acbf43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,6 +121,9 @@ include = [ "pytest_django_test/*", "tests/*", ] +omit = [ + "pytest_django/_version.py", # coverage fails when the file stops existing randomly, see .gitignore +] skip_covered = true exclude_lines = [ "pragma: no cover", diff --git a/tox.ini b/tox.ini index 59d4cb57..d6d0e80c 100644 --- a/tox.ini +++ b/tox.ini @@ -39,8 +39,6 @@ commands = coverage: coverage erase {env:PYTESTDJANGO_TEST_RUNNER:pytest} {posargs:tests} coverage: coverage combine - coverage: coverage report - coverage: coverage xml [testenv:linting] dependency_groups = linting