CI/CD and Coverage Guide
This guide explains the continuous integration (CI) pipeline and code coverage reporting setup for britecore_sdk.
Overview
The project uses:
GitHub Actions — automated testing, linting, docs building
DeepSource — static analysis and coverage tracking
Codecov — coverage artifacts storage
pytest — test framework with coverage collection
GitHub Actions Workflows
Location
.github/workflows/
├── tests.yml # Run pytest + coverage on all Python versions
├── lint.yml # Run ruff, black, mypy checks
├── ci.yml # Coordination job
└── docs.yml # Build Sphinx documentation
tests.yml — Test Matrix
Trigger: Push to master, main, develop; pull requests to these branches
What it does:
Run tests on Python 3.11, 3.12, 3.13, 3.14 (full matrix)
Collect coverage from all runs
Upload coverage to Codecov and DeepSource (from Python 3.11, non-randomized run)
Generate coverage HTML report
Key steps:
- name: Run tests with pytest
run: pytest tests/ -v --cov=src/britecore_sdk --cov-report=xml
- name: Upload coverage to Codecov
if: matrix.python-version == '3.11'
uses: codecov/codecov-action@v4
- name: Report test coverage to DeepSource
if: matrix.python-version == '3.11' && matrix.randomized == false
uses: deepsourcelabs/test-coverage-action@master
with:
key: python
coverage-file: coverage.xml
dsn: ${{ secrets.DEEPSOURCE_DSN }}
Why one canonical upload only?
Tests run on all versions for compatibility
But uploading from every matrix leg creates duplicate/noisy reports
3.11 is the minimum supported version, so it’s canonical
lint.yml — Code Quality
Trigger: Same as tests
What it does:
Run ruff (linting: E9, F63, F7, F82)
Run black (formatting check)
Run mypy (type checking on core modules)
Passes silently — all checks use continue-on-error: true to not block PRs.
docs.yml — Documentation Build
Trigger: Same as tests
What it does:
Install Sphinx + dependencies
Build docs using the dummy builder (quick validation)
Upload
htmlcov/artifacts
Why dummy builder?
Fast validation that docs syntax is correct
Doesn’t generate full HTML (that’s optional locally)
Ensures docs can be built in any environment
ci.yml — Coordination
Simple status check. Can be expanded for complex workflows.
DeepSource Integration
What it does
DeepSource runs on every PR to:
Static analysis — finds code smell, potential bugs
Test coverage — tracks which code paths are tested
Secret detection — flags committed credentials and tokens
Enabled Analyzers
In .deepsource.toml:
[[analyzers]]
name = "python" # Static analysis
enabled = true
[analyzers.meta]
runtime_version = "3.x.x"
max_line_length = 120
skip_doc_coverage = ["module", "magic", "init", "class", "nonpublic"]
[[analyzers]]
name = "secrets" # Credential detection
enabled = true
[[analyzers]]
name = "test-coverage" # Coverage tracking
enabled = true
Setup (One-time)
Connect GitHub repo to DeepSource:
Go to app.deepsource.com
Link your GitHub account
Add
sshimek42/britecore_sdk
Add
DEEPSOURCE_DSNsecret to GitHub:In DeepSource → Settings → Integrations → Reporting
Copy the DSN value
In GitHub → Settings → Secrets → Actions
Create secret:
DEEPSOURCE_DSN= (paste DSN)
Verify in PR:
Open a PR or push to your branch
Check that DeepSource status check appears
All analyzers should be green
Understanding DeepSource Results
PR Check Status:
✅ All checks passed — No new issues, coverage acceptable
⚠️ Analysis warnings — New static-analysis or documentation/style findings were reported
🔴 Analysis failed — Issues found (security, type errors, etc.)
Coverage Interpretation:
Lines covered — Code paths executed by tests
Uncovered lines — Code paths not tested
Covered % — Percentage of total lines with test coverage
Common findings:
PYL-W0404— Duplicate import (low severity, often defer)PTC-W0062— Mergeablewithblocks (cosmetic, safe to ignore)PYL-E0401— Import errors (fix immediately)
Workflow
Push feature branch → DeepSource runs analysis
Review PR checks → DeepSource shows issues (if any)
Fix issues (or suppress if false positive) → Commit
Checks pass → Ready to merge
Coverage Reports
Codecov
Purpose: Long-term coverage tracking and trend analysis
What’s uploaded: coverage.xml from pytest-cov
Access:
GitHub PR → Codecov check → “View report on Codecov”
Or:
https://app.codecov.io/gh/sshimek42/britecore_sdk
Useful for:
Tracking coverage over time
Comparing coverage across branches
Setting coverage gates (e.g., fail if coverage drops below 75%)
DeepSource Coverage
Purpose: Integrated coverage analysis (alongside static analysis)
What’s uploaded: coverage.deepsource.xml (a path-rewritten copy of coverage.xml) via deepsourcelabs/test-coverage-action
Why a separate file?
pytest-cov with --cov=src/britecore_sdk produces coverage.xml with package-relative paths
(e.g., __init__.py, api/britecore_api_client.py). DeepSource requires repo-relative paths
(e.g., src/britecore_sdk/__init__.py) to map files back to VCS. The CI step
“Rewrite coverage paths for DeepSource” patches all filename attributes before upload.
Access:
GitHub PR → DeepSource check → Link to run
Or:
https://app.deepsource.com/gh/sshimek42/britecore_sdk
Useful for:
Flagging uncovered code paths in PRs
Setting baseline coverage requirements
Visualizing coverage + issues together
Troubleshooting “files not present in VCS” warning:
If DeepSource reports coverage files not found in VCS, check that:
The “Rewrite coverage paths for DeepSource” CI step ran (only on
python-version == '3.11' && randomized == false).coverage.deepsource.xmlwas generated — if not, the DeepSource step falls back to an empty report.coverage.xmlexists in the repo root after the pytest step.
Local Coverage Reports
After running tests locally:
pytest tests/ --cov=src/britecore_sdk --cov-report=html
open htmlcov/index.html
This creates a local HTML report showing line-by-line coverage.
Test Coverage Targets
From pytest.ini:
[pytest]
addopts = --cov=src/britecore_sdk --cov-report=html --cov-report=term-missing --strict-markers
Coverage gate:
From .github/workflows/tests.yml:
- name: Generate coverage report
run: coverage report --fail-under=72
Current enforced baseline: 72% coverage
Ratchet policy:
Do not decrease
--fail-underonce raised.Raise by +1 to +2 only when test additions make the increase sustainable.
Near-term target is to move from 72% to 75%, then continue stepping upward.
Modules with higher expectations:
src/britecore_sdk/settings/— 90%+src/britecore_sdk/api/britecore_api_client.py— 80%+Core validators — 85%+
Local Testing and Coverage
Install Dev Dependencies
pip install -e ".[dev]"
Run All Tests
pytest tests/ -v --cov=src/britecore_sdk --cov-report=html
Run Specific Test Category
# Unit tests only
pytest tests/unit -m unit -v
# Integration tests only
pytest tests/integration -m integration -v
# Slow tests (sandbox)
pytest tests/ -m slow -v
Check Coverage for Specific Module
coverage report src/britecore_sdk/api/britecore_api_client.py
Run Linters Locally
# Ruff
ruff check src/britecore_sdk
# Black (check only)
black --check src/britecore_sdk
# MyPy
mypy src/britecore_sdk
Troubleshooting CI
“DeepSource: Python” or “test-coverage” check is failing
Common causes:
Missing
DEEPSOURCE_DSNsecretCheck GitHub → Settings → Secrets
Confirm secret is named exactly
DEEPSOURCE_DSNRegenerate if unsure (DeepSource → Settings → Integrations → Reporting)
Python analyzer misconfiguration
Check
.deepsource.tomlhas:[[analyzers]] name = "python" enabled = true
Verify
runtime_version = "3.x.x"in meta section
Test-coverage analyzer not enabled
Check
.deepsource.tomlhas:[[analyzers]] name = "test-coverage" enabled = true
Coverage.xml not generated
Ensure
pytestcommand includes--cov-report=xmlCheck
coverage.xmlexists in repo root after local test run
Debug steps:
# Run tests locally and verify coverage.xml
pytest tests/ --cov=src/britecore_sdk --cov-report=xml
ls coverage.xml # Should exist
# Check DeepSource config syntax
python -c "import tomllib; tomllib.loads(open('.deepsource.toml').read())"
Coverage drop between PRs
Check if coverage gate is enforced:
coverage report --fail-under=72
Add tests for uncovered code:
Run locally:
pytest --cov --cov-report=htmlOpen
htmlcov/index.htmlFind red (uncovered) lines
Add tests for those paths
View coverage per file:
coverage report -m # Shows uncovered lines
Best Practices
Before Pushing
Run tests locally:
pytest tests/ --cov=src/britecore_sdk
Check coverage:
coverage report --fail-under=72
Lint:
black --check src/ ruff check src/ mypy src/britecore_sdk/api/britecore_api_client.py
Verify no uncommitted secrets:
git status # Should not show .secrets.toml modified
In PRs
Address DeepSource issues — don’t suppress unless false positive
Maintain or improve coverage — don’t let it drop
Keep formatting consistent — let black/isort auto-fix
Type-check critical paths — mypy helps catch bugs early
Merging
All CI checks must pass (tests, lint, DeepSource)
Coverage must be >= 72% (current baseline; ratcheted upward over time)
At least one approval from maintainer
Commits should be squashed or well-organized
See Also
tests/README.md — Test suite guide
.github/workflows/tests.yml — Workflow definition
.deepsource.toml — DeepSource configuration
pytest.ini — pytest defaults (test discovery, markers, coverage addopts)
pyproject.toml — coverage, lint, formatter, and mypy settings
Bash Equivalents (Common Local Commands)
pip install -e ".[dev]"
pytest tests/ -v --cov=src/britecore_sdk --cov-report=html
pytest tests/unit -m unit -v
pytest tests/integration -m integration -v
coverage report --fail-under=72
coverage report -m
ruff check src/britecore_sdk
black --check src/britecore_sdk
mypy src/britecore_sdk
python -c "import tomllib; tomllib.loads(open('.deepsource.toml').read())"
git status