Skip to content

Commit 5dfdee3

Browse files
authored
[CI]: Improve CI and split out coverage as separate workflow (#29)
## Description Separates coverage analysis from the CI test workflow into an independent `coverage.yml` workflow, and applies several CI hardening improvements. **Changes:** - **Split coverage into `coverage.yml`**: Coverage collection, reporting, and threshold enforcement now run in a dedicated workflow with a single Python 3.12 job, independent from the test matrix. This gives separate status checks in PRs — `CI` for correctness, `Coverage` for quality — enabling independent branch protection policies (e.g., requiring CI but making coverage advisory). - **Remove `--cov` from test workflow**: The `test` job in `ci.yml` now runs plain `pytest` without coverage instrumentation, simplifying the job and slightly improving test performance. - **Add `needs: lint` to test job**: Tests now wait for lint to pass before running, avoiding wasted compute on 3 matrix jobs when the code doesn't lint. - **Add `timeout-minutes: 10` to all jobs**: Prevents hung jobs from consuming runners for the default 6-hour limit. - **Coverage Job Summary**: The coverage workflow writes a markdown coverage table directly to the GitHub Actions Job Summary page, providing visibility without external services or artifact downloads. - **Separated failure signals**: Test failures and coverage threshold failures produce distinct step-level signals in the coverage workflow. The threshold is enforced via `pyproject.toml` `[tool.coverage.report] fail_under` (DRY — single source of truth). ## Breaking changes None. No changes to runtime code, test code, or pyproject.toml configuration. Branch protection rules may need updating to add the new `Coverage` status check if desired. ## Checklist - [x] `pre-commit run --all-files` passes - [x] Tests added or updated for changes <!-- No test changes needed — CI workflow only --> - [x] Documentation updated <!-- Self-documenting: workflow comments explain non-obvious behaviors -->
1 parent 23f1f18 commit 5dfdee3

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
lint:
1717
name: Lint & Type Check
1818
runs-on: ubuntu-latest
19+
timeout-minutes: 10
1920
permissions:
2021
contents: read
2122
steps:
@@ -48,7 +49,9 @@ jobs:
4849

4950
test:
5051
name: Test (Python ${{ matrix.python-version }})
52+
needs: lint
5153
runs-on: ubuntu-latest
54+
timeout-minutes: 10
5255
permissions:
5356
contents: read
5457
strategy:
@@ -76,5 +79,4 @@ jobs:
7679
run: uv sync --frozen
7780

7881
- name: Run tests
79-
# Coverage threshold (fail_under) is enforced via pyproject.toml [tool.coverage.report]
80-
run: uv run pytest tests/unit --cov=rampart --cov-report=xml --cov-report=term-missing
82+
run: uv run pytest tests/unit

.github/workflows/coverage.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Coverage
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
concurrency:
10+
group: coverage-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions: {}
14+
15+
jobs:
16+
coverage:
17+
name: Coverage
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 10
20+
permissions:
21+
contents: read
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25+
with:
26+
persist-credentials: false
27+
28+
- name: Set up Python
29+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
30+
with:
31+
python-version: "3.12"
32+
33+
- name: Set up uv
34+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
35+
with:
36+
enable-cache: true
37+
38+
- name: Install dependencies
39+
run: uv sync --frozen
40+
41+
- name: Run tests with coverage
42+
id: tests
43+
# --cov-fail-under=0 overrides pyproject.toml [tool.coverage.report] fail_under
44+
# so pytest doesn't exit non-zero on low coverage; threshold is checked separately below.
45+
run: uv run pytest tests/unit --cov=rampart --cov-report=term-missing --cov-fail-under=0
46+
47+
- name: Coverage summary
48+
if: ${{ steps.tests.outcome == 'success' }}
49+
run: |
50+
echo '## Coverage Report' >> $GITHUB_STEP_SUMMARY
51+
uv run coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
52+
53+
- name: Check coverage threshold
54+
if: ${{ steps.tests.outcome == 'success' }}
55+
# Threshold is defined in pyproject.toml [tool.coverage.report] fail_under
56+
run: uv run coverage report

0 commit comments

Comments
 (0)