def _get_src_path_line_nodes(self, xml_document, src_path):
        """
        Returns a list of nodes containing line information for `src_path`
        in `xml_document`.

        If file is not present in `xml_document`, return None
        """

        # Remove git_root from src_path for searching the correct filename
        # If cwd is `/home/user/work/diff-cover/diff_cover`
        # and src_path is `diff_cover/violations_reporter.py`
        # search for `violations_reporter.py`
        src_rel_path = GitPathTool.relative_path(src_path)

        # If cwd is `/home/user/work/diff-cover/diff_cover`
        # and src_path is `other_package/some_file.py`
        # search for `/home/user/work/diff-cover/other_package/some_file.py`
        src_abs_path = GitPathTool.absolute_path(src_path)

        xpath_template = ".//class[@filename='{0}']/lines/line"
        xpath = None

        src_node_xpath = ".//class[@filename='{0}']".format(src_rel_path)
        if xml_document.find(src_node_xpath) is not None:
            xpath = xpath_template.format(src_rel_path)

        src_node_xpath = ".//class[@filename='{0}']".format(src_abs_path)
        if xml_document.find(src_node_xpath) is not None:
            xpath = xpath_template.format(src_abs_path)

        if xpath is None:
            return None

        return xml_document.findall(xpath)
    def _get_src_path_line_nodes(self, xml_document, src_path):
        """
        Returns a list of nodes containing line information for `src_path`
        in `xml_document`.

        If file is not present in `xml_document`, return None
        """

        # Remove git_root from src_path for searching the correct filename
        # If cwd is `/home/user/work/diff-cover/diff_cover`
        # and src_path is `diff_cover/violations_reporter.py`
        # search for `violations_reporter.py`
        src_rel_path = GitPathTool.relative_path(src_path)

        # If cwd is `/home/user/work/diff-cover/diff_cover`
        # and src_path is `other_package/some_file.py`
        # search for `/home/user/work/diff-cover/other_package/some_file.py`
        src_abs_path = GitPathTool.absolute_path(src_path)

        xpath = ".//class"
        classes = [class_tree for class_tree in xml_document.findall(xpath)
                   or []]
        classes = ([clazz for clazz in classes
                    if clazz.get('filename') == src_abs_path]
                   or
                   [clazz for clazz in classes
                    if clazz.get('filename') == src_rel_path])
        if not classes:
            return None

        lines = [clazz.findall('./lines/line') for clazz in classes]
        return [elem for elem in itertools.chain(*lines)]
Exemple #3
0
def main():
    """
    Main entry point for the tool, used by setup.py
    """
    progname = sys.argv[0]

    # Init the path tool to work with the current directory
    try:
        cwd = os.getcwdu()
    except AttributeError:
        cwd = os.getcwd()

    GitPathTool.set_cwd(cwd)

    if progname.endswith('diff-cover'):
        arg_dict = parse_coverage_args(sys.argv[1:])
        generate_coverage_report(
            arg_dict['coverage_xml'],
            arg_dict['compare_branch'],
            html_report=arg_dict['html_report'],
        )

    elif progname.endswith('diff-quality'):
        arg_dict = parse_quality_args(sys.argv[1:])
        tool = arg_dict['violations']
        user_options = arg_dict.get('options')
        if user_options:
            user_options = user_options[1:-1]  # Strip quotes
        reporter_class = QUALITY_REPORTERS.get(tool)

        if reporter_class is not None:
            # If we've been given pre-generated reports,
            # try to open the files
            input_reports = []

            for path in arg_dict['input_reports']:
                try:
                    input_reports.append(open(path, 'rb'))
                except IOError:
                    LOGGER.warning("Could not load '{0}'".format(path))

            try:
                reporter = reporter_class(tool, input_reports, user_options=user_options)
                generate_quality_report(
                    reporter,
                    arg_dict['compare_branch'],
                    arg_dict['html_report']
                )

            # Close any reports we opened
            finally:
                for file_handle in input_reports:
                    file_handle.close()
        else:
            LOGGER.error("Quality tool not recognized: '{0}'".format(tool))
            exit(1)
    def test_absolute_path(self):
        self._set_git_root('/home/user/work/diff-cover')
        expected = '/home/user/work/diff-cover/other_package/file.py'
        cwd = '/home/user/work/diff-cover/diff_cover'

        tool = GitPathTool(cwd)
        path = tool.absolute_path('other_package/file.py')

        # Expect absolute path to file.py
        self.assertEqual(path, expected)
Exemple #5
0
    def test_project_root_command(self):
        self._set_git_root(b'/phony/path')

        GitPathTool.set_cwd(b'/phony/path')

        # Expect that the correct command was executed
        expected = ['git', 'rev-parse', '--show-toplevel', '--encoding=utf-8']
        self.subprocess.Popen.assert_called_with(
            expected, stdout=self.subprocess.PIPE, stderr=self.subprocess.PIPE
        )
Exemple #6
0
    def test_relative_path(self):
        self._set_git_root(b'/home/user/work/diff-cover')
        expected = 'violations_reporter.py'
        cwd = '/home/user/work/diff-cover/diff_cover'

        GitPathTool.set_cwd(cwd)
        path = GitPathTool.relative_path('diff_cover/violations_reporter.py')

        # Expect relative path from diff_cover
        self.assertEqual(path, expected)
Exemple #7
0
    def test_absolute_path(self):
        self._set_git_root(b'/home/user/work dir/diff-cover\n--encoding=utf-8\n')
        expected = '/home/user/work dir/diff-cover/other_package/file.py'
        cwd = '/home/user/work dir/diff-cover/diff_cover'

        GitPathTool.set_cwd(cwd)
        path = GitPathTool.absolute_path('other_package/file.py')

        # Expect absolute path to file.py
        self.assertEqual(path, expected)
Exemple #8
0
    def test_set_cwd_unicode_byte_passed_in_for_cwd(self):
        self._set_git_root(b"\xe2\x94\xbb\xe2\x94\x81\xe2\x94\xbb\n--encoding=utf-8\n")
        expected = '\u253b\u2501\u253b/other_package/file.py'
        cwd = b'\\u253b\\u2501\\u253b/diff_cover'

        GitPathTool.set_cwd(cwd)
        path = GitPathTool.absolute_path('other_package/file.py')

        # Expect absolute path to file.py
        self.assertEqual(path, expected)
    def _get_classes(self, xml_document, src_path):
        """
        Given a path and parsed xml_document provides class nodes
        with the relevant lines

        First, we look to see if xml_document contains a source
        node providing paths to search for

        If we don't have that we check each nodes filename attribute
        matches an absolute path

        Finally, if we found no nodes, we check the filename attribute
        for the relative path
        """
        # Remove git_root from src_path for searching the correct filename
        # If cwd is `/home/user/work/diff-cover/diff_cover`
        # and src_path is `diff_cover/violations_reporter.py`
        # search for `violations_reporter.py`
        src_rel_path = self._to_unix_path(GitPathTool.relative_path(src_path))

        # If cwd is `/home/user/work/diff-cover/diff_cover`
        # and src_path is `other_package/some_file.py`
        # search for `/home/user/work/diff-cover/other_package/some_file.py`
        src_abs_path = self._to_unix_path(GitPathTool.absolute_path(src_path))

        # cobertura sometimes provides the sources for the measurements
        # within it. If we have that we outta use it
        sources = xml_document.findall('sources/source')
        sources = [source.text for source in sources]
        classes = [class_tree
                   for class_tree in xml_document.findall(".//class")
                   or []]

        classes = (
            [clazz for clazz in classes if
             src_abs_path in [
                 self._to_unix_path(
                     os.path.join(
                         source,
                         clazz.get('filename')
                     )
                 ) for source in sources]]
            or
            [clazz for clazz in classes if
             self._to_unix_path(clazz.get('filename')) == src_abs_path]
            or
            [clazz for clazz in classes if
             self._to_unix_path(clazz.get('filename')) == src_rel_path]
        )
        return classes
Exemple #10
0
    def load_snippets(cls, src_path, violation_lines):
        """
        Load snippets from the file at `src_path` to show
        violations on lines in the list `violation_lines`
        (list of line numbers, starting at index 0).

        The file at `src_path` should be a text file (not binary).

        Returns a list of `Snippet` instances.

        Raises an `IOError` if the file could not be loaded.
        """
        # Load the contents of the file
        with openpy(GitPathTool.relative_path(src_path)) as src_file:
            contents = src_file.read()

        # Convert the source file to unicode (Python < 3)
        if isinstance(contents, six.binary_type):
            contents = contents.decode('utf-8', 'replace')

        # Construct a list of snippet ranges
        src_lines = contents.split('\n')
        snippet_ranges = cls._snippet_ranges(len(src_lines), violation_lines)

        # Parse the source into tokens
        token_stream = cls._parse_src(contents, src_path)

        # Group the tokens by snippet
        token_groups = cls._group_tokens(token_stream, snippet_ranges)

        return [
            Snippet(tokens, src_path, start, violation_lines)
            for (start, _), tokens in sorted(token_groups.items())
        ]
    def parse_reports(self, reports):
        """
        Args:
            reports: list[str] - output from the report
        Return:
            A dict[Str:Violation]
            Violation is a simple named tuple Defined above
        """
        violations_dict = defaultdict(list)
        for report in reports:
            xml_document = cElementTree.fromstring("".join(report))
            bugs = xml_document.findall(".//BugInstance")
            for bug in bugs:
                category = bug.get('category')
                short_message = bug.find('ShortMessage').text
                line = bug.find('SourceLine')
                if line.get('start') is None or line.get('end') is None:
                    continue
                start = int(line.get('start'))
                end = int(line.get('end'))
                for line_number in range(start, end+1):
                    error_str = u"{0}: {1}".format(category, short_message)
                    violation = Violation(line_number, error_str)
                    filename = GitPathTool.relative_path(
                        line.get('sourcepath'))
                    violations_dict[filename].append(violation)

        return violations_dict
Exemple #12
0
    def _measured_source_path_matches(self, package_name, file_name, src_path):
        # find src_path in any of the source roots
        if not src_path.endswith(file_name):
            return False

        norm_src_path = os.path.normcase(src_path)
        for root in self._src_roots:
            if (os.path.normcase(
                    GitPathTool.relative_path(
                        os.path.join(root, package_name,
                                     file_name))) == norm_src_path):
                return True
        return False
Exemple #13
0
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    argv = argv or sys.argv
    arg_dict = parse_coverage_args(argv[1:])

    quiet = arg_dict["quiet"]
    level = logging.ERROR if quiet else logging.WARNING
    logging.basicConfig(format="%(message)s", level=level)

    GitPathTool.set_cwd(directory)
    fail_under = arg_dict.get("fail_under")
    percent_covered = generate_coverage_report(
        arg_dict["coverage_xml"],
        arg_dict["compare_branch"],
        html_report=arg_dict["html_report"],
        json_report=arg_dict["json_report"],
        markdown_report=arg_dict["markdown_report"],
        css_file=arg_dict["external_css_file"],
        ignore_staged=arg_dict["ignore_staged"],
        ignore_unstaged=arg_dict["ignore_unstaged"],
        exclude=arg_dict["exclude"],
        src_roots=arg_dict["src_roots"],
        diff_range_notation=arg_dict["diff_range_notation"],
        ignore_whitespace=arg_dict["ignore_whitespace"],
        quiet=quiet,
        show_uncovered=arg_dict["show_uncovered"],
    )

    if percent_covered >= fail_under:
        return 0
    LOGGER.error("Failure. Coverage is below %i%%.", fail_under)
    return 1
    def _get_src_path_line_nodes(xml_document, src_path):
        """
        Return a list of nodes containing line information for `src_path`
        in `xml_document`.

        If file is not present in `xml_document`, return None
        """
        files = [file_tree
                 for file_tree in xml_document.findall(".//file")
                 if GitPathTool.relative_path(file_tree.get('path')) == src_path
                 or []]
        if not files:
            return None
        lines = [file_tree.findall('./line[@type="stmt"]')
                 for file_tree in files]
        return [elem for elem in itertools.chain(*lines)]
Exemple #15
0
    def _get_src_path_line_nodes(xml_document, src_path):
        """
        Return a list of nodes containing line information for `src_path`
        in `xml_document`.

        If file is not present in `xml_document`, return None
        """
        files = [
            file_tree for file_tree in xml_document.findall(".//file") if
            GitPathTool.relative_path(file_tree.get('path')) == src_path or []
        ]
        if not files:
            return None
        lines = [
            file_tree.findall('./line[@type="stmt"]') for file_tree in files
        ]
        return [elem for elem in itertools.chain(*lines)]
Exemple #16
0
    def get_src_path_line_nodes_clover(xml_document, src_path):
        """
        Return a list of nodes containing line information for `src_path`
        in `xml_document`.

        If file is not present in `xml_document`, return None
        """

        files = [
            file_tree for file_tree in xml_document.findall(".//file")
            if GitPathTool.relative_path(file_tree.get("path")) == src_path
        ]
        if not files:
            return None
        lines = []
        for file_tree in files:
            lines.append(file_tree.findall('./line[@type="stmt"]'))
            lines.append(file_tree.findall('./line[@type="cond"]'))
        return list(itertools.chain(*lines))
Exemple #17
0
def generate_coverage_report(coverage_xml, compare_branch, html_report=None):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch, git_diff=GitDiffTool())

    xml_roots = [etree.parse(xml_root) for xml_root in coverage_xml]
    git_path = GitPathTool(os.getcwd())
    coverage = XmlCoverageReporter(xml_roots, git_path)

    # Build a report generator
    if html_report is not None:
        reporter = HtmlReportGenerator(coverage, diff)
        output_file = open(html_report, "w")
    else:
        reporter = StringReportGenerator(coverage, diff)
        output_file = sys.stdout

    # Generate the report
    reporter.generate_report(output_file)
Exemple #18
0
 def parse_reports(self, reports):
     """
     Args:
         reports: list[str] - output from the report
     Return:
         A dict[Str:Violation]
         Violation is a simple named tuple Defined above
     """
     violations_dict = defaultdict(list)
     for report in reports:
         xml_document = etree.fromstring("".join(report))
         files = xml_document.findall(".//file")
         for file_tree in files:
             for error in file_tree.findall('error'):
                 line_number = error.get('line')
                 error_str = "{}: {}".format(error.get('severity'),
                                             error.get('message'))
                 violation = Violation(int(line_number), error_str)
                 filename = GitPathTool.relative_path(file_tree.get('name'))
                 violations_dict[filename].append(violation)
     return violations_dict
 def parse_reports(self, reports):
     """
     Args:
         reports: list[str] - output from the report
     Return:
         A dict[Str:Violation]
         Violation is a simple named tuple Defined above
     """
     violations_dict = defaultdict(list)
     for report in reports:
         xml_document = cElementTree.fromstring("".join(report))
         files = xml_document.findall(".//file")
         for file_tree in files:
             for error in file_tree.findall('error'):
                 line_number = error.get('line')
                 error_str = u"{0}: {1}".format(error.get('severity'),
                                                error.get('message'))
                 violation = Violation(int(line_number), error_str)
                 filename = GitPathTool.relative_path(file_tree.get('name'))
                 violations_dict[filename].append(violation)
     return violations_dict
    def parse_reports(self, reports):
        """
        Args:
            reports: list[str] - output from the report
        Return:
            A dict[Str:Violation]
            Violation is a simple named tuple Defined above
        """
        violations_dict = defaultdict(list)
        for report in reports:
            xml_document = etree.fromstring("".join(report))
            node_files = xml_document.findall(".//file")
            for node_file in node_files:
                for error in node_file.findall("violation"):
                    line_number = error.get("beginline")
                    error_str = "{}: {}".format(error.get("rule"), error.text.strip())
                    violation = Violation(int(line_number), error_str)
                    filename = GitPathTool.relative_path(node_file.get("name"))
                    filename = filename.replace(os.sep, "/")
                    violations_dict[filename].append(violation)

        return violations_dict
Exemple #21
0
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    argv = argv or sys.argv
    # Init the path tool to work with the specified directory,
    # or the current directory if it isn't set.
    if not directory:
        try:
            directory = os.getcwdu()
        except AttributeError:
            directory = os.getcwd()

    progname = argv[0]

    GitPathTool.set_cwd(directory)

    if progname.endswith('diff-cover'):
        arg_dict = parse_coverage_args(argv[1:])
        fail_under = arg_dict.get('fail_under')
        percent_covered = generate_coverage_report(
            arg_dict['coverage_xml'],
            arg_dict['compare_branch'],
            html_report=arg_dict['html_report'],
            ignore_unstaged=arg_dict['ignore_unstaged'],
        )

        if percent_covered >= fail_under:
            return 0
        else:
            LOGGER.error("Failure. Coverage is below {0}%.".format(fail_under))
            return 1

    elif progname.endswith('diff-quality'):
        arg_dict = parse_quality_args(argv[1:])
        fail_under = arg_dict.get('fail_under')
        tool = arg_dict['violations']
        user_options = arg_dict.get('options')
        if user_options:
            # strip quotes if present
            first_char = user_options[0]
            last_char = user_options[-1]
            if first_char == last_char and first_char in ('"', "'"):
                user_options = user_options[1:-1]
        reporter_class = QUALITY_REPORTERS.get(tool)

        if reporter_class is not None:
            # If we've been given pre-generated reports,
            # try to open the files
            input_reports = []

            for path in arg_dict['input_reports']:
                try:
                    input_reports.append(open(path, 'rb'))
                except IOError:
                    LOGGER.warning("Could not load '{0}'".format(path))
            try:
                reporter = reporter_class(tool, input_reports, user_options=user_options)
                percent_passing = generate_quality_report(
                    reporter,
                    arg_dict['compare_branch'],
                    arg_dict['html_report'],
                    arg_dict['ignore_unstaged'],
                )
                if percent_passing >= fail_under:
                    return 0
                else:
                    LOGGER.error("Failure. Quality is below {0}%.".format(fail_under))
                    return 1

            except ImportError:
                LOGGER.error(
                    "Quality tool not installed: '{0}'".format(tool)
                )
                return 1
            # Close any reports we opened
            finally:
                for file_handle in input_reports:
                    file_handle.close()

        else:
            LOGGER.error("Quality tool not recognized: '{0}'".format(tool))
            return 1
Exemple #22
0
    def generateReport(self, base_path, repository, commit, branch, pr):
        """
        Combine coverage data files, generate XML report and send to
        codecov.io.
        """

        # The path to save the reports
        path = os.path.join(base_path, repository, 'commit', commit)
        git_repo_path = os.path.join(base_path, repository, 'git-repo')

        # This check is here to help with testing
        if self.github_base_url is not None:  # pragma: no cover
            # self.notifyGithub(repository, commit)
            self.cloneGitRepo(repository, git_repo_path, commit)

        # Coverage.py will delete the coverage data files when
        # combining them. We don't want that, so let's copy to a
        # temporary dir first.
        tempdir = tempfile.mkdtemp(dir=tempfile.gettempdir())
        coverage_files = glob.glob(
            os.path.join(path, '%s*' % COVERAGE_DATA_PREFIX))
        self.log_message('Copying files to %s', tempdir)
        for coverage_file in coverage_files:
            shutil.copy(coverage_file, tempdir)

        # Save actual path and move to the cloned repository
        old_path = os.getcwd()
        os.chdir(os.path.join(git_repo_path))

        try:
            self.log_message('Starting to combine coverage files...')
            combined_coverage_file = os.path.join(path,
                                                  COVERAGE_DATA_PREFIX[:-1])
            env = os.environ.copy()
            env['COVERAGE_FILE'] = combined_coverage_file

            # FIXME:4516:
            # We call coverage combine three times, one for non-windows
            # generated files, one for windows generated files and
            # one for combine the two calls.
            args = ['coverage', 'combine']
            non_win_files = [
                f for f in glob.glob('%s/*' % tempdir) if 'win' not in f
            ]
            if non_win_files:
                self.log_message('Combining non-windows files.')
                call(args + non_win_files, env=env)

            win_files = glob.glob('%s/*win*' % tempdir)
            if win_files:
                env['COVERAGE_FILE'] = '%s.win' % (combined_coverage_file)
                self.log_message('Combining windows files.')
                call(args + win_files, env=env)

                # Manually replace the windows path for linux path
                windows_file = open('%s.win' % combined_coverage_file)
                content = windows_file.read()
                windows_file.close()
                new_content = content.replace('\\\\', '/')
                windows_file = open('%s.win' % combined_coverage_file, 'w')
                windows_file.write(new_content)
                windows_file.close()

                self.log_message('Merging windows and non-windows files.')
                env['COVERAGE_FILE'] = combined_coverage_file
                call([
                    'coverage', 'combine', '-a',
                    '%s.win' % combined_coverage_file
                ],
                     env=env)

            shutil.rmtree(tempdir)

            self.log_message('Files combined, generating xml report.')
            call([
                'coverage',
                'xml',
                '-o',
                os.path.join(path, 'coverage.xml'),
            ],
                 env=env)

            # Delete the data file after the xml file is generated.
            os.remove(combined_coverage_file)

            self.log_message('XML file created at %s',
                             os.path.join(path, 'coverage.xml'))

            if self.github is not None:  # pragma: no cover
                # Generate the diff-coverage report.
                from diff_cover.tool import generate_coverage_report
                from diff_cover.git_path import GitPathTool
                GitPathTool.set_cwd(os.getcwd())
                self.log_message('Generating diff-cover')
                coverage_diff = generate_coverage_report(
                    [os.path.join(path, 'coverage.xml')], 'master',
                    os.path.join(path, 'diff-cover.html'))
                self.log_message('Diff-cover generated, now notifying github.')
                self.notifyGithub(repository, commit, None, coverage_diff)

                codecov_token = self.codecov_tokens.get(repository, None)
                if codecov_token:
                    self.log_message('Publishing to codecov.io')
                    self.publishToCodecov(codecov_token, path, branch, pr)

        finally:
            os.chdir(old_path)
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """

    argv = argv or sys.argv
    arg_dict = parse_quality_args(argv[1:])

    quiet = arg_dict["quiet"]
    level = logging.ERROR if quiet else logging.WARNING
    logging.basicConfig(format="%(message)s", level=level)

    GitPathTool.set_cwd(directory)
    fail_under = arg_dict.get("fail_under")
    tool = arg_dict["violations"]
    user_options = arg_dict.get("options")
    if user_options:
        # strip quotes if present
        first_char = user_options[0]
        last_char = user_options[-1]
        if first_char == last_char and first_char in ('"', "'"):
            user_options = user_options[1:-1]
    reporter = None
    driver = QUALITY_DRIVERS.get(tool)
    if driver is None:
        # The requested tool is not built into diff_cover. See if another Python
        # package provides it.
        pm = pluggy.PluginManager("diff_cover")
        pm.add_hookspecs(hookspecs)
        pm.load_setuptools_entrypoints("diff_cover")
        for hookimpl in pm.hook.diff_cover_report_quality.get_hookimpls():
            if hookimpl.plugin_name == tool:
                reporter = hookimpl.function()
                break

    if reporter or driver:
        input_reports = []
        try:
            if driver is not None:
                # If we've been given pre-generated reports,
                # try to open the files

                for path in arg_dict["input_reports"]:
                    try:
                        input_reports.append(open(path, "rb"))
                    except OSError:
                        LOGGER.warning(f"Could not load '{path}'")
                reporter = QualityReporter(driver, input_reports, user_options)

            percent_passing = generate_quality_report(
                reporter,
                arg_dict["compare_branch"],
                html_report=arg_dict["html_report"],
                css_file=arg_dict["external_css_file"],
                ignore_staged=arg_dict["ignore_staged"],
                ignore_unstaged=arg_dict["ignore_unstaged"],
                exclude=arg_dict["exclude"],
                include=arg_dict["include"],
                diff_range_notation=arg_dict["diff_range_notation"],
                ignore_whitespace=arg_dict["ignore_whitespace"],
                quiet=quiet,
            )
            if percent_passing >= fail_under:
                return 0

            LOGGER.error("Failure. Quality is below %i.", fail_under)
            return 1

        except ImportError:
            LOGGER.error("Quality tool not installed: '%s'", tool)
            return 1
        except OSError as exc:
            LOGGER.error("Failure: '%s'", str(exc))
            return 1
        # Close any reports we opened
        finally:
            for file_handle in input_reports:
                file_handle.close()

    else:
        LOGGER.error("Quality tool not recognized: '%s'", tool)
        return 1
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    logging.basicConfig(format='%(message)s')

    argv = argv or sys.argv
    arg_dict = parse_quality_args(argv[1:])
    GitPathTool.set_cwd(directory)
    fail_under = arg_dict.get('fail_under')
    tool = arg_dict['violations']
    user_options = arg_dict.get('options')
    if user_options:
        # strip quotes if present
        first_char = user_options[0]
        last_char = user_options[-1]
        if first_char == last_char and first_char in ('"', "'"):
            user_options = user_options[1:-1]
    reporter = None
    driver = QUALITY_DRIVERS.get(tool)
    if driver is None:
        # The requested tool is not built into diff_cover. See if another Python
        # package provides it.
        pm = pluggy.PluginManager('diff_cover')
        pm.add_hookspecs(hookspecs)
        pm.load_setuptools_entrypoints('diff_cover')
        for hookimpl in pm.hook.diff_cover_report_quality.get_hookimpls():
            if hookimpl.plugin_name == tool:
                reporter = hookimpl.function()
                break

    if reporter or driver:
        input_reports = []
        try:
            if driver is not None:
                # If we've been given pre-generated reports,
                # try to open the files

                for path in arg_dict['input_reports']:
                    try:
                        input_reports.append(open(path, 'rb'))
                    except IOError:
                        LOGGER.warning("Could not load '{}'".format(path))
                reporter = QualityReporter(driver, input_reports, user_options)

            percent_passing = generate_quality_report(
                reporter,
                arg_dict['compare_branch'],
                html_report=arg_dict['html_report'],
                css_file=arg_dict['external_css_file'],
                ignore_staged=arg_dict['ignore_staged'],
                ignore_unstaged=arg_dict['ignore_unstaged'],
                exclude=arg_dict['exclude'],
                diff_range_notation=arg_dict['diff_range_notation'],
            )
            if percent_passing >= fail_under:
                return 0
            else:
                LOGGER.error("Failure. Quality is below {}%.".format(fail_under))
                return 1

        except (ImportError, EnvironmentError):
            LOGGER.error(
                "Quality tool not installed: '{}'".format(tool)
            )
            return 1
        # Close any reports we opened
        finally:
            for file_handle in input_reports:
                file_handle.close()

    else:
        LOGGER.error("Quality tool not recognized: '{}'".format(tool))
        return 1
Exemple #25
0
def main():
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    progname = sys.argv[0]

    # Init the path tool to work with the current directory
    try:
        cwd = os.getcwdu()
    except AttributeError:
        cwd = os.getcwd()

    GitPathTool.set_cwd(cwd)

    if progname.endswith('diff-cover'):
        arg_dict = parse_coverage_args(sys.argv[1:])
        percent_covered = generate_coverage_report(
            arg_dict['coverage_xml'],
            arg_dict['compare_branch'],
            html_report=arg_dict['html_report'],
        )

        if percent_covered >= arg_dict.get('fail_under'):
            return 0
        else:
            return 1

    elif progname.endswith('diff-quality'):
        arg_dict = parse_quality_args(sys.argv[1:])
        tool = arg_dict['violations']
        user_options = arg_dict.get('options')
        if user_options:
            user_options = user_options[1:-1]  # Strip quotes
        reporter_class = QUALITY_REPORTERS.get(tool)

        if reporter_class is not None:
            # If we've been given pre-generated reports,
            # try to open the files
            input_reports = []

            for path in arg_dict['input_reports']:
                try:
                    input_reports.append(open(path, 'rb'))
                except IOError:
                    LOGGER.warning("Could not load '{0}'".format(path))
            try:
                reporter = reporter_class(tool,
                                          input_reports,
                                          user_options=user_options)
                percent_passing = generate_quality_report(
                    reporter, arg_dict['compare_branch'],
                    arg_dict['html_report'])
                if percent_passing >= arg_dict.get('fail_under'):
                    return 0
                else:
                    return 1

            except ImportError:
                LOGGER.error("Quality tool not installed: '{0}'".format(tool))
                return 1
            # Close any reports we opened
            finally:
                for file_handle in input_reports:
                    file_handle.close()

        else:
            LOGGER.error("Quality tool not recognized: '{0}'".format(tool))
            return 1
Exemple #26
0
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    argv = argv or sys.argv
    # Init the path tool to work with the specified directory,
    # or the current directory if it isn't set.
    if not directory:
        try:
            directory = os.getcwdu()
        except AttributeError:
            directory = os.getcwd()

    progname = argv[0]

    GitPathTool.set_cwd(directory)

    if progname.endswith('diff-cover'):
        arg_dict = parse_coverage_args(argv[1:])
        fail_under = arg_dict.get('fail_under')
        percent_covered = generate_coverage_report(
            arg_dict['coverage_xml'],
            arg_dict['compare_branch'],
            html_report=arg_dict['html_report'],
        )

        if percent_covered >= fail_under:
            return 0
        else:
            LOGGER.error("Failure. Coverage is below {0}%.".format(fail_under))
            return 1

    elif progname.endswith('diff-quality'):
        arg_dict = parse_quality_args(argv[1:])
        fail_under = arg_dict.get('fail_under')
        tool = arg_dict['violations']
        user_options = arg_dict.get('options')
        if user_options:
            # strip quotes if present
            first_char = user_options[0]
            last_char = user_options[-1]
            if first_char == last_char and first_char in ('"', "'"):
                user_options = user_options[1:-1]
        reporter_class = QUALITY_REPORTERS.get(tool)

        if reporter_class is not None:
            # If we've been given pre-generated reports,
            # try to open the files
            input_reports = []

            for path in arg_dict['input_reports']:
                try:
                    input_reports.append(open(path, 'rb'))
                except IOError:
                    LOGGER.warning("Could not load '{0}'".format(path))
            try:
                reporter = reporter_class(tool, input_reports, user_options=user_options)
                percent_passing = generate_quality_report(
                    reporter,
                    arg_dict['compare_branch'],
                    arg_dict['html_report']
                )
                if percent_passing >= fail_under:
                    return 0
                else:
                    LOGGER.error("Failure. Quality is below {0}%.".format(fail_under))
                    return 1

            except ImportError:
                LOGGER.error(
                    "Quality tool not installed: '{0}'".format(tool)
                )
                return 1
            # Close any reports we opened
            finally:
                for file_handle in input_reports:
                    file_handle.close()

        else:
            LOGGER.error("Quality tool not recognized: '{0}'".format(tool))
            return 1
Exemple #27
0
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    logging.basicConfig(format='%(message)s')

    argv = argv or sys.argv
    # Init the path tool to work with the specified directory,
    # or the current directory if it isn't set.
    if not directory:
        try:
            directory = os.getcwdu()
        except AttributeError:
            directory = os.getcwd()

    progname = argv[0]
    filename = os.path.basename(progname)
    name, _ = os.path.splitext(filename)

    if 'diff-cover' in name:
        arg_dict = parse_coverage_args(argv[1:])
        GitPathTool.set_cwd(directory)
        fail_under = arg_dict.get('fail_under')
        percent_covered = generate_coverage_report(
            arg_dict['coverage_xml'],
            arg_dict['compare_branch'],
            html_report=arg_dict['html_report'],
            css_file=arg_dict['external_css_file'],
            ignore_staged=arg_dict['ignore_staged'],
            ignore_unstaged=arg_dict['ignore_unstaged'],
            exclude=arg_dict['exclude'],
            src_roots=arg_dict['src_roots'],
        )

        if percent_covered >= fail_under:
            return 0
        else:
            LOGGER.error("Failure. Coverage is below {}%.".format(fail_under))
            return 1

    elif 'diff-quality' in name:
        arg_dict = parse_quality_args(argv[1:])
        GitPathTool.set_cwd(directory)
        fail_under = arg_dict.get('fail_under')
        tool = arg_dict['violations']
        user_options = arg_dict.get('options')
        if user_options:
            # strip quotes if present
            first_char = user_options[0]
            last_char = user_options[-1]
            if first_char == last_char and first_char in ('"', "'"):
                user_options = user_options[1:-1]
        driver = QUALITY_DRIVERS.get(tool)

        if driver is not None:
            # If we've been given pre-generated reports,
            # try to open the files
            input_reports = []

            for path in arg_dict['input_reports']:
                try:
                    input_reports.append(open(path, 'rb'))
                except IOError:
                    LOGGER.warning("Could not load '{}'".format(path))
            try:
                reporter = QualityReporter(driver, input_reports, user_options)
                percent_passing = generate_quality_report(
                    reporter,
                    arg_dict['compare_branch'],
                    html_report=arg_dict['html_report'],
                    css_file=arg_dict['external_css_file'],
                    ignore_staged=arg_dict['ignore_staged'],
                    ignore_unstaged=arg_dict['ignore_unstaged'],
                    exclude=arg_dict['exclude'],
                )
                if percent_passing >= fail_under:
                    return 0
                else:
                    LOGGER.error("Failure. Quality is below {}%.".format(fail_under))
                    return 1

            except (ImportError, EnvironmentError):
                LOGGER.error(
                    "Quality tool not installed: '{}'".format(tool)
                )
                return 1
            # Close any reports we opened
            finally:
                for file_handle in input_reports:
                    file_handle.close()

        else:
            LOGGER.error("Quality tool not recognized: '{}'".format(tool))
            return 1

    else:
        assert False, 'Expect diff-cover or diff-quality in {}'.format(name)
Exemple #28
0
def main(argv=None, directory=None):
    """
    Main entry point for the tool, used by setup.py
    Returns a value that can be passed into exit() specifying
    the exit code.
    1 is an error
    0 is successful run
    """
    logging.basicConfig(format='%(message)s')

    argv = argv or sys.argv
    # Init the path tool to work with the specified directory,
    # or the current directory if it isn't set.
    if not directory:
        try:
            directory = os.getcwdu()
        except AttributeError:
            directory = os.getcwd()

    progname = argv[0]
    filename = os.path.basename(progname)
    name, _ = os.path.splitext(filename)

    if 'diff-cover' in name:
        arg_dict = parse_coverage_args(argv[1:])
        GitPathTool.set_cwd(directory)
        fail_under = arg_dict.get('fail_under')
        percent_covered = generate_coverage_report(
            arg_dict['coverage_xml'],
            arg_dict['compare_branch'],
            html_report=arg_dict['html_report'],
            css_file=arg_dict['external_css_file'],
            ignore_unstaged=arg_dict['ignore_unstaged'],
        )

        if percent_covered >= fail_under:
            return 0
        else:
            LOGGER.error("Failure. Coverage is below {0}%.".format(fail_under))
            return 1

    elif 'diff-quality' in name:
        arg_dict = parse_quality_args(argv[1:])
        GitPathTool.set_cwd(directory)
        fail_under = arg_dict.get('fail_under')
        tool = arg_dict['violations']
        user_options = arg_dict.get('options')
        if user_options:
            # strip quotes if present
            first_char = user_options[0]
            last_char = user_options[-1]
            if first_char == last_char and first_char in ('"', "'"):
                user_options = user_options[1:-1]
        driver = QUALITY_DRIVERS.get(tool)

        if driver is not None:
            # If we've been given pre-generated reports,
            # try to open the files
            input_reports = []

            for path in arg_dict['input_reports']:
                try:
                    input_reports.append(open(path, 'rb'))
                except IOError:
                    LOGGER.warning("Could not load '{0}'".format(path))
            try:
                reporter = QualityReporter(driver, input_reports, user_options)
                percent_passing = generate_quality_report(
                    reporter,
                    arg_dict['compare_branch'],
                    html_report=arg_dict['html_report'],
                    css_file=arg_dict['external_css_file'],
                    ignore_unstaged=arg_dict['ignore_unstaged'],
                )
                if percent_passing >= fail_under:
                    return 0
                else:
                    LOGGER.error("Failure. Quality is below {0}%.".format(fail_under))
                    return 1

            except (ImportError, EnvironmentError):
                LOGGER.error(
                    "Quality tool not installed: '{0}'".format(tool)
                )
                return 1
            # Close any reports we opened
            finally:
                for file_handle in input_reports:
                    file_handle.close()

        else:
            LOGGER.error("Quality tool not recognized: '{0}'".format(tool))
            return 1

    else:
        assert False, 'Expect diff-cover or diff-quality in {0}'.format(name)
 def _measured_source_path_matches(self, package_name, file_name, src_path):
     # find src_path in any of the source roots
     for root in self._src_roots:
         if GitPathTool.relative_path(
                 os.path.join(root, package_name, file_name)) == src_path:
             return True