From 5393efc6cd53d45ebfa0706cd4c5bf8fbed5db7f Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Tue, 7 Jul 2026 20:27:39 +0200 Subject: [PATCH 1/4] Enforce a 95% combined coverage floor in CI and local runs. Configure fail_under in pyproject.toml and read it in the coverage-report workflow so the threshold stays in one place. Co-authored-by: Cursor --- .gitea/workflows/test.yml | 17 +++++++++++++++-- README.md | 9 ++++++++- pyproject.toml | 8 ++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index e57424b..371a1d7 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -112,8 +112,21 @@ jobs: - name: Combine coverage report run: | uv run coverage combine coverage-unit/.coverage coverage-integration/.coverage - uv run coverage report -m --include='python_repositories/*' > coverage.txt - cat coverage.txt + uv run coverage report -m --include='python_repositories/*' --fail-under=0 > coverage.txt + + - name: Show coverage report + run: cat coverage.txt + + - name: Enforce coverage floor + run: | + FAIL_UNDER=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['tool']['coverage']['report']['fail_under'])") + echo "Checking combined coverage against ${FAIL_UNDER}% floor..." + if uv run coverage report --fail-under="$FAIL_UNDER" --include='python_repositories/*'; then + echo "Coverage floor met." + else + echo "::error::Combined coverage is below the ${FAIL_UNDER}% floor" + exit 1 + fi - name: Post coverage summary to PR if: github.event_name == 'pull_request' diff --git a/README.md b/README.md index cb93dff..a38bf1d 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,14 @@ uv run pytest -v # full suite (requires Doc Integration tests are marked with `@pytest.mark.integration` and require Docker (testcontainers). Run unit tests alone for quick local feedback. -CI runs unit and integration tests in parallel with coverage, then merges `.coverage` artifacts in a follow-up job (via [christopherhx/gitea-\*-artifact@v4](https://github.com/christopherHX/gitea-upload-artifact) for Gitea 1.26 compatibility). +CI runs unit and integration tests in parallel with coverage, then merges `.coverage` artifacts in a follow-up job (via [christopherhx/gitea-\*-artifact@v4](https://github.com/christopherHX/gitea-upload-artifact) for Gitea 1.26 compatibility). Combined coverage must be at least **95%**; the floor is set by [`fail_under` in `pyproject.toml`](pyproject.toml#L45-L48) and enforced after merging unit and integration coverage, not on unit-only runs. + +To check coverage locally (requires Docker for the full suite): + +```bash +uv run pytest --cov=python_repositories --cov-report= +uv run coverage report +``` `pre-commit` is included in the dev dependency group. `uv sync` installs the CLI, but git does not run hooks until you install them with `pre-commit install` (one time per clone). After that, commits run the checks defined in [`.pre-commit-config.yaml`](.pre-commit-config.yaml) (ruff, mypy, pyupgrade, prettier, and general file hygiene). diff --git a/pyproject.toml b/pyproject.toml index 8735bd0..27359f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,14 @@ markers = [ "integration: tests requiring Docker containers (deselect with '-m \"not integration\"')", ] +[tool.coverage.run] +source = ["python_repositories"] + +[tool.coverage.report] +fail_under = 95 +show_missing = true +precision = 2 + [tool.uv.sources] python-utils = { index = "gitea" } From 34632980badd17c03b39e8ce2f2b2e62d9261e55 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Tue, 7 Jul 2026 20:33:21 +0200 Subject: [PATCH 2/4] Skip coverage floor check in partial CI test jobs. Unit and integration jobs each produce partial coverage; pytest-cov reads fail_under from pyproject.toml unless overridden with --cov-fail-under=0. Co-authored-by: Cursor --- .gitea/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 371a1d7..17e7a67 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -30,7 +30,8 @@ jobs: run: | uv run pytest tests/unit/ -m "not integration" \ --cov=python_repositories \ - --cov-report= + --cov-report= \ + --cov-fail-under=0 - name: Upload unit coverage uses: https://github.com/christopherHX/gitea-upload-artifact@v4 @@ -66,7 +67,8 @@ jobs: run: | uv run pytest -m integration \ --cov=python_repositories \ - --cov-report= + --cov-report= \ + --cov-fail-under=0 - name: Upload integration coverage uses: https://github.com/christopherHX/gitea-upload-artifact@v4 From 5c8cd841b6a25ac7a694c5fc848dfc794c90337e Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Tue, 7 Jul 2026 20:34:54 +0200 Subject: [PATCH 3/4] Document where combined coverage floor is enforced in CI. Clarify that unit and integration jobs skip the floor check because they only produce partial coverage. Co-authored-by: Cursor --- .gitea/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 17e7a67..43376f7 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -28,6 +28,7 @@ jobs: - name: Run unit tests run: | + # --cov-fail-under=0: partial coverage only; floor is checked in coverage-report. uv run pytest tests/unit/ -m "not integration" \ --cov=python_repositories \ --cov-report= \ @@ -65,6 +66,7 @@ jobs: - name: Run integration tests run: | + # --cov-fail-under=0: partial coverage only; floor is checked in coverage-report. uv run pytest -m integration \ --cov=python_repositories \ --cov-report= \ @@ -79,6 +81,7 @@ jobs: compression-level: 0 coverage-report: + # Merges unit + integration coverage and enforces fail_under from pyproject.toml. needs: [unit-tests, integration-tests] runs-on: ubuntu-latest if: github.event_name == 'pull_request' || github.event_name == 'push' @@ -113,6 +116,7 @@ jobs: - name: Combine coverage report run: | + # --fail-under=0 so the full report is always written before the floor check. uv run coverage combine coverage-unit/.coverage coverage-integration/.coverage uv run coverage report -m --include='python_repositories/*' --fail-under=0 > coverage.txt @@ -121,6 +125,7 @@ jobs: - name: Enforce coverage floor run: | + # Reads fail_under from pyproject.toml; only combined coverage is evaluated here. FAIL_UNDER=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['tool']['coverage']['report']['fail_under'])") echo "Checking combined coverage against ${FAIL_UNDER}% floor..." if uv run coverage report --fail-under="$FAIL_UNDER" --include='python_repositories/*'; then From a381d456501808f16e584e1c98e1f2b60af9391b Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Tue, 7 Jul 2026 20:39:08 +0200 Subject: [PATCH 4/4] Lower combined coverage floor from 95% to 90%. Update fail_under in pyproject.toml and the README to match. Co-authored-by: Cursor --- README.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a38bf1d..4542d32 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ uv run pytest -v # full suite (requires Doc Integration tests are marked with `@pytest.mark.integration` and require Docker (testcontainers). Run unit tests alone for quick local feedback. -CI runs unit and integration tests in parallel with coverage, then merges `.coverage` artifacts in a follow-up job (via [christopherhx/gitea-\*-artifact@v4](https://github.com/christopherHX/gitea-upload-artifact) for Gitea 1.26 compatibility). Combined coverage must be at least **95%**; the floor is set by [`fail_under` in `pyproject.toml`](pyproject.toml#L45-L48) and enforced after merging unit and integration coverage, not on unit-only runs. +CI runs unit and integration tests in parallel with coverage, then merges `.coverage` artifacts in a follow-up job (via [christopherhx/gitea-\*-artifact@v4](https://github.com/christopherHX/gitea-upload-artifact) for Gitea 1.26 compatibility). Combined coverage must be at least **90%**; the floor is set by [`fail_under` in `pyproject.toml`](pyproject.toml#L45-L48) and enforced after merging unit and integration coverage, not on unit-only runs. To check coverage locally (requires Docker for the full suite): diff --git a/pyproject.toml b/pyproject.toml index 27359f9..d9f2ef3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ markers = [ source = ["python_repositories"] [tool.coverage.report] -fail_under = 95 +fail_under = 90 show_missing = true precision = 2