diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9ed769..de8161d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,21 @@ jobs: python-version: ${{ matrix.python-version }} - run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential swig libpcsclite-dev - run: pip install -e ".[dev]" - - run: pytest -q -m "not real_card" + # Bare --cov picks up [tool.coverage.run] source; the project-wide floor comes + # from [tool.coverage.report] fail_under, so there is one place to edit when + # ratcheting. Both matrix entries are measured: src carries no version-specific + # branches today, so 3.10 and 3.14 are expected to report the same number, and a + # divergence is itself worth seeing. + - run: pytest -q -m "not real_card" --cov --cov-report=term-missing --cov-report=xml + # Second, tighter floor on the layer that actually needs to move: the command + # modules hold 1699 of the 2158 missed statements. coverage.py has no per-file + # fail_under, so this is a separate report over the same data. + - run: coverage report --include='src/cryptnox_id_cli/cli/commands/*' --fail-under=36 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + if: ${{ !env.ACT && matrix.python-version == '3.14' }} + with: + name: coverage + path: coverage.xml build: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index f6912a5..8605695 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ env/ .pytest_cache/ .ruff_cache/ .coverage +coverage.xml htmlcov/ # Docs build diff --git a/CHANGELOG.md b/CHANGELOG.md index d35f653..5120e1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 mechanisms. - `perso generate-key --create-key-object` - the same dev/eval fallback `import-key` already had. +- Coverage measurement in CI: `pytest-cov` in the `dev` extra, a project-wide + floor from `fail_under`, and a tighter floor over the command modules. With + branch coverage enabled both floors compare the combined statement-and-branch + percentage, which sits below line coverage alone. ## [1.0.3] - 2026-08-31 diff --git a/README.md b/README.md index 9c4db9b..5032cfe 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,17 @@ pytest -q -m "not real_card" Unit tests use a mock transport — no reader or card required. Real-card tests are opt-in (`-m real_card`) and never run in CI. +To measure coverage locally, the same way CI does: + +```bash +pytest -q -m "not real_card" --cov --cov-report=term-missing +``` + +CI enforces two floors: a project-wide one from `fail_under` in `pyproject.toml`, +and a tighter one over `src/cryptnox_id_cli/cli/commands/`. Because branch +coverage is enabled, both compare the **combined** statement-and-branch +percentage that `coverage report` prints, which sits below line coverage alone. + --- ## License diff --git a/pyproject.toml b/pyproject.toml index a208b70..eb71024 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ Changelog = "https://github.com/cryptnox/cryptnox-id-cli/blob/main/CHANGELOG.md" [project.optional-dependencies] dev = [ "pytest>=7.4", + "pytest-cov>=5.0", "ruff>=0.4", "mypy>=1.8", "pyinstaller>=6.0", @@ -103,4 +104,20 @@ markers = [ "real_card: test requires a physical card on the ACS reader (opt-in)", "destructive: test mutates the card; requires CRYPTNOX_ALLOW_DESTRUCTIVE_TESTS=1", ] +# Deliberately no --cov here: it would make a bare `pytest` fail for anyone without +# pytest-cov installed, and slow every local run. CI passes the flags explicitly. addopts = "-ra" + +[tool.coverage.run] +source = ["cryptnox_id_cli"] +branch = true + +[tool.coverage.report] +show_missing = true +skip_covered = true +# NOTE: with branch = true, this gate compares the COMBINED statement-and-branch +# percentage that `coverage report` prints - not line coverage alone. At the time +# this gate was introduced the three numbers were 60.25% combined, 64.11% line, +# 43.62% branch, so reading it as a line-coverage floor overstates the suite by +# four points. Raise it in the same commit as the tests that earn the increase. +fail_under = 60