Coverage Ingestion
CodeStax reads your test-coverage reports to compute the Coverage A–E rating, emit coverage-gap findings, and drive the new_coverage_min quality gate. Four formats are supported out of the box.
Supported Formats
| Format | File pattern | Language/framework examples |
|---|---|---|
| LCOV | lcov.info, coverage.lcov | JS/TS (Jest, Vitest), C/C++ (gcov), Python (coverage.py --lcov) |
| Cobertura XML | coverage.xml, cobertura.xml, coverage-cobertura.xml | Python (coverage.py), PHP (PHPUnit), Ruby (SimpleCov) |
| JaCoCo XML | jacoco.xml, build/reports/jacoco/test/jacocoTestReport.xml | Java (Maven, Gradle), Kotlin, Scala |
| Clover XML | clover.xml | PHP (PHPUnit), JS (Karma, Jest legacy) |
Two Ways to Ingest
1. Auto-detect (default)
Every scan walks the cloned repo (bounded depth 6) looking for known filenames. Any matches are parsed automatically. No action needed if your CI writes reports to standard paths AND commits them to the scanned branch.
But most teams don’t commit coverage artifacts to the repo. For those, use upload.
2. Upload from CI
Push the coverage report to CodeStax from your CI pipeline after tests run:
# Trigger a scan, get the scan_id back
SCAN_ID=$(curl -sf -X POST \
-H "Authorization: Bearer $CODESTAX_JWT" \
"https://codestax.co/api/scans/trigger/$REPO_ID" | jq -r .id)
# Wait for scan completion, then upload coverage
curl -X POST "https://codestax.co/api/quality/coverage/upload" \
-H "Authorization: Bearer $CODESTAX_JWT" \
-F "scan_id=$SCAN_ID" \
-F "report_format=lcov" \
-F "file=@coverage/lcov.info"Max file size: 25 MB.
CI Recipes
GitHub Actions (LCOV from Jest)
- name: Run tests with coverage
run: npm test -- --coverage
- name: Upload coverage to CodeStax
if: steps.trigger.outputs.scan_id != ''
run: |
curl -X POST "https://codestax.co/api/quality/coverage/upload" \
-H "Authorization: Bearer ${{ secrets.CODESTAX_JWT }}" \
-F "scan_id=${{ steps.trigger.outputs.scan_id }}" \
-F "file=@coverage/lcov.info"GitLab CI (Cobertura from pytest)
test:
script:
- pytest --cov --cov-report=xml
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
after_script:
- |
curl -X POST "https://codestax.co/api/quality/coverage/upload" \
-H "Authorization: Bearer $CODESTAX_JWT" \
-F "scan_id=$SCAN_ID" \
-F "file=@coverage.xml"Jenkins (JaCoCo from Gradle)
stage('Upload coverage to CodeStax') {
steps {
sh '''
curl -X POST "https://codestax.co/api/quality/coverage/upload" \
-H "Authorization: Bearer $CODESTAX_JWT" \
-F "scan_id=$SCAN_ID" \
-F "file=@build/reports/jacoco/test/jacocoTestReport.xml"
'''
}
}What You Get
Once ingested, coverage data drives:
- Coverage rating (A–E) — shipped with every scan in
GET /quality/ratings/:scan_id - Coverage % dashboard widget on scan detail
- Per-file coverage table — sortable, color-coded (below 60% red, below 80% yellow)
- Coverage-gap findings — files below threshold emitted as
type: "coverage_gap"with severity new_coverage_minquality gate — configurable threshold in org policy
Thresholds
Default thresholds for coverage-gap findings:
- Files < 60% coverage →
highseverity - Files ≥ 60% but < configured
quality_coverage_low_threshold(default 60) → not emitted unless customized - Files < 30% →
critical
Configurable per-org via scanner config:
quality_coverage_low_threshold(default 60)quality_coverage_critical_threshold(default 30)
Tiny files (< 20 lines) are skipped to reduce noise.
Auto-Detect Path Matching
The auto-detector scans these paths in your cloned repo (up to 6 dirs deep from root):
lcov.info/coverage.lcov/lcov-report.infocoverage.xml/cobertura.xml/cobertura-coverage.xml/coverage-cobertura.xmljacoco.xml/jacocoTestReport.xmlclover.xml
Skipped dirs: node_modules, .git, __pycache__, .venv, venv, env, dist, .next, .nuxt, .cache.
Querying Coverage
# Get aggregate + per-file
curl -H "Authorization: Bearer $JWT" \
https://codestax.co/api/quality/coverage/12345 | jq
# Output shape:
# {
# "scan_id": 12345,
# "file_count": 847,
# "lines_total": 42100,
# "lines_covered": 38700,
# "coverage_pct": 91.92,
# "files": [ { file_path, lines_total, lines_covered, ... } ]
# }Common Issues
| Symptom | Cause | Fix |
|---|---|---|
| Coverage widget empty after scan | No reports found + no upload | Add upload step to CI, or commit reports |
| ”Format detection failed” | Unknown extension | Pass explicit report_format=<lcov|cobertura|jacoco|clover> |
| File > 25 MB rejected | Report too big | Split by package, or upload multiple times per subdir |
| File paths don’t match source | Absolute paths in report | Use --cov-report=xml:<path> flags to write relative paths |
Related
- Coverage Scanner
- Quality Ratings
- Set Up Quality Gates — enforce coverage thresholds on PRs