Automatically find diff lines that need test coverage. Also finds diff lines that have violations (according to tools such as pycodestyle, pyflakes, flake8, or pylint). This is used as a code quality metric during code reviews.
Diff coverage is the percentage of new or modified lines that are covered by tests. This provides a clear and achievable standard for code review: If you touch a line of code, that line should be covered. Code coverage is every developer's responsibility!
The diff-cover
command line tool compares an XML coverage report
with the output of git diff
. It then reports coverage information
for lines in the diff.
Currently, diff-cover
requires that:
- You are using
git
for version control. - Your test runner generates coverage reports in Cobertura, Clover or JaCoCo XML format.
Supported XML coverage reports can be generated with many coverage tools, including:
- Cobertura (Java)
- Clover (Java)
- JaCoCo (Java)
- coverage.py (Python)
- JSCover (JavaScript)
- lcov_to_cobertura (C/C++)
diff-cover
is designed to be extended. If you are interested
in adding support for other version control systems or coverage
report formats, see below for information on how to contribute!
To install the latest release:
pip install diff_cover
To install the development version:
git clone https://github.com/Bachmann1234/diff-cover.git
cd diff-cover
python setup.py install
- Set the current working directory to a
git
repository. - Run your test suite under coverage and generate a [Cobertura, Clover or JaCoCo] XML report. For example, using pytest-cov:
pytest --cov --cov-report=xml
This will create a coverage.xml
file in the current working directory.
NOTE: If you are using a different coverage generator, you will need to use different commands to generate the coverage XML report.
- Run
diff-cover
:
diff-cover coverage.xml
This will compare the current git
branch to origin/master
and print
the diff coverage report to the console.
You can also generate an HTML, JSON or Markdown version of the report:
diff-cover coverage.xml --html-report report.html
diff-cover coverage.xml --json-report report.json
diff-cover coverage.xml --markdown-report report.md
In the case that one has multiple xml reports form multiple test suites, you
can get a combined coverage report (a line is counted as covered if it is
covered in ANY of the xml reports) by running diff-cover
with multiple
coverage reports as arguments. You may specify any arbitrary number of coverage
reports:
diff-cover coverage1.xml coverage2.xml
You can use diff-cover to see quality reports on the diff as well by running
diff-quality
.
diff-quality --violations=<tool>
Where tool
is the quality checker to use. Currently pycodestyle
, pyflakes
,
flake8
, pylint
, checkstyle
, checkstylexml
are supported, but more
checkers can (and should!) be supported. See the section "Adding diff-quality`
Support for a New Quality Checker".
NOTE: There's no way to run findbugs
from diff-quality
as it operating
over the generated java bytecode and should be integrated into the build
framework.
Like diff-cover
, HTML, JSON or Markdown reports can be generated with
diff-quality --violations=<tool> --html-report report.html
diff-quality --violations=<tool> --json-report report.json
diff-quality --violations=<tool> --markdown-report report.md
If you have already generated a report using pycodestyle
, pyflakes
, flake8
,
pylint
, checkstyle
, checkstylexml
, or findbugs
you can pass the report
to diff-quality
. This is more efficient than letting diff-quality
re-run
pycodestyle
, pyflakes
, flake8
, pylint
, checkstyle
, or checkstylexml
.
# For pylint < 1.0
pylint -f parseable > pylint_report.txt
# For pylint >= 1.0
pylint --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" > pylint_report.txt
# Use the generated pylint report when running diff-quality
diff-quality --violations=pylint pylint_report.txt
# Use a generated pycodestyle report when running diff-quality.
pycodestyle > pycodestyle_report.txt
diff-quality --violations=pycodestyle pycodestyle_report.txt
Note that you must use the -f parseable
option to generate
the pylint
report for pylint versions less than 1.0 and the
--msg-template
option for versions >= 1.0.
diff-quality
will also accept multiple pycodestyle
, pyflakes
, flake8
,
or pylint
reports:
diff-quality --violations=pylint report_1.txt report_2.txt
If you need to pass in additional options you can with the options
flag
diff-quality --violations=pycodestyle --options="--exclude='*/migrations*' --statistics" pycodestyle_report.txt
By default, diff-cover
compares the current branch to origin/master
. To specify a different compare branch:
diff-cover coverage.xml --compare-branch=origin/release
To have diff-cover
and diff-quality
return a non zero status code if the report quality/coverage percentage is
below a certain threshold specify the fail-under parameter
diff-cover coverage.xml --fail-under=80
diff-quality --violations=pycodestyle --fail-under=80
The above will return a non zero status if the coverage or quality score was below 80%.
Issue: diff-cover
always reports: "No lines with coverage information in this diff."
Solution: diff-cover
matches source files in the coverage XML report with
source files in the git diff
. For this reason, it's important
that the relative paths to the files match. If you are using coverage.py
to generate the coverage XML report, then make sure you run
diff-cover
from the same working directory.
Issue: GitDiffTool._execute()
raises the error:
fatal: ambiguous argument 'origin/master...HEAD': unknown revision or path not in the working tree.
This is known to occur when running diff-cover
in Travis CI
Solution: Fetch the remote master branch before running diff-cover
:
git fetch origin master:refs/remotes/origin/master
Issue: diff-quality
reports "diff_cover.violations_reporter.QualityReporterError: No config file found, using default configuration"
Solution: Your project needs a pylintrc file. Provide this file (it can be empty) and diff-quality
should run without issue.
Issue: diff-quality
reports "Quality tool not installed"
Solution: diff-quality
assumes you have the tool you wish to run against your diff installed. If you do not have it
then install it with your favorite package manager.
The code in this repository is licensed under the Apache 2.0 license.
Please see LICENSE.txt
for details.
Contributions are very welcome. The easiest way is to fork this repo, and then make a pull request from your fork. The first time you make a pull request, you may be asked to sign a Contributor Agreement.
NOTE: diff-quality
supports a plugin model, so new tools can be integrated
without requiring changes to this repo. See the section "Adding diff-quality`
Support for a New Quality Checker".
diff-cover is written to support many versions of Python. The best way to set
your machine up for development is to make sure you have tox
installed which
can be installed using pip
.
pip install tox
Now by simply running tox
from the project root you will have environments
for all the supported Python versions. These will be in the .tox
directory.
To create a specific Python dev environment just make a virtualenv for your Python
version and then install the appropriate test-requirements
file.
For example, setting up Python 3:
pyvenv venv
source venv/bin/activate
pip install -r test-requirements.txt
I would also suggest running this command after. This will make it so git blame ignores the commit that formatted the entire codebase.
git config blame.ignoreRevsFile .git-blame-ignore-revs
Adding support for a new quality checker is simple. diff-quality
supports
plugins using the popular Python
[pluggy
package](https://pluggy.readthedocs.io/en/latest/).
If the quality checker is already implemented as a Python package, great! If not, [create a Python package](https://packaging.python.org/tutorials/packaging-projects/) to host the plugin implementation.
In the Python package's setup.py
file, define an entry point for the plugin,
e.g.
Notes:
* The dictionary key for the entry point must be named diff_cover
* The value must be in the format TOOL_NAME = YOUR_PACKAGE.PLUGIN_MODULE
When your package is installed,``diff-quality`` uses this information to
look up the tool package and module based on the tool name provided to the
--violations
option of the diff-quality
command, e.g.:
The plugin implementation will look something like the example below. This is a simplified example based on a working plugin implementation.
Important notes:
* diff-quality
is looking for a plugin function:
- Located in your package's module that was listed in the
setup.py
entry point.- Marked with the
@diff_cover_hookimpl
decorator- Named
diff_cover_report_quality
. (This distinguishes it from any other plugin typesdiff_cover
may support.)
The function should return an object with the following properties and methods: *
supported_extensions
property with a list of supported file extensions *violations()
function that returns a list ofViolation
objects forthe specified
src_path
. For more details on this function and other possible reporting-related methods, see theBaseViolationReporter
class [here](https://github.com/Bachmann1234/diff_cover/blob/master/diff_cover/violationsreporters/base.py).
Shout out to the original author of diff-cover Will Daly and the original author of diff-quality Sarina Canelake.
Originally created with the support of edX.