Skip to content

Commit 25d0235

Browse files
committed
✨ Template | CI: add coverage (none/basic/codecov)
Generated packages can now optionally include test coverage measurement and CI enforcement. A new `coverage` Copier question offers three tiers: `none` (default, preserving current behavior), `basic` (50% minimum threshold with GitHub Actions job summary), and `codecov` (Codecov upload with a `.codecov.yml` that prevents coverage regression). The CI workflow is converted from static YAML to a Jinja template (`ci.yaml.jinja`) so the test step can be conditionalized. Coverage config (`[tool.coverage.run]`, `[tool.coverage.report]`) is added to the generated `pyproject.toml` for the `basic` and `codecov` tiers. Also adds `hatch run test-cov` to the template repo for local coverage verification, and updates feature lists and developer docs to reflect the new capability.
1 parent 0684d81 commit 25d0235

9 files changed

Lines changed: 105 additions & 41 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ Template for Python packages based on [`copier`](https://copier.readthedocs.io/e
88

99
* 📦 **Package management**:
1010
- Develop with your preferred tools (extras, [`uv`](https://docs.astral.sh/uv/) or [Hatch](https://hatch.pypa.io/)).
11+
- Bespoke dev tooling for generating CHANGELOGs automatically based on emoji-typed commit messages.
1112
- Build your package with [Hatch](https://hatch.pypa.io/).
1213
* 🧹 [**Pre-commit**](https://pre-commit.com/): Format and lint your code with [Ruff](https://docs.astral.sh/ruff/).
13-
* 🧪 **Tests**: Write tests with [`pytest`](https://docs.pytest.org/en/stable/).
14+
* 🧪 **Tests**: Write tests with [`pytest`](https://docs.pytest.org/en/stable/), with optional coverage reporting (basic summary or [Codecov](https://about.codecov.io/) integration).
1415
* 📚 **Documentation**: Write docs in [MyST](https://mystmd.org/) or [MkDocs](https://www.mkdocs.org/).
1516
* ⚙️ **GitHub Actions**:
1617
* Deploy documentation to [GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site) or [Read the Docs](https://about.readthedocs.com/).

copier.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ type_check:
3131
- strict
3232
default: loose
3333

34+
coverage:
35+
type: str
36+
help: 'What level of test coverage reporting do you want?'
37+
choices:
38+
- none
39+
- basic
40+
- codecov
41+
default: none
42+
3443
_subdirectory: template
3544
_message_after_copy: |
3645
The `{{package_name}}` package has been created successfully!

docs/developer.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ Other scripts for the default environment:
2727
* `check`: Copy/Update the template in the `.tmp` directory and check the rendered files by linting them with `hatch fmt -l`.
2828
* `clean`: Remove the `.tmp` directory and any Ruff caches.
2929
* `install`: Copy/Update the template in the `.tmp` directory and install it with `uv pip install`.
30-
* `test`: Copy/Update the template in the `.tmp` directory run the test suite with `pytest`.
30+
* `test`: Copy/Update the template in the `.tmp` directory and run the test suite with `pytest`.
31+
* `test-cov`: Copy/Update the template in the `.tmp` directory and run the test suite with coverage enabled.
3132

3233
## Documentation
3334

docs/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ A `copier`-based template for Python packages.
66

77
* 📦 **Package management**:
88
- Develop with your preferred tools (extras, [`uv`](https://docs.astral.sh/uv/) or [Hatch](https://hatch.pypa.io/)).
9+
- Bespoke dev tooling for generating CHANGELOGs automatically based on emoji-typed commit messages.
910
- Build your package with [Hatch](https://hatch.pypa.io/).
1011
* 🧹 [**Pre-commit**](https://pre-commit.com/): Format and lint your code with [Ruff](https://docs.astral.sh/ruff/).
11-
* 🧪 **Tests**: Write tests with [`pytest`](https://docs.pytest.org/en/stable/).
12+
* 🧪 **Tests**: Write tests with [`pytest`](https://docs.pytest.org/en/stable/), with optional coverage reporting (basic summary or [Codecov](https://about.codecov.io/) integration).
1213
* 📚 **Documentation**: Write docs in [MyST](https://mystmd.org/) or [MkDocs](https://www.mkdocs.org/).
1314
* ⚙️ **GitHub Actions**:
1415
* Deploy documentation to [GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site) or [Read the Docs](https://about.readthedocs.com/).

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ scripts.test = [
1919
"copier copy --vcs-ref=HEAD . .tmp/py-package -f",
2020
"cd .tmp/py-package && hatch test -v -- -s",
2121
]
22+
scripts.test-cov = [
23+
"copier copy --vcs-ref=HEAD . .tmp/py-package -f",
24+
"cd .tmp/py-package && hatch test --cover -v -- -s",
25+
]
2226
scripts.clean = [
2327
"ruff clean",
2428
"rm -rf .tmp",

template/.github/workflows/ci.yaml

Lines changed: 0 additions & 38 deletions
This file was deleted.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
pre-commit:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Install Python
16+
uses: actions/setup-python@v5
17+
with:
18+
python-version: '3.13'
19+
20+
- name: Install Hatch
21+
run: pip install hatch
22+
23+
- name: Run pre-commit
24+
run: hatch run pre-commit:run --all-files
25+
26+
tests:
27+
runs-on: ubuntu-latest
28+
strategy:
29+
matrix:
30+
python-version: ['3.10', '3.14']
31+
32+
steps:
33+
- uses: actions/checkout@v4
34+
- uses: actions/setup-python@v5
35+
with:
36+
python-version: {% raw %}${{ matrix.python-version }}{% endraw %}
37+
- run: pip install hatch
38+
{%- if coverage == 'none' %}
39+
- run: hatch test
40+
{%- else %}
41+
- run: hatch test --cover --cover-min 50
42+
43+
- name: Install coverage
44+
if: always()
45+
run: pip install coverage[toml]
46+
47+
- name: Coverage summary
48+
if: always()
49+
run: |
50+
echo '## Test Coverage' >> $GITHUB_STEP_SUMMARY
51+
echo '```' >> $GITHUB_STEP_SUMMARY
52+
coverage report >> $GITHUB_STEP_SUMMARY 2>&1 || true
53+
echo '```' >> $GITHUB_STEP_SUMMARY
54+
{%- endif %}
55+
{%- if coverage == 'codecov' %}
56+
57+
- name: Generate coverage XML
58+
if: always()
59+
run: coverage xml
60+
61+
- name: Upload coverage to Codecov
62+
if: always()
63+
uses: codecov/codecov-action@v5
64+
with:
65+
files: coverage.xml
66+
fail_ci_if_error: false
67+
{%- endif %}

template/pyproject.toml.jinja

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ run = "pytest {args}"
8282

8383
[[tool.hatch.envs.hatch-test.matrix]]
8484
python = ["3.10", "3.11", "3.12", "3.13", "3.14"]
85+
{%- if coverage != 'none' %}
86+
87+
[tool.coverage.run]
88+
source = ["{{ package_name.lower().replace('-', '_') }}"]
89+
branch = true
90+
91+
[tool.coverage.report]
92+
show_missing = true
93+
{%- endif %}
8594

8695
[tool.ruff]
8796
lint.ignore = [
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
coverage:
2+
status:
3+
project:
4+
default:
5+
target: auto
6+
threshold: 0%
7+
patch:
8+
default:
9+
target: auto
10+
threshold: 0%

0 commit comments

Comments
 (0)