DeepSource Autofix and Test Coverage Enforcement: A Practical Guide
DeepSource combines static analysis with automated code fixes — it doesn't just report issues, it opens PRs to fix them. This guide covers DeepSource setup, autofix configuration, coverage enforcement, and integrating quality gates into your CI pipeline.
What Makes DeepSource Different
Most code quality tools report problems and stop. DeepSource goes further:
- Autofix PRs — for many issues, DeepSource opens a pull request with the fix already written
- Transformers — automated code style and formatting fixes (Black, isort, gofmt, Prettier)
- Coverage enforcement — sets a minimum coverage threshold and fails PRs that drop below it
- Native GitHub/GitLab integration — no separate CI step; analysis runs on DeepSource's infrastructure
This changes the workflow from "find issues → manually fix" to "find issues → accept fix PR."
Setup
Connect to GitHub
- Go to deepsource.io and sign in with GitHub
- Select your repository to analyze
- DeepSource auto-detects your tech stack and suggests analyzers
Create .deepsource.toml
All DeepSource configuration lives in .deepsource.toml at the repo root:
version = 1
[[analyzers]]
name = "python"
enabled = true
[analyzers.meta]
runtime_version = "3.x.x"
max_line_length = 120
[[analyzers]]
name = "test-coverage"
enabled = true
[analyzers.meta]
should_fail_with_low_coverage = true
coverage_threshold = 80
[[analyzers]]
name = "secrets"
enabled = true
[[transformers]]
name = "black"
enabled = true
[[transformers]]
name = "isort"
enabled = trueFor JavaScript/TypeScript:
version = 1
[[analyzers]]
name = "javascript"
enabled = true
[analyzers.meta]
environment = ["browser", "node"]
[[analyzers]]
name = "typescript"
enabled = true
[[analyzers]]
name = "test-coverage"
enabled = true
[analyzers.meta]
should_fail_with_low_coverage = true
coverage_threshold = 75
[[transformers]]
name = "prettier"
enabled = true
[[transformers]]
name = "eslint"
enabled = trueFor Go:
version = 1
[[analyzers]]
name = "go"
enabled = true
[[analyzers]]
name = "test-coverage"
enabled = true
[analyzers.meta]
should_fail_with_low_coverage = true
coverage_threshold = 70
[[transformers]]
name = "gofmt"
enabled = trueAutofix in Practice
When DeepSource finds a fixable issue, it opens a PR from a deepsource-fix branch. The PR description explains the issue and shows the diff.
What DeepSource Can Autofix
Python:
E501— line too long (reformatted by Black)isortviolations — import orderingW292— no newline at end of fileF401— unused importsE711— comparison to None with==(should beis)- Security:
B105— hardcoded password string - Antipatterns: mutable default arguments, incorrect
super()usage
JavaScript/TypeScript:
- ESLint fixable rules (
no-var,prefer-const,arrow-body-style, semicolons) - Prettier formatting violations
no-unused-vars(can auto-remove in some cases)- Import ordering
Java:
- Unused imports
- String comparisons with
==instead of.equals() - Empty catch blocks (adds comment)
Reviewing Autofix PRs
Autofix PRs should be reviewed, not blindly merged. Common gotchas:
- Black reformats long strings in ways that lose intentional alignment
- isort changes import order in files with conditional imports that depend on order
- Removing "unused" imports that are actually used for side effects
Configure which autofixes run by enabling/disabling individual transformers in .deepsource.toml.
Test Coverage Enforcement
Uploading Coverage Reports
DeepSource requires you to upload coverage in your CI pipeline:
Python (pytest):
# .github/workflows/test.yml
- name: Run tests with coverage
run: |
pip install pytest pytest-cov
pytest --cov=src --cov-report xml:coverage.xml
- name: Upload coverage to DeepSource
uses: deepsourcelabs/test-coverage-action@master
with:
key: python
coverage-file: coverage.xml
dsn: ${{ secrets.DEEPSOURCE_DSN }}JavaScript (Jest):
- name: Run tests with coverage
run: |
npm run test -- --coverage --coverageReporters=lcov
- name: Upload coverage to DeepSource
uses: deepsourcelabs/test-coverage-action@master
with:
key: javascript
coverage-file: coverage/lcov.info
dsn: ${{ secrets.DEEPSOURCE_DSN }}Go:
- name: Run tests with coverage
run: go test ./... -coverprofile=coverage.out
- name: Convert to lcov format
run: |
go install github.com/jandelgado/gcov2lcov@latest
gcov2lcov -infile=coverage.out -outfile=coverage.lcov
- name: Upload coverage to DeepSource
uses: deepsourcelabs/test-coverage-action@master
with:
key: go
coverage-file: coverage.lcov
dsn: ${{ secrets.DEEPSOURCE_DSN }}DSN (Data Source Name)
Find your DSN in DeepSource Dashboard → Settings → Reporting → Test Coverage:
DEEPSOURCE_DSN=https://yourtoken@deepsource.ioAdd this as a GitHub repository secret.
Configuring Coverage Thresholds
In .deepsource.toml, the coverage analyzer configuration:
[[analyzers]]
name = "test-coverage"
enabled = true
[analyzers.meta]
# Fail PRs that drop overall coverage below this %
should_fail_with_low_coverage = true
coverage_threshold = 80
# Allow coverage to drop by this amount on PRs (avoid blocking every PR)
max_decrease_threshold = 2With should_fail_with_low_coverage = true, DeepSource reports a failing check on GitHub PRs when:
- Overall coverage drops below
coverage_threshold - Coverage on the PR's changed files is below threshold
Per-File Coverage Visibility
DeepSource shows coverage per file in the PR diff. This makes it easy to see exactly which new lines aren't covered, rather than just an overall percentage.
Analyzer Configuration Deep Dive
Python Analyzer
[[analyzers]]
name = "python"
enabled = true
[analyzers.meta]
runtime_version = "3.x.x"
max_line_length = 120
# Skip specific files
skip_doc_coverage = false # Set true to not require docstrings
# Enable specific checks
type_stubs = ["boto3-stubs", "types-requests"]Disabling Specific Issues
Add inline comments to suppress specific issues:
import os # noqa: F401 - used by downstream modules via __init__.py
password = "dev-only-not-prod" # skipcq: PY-A0001 - local dev config onlyOr configure globally in .deepsource.toml:
[[analyzers]]
name = "python"
enabled = true
[analyzers.meta]
skip_issues = ["PY-W0069", "PYL-W0611"]Running DeepSource Locally
The deepsource CLI lets you run analysis locally before pushing:
# Install
curl https://deepsource.io/cli <span class="hljs-pipe">| sh
<span class="hljs-comment"># Analyze current directory
deepsource analyze --directory . --analyzer python
<span class="hljs-comment"># Upload coverage from local test run
deepsource report --analyzer test-coverage --key python --value-file coverage.xmlComparing DeepSource to Alternatives
| Feature | DeepSource | SonarQube | CodeClimate |
|---|---|---|---|
| Autofix PRs | ✅ | ❌ | ❌ |
| Auto-transformers | ✅ (Black, Prettier, gofmt) | ❌ | ❌ |
| Self-hosting | ✅ (Enterprise) | ✅ | ❌ |
| Secrets detection | ✅ | ✅ | ❌ |
| Custom rules | Limited | ✅ (Java plugins) | Limited |
| Pricing (OSS) | Free | Free (SonarCloud) | Free |
DeepSource's autofix is its standout feature. For teams drowning in "your code has 847 issues" reports, automated fixes convert backlog into merged PRs.
Full CI Workflow
name: CI with DeepSource
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt pytest pytest-cov
- name: Run tests
run: |
pytest \
--cov=src \
--cov-report=xml:coverage.xml \
tests/
- name: Upload coverage to DeepSource
uses: deepsourcelabs/test-coverage-action@master
if: always() # Upload even if tests fail
with:
key: python
coverage-file: coverage.xml
dsn: ${{ secrets.DEEPSOURCE_DSN }}Note: Always upload coverage even when tests fail (if: always()). This lets DeepSource show which tests failed and what coverage those failures affect.
Summary
DeepSource's autofix workflow is its primary differentiator:
- Static analysis finds issues — bugs, security vulnerabilities, code smells
- Autofix opens a PR — you review and merge, not manually implement
- Transformers format code — Black, isort, Prettier run on push
- Coverage gate blocks merges — PRs that drop below threshold fail CI
For teams with significant technical debt, the autofix feature converts abstract "we should fix this" into concrete "here's the PR, approve it."
The coverage enforcement is straightforward but effective: define a threshold in .deepsource.toml, upload coverage in CI, and let DeepSource block merges that regress coverage below the line.