Giter Club home page Giter Club logo

diff_cover's Introduction

diff-cover PyPI version Conda version Build Status

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.

Overview

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, or LCov format.

Supported XML or LCov coverage reports can be generated with many coverage tools, including:

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!

Installation

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
poetry install
poetry shell

Getting Started

  1. Set the current working directory to a git repository.
  2. 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.

  1. Run diff-cover:
diff-cover coverage.xml

This will compare the current git branch to origin/main 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

Multiple XML Coverage Reports

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

Quality Coverage

You can use diff-cover to see quality reports on the diff as well by running diff-quality.

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

Compare Branch

By default, diff-cover compares the current branch to origin/main. To specify a different compare branch:

diff-cover coverage.xml --compare-branch=origin/release

Fail Under

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

Exclude/Include paths

Explicit exclusion of paths is possible for both diff-cover and diff-quality, while inclusion is only supported for diff-quality (since 5.1.0).

The exclude option works with fnmatch, include with glob. Both options can consume multiple values. Include options should be wrapped in double quotes to prevent shell globbing. Also they should be relative to the current git directory.

diff-cover coverage.xml --exclude setup.py
diff-quality --violations=pycodestyle --exclude setup.py

diff-quality --violations=pycodestyle --include project/foo/**

The following is executed for every changed file:

  1. check if any include pattern was specified
  2. if yes, check if the changed file is part of at least one include pattern
  3. check if the file is part of any exclude pattern

Ignore/Include based on file status in git

Both diff-cover and diff-quality allow users to ignore and include files based on the git status: staged, unstaged, untracked:

  • --ignore-staged: ignore all staged files (by default include them)
  • --ignore-unstaged: ignore all unstaged files (by default include them)
  • --include-untracked: include all untracked files (by default ignore them)

Quiet mode

Both diff-cover and diff-quality support a quiet mode which is disable by default. It can be enabled by using the -q/--quiet flag:

diff-cover coverage.xml -q
diff-quality --violations=pycodestyle -q

If enabled, the tool will only print errors and failures but no information or warning messages.

Configuration files

Both tools allow users to specify the options in a configuration file with --config-file/`-c`:

diff-cover coverage.xml --config-file myconfig.toml
diff-quality --violations=pycodestyle --config-file myconfig.toml

Currently, only TOML files are supported. Please note, that only non-mandatory options are supported. If an option is specified in the configuration file and over the command line, the value of the command line is used.

TOML configuration

The parser will only react to configuration files ending with .toml. To use it, install diff-cover with the extra requirement toml.

The option names are the same as on the command line, but all dashes should be underscores. If an option can be specified multiple times, the configuration value should be specified as a list.

[tool.diff_cover]
compare_branch = "origin/feature"
quiet = true

[tool.diff_quality]
compare_branch = "origin/feature"
ignore_staged = true

Troubleshooting

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/main...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 main branch before running diff-cover:

git fetch origin master:refs/remotes/origin/main

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.

Issue: diff-quality reports no quality issues

Solution: You might use a pattern like diff-quality --violations foo *.py. The last argument is not used to specify the files but for the quality tool report. Remove it to resolve the issue

License

The code in this repository is licensed under the Apache 2.0 license. Please see LICENSE.txt for details.

How to Contribute

Contributions are very welcome. The easiest way is to fork this repo, and then make a pull request from your fork.

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

Setting Up For Development

This project is managed with poetry this can be installed with pip poetry manages a python virtual environment and organizes dependencies. It also packages this project.

pip install poetry
poetry install

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 diff-quality Support for a New Quality Checker ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 to host the plugin implementation.

In the Python package's setup.py file, define an entry point for the plugin, e.g.

setup(
    ...
    entry_points={
        'diff_cover': [
            'sqlfluff = sqlfluff.diff_quality_plugin'
        ],
    },
    ...
)

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

$ diff-quality --violations sqlfluff

The plugin implementation will look something like the example below. This is a simplified example based on a working plugin implementation.

from diff_cover.hook import hookimpl as diff_cover_hookimpl
from diff_cover.violationsreporters.base import BaseViolationReporter, Violation

class SQLFluffViolationReporter(BaseViolationReporter):
    supported_extensions = ['sql']

    def __init__(self):
        super(SQLFluffViolationReporter, self).__init__('sqlfluff')

    def violations(self, src_path):
        return [
            Violation(violation.line_number, violation.description)
            for violation in get_linter().get_violations(src_path)
        ]

    def measured_lines(self, src_path):
        return None

    @staticmethod
    def installed():
        return True


@diff_cover_hookimpl
def diff_cover_report_quality():
    return SQLFluffViolationReporter()

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 types diff_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 of Violation objects for the specified src_path. For more details on this function and other possible reporting-related methods, see the BaseViolationReporter class here.

Special Thanks

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.

diff_cover's People

Contributors

abmaonline avatar agroszer avatar bachmann1234 avatar barrywhart avatar bit-ranger avatar bjacobel avatar cpennington avatar dashea avatar dependabot[bot] avatar dundee avatar f18m avatar glyph avatar hugovk avatar ihoover avatar jtauber avatar julian avatar kasium avatar maho avatar mgedmin avatar mihaibivol avatar mr-c avatar msabramo avatar newbery avatar nicoddemus avatar noahp avatar peterg79 avatar sarina avatar singingwolfboy avatar wedaly avatar ziafazal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diff_cover's Issues

diff-quality does not find the driver when giving html-report a full path

This succeeds: diff-quality --violation=flake8 --html-report "index.html"

This fails: diff-quality --violation=flake8 --html-report="test-results/index.html" with Quality tool not installed: 'flake8'

I donโ€™t know whether diff-cover should support full paths ; but the error is confusing.

Thanks !

Option to use external CSS

Jenkins sets a restrictive content security policy that forbids inline CSS. This means diff-cover reports in my Jenkins workspace are basically unreadable: https://issues.jenkins-ci.org/browse/JENKINS-32590

ekrano nuotrauka is 2016-01-25 11-12-30

What do you think about a command-line option --external-css=style.css that would write a separate style.css file and put a <link rel="stylesheet" href="style.css"> instead of the inline <style>...</style> in the generate HTML?

I could create a pull request, if you think adding such a workarund into diff-cover is reasonable.

jacoco - No lines with coverage information in this diff

use the following command, prompt "No lines with coverage information in this diff."

diff-cover coverage.xml --compare-branch=origin/develop

Diff Coverage
Diff: origin/develop...HEAD, staged and unstaged changes
No lines with coverage information in this diff.

Pylint fails to run if no pylintrc is present

$ diff-quality --violations=pylint
Traceback (most recent call last):
  File "/home/kenji/.virtualenvs/whmonit/bin/diff-quality", line 11, in <module>
    sys.exit(main())
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/tool.py", line 344, in main
    ignore_unstaged=arg_dict['ignore_unstaged'],
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/tool.py", line 266, in generate_quality_report
    reporter.generate_report(output_file)
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/report_generator.py", line 216, in generate_report
    report = template.render(self._context())
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/report_generator.py", line 260, in _context
    (src, self._src_path_stats(src)) for src in self.src_paths()
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/report_generator.py", line 83, in src_paths
    return set(src for src, summary in self._diff_violations().items()
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/report_generator.py", line 176, in _diff_violations
    ) for src_path in self._diff.src_paths_changed()
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/report_generator.py", line 176, in <genexpr>
    ) for src_path in self._diff.src_paths_changed()
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/violationsreporters/base.py", line 157, in violations
    output, _ = execute(command)
  File "/home/kenji/.virtualenvs/whmonit/lib/python2.7/site-packages/diff_cover/command_runner.py", line 43, in execute
    raise CommandError(stderr)
diff_cover.command_runner.CommandError: No config file found, using default configuration

This is certainly true that there's no config file, but why is it a fatal error? It should let it do as it says :-). [touch .pylintrc works around it, of course.]

diff-quality checks only the first modified file

Hi,

When running diff-quality --violations pyflakes --compare-branch master (i.e. letting diff-quality run pyflakes itself), only the first modified file is checked.

To reproduce:

git clone [email protected]:fperrin/diff-cover-issue-demo.git
cd diff-cover-issue-demo/
git checkout check_only_first 
diff-quality --violations pyflakes 

This reports only the issue in hello.py, but if you git diff master.. it's obvious you should have a warning in hi.py too.

I think the problem is in violationsreporter.base.QualityReporter.violations; after checking the first file, self.reports is set, so when violations() is called on the second file, it does nothing.

git's noprefix option breaks diff-cover

I have this in my .gitconfig:

[diff]
	noprefix = true

This breaks diff-cover's regex, which expects there to be a/ and b/ prefixes in the diff output.

It's easy enough to disable the option, but I'd love to find a way to have the option for my normal use and have diff-cover still work. :)

Missing CHANGELOG for 2.0

Howdy,

First of all thanks for sharing this tool, it is very useful!

I don't see a CHANGELOG entry for the 2.0 release. Was this an oversight?

Cheers

diff-quality tries to check deleted files

Hi,

When running diff-quality --violations pyflakes --compare-branch master (i.e. letting diff-quality run pyflakes itself), then if files have been deleted, diff-quality tries to run pyflakes on deleted files.

To reproduce:

git clone [email protected]:fperrin/diff-cover-issue-demo.git cd diff-cover-issue-demo/ git checkout try_deleted diff-quality --violations pyflakes --compare-branch master

This fails with pyflakes trying to parse hello.py, which has been deleted in branch try_deleted compared to master.

The following command returns the interesting files to check: git diff --name-only --diff-filter=ACMR master..; however:

  • not sure how supported across git releases the above options are;
  • this would require a second run of git to find the modified line offsets.

diff-quality not picking up quality issues

I've just tried diff-quality for the first time and can't get it to work as expected - it does not pick up problems in style which I see when I run pep8 on the whole file (and on the git diff file).

diff-quality --compare-branch=cclib-master --violations=pep8 *.py
-------------
Diff Quality
Quality Report: pep8
Diff: cclib-master...HEAD, staged, and unstaged changes
-------------
src/cclib/parser/logfileparser.py (100%)
test/data/testvib.py (100%)
-------------
Total:   24 lines
Violations: 0 lines
% Quality: 100%

But if I use git diff to make a file containing the differing lines, and run pep8 on that, it finds style errors I'm expecting, in this case E231 missing whitespace after ',' (as well as errors related to the fact that I'm running pep8 on a diff report rather than a valid python file).

git diff cclib-master:./logfileparser.py logfileparser.py >my_diff
pep8 --show-source my_diff | grep -A 1 E231
my_diff:5:7: E231 missing whitespace after ','
@@ -37,15 +37,35 @@ logging.logMultiprocessing =  0
--
my_diff:5:14: E231 missing whitespace after ','
@@ -37,15 +37,35 @@ logging.logMultiprocessing =  0
--
my_diff:10:34: E231 missing whitespace after ','
+        line = super(bz2.BZ2File,self).__next__()

I also tried running diff-quality with flake8, and pylint and got the same result - no problems highlighted.

Any ideas as to what could be going wrong ?

Run diff-cover error

os: windows 10
python version: 3.6.5
Installed with pip install diff_cover command

error info:
Traceback (most recent call last):
File "D:\program\python\lib\site-packages\pkg_resources_init_.py", line 346, in get_provider
module = sys.modules[moduleOrReq]
KeyError: None

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "D:\program\python\Scripts\diff-cover-script.py", line 11, in
load_entry_point('diff-cover==1.0.7', 'console_scripts', 'diff-cover')()
File "D:\program\python\lib\site-packages\pkg_resources_init_.py", line 480, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "D:\program\python\lib\site-packages\pkg_resources_init_.py", line 2693, in load_entry_point
return ep.load()
File "D:\program\python\lib\site-packages\pkg_resources_init_.py", line 2324, in load
return self.resolve()
File "D:\program\python\lib\site-packages\pkg_resources_init_.py", line 2330, in resolve
module = import(self.module_name, fromlist=['name'], level=0)
File "", line 971, in _find_and_load
File "", line 955, in _find_and_load_unlocked
File "", line 656, in _load_unlocked
File "", line 626, in _load_backward_compatible
File "D:\program\python\lib\site-packages\diff_cover-1.0.7-py3.6.egg\diff_cover\tool.py", line 18, in
File "", line 971, in _find_and_load
File "", line 955, in _find_and_load_unlocked
File "", line 656, in _load_unlocked
File "", line 626, in load_backward_compatible
File "D:\program\python\lib\site-packages\diff_cover-1.0.7-py3.6.egg\diff_cover\report_generator.py", line 181, in
File "D:\program\python\lib\site-packages\jinja2\loaders.py", line 224, in init
provider = get_provider(package_name)
File "D:\program\python\lib\site-packages\pkg_resources_init
.py", line 348, in get_provider
import(moduleOrReq)
TypeError: import() argument 1 must be str, not None

diff-quality --options with quotes do not pass to subprocess properly

To reproduce, I created a test branch and touched one long line in a "migrations" directory. I then ran the example given in the docs:

(addgene-core)pam@bento-local:/projects/addgene-core$ diff-quality --violations=pep8 --options="--exclude='*/migrations*' --statistics" pep8_report.txt
No handlers could be found for logger "diff_cover.tool"
-------------
Diff Quality
Quality Report: pep8
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
src/django/lims/tasks/migrations/0001_initial.py (0.0%):
    24: E501 line too long (130 > 79 characters)
-------------
Total:   1 line
Violations: 1 line
% Quality: 0%
-------------

Diff Cover Version:

(addgene-core)pam@bento-local:/projects/addgene-core$ pip freeze | grep diff
diff-cover==0.9.5

My analysis:

  1. This is a "hard problem" with passing quotes in arguments to Popen (command_runner.py) I think it would work with "shell=True", but that entails a number of security concerns.
  2. The tests make sure that the "--options" value is parsed from the diff-quality command line (test_args.py), but there is no integration test of an "--options" with embedded quotes (test_integrations.py only tests --options="--violations_test_file.py"

Html reporter can have trouble with binary files

Hi! - I spent a bit time looking at this today, but unfortunately I'm out of time.

We had a PR today ( edx/edx-platform#6921 ) which introduced some binary files (including .bcmap and .png). These ended up causing failures when running diff-quality with the --html-report flag. (Without the flag, there are no errors). See console output here: https://build.testeng.edx.org/job/edx-platform-all-tests-pr/1202/SHARD=1,TEST_SUITE=quality,label_exp=jenkins-worker/console

Unfo it is a large commit and I was unable to isolate the offending file(s). I did attempt to reproduce this problem locally by creating a .bin and a .tar file, but I was unable to reproduce the error :( Thought, at best, I could log it here.

`from lazy import lazy` is broken in Python 3.5

3.5 changed the semantics of import a little bit, one result being that the way lazy sets itself up is no longer what is expected. from lazy import lazy ends up with the module lazy.lazy loaded as "lazy" instead of the class within that module, and diff-cover now crashes with "TypeError: 'module' object is not callable"

I've opened a PR to fix lazy at stefanholek/lazy#3 but the project is kind of a ghost town it seems, so I'm not sure how it should best be handled.

diff-quality doesn't work with eslint

I have a git repo with python and javascript files. The structure is:

- docker
- scripts
- my_project
--- static
------ .eslintrc.js
------ package.json
------ js
--- app1
--- app2

The structure is typical for django projects.
Eslint generates reports with absolute path by default, e.g.
/home/godlark/PycharmProjects/mye_repo/my_project/static/js/index.js
but diff-quality expects paths relative to the root directory of repo, e.g.
my_projects/static/js/index.js
I was able to create a custom formatter for eslint to generate reports with relative path, e.g.
js/index.js
But it still doesn't match. The solution is to run in diff-cover command git diff --relative instead git diff

diff-quality won't fail on new Pylint issues?

I want my full test suite to fail when a new pylint problem is introduced.

So I've introduced a function calledLikeThis() which got me a nice
C:112, 4: Invalid method name "calledLikeThis" (invalid-name)
in the worktree, ran my tests, pylint, etc. and then
diff-quality --violations=pylint pylint_report.txt --fail-under=100
But it returns 0 instead of some error code.

Am I doing something wrong or is my usage not the intended one?

generator jacoco html report

Hi,Thank you for your reply.
I use coverage generator is jacoco,want to create the coverage html report.But failed!

command line:
diff-cover app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml --html-report report.html --compare-branch=remote/v2.0.0

error info:
Traceback (most recent call last):
File "/usr/local/bin/diff-cover", line 11, in
sys.exit(main())
File "/Library/Python/2.7/site-packages/diff_cover/tool.py", line 348, in main
exclude=arg_dict['exclude'],
File "/Library/Python/2.7/site-packages/diff_cover/tool.py", line 267, in generate_coverage_report
reporter = HtmlReportGenerator(coverage, diff, css_url=css_url)
UnboundLocalError: local variable 'coverage' referenced before assignment

AttributeError: 'NoneType' object has no attribute 'strip'

Hi,

I use Coverlet to generate a coverage report in cobertura format for my .net project. But I got en error:

AttributeError: 'NoneType' object has no attribute 'strip'

Have I done anything wrong here?
diff-cover coverage.cobertura.xml Traceback (most recent call last): File "C:\Users\c624jh1\AppData\Local\Programs\Python\Python37-32\Scripts\diff-cover-script.py", line 11, in <module> load_entry_point('diff-cover==1.0.5', 'console_scripts', 'diff-cover')() File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\tool.py", line 350, in main src_roots=arg_dict['src_roots'], File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\tool.py", line 279, in generate_coverage_report reporter.generate_report(output_file) File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\report_generator.py", line 215, in generate_report report = template.render(self._context()) File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\report_generator.py", line 259, in _context src: self._src_path_stats(src) for src in self.src_paths() File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\report_generator.py", line 83, in src_paths return {src for src, summary in self._diff_violations().items() File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\report_generator.py", line 175, in _diff_violations for src_path in self._diff.src_paths_changed() File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\report_generator.py", line 175, in <dictcomp> for src_path in self._diff.src_paths_changed() File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\violationsreporters\violations_reporter.py", line 230, in violations self._cache_file(src_path) File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\violationsreporters\violations_reporter.py", line 190, in _cache_file line_nodes = self._get_src_path_line_nodes_cobertura(xml_document, src_path) File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\violationsreporters\violations_reporter.py", line 103, in _get_src_path_line_nodes_cobertura classes = self._get_classes(xml_document, src_path) File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\violationsreporters\violations_reporter.py", line 85, in _get_classes [clazz for clazz in classes if File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\violationsreporters\violations_reporter.py", line 92, in <listcomp> ) for source in sources]] File "c:\users\c624jh1\appdata\local\programs\python\python37-32\lib\site-packages\diff_cover\violationsreporters\violations_reporter.py", line 92, in <listcomp> ) for source in sources]] AttributeError: 'NoneType' object has no attribute 'strip'\

It isn't clear that edx/diff-cover is obsolete

There are commits on edx/diff-cover since the shift over to this repo. Those commits look like duplicates of ones made here. There are also issues opened on the edx/diff-cover repo. Shouldn't we close that repo completely?

question regarding fair use of your open source code

thank you for releasing your code as open source - I find it quite useful.

I am the maintainer of the metrics package and I plan to use 120 lines of your code (parse_diff_lines) for the upcoming metrics.gitinfo plugin.

I see that you use apache 2.0 license so this should be compatible with the MIT license I use.

I am using parse_diff_lines from here:
https://github.com/Bachmann1234/diff-cover/blob/34c9c4c0801137413e9b955f40649a5c2c2ec724/diff_cover/diff_reporter.py

here is how I intend to use your code:
https://github.com/markfink/metrics.gitinfo/blob/master/metrics_gitinfo/git_diff_muncher.py

please let me know if you see any license (or other) issues how I use your code. Thank you.
-Mark

When running pylint, diff-cover will complain about ignored files

When diff-cover runs pylint itself (rather than operating on previously created reports), it runs pylint once per changed file. One of those files could be an ignored file, because it's matched by the [MASTER] ignored= setting in the pylintrc file. In that case, pylint doesn't ignore the file because the explicit file name on the command line overrides the ignored setting in the rc file.

As a result, diff-cover will show pylint errors for ignored files when it runs pylint itself, and won't when it uses pre-created reports.

Running tox looks like it fails, but it succeeds?

I ran tox, and got this output:

$ tox
GLOB sdist-make: /src/devstack/more/diff-cover/setup.py
py26 create: /src/devstack/more/diff-cover/.tox/py26
py26 installdeps: -r/src/devstack/more/diff-cover/requirements/test-requirements-py26.txt, argparse, unittest2
py26 inst: /src/devstack/more/diff-cover/.tox/dist/diff_cover-0.7.4.zip
py26 runtests: PYTHONHASHSEED='3538095435'
py26 runtests: commands[0] | coverage run -m nose
..usage: python2.6 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python2.6 -m nose: error: too few arguments
usage: python2.6 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python2.6 -m nose: error: too few arguments
....usage: python2.6 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python2.6 -m nose: error: argument --violations is required
usage: python2.6 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python2.6 -m nose: error: argument --violations is required
..............................................................................................................................................................
----------------------------------------------------------------------
Ran 164 tests in 2.804s

OK
py26 runtests: commands[1] | coverage xml
py26 runtests: commands[2] | git fetch origin master:refs/remotes/origin/master
WARNING:test command found but not installed in testenv
  cmd: /usr/local/bin/git
  env: /src/devstack/more/diff-cover/.tox/py26
Maybe forgot to specify a dependency?
py26 runtests: commands[3] | diff-cover coverage.xml
-------------
Diff Coverage
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with coverage information in this diff.
-------------
py26 runtests: commands[4] | diff-quality --violation=pep8
-------------
Diff Quality
Quality Report: pep8
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py26 runtests: commands[5] | diff-quality --violation=pyflakes
-------------
Diff Quality
Quality Report: pyflakes
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py26 runtests: commands[6] | diff-quality --violation=pylint
-------------
Diff Quality
Quality Report: pylint
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py27 create: /src/devstack/more/diff-cover/.tox/py27
py27 installdeps: -r/src/devstack/more/diff-cover/requirements/test-requirements-py27-py3.txt
py27 inst: /src/devstack/more/diff-cover/.tox/dist/diff_cover-0.7.4.zip
py27 runtests: PYTHONHASHSEED='3538095435'
py27 runtests: commands[0] | coverage run -m nose
..usage: python2.7 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python2.7 -m nose: error: too few arguments
usage: python2.7 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python2.7 -m nose: error: too few arguments
....usage: python2.7 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python2.7 -m nose: error: argument --violations is required
usage: python2.7 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python2.7 -m nose: error: argument --violations is required
..............................................................................................................................................................
----------------------------------------------------------------------
Ran 164 tests in 2.536s

OK
py27 runtests: commands[1] | coverage xml
py27 runtests: commands[2] | git fetch origin master:refs/remotes/origin/master
WARNING:test command found but not installed in testenv
  cmd: /usr/local/bin/git
  env: /src/devstack/more/diff-cover/.tox/py27
Maybe forgot to specify a dependency?
py27 runtests: commands[3] | diff-cover coverage.xml
-------------
Diff Coverage
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with coverage information in this diff.
-------------
py27 runtests: commands[4] | diff-quality --violation=pep8
-------------
Diff Quality
Quality Report: pep8
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py27 runtests: commands[5] | diff-quality --violation=pyflakes
-------------
Diff Quality
Quality Report: pyflakes
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py27 runtests: commands[6] | diff-quality --violation=pylint
-------------
Diff Quality
Quality Report: pylint
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py33 create: /src/devstack/more/diff-cover/.tox/py33
py33 installdeps: -r/src/devstack/more/diff-cover/requirements/test-requirements-py27-py3.txt
py33 inst: /src/devstack/more/diff-cover/.tox/dist/diff_cover-0.7.4.zip
py33 runtests: PYTHONHASHSEED='3538095435'
py33 runtests: commands[0] | coverage run -m nose
..usage: python3.3 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python3.3 -m nose: error: the following arguments are required: coverage_xml
usage: python3.3 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python3.3 -m nose: error: the following arguments are required: coverage_xml
....usage: python3.3 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python3.3 -m nose: error: the following arguments are required: --violations
usage: python3.3 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python3.3 -m nose: error: the following arguments are required: --violations
..............................................................................................................................................................
----------------------------------------------------------------------
Ran 164 tests in 3.219s

OK
py33 runtests: commands[1] | coverage xml
py33 runtests: commands[2] | git fetch origin master:refs/remotes/origin/master
WARNING:test command found but not installed in testenv
  cmd: /usr/local/bin/git
  env: /src/devstack/more/diff-cover/.tox/py33
Maybe forgot to specify a dependency?
py33 runtests: commands[3] | diff-cover coverage.xml
-------------
Diff Coverage
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with coverage information in this diff.
-------------
py33 runtests: commands[4] | diff-quality --violation=pep8
-------------
Diff Quality
Quality Report: pep8
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py33 runtests: commands[5] | diff-quality --violation=pyflakes
-------------
Diff Quality
Quality Report: pyflakes
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py33 runtests: commands[6] | diff-quality --violation=pylint
-------------
Diff Quality
Quality Report: pylint
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py34 create: /src/devstack/more/diff-cover/.tox/py34
py34 installdeps: -r/src/devstack/more/diff-cover/requirements/test-requirements-py27-py3.txt
py34 inst: /src/devstack/more/diff-cover/.tox/dist/diff_cover-0.7.4.zip
py34 runtests: PYTHONHASHSEED='3538095435'
py34 runtests: commands[0] | coverage run -m nose
..usage: python3.4 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python3.4 -m nose: error: the following arguments are required: coverage_xml
usage: python3.4 -m nose [-h] [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--fail-under FAIL_UNDER] [--ignore-unstaged]
                         coverage_xml [coverage_xml ...]
python3.4 -m nose: error: the following arguments are required: coverage_xml
....usage: python3.4 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python3.4 -m nose: error: the following arguments are required: --violations
usage: python3.4 -m nose [-h] --violations VIOLATIONS
                         [--html-report HTML_REPORT]
                         [--compare-branch COMPARE_BRANCH]
                         [--options [OPTIONS]] [--fail-under FAIL_UNDER]
                         [--ignore-unstaged]
                         [input_reports [input_reports ...]]
python3.4 -m nose: error: the following arguments are required: --violations
..............................................................................................................................................................
----------------------------------------------------------------------
Ran 164 tests in 3.189s

OK
py34 runtests: commands[1] | coverage xml
py34 runtests: commands[2] | git fetch origin master:refs/remotes/origin/master
WARNING:test command found but not installed in testenv
  cmd: /usr/local/bin/git
  env: /src/devstack/more/diff-cover/.tox/py34
Maybe forgot to specify a dependency?
py34 runtests: commands[3] | diff-cover coverage.xml
-------------
Diff Coverage
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with coverage information in this diff.
-------------
py34 runtests: commands[4] | diff-quality --violation=pep8
-------------
Diff Quality
Quality Report: pep8
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py34 runtests: commands[5] | diff-quality --violation=pyflakes
-------------
Diff Quality
Quality Report: pyflakes
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
py34 runtests: commands[6] | diff-quality --violation=pylint
-------------
Diff Quality
Quality Report: pylint
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
pypy create: /src/devstack/more/diff-cover/.tox/pypy
pypy installdeps: -r/src/devstack/more/diff-cover/requirements/test-requirements-py27-py3.txt
pypy inst: /src/devstack/more/diff-cover/.tox/dist/diff_cover-0.7.4.zip
pypy runtests: PYTHONHASHSEED='3538095435'
pypy runtests: commands[0] | coverage run -m nose
..usage: pypy -m nose [-h] [--html-report HTML_REPORT]
                    [--compare-branch COMPARE_BRANCH]
                    [--fail-under FAIL_UNDER] [--ignore-unstaged]
                    coverage_xml [coverage_xml ...]
pypy -m nose: error: too few arguments
usage: pypy -m nose [-h] [--html-report HTML_REPORT]
                    [--compare-branch COMPARE_BRANCH]
                    [--fail-under FAIL_UNDER] [--ignore-unstaged]
                    coverage_xml [coverage_xml ...]
pypy -m nose: error: too few arguments
....usage: pypy -m nose [-h] --violations VIOLATIONS [--html-report HTML_REPORT]
                    [--compare-branch COMPARE_BRANCH] [--options [OPTIONS]]
                    [--fail-under FAIL_UNDER] [--ignore-unstaged]
                    [input_reports [input_reports ...]]
pypy -m nose: error: argument --violations is required
usage: pypy -m nose [-h] --violations VIOLATIONS [--html-report HTML_REPORT]
                    [--compare-branch COMPARE_BRANCH] [--options [OPTIONS]]
                    [--fail-under FAIL_UNDER] [--ignore-unstaged]
                    [input_reports [input_reports ...]]
pypy -m nose: error: argument --violations is required
..............................................................................................................................................................
----------------------------------------------------------------------
Ran 164 tests in 19.640s

OK
pypy runtests: commands[1] | coverage xml
pypy runtests: commands[2] | git fetch origin master:refs/remotes/origin/master
WARNING:test command found but not installed in testenv
  cmd: /usr/local/bin/git
  env: /src/devstack/more/diff-cover/.tox/pypy
Maybe forgot to specify a dependency?
pypy runtests: commands[3] | diff-cover coverage.xml
-------------
Diff Coverage
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with coverage information in this diff.
-------------
pypy runtests: commands[4] | diff-quality --violation=pep8
-------------
Diff Quality
Quality Report: pep8
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
pypy runtests: commands[5] | diff-quality --violation=pyflakes
-------------
Diff Quality
Quality Report: pyflakes
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
pypy runtests: commands[6] | diff-quality --violation=pylint
-------------
Diff Quality
Quality Report: pylint
Diff: origin/master...HEAD, staged, and unstaged changes
-------------
No lines with quality information in this diff.
-------------
___________________________________________________________________________ summary ____________________________________________________________________________
  py26: commands succeeded
  py27: commands succeeded
  py33: commands succeeded
  py34: commands succeeded
  pypy: commands succeeded
  congratulations :)
$

There are many instances of nose complaining about bad arguments, but the test suite claims everything passed. Maybe that nose output should be suppressed?

Command "git diff {branch}...HEAD" fails (master fetch doesn't help)

Jenkins SCM module does the following (minimal representation, it actually does a few more things):

git checkout [email protected]:<path>.git <dir>
cd <dir>
git checkout -f <commit-hash>

If I invoke git diff {branch}...HEAD (as is done by diff-cover), I get the same error as is produced when running diff-cover:

Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Preceding the diff with the recommended fetch does not work either:

git fetch origin $(TARGET_BRANCH):refs/remotes/origin/$(TARGET_BRANCH)

In this case, TARGET_BRANCH is "master", which is the repo's default branch.

Output of "git branch":

% git branch
* (HEAD detached at 0fcb182)
  master

The full Jenkins SCM operation looks like this:

 > git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
 > git config remote.origin.url [email protected]:<repo-path> # timeout=10
Fetching upstream changes from [email protected]:<repo-path>
 > git --version # timeout=10
using GIT_SSH to set credentials 
 > git -c core.askpass=true fetch --tags --progress [email protected]:<repo-path> +refs/pull/*:refs/remotes/origin/pr/* +refs/heads/master:refs/remotes/origin/master
 > git rev-parse 0fcb1822ad5bcf71b9e0c7cddb85dcd5a54d4967^{commit} # timeout=10
Checking out Revision 0fcb1822ad5bcf71b9e0c7cddb85dcd5a54d4967 (detached)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f 0fcb1822ad5bcf71b9e0c7cddb85dcd5a54d4967
 > git rev-list 7ea84cf781acc06bb72767860dc1132d5663a90d # timeout=10

How run diff-cover?

my steps as below:
1)I download the code files to my local directory(C:\Users\Desktop\coverage\test) by git clone
2)Generate the code file XML coverage report by JSCover tool
3)change to C:\Users\Desktop\coverage\test
and run: diff-cover C:\Users\Desktop\coverage\test\testjson26\cobertura-coverage.xml --compare-branch=C:\Users\Desktop\coverage\test\testjson26
have a error:
Traceback (most recent call last):
File "C:\Python27\Scripts\diff-cover-script.py", line 9, in
load_entry_point('diff-cover==0.9.10', 'console_scripts', 'diff-cover')()
File "build\bdist.win32\egg\diff_cover\tool.py", line 280, in main
File "build\bdist.win32\egg\diff_cover\git_path.py", line 30, in set_cwd
File "build\bdist.win32\egg\diff_cover\git_path.py", line 64, in _git_root
File "build\bdist.win32\egg\diff_cover\command_runner.py", line 28, in execute
File "C:\Python27\lib\subprocess.py", line 710, in init
errread, errwrite)
File "C:\Python27\lib\subprocess.py", line 958, in _execute_child
startupinfo)
WindowsError: [Error 2]
Looking forward to your answer, Thank you very much.

diff-cover fails with no message on Windows

Running diff-cover ends up calling tool.py which examines sys.argv[0] to see if it ends with diff-cover or diff-quality. For me, this is actually C:\Python27\Scripts\diff-cover-script.py, so nothing happens.

option to provide diff

On our CI servers we usually download our code via github archive links instead of maintaining a local clone. This is incompatible with diff-cover, which requires a local clone with history.

What do you think about an interface that allows the diff to be passed in? That'd let us fetch it from the github api (and may also help with supporting other diff providers, like #16).

diff-cover takes entire project as diff

Hi,

I use diff-cover successfully and with great pleasure for my personal projects and tried implementing it at work to ease development.
Unfortunately despite checking that the diff is empty (branch is a fresh copy of master) when I run diff-cover on the previously generated coverage.xml (on the unchanged copy of master) it will report every single file in the coverage.xml that is missing coverage as missing, completely ignoring the fact that there is no diff and the report should be empty!

The projects structure is quite nested.
main_dir/sub_dir/src/project/code_folder_1 etc.

tests are in:
main_dir/sub_dir/tests

I am running diff-cover from main_dir.

Do you think there can be a problem with file paths ?

Btw. the same problem applies to diff-quality. Also it was unable to see .flake8 config file present in the folder from which I am running diff-quality command.

Many thanks for looking into this :).

Tom

diff-cover --external-css-file fails with TemplateNotFound

It looks like https://pypi.python.org/packages/source/d/diff_cover/diff_cover-0.9.0.tar.gz is missing some files in the templates/ directory, and so the new feature introduced by #35 doesn't work:

diff-cover --html-report var/diff-cover/index.html --external-css var/diff-cover/style.css var/coverage.xml
Traceback (most recent call last):
  File "bin/diff-cover", line 22, in <module>
    sys.exit(diff_cover.tool.main())
  File "/var/lib/jenkins-slave/workspace/labtarna-branch/eggs/diff_cover-0.9.0-py2.7.egg/diff_cover/tool.py", line 286, in main
    ignore_unstaged=arg_dict['ignore_unstaged'],
  File "/var/lib/jenkins-slave/workspace/labtarna-branch/eggs/diff_cover-0.9.0-py2.7.egg/diff_cover/tool.py", line 220, in generate_coverage_report
    reporter.generate_css(output_file)
  File "/var/lib/jenkins-slave/workspace/labtarna-branch/eggs/diff_cover-0.9.0-py2.7.egg/diff_cover/report_generator.py", line 230, in generate_css
    template = TEMPLATE_ENV.get_template(self.CSS_TEMPLATE_NAME)
  File "/var/lib/jenkins-slave/workspace/labtarna-branch/eggs/Jinja2-2.8-py2.7.egg/jinja2/environment.py", line 812, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/var/lib/jenkins-slave/workspace/labtarna-branch/eggs/Jinja2-2.8-py2.7.egg/jinja2/environment.py", line 774, in _load_template
    cache_key = self.loader.get_source(self, name)[1]
  File "/var/lib/jenkins-slave/workspace/labtarna-branch/eggs/Jinja2-2.8-py2.7.egg/jinja2/loaders.py", line 235, in get_source
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: external_style.css

I recommend https://pypi.python.org/pypi/check-manifest to avoid this kind of issue in the future ;)

add an option to exclude files

The problem is with pylint, diif_cover launches pylint with a given changed file, but pylint ignore does not work in that case.

e.g.

  • there's a change in data/folder/dontwantthat.py
  • pylint.rc has
    ignore=CVS,folder

pylint still checks the file

provide -m entry points

Currently the user can only call the diff_cover or diff_quality scripts, would be nice inside CI and on Windows to be able to access the command without mangling with the path, this is possible by using python -m diff_cover, we need to provide a main file for this.

New line in source text causing diff cover to report incorrectly

Say, I have a cobertura report in the following format,

<?xml version="1.0"?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
<coverage 
line-rate="0.33" lines-valid="6699" lines-covered="2179" branches-valid="393" branches-covered="165" branch-rate="0.42" complexity="0" version="1.0" timestamp="1531218279433">
    <sources>        
        <source>
            /apps/jenkins/src/main/scala
        </source>
    </sources>
</coverage>

The code at [1] is not stripping the source name before comparing with git diff. Due to this, diff cover is producing incorrect reports. Ideally, code at [1] should look like this,

[clazz for clazz in classes if
             src_abs_path in [
                 self._to_unix_path(
                     os.path.join(
                         source.strip(' \t\n\r'),
                         clazz.get('filename')
                     )
                 ) for source in sources]]

Let me know if I need to create a PR.

[1] https://github.com/Bachmann1234/diff-cover/blob/master/diff_cover/violationsreporters/violations_reporter.py#L87

diff-quality will not report too many blank lines if this is the only diff

Hi,

This is probably hard to crack.
Example:
Original code, contains 2 empty lines between function and class as it should.

def dummy():
    return 1


class Blah:
    pass

Now lets add 2 surplus empty lines above the class (so now we have 4 empty lines, running flake8 on its own will pick it up as it scans the whole file), this is now the only diff in this file - just empty space.

def dummy():
    return 1




class Blah:
    pass

run:
diff-quality --violations=flake8

Reports that:

Total:   2 lines
Violations: 0 lines
% Quality: 100%

Now keep the above change and modify the name of the class.

def dummy():
    return 1




class Blah_new:
    pass

run:
diff-quality --violations=flake8

Reports that:

some_file.py:45: E303 too many blank lines (4)
-------------
Total:   3 lines
Violations: 1 line
% Quality: 66%

Not sure if this can be improved as it is just empty space that is incorrect and we operate only on the diff...
Identical situation happens if we remove the empty line between the function and the class definitions and keep only one line (should be 2) - this will not be reported unless the lines above/below the empty space change in this file.

Maybe for the diff-quality the operation should be performed on whole files taking them from the list of the changed ones as opposed to working just on the diff itself? Is it doable?

Just wanted to mention this behaviour.

Tom

Support comparing against the previous commit on the same branch

It would be great if diff-cover supported the ability to see the diff coverage between the current commit and the previous commit on the same branch.

Or, more generally, the ability to see the diff coverage between the current commit and an arbitrary commit.

Is this ability implicitly supported with the Compare Branch feature? (i.e. How does the tool handle receiving a commit SHA via --compare-branch?) If so, can we make the support explicit? If not, how difficult do you think it would be to add?

Thanks for maintaining this project!

if the absolute path of the git repository have a blank space, the git_root in diff_cover\git_path.py will be wrong

Currently, the git_root in diff_cover\git_path.py is as follow:
[ver 0.8.5]
line- 68 git_root = stdout.split()[0] if stdout else u''

if the absolute path of the git repository have a blank space, for example,
it is "C:\Users\Work Module\test", git_root will be "C:\Users\Work", but git_root should be "C:\Users\Work Module\test" in fact.

I think the code should be git_root = stdout.split('\n')[0] if stdout else u'', because the sdout of "git rev-parse --show-toplevel --encoding=utf-8" should be separated by a line break not a blank space.

Hg support

Hi,

I would like to know if there is any plan of giving support for mercurial (hg). Would it be difficult to implement this upgrade in a fork and then try to submit the code to the original project.

At my organization, we use Bitbucket + hg and we would love to introduce something like a pep8/coverage checked for a diff, and this is the most interesting tool I have seen so far.

Thanks

`diff-quality --violations=pylint` fails because of innocuous stderr output from pylint

This started happening today -- I'm guessing it's due to a recent change in pylint.

If I run diff-quality --violations=pylint, it fails with the following output:

$ diff-quality --violations=pylint
> /usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/command_runner.py(53)run_command_for_code()
Traceback (most recent call last):
  File "/usr/local/pyenv/versions/mcdsu-2.7.13/bin/diff-quality", line 11, in <module>
    sys.exit(main())
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/tool.py", line 376, in main
    exclude=arg_dict['exclude'],
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/tool.py", line 296, in generate_quality_report
    reporter.generate_report(output_file)
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/report_generator.py", line 216, in generate_report
    report = template.render(self._context())
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/report_generator.py", line 260, in _context
    (src, self._src_path_stats(src)) for src in self.src_paths()
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/report_generator.py", line 83, in src_paths
    return set(src for src, summary in self._diff_violations().items()
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/report_generator.py", line 176, in _diff_violations
    ) for src_path in self._diff.src_paths_changed()
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/report_generator.py", line 176, in <genexpr>
    ) for src_path in self._diff.src_paths_changed()
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/violationsreporters/base.py", line 157, in violations
    output, _ = execute(command)
  File "/usr/local/pyenv/versions/2.7.13/envs/mcdsu-2.7.13/lib/python2.7/site-packages/diff_cover/command_runner.py", line 43, in execute
    raise CommandError(stderr)
diff_cover.command_runner.CommandError: Using config file /opt/dev/src/.pylintrc

Note the stderr output does not indicate an actual error, it's simply notifying what configuration file pylint is using. This message is coming from here.

This occurs with diff_cover version 1.0.0 and pylint version 1.8.1.

Add an api for getting results as JSON or python dicts

Cool work :-)

I am working on a similar project but we are including also isort and yapf as part of the process, the idea is to have a single tool for all checks and automatic formatting.

It would be great if there was api to get stuff out as dict, so users can format the results as they please (include colors.. etc)

from diff_cover.api import flake8_runner, pylint_runner, pep8_runner, pydocstyle_runner

result = flake8_runner(path, staged_only=True, branch...)

# result
result = {'file.py': {'line': #, 'column': #, 'code': #,  'message': '' }...}

# or like pylint does
    {
        "message": "Unused tmpfolder imported from****,
        "obj": "",
        "line": 20,
        "symbol": "unused-import",
        "path": "***",
        "module": "***",
        "column": 0,
        "type": "warning"
    }

I have already some work on this direction so I could integrate it with your work.


Have you considered also making the tool run for everything (that is, not caring if changes are on version control)?

tests failed in GitPathTool

I ran python setup.py test and have tests failed.

======================================================================
ERROR: test_empty_file (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 169, in test_empty_file
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_end_range_on_violation (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 185, in test_end_range_on_violation
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_load_declared_arabic (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 222, in test_load_declared_arabic
    'snippet_arabic_output.html')
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 197, in _compare_snippets_html_output
    Snippet.load_snippets_html(filename, violations)
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 137, in load_snippets_html
    snippet_list = cls.load_snippets(src_path, violation_lines)
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_load_snippets_html (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 212, in test_load_snippets_html
    'snippet_list.html')
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 197, in _compare_snippets_html_output
    Snippet.load_snippets_html(filename, violations)
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 137, in load_snippets_html
    snippet_list = cls.load_snippets(src_path, violation_lines)
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_load_utf8_snippets (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 217, in test_load_utf8_snippets
    'snippet_unicode_html_output.html')
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 197, in _compare_snippets_html_output
    Snippet.load_snippets_html(filename, violations)
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 137, in load_snippets_html
    snippet_list = cls.load_snippets(src_path, violation_lines)
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_multiple_snippets (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 145, in test_multiple_snippets
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_no_lag_line (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 157, in test_no_lag_line
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_no_lead_line (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 151, in test_no_lead_line
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_no_violations (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 175, in test_no_violations
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_one_line_file (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 163, in test_one_line_file
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

======================================================================
ERROR: test_one_snippet (diff_cover.tests.test_snippets.SnippetLoaderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 139, in test_one_snippet
    self._assert_line_range(violations, expected_ranges)
  File "/home/dza/source/diff-cover/diff_cover/tests/test_snippets.py", line 239, in _assert_line_range
    self._src_path, violation_lines
  File "/home/dza/source/diff-cover/diff_cover/snippets.py", line 154, in load_snippets
    with openpy(GitPathTool.relative_path(src_path)) as src_file:
  File "/home/dza/source/diff-cover/diff_cover/git_path.py", line 41, in relative_path
    root_rel_path = os.path.relpath(cls._cwd, cls._root)
  File "/home/dza/source/diff-cover/env2/lib/python2.7/posixpath.py", line 428, in relpath
    raise ValueError("no path specified")
ValueError: no path specified

----------------------------------------------------------------------
Ran 219 tests in 2.962s

FAILED (errors=11)
Test failed: <unittest.runner.TextTestResult run=219 errors=11 failures=0>
error: Test failed: <unittest.runner.TextTestResult run=219 errors=11 failures=0>

"SyntaxError: invalid syntax" from running latest diff-cover

diff-cover just started failing in our CI environment, perhaps as a result of the latest release. The same command seemed to work yesterday. Note that the change I made that triggered the latest build did change coverage, and I have not tried to verify whether this error occurs with a different version of diff-cover or with the older version of my project.

Running "shell:diff-cover" (shell) task
Traceback (most recent call last):
  File "/usr/bin/diff-cover", line 9, in <module>
    load_entry_point('diff-cover==1.0.7', 'console_scripts', 'diff-cover')()
  File "/usr/lib/python2.6/site-packages/pkg_resources/__init__.py", line 542, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python2.6/site-packages/pkg_resources/__init__.py", line 2570, in load_entry_point
    return ep.load()
  File "/usr/lib/python2.6/site-packages/pkg_resources/__init__.py", line 2230, in load
    return self.resolve()
  File "/usr/lib/python2.6/site-packages/pkg_resources/__init__.py", line 2236, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/lib/python2.6/site-packages/diff_cover/tool.py", line 18, in <module>
    from diff_cover.report_generator import (
  File "/usr/lib/python2.6/site-packages/diff_cover/report_generator.py", line 18
    violation.line for violation in violations
                     ^
SyntaxError: invalid syntax

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.