예제 #1
0
def report_outcome(matches: List["MatchError"], options) -> int:
    """Display information about how to skip found rules.

    Returns exit code, 2 if erros were found, 0 when only warnings were found.
    """
    failure = False
    msg = """\
You can skip specific rules by adding them to the skip_list section of your configuration file:
```yaml
# .ansible-lint
warn_list:  # or 'skip_list' to silence them completely
"""
    matched_rules = {match.rule.id: match.rule.shortdesc for match in matches}
    for id in sorted(matched_rules.keys()):
        if id not in options.warn_list:
            msg += f"  - '{id}'  # {matched_rules[id]}'\n"
            failure = True
    msg += "```"

    if failure:
        if not options.quiet and not options.parseable:
            console.print(Markdown(msg))
        return 2
    else:
        return 0
예제 #2
0
    def render_matches(self, matches: List) -> None:
        """Display given matches."""
        if isinstance(self.formatter, formatters.CodeclimateJSONFormatter):
            # If formatter CodeclimateJSONFormatter is chosen,
            # then print only the matches in JSON
            console.print(
                self.formatter.format_result(matches), markup=False, highlight=False
            )
            return None

        ignored_matches = [match for match in matches if match.ignored]
        fatal_matches = [match for match in matches if not match.ignored]
        # Displayed ignored matches first
        if ignored_matches:
            _logger.warning(
                "Listing %s violation(s) marked as ignored, likely already known",
                len(ignored_matches),
            )
            for match in ignored_matches:
                if match.ignored:
                    # highlight must be off or apostrophes may produce unexpected results
                    console.print(self.formatter.format(match), highlight=False)
        if fatal_matches:
            _logger.warning(
                "Listing %s violation(s) that are fatal", len(fatal_matches)
            )
            for match in fatal_matches:
                if not match.ignored:
                    console.print(self.formatter.format(match), highlight=False)

        # If run under GitHub Actions we also want to emit output recognized by it.
        if os.getenv('GITHUB_ACTIONS') == 'true' and os.getenv('GITHUB_WORKFLOW'):
            formatter = formatters.AnnotationsFormatter(self.options.cwd, True)
            for match in matches:
                console.print(formatter.format(match), markup=False, highlight=False)
예제 #3
0
def _render_matches(
        matches: List,
        options: "Namespace",
        formatter: Any,
        cwd: Union[str, pathlib.Path]):

    ignored_matches = [match for match in matches if match.ignored]
    fatal_matches = [match for match in matches if not match.ignored]
    # Displayed ignored matches first
    if ignored_matches:
        _logger.warning(
            "Listing %s violation(s) marked as ignored, likely already known",
            len(ignored_matches))
        for match in ignored_matches:
            if match.ignored:
                # highlight must be off or apostrophes may produce unexpected results
                console.print(
                    formatter.format(match), highlight=False)
    if fatal_matches:
        _logger.warning("Listing %s violation(s) that are fatal", len(fatal_matches))
        for match in fatal_matches:
            if not match.ignored:
                console.print(formatter.format(match), highlight=False)

    # If run under GitHub Actions we also want to emit output recognized by it.
    if os.getenv('GITHUB_ACTIONS') == 'true' and os.getenv('GITHUB_WORKFLOW'):
        formatter = formatters.AnnotationsFormatter(cwd, True)
        for match in matches:
            console.print(formatter.format(match), markup=False, highlight=False)
예제 #4
0
def main(argv: Optional[List[str]] = None) -> int:
    """Linter CLI entry point."""
    if argv is None:
        argv = sys.argv
    initialize_options(argv[1:])

    console_options["force_terminal"] = options.colored
    reconfigure(console_options)

    initialize_logger(options.verbosity)
    _logger.debug("Options: %s", options)

    app = App(options=options)

    prepare_environment()
    check_ansible_presence(exit_on_error=True)

    # On purpose lazy-imports to avoid pre-loading Ansible
    # pylint: disable=import-outside-toplevel
    from ansiblelint.generate_docs import rules_as_rich, rules_as_rst, rules_as_str
    from ansiblelint.rules import RulesCollection

    rules = RulesCollection(options.rulesdirs)

    if options.listrules:

        _rule_format_map: Dict[str, Callable[..., Any]] = {
            'plain': rules_as_str,
            'rich': rules_as_rich,
            'rst': rules_as_rst,
        }

        console.print(_rule_format_map[options.format](rules), highlight=False)
        return 0

    if options.listtags:
        console.print(render_yaml(rules.listtags()))
        return 0

    if isinstance(options.tags, str):
        options.tags = options.tags.split(',')

    from ansiblelint.runner import _get_matches

    result = _get_matches(rules, options)

    mark_as_success = False
    if result.matches and options.progressive:
        _logger.info(
            "Matches found, running again on previous revision in order to detect regressions"
        )
        with _previous_revision():
            old_result = _get_matches(rules, options)
            # remove old matches from current list
            matches_delta = list(set(result.matches) - set(old_result.matches))
            if len(matches_delta) == 0:
                _logger.warning(
                    "Total violations not increased since previous "
                    "commit, will mark result as success. (%s -> %s)",
                    len(old_result.matches),
                    len(matches_delta),
                )
                mark_as_success = True

            ignored = 0
            for match in result.matches:
                # if match is not new, mark is as ignored
                if match not in matches_delta:
                    match.ignored = True
                    ignored += 1
            if ignored:
                _logger.warning(
                    "Marked %s previously known violation(s) as ignored due to"
                    " progressive mode.",
                    ignored,
                )

    app.render_matches(result.matches)

    return report_outcome(result,
                          mark_as_success=mark_as_success,
                          options=options)
예제 #5
0
def main(argv: List[str] = None) -> int:
    """Linter CLI entry point."""
    if argv is None:
        argv = sys.argv

    cwd = pathlib.Path.cwd()

    options = cli.get_config(argv[1:])

    if options.colored is None:
        options.colored = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
    if options.colored is not None:
        console_options["force_terminal"] = options.colored
        reconfigure(console_options)

    initialize_logger(options.verbosity)
    _logger.debug("Options: %s", options)

    formatter_factory = choose_formatter_factory(options)
    formatter = formatter_factory(cwd, options.display_relative_path)

    rulesdirs = get_rules_dirs([str(rdir) for rdir in options.rulesdir],
                               options.use_default_rules)
    rules = RulesCollection(rulesdirs)

    if options.listrules:
        console.print(
            _rule_format_map[options.format](rules),
            highlight=False)
        return 0

    if options.listtags:
        console.print(
            render_yaml(rules.listtags())
            )
        return 0

    if isinstance(options.tags, str):
        options.tags = options.tags.split(',')

    options.skip_list = _sanitize_list_options(options.skip_list)
    options.warn_list = _sanitize_list_options(options.warn_list)

    result = _get_matches(rules, options)

    mark_as_success = False
    if result.matches and options.progressive:
        _logger.info(
            "Matches found, running again on previous revision in order to detect regressions")
        with _previous_revision():
            old_result = _get_matches(rules, options)
            # remove old matches from current list
            matches_delta = list(set(result.matches) - set(old_result.matches))
            if len(matches_delta) == 0:
                _logger.warning(
                    "Total violations not increased since previous "
                    "commit, will mark result as success. (%s -> %s)",
                    len(old_result.matches), len(matches_delta))
                mark_as_success = True

            ignored = 0
            for match in result.matches:
                # if match is not new, mark is as ignored
                if match not in matches_delta:
                    match.ignored = True
                    ignored += 1
            if ignored:
                _logger.warning(
                    "Marked %s previously known violation(s) as ignored due to"
                    " progressive mode.", ignored)

    _render_matches(result.matches, options, formatter, cwd)

    return report_outcome(result, mark_as_success=mark_as_success, options=options)
예제 #6
0
def main() -> int:
    """Linter CLI entry point."""
    cwd = pathlib.Path.cwd()

    options = cli.get_config(sys.argv[1:])

    initialize_logger(options.verbosity)
    _logger.debug("Options: %s", options)

    formatter_factory = choose_formatter_factory(options)
    formatter = formatter_factory(cwd, options.display_relative_path)

    rulesdirs = get_rules_dirs([str(rdir) for rdir in options.rulesdir],
                               options.use_default_rules)
    rules = RulesCollection(rulesdirs)

    if options.listrules:
        console.print(_rule_format_map[options.format](rules), highlight=False)
        return 0

    if options.listtags:
        print(rules.listtags())
        return 0

    if isinstance(options.tags, str):
        options.tags = options.tags.split(',')

    skip = set()
    for s in options.skip_list:
        skip.update(str(s).split(','))
    options.skip_list = frozenset(skip)

    if not options.playbook:
        # no args triggers auto-detection mode
        playbooks = get_playbooks_and_roles(options=options)
    else:
        playbooks = sorted(set(options.playbook))

    matches = list()
    checked_files: Set[str] = set()
    for playbook in playbooks:
        runner = Runner(rules, playbook, options.tags, options.skip_list,
                        options.exclude_paths, options.verbosity,
                        checked_files)
        matches.extend(runner.run())

    # Assure we do not print duplicates and the order is consistent
    matches = sorted(set(matches))

    for match in matches:
        print(formatter.format(match, options.colored))

    # If run under GitHub Actions we also want to emit output recognized by it.
    if os.getenv('GITHUB_ACTIONS') == 'true' and os.getenv('GITHUB_WORKFLOW'):
        formatter = formatters.AnnotationsFormatter(cwd, True)
        for match in matches:
            print(formatter.format(match))

    if matches:
        return report_outcome(matches, options=options)
    else:
        return 0
예제 #7
0
def main() -> int:
    """Linter CLI entry point."""
    cwd = pathlib.Path.cwd()

    options = cli.get_config(sys.argv[1:])

    initialize_logger(options.verbosity)
    _logger.debug("Options: %s", options)

    formatter_factory = choose_formatter_factory(options)
    formatter = formatter_factory(cwd, options.display_relative_path)

    rulesdirs = get_rules_dirs([str(rdir) for rdir in options.rulesdir],
                               options.use_default_rules)
    rules = RulesCollection(rulesdirs)

    if options.listrules:
        console.print(_rule_format_map[options.format](rules), highlight=False)
        return 0

    if options.listtags:
        print(rules.listtags())
        return 0

    if isinstance(options.tags, str):
        options.tags = options.tags.split(',')

    skip = set()
    for s in options.skip_list:
        skip.update(str(s).split(','))
    options.skip_list = frozenset(skip)

    matches = _get_matches(rules, options)

    # Assure we do not print duplicates and the order is consistent
    matches = sorted(set(matches))

    mark_as_success = False
    if matches and options.progressive:
        _logger.info(
            "Matches found, running again on previous revision in order to detect regressions"
        )
        with _previous_revision():
            old_matches = _get_matches(rules, options)
            # remove old matches from current list
            matches_delta = list(set(matches) - set(old_matches))
            if len(matches_delta) == 0:
                _logger.warning(
                    "Total violations not increased since previous "
                    "commit, will mark result as success. (%s -> %s)",
                    len(old_matches), len(matches_delta))
                mark_as_success = True

            ignored = 0
            for match in matches:
                # if match is not new, mark is as ignored
                if match not in matches_delta:
                    match.ignored = True
                    ignored += 1
            if ignored:
                _logger.warning(
                    "Marked %s previously known violation(s) as ignored due to"
                    " progressive mode.", ignored)

    _render_matches(matches, options, formatter, cwd)

    if matches and not mark_as_success:
        return report_outcome(matches, options=options)
    else:
        return 0