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:

  1. Run tests on Python 3.11, 3.12, 3.13, 3.14 (full matrix)

  2. Collect coverage from all runs

  3. Upload coverage to Codecov and DeepSource (from Python 3.11, non-randomized run)

  4. 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:

  1. Run ruff (linting: E9, F63, F7, F82)

  2. Run black (formatting check)

  3. 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:

  1. Install Sphinx + dependencies

  2. Build docs using the dummy builder (quick validation)

  3. 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:

  1. Static analysis — finds code smell, potential bugs

  2. Test coverage — tracks which code paths are tested

  3. 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)

  1. Connect GitHub repo to DeepSource:

  2. Add DEEPSOURCE_DSN secret to GitHub:

    • In DeepSource → Settings → Integrations → Reporting

    • Copy the DSN value

    • In GitHub → Settings → Secrets → Actions

    • Create secret: DEEPSOURCE_DSN = (paste DSN)

  3. 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 — Mergeable with blocks (cosmetic, safe to ignore)

  • PYL-E0401 — Import errors (fix immediately)

Workflow

  1. Push feature branch → DeepSource runs analysis

  2. Review PR checks → DeepSource shows issues (if any)

  3. Fix issues (or suppress if false positive) → Commit

  4. 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:

  1. The “Rewrite coverage paths for DeepSource” CI step ran (only on python-version == '3.11' && randomized == false).

  2. coverage.deepsource.xml was generated — if not, the DeepSource step falls back to an empty report.

  3. coverage.xml exists 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-under once 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:

  1. Missing DEEPSOURCE_DSN secret

    • Check GitHub → Settings → Secrets

    • Confirm secret is named exactly DEEPSOURCE_DSN

    • Regenerate if unsure (DeepSource → Settings → Integrations → Reporting)

  2. Python analyzer misconfiguration

    • Check .deepsource.toml has:

      [[analyzers]]
      name = "python"
      enabled = true
      
    • Verify runtime_version = "3.x.x" in meta section

  3. Test-coverage analyzer not enabled

    • Check .deepsource.toml has:

      [[analyzers]]
      name = "test-coverage"
      enabled = true
      
  4. Coverage.xml not generated

    • Ensure pytest command includes --cov-report=xml

    • Check coverage.xml exists 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

  1. Check if coverage gate is enforced:

    coverage report --fail-under=72
    
  2. Add tests for uncovered code:

    • Run locally: pytest --cov --cov-report=html

    • Open htmlcov/index.html

    • Find red (uncovered) lines

    • Add tests for those paths

  3. View coverage per file:

    coverage report -m  # Shows uncovered lines
    

Best Practices

Before Pushing

  1. Run tests locally:

    pytest tests/ --cov=src/britecore_sdk
    
  2. Check coverage:

    coverage report --fail-under=72
    
  3. Lint:

    black --check src/
    ruff check src/
    mypy src/britecore_sdk/api/britecore_api_client.py
    
  4. Verify no uncommitted secrets:

    git status  # Should not show .secrets.toml modified
    

In PRs

  1. Address DeepSource issues — don’t suppress unless false positive

  2. Maintain or improve coverage — don’t let it drop

  3. Keep formatting consistent — let black/isort auto-fix

  4. 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

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