Exemplo n.º 1
0
    def __init__(
            self,
            message: Optional[str] = None,
            linenumber: int = 0,
            column: Optional[int] = None,
            details: str = "",
            filename: Optional[Union[str, Lintable]] = None,
            rule: BaseRule = RuntimeErrorRule(),
            tag: Optional[str] = None,  # optional fine-graded tag
    ) -> None:
        """Initialize a MatchError instance."""
        super().__init__(message)

        if rule.__class__ is RuntimeErrorRule and not message:
            raise TypeError(
                f'{self.__class__.__name__}() missing a '
                "required argument: one of 'message' or 'rule'", )

        self.message = message or getattr(rule, 'shortdesc', "")
        self.linenumber = linenumber
        self.column = column
        self.details = details
        self.filename = ""
        if filename:
            if isinstance(filename, Lintable):
                self.filename = normpath(str(filename.path))
            else:
                self.filename = normpath(filename)
        self.rule = rule
        self.ignored = False  # If set it will be displayed but not counted as failure
        # This can be used by rules that can report multiple errors type, so
        # we can still filter by them.
        self.tag = tag
Exemplo n.º 2
0
def get_config(arguments: List[str]) -> Namespace:
    parser = get_cli_parser()
    options = parser.parse_args(arguments)

    file_config = load_config(options.config_file)

    config = merge_config(file_config, options)

    options.rulesdirs = get_rules_dirs(options.rulesdir, options.use_default_rules)

    if options.project_dir == ".":
        project_dir = os.path.dirname(
            os.path.abspath(
                options.config_file or f"{guess_project_dir()}/.ansible-lint"
            )
        )
        options.project_dir = normpath(project_dir)
    if not options.project_dir or not os.path.exists(options.project_dir):
        raise RuntimeError(
            f"Failed to determine a valid project_dir: {options.project_dir}"
        )

    # Compute final verbosity level by subtracting -q counter.
    options.verbosity -= options.quiet
    return config
Exemplo n.º 3
0
    def __init__(
            self,
            message: Optional[str] = None,
            # most linters report use (1,1) base, including yamllint and flake8
            # we should never report line 0 or column 0 in output.
            linenumber: int = 1,
            column: Optional[int] = None,
            details: str = "",
            filename: Optional[Union[str, Lintable]] = None,
            rule: BaseRule = RuntimeErrorRule(),
            tag: Optional[str] = None,  # optional fine-graded tag
    ) -> None:
        """Initialize a MatchError instance."""
        super().__init__(message)

        if rule.__class__ is RuntimeErrorRule and not message:
            raise TypeError(
                f'{self.__class__.__name__}() missing a '
                "required argument: one of 'message' or 'rule'", )

        self.message = message or getattr(rule, 'shortdesc', "")

        # Safety measture to ensure we do not endup with incorrect indexes
        if linenumber == 0:
            raise RuntimeError(
                "MatchError called incorrectly as line numbers start with 1")
        if column == 0:
            raise RuntimeError(
                "MatchError called incorrectly as column numbers start with 1")

        self.linenumber = linenumber
        self.column = column
        self.details = details
        self.filename = ""
        if filename:
            if isinstance(filename, Lintable):
                self.filename = normpath(str(filename.path))
            else:
                self.filename = normpath(filename)
        self.rule = rule
        self.ignored = False  # If set it will be displayed but not counted as failure
        # This can be used by rules that can report multiple errors type, so
        # we can still filter by them.
        self.tag = tag
Exemplo n.º 4
0
def get_config(arguments: List[str]) -> Namespace:
    parser = get_cli_parser()
    options = parser.parse_args(arguments)

    file_config = load_config(options.config_file)

    config = merge_config(file_config, options)

    options.rulesdirs = get_rules_dirs(options.rulesdir,
                                       options.use_default_rules)

    if not options.project_dir:
        project_dir = os.path.dirname(
            os.path.abspath(options.config_file
                            or f"{guess_project_dir()}/.ansiblelint"))
        options.project_dir = normpath(project_dir)

    return config
Exemplo n.º 5
0
    def __init__(self,
                 message=None,
                 linenumber=0,
                 details: str = "",
                 filename=None,
                 rule=None) -> None:
        """Initialize a MatchError instance."""
        super().__init__(message)

        if not (message or rule):
            raise TypeError(
                f'{self.__class__.__name__}() missing a '
                "required argument: one of 'message' or 'rule'", )

        self.message = message or getattr(rule, 'shortdesc', "")
        self.linenumber = linenumber
        self.details = details
        self.filename = normpath(filename) if filename else None
        self.rule = rule
Exemplo n.º 6
0
def get_config(arguments: List[str]) -> Namespace:
    parser = get_cli_parser()
    options = parser.parse_args(arguments)

    file_config = load_config(options.config_file)

    config = merge_config(file_config, options)

    options.rulesdirs = get_rules_dirs(options.rulesdir,
                                       options.use_default_rules)

    if not options.project_dir:
        project_dir = os.path.dirname(
            os.path.abspath(options.config_file
                            or f"{guess_project_dir()}/.ansible-lint"))
        options.project_dir = normpath(project_dir)

    # print(666, options.quiet, options.verbosity)
    # Compute final verbosity level by subtracting -q counter.
    options.verbosity -= options.quiet
    return config
Exemplo n.º 7
0
def test_normpath_with_path_object(path):
    """Ensure that relative parent dirs are normalized in paths."""
    assert normpath(path) == "a"
Exemplo n.º 8
0
def get_lintables(options: Namespace = Namespace(),
                  args: Optional[List[str]] = None) -> List[Lintable]:
    """Detect files and directories that are lintable."""
    lintables: List[Lintable] = []

    # passing args bypass auto-detection mode
    if args:
        for arg in args:
            if os.path.isdir(arg):
                lintables.append(Lintable(arg, kind="role"))
            elif os.path.isfile(arg):
                lintables.append(Lintable(arg, kind="playbook"))
            else:
                _logger.warning("Unable to access %s", arg)
    else:

        files = get_yaml_files(options)

        playbooks: List[str] = []
        role_dirs: List[str] = []
        role_internals = {
            'defaults',
            'files',
            'handlers',
            'meta',
            'tasks',
            'templates',
            'vars',
        }

        # detect role in repository root:
        if 'tasks/main.yml' in files or 'tasks/main.yaml' in files:
            role_dirs.append('.')

        for p in map(Path, files):

            try:
                for file_path in options.exclude_paths:
                    if str(p.resolve()).startswith(str(file_path)):
                        raise FileNotFoundError(
                            f'File {file_path} matched exclusion entry: {p}')
            except FileNotFoundError as e:
                _logger.debug('Ignored %s due to: %s', p, e)
                continue

            if (next((i for i in p.parts if i.endswith('playbooks')), None)
                    or 'playbook' in p.parts[-1]):
                playbooks.append(normpath(p))
                continue

            # ignore if any folder ends with _vars
            if next((i for i in p.parts if i.endswith('_vars')), None):
                continue
            elif 'roles' in p.parts or '.' in role_dirs:
                if 'tasks' in p.parts and p.parts[-1] in [
                        'main.yaml', 'main.yml'
                ]:
                    role_dirs.append(str(p.parents[1]))
                    continue
                elif role_internals.intersection(p.parts):
                    continue
                elif 'tests' in p.parts:
                    playbooks.append(normpath(p))
            if 'molecule' in p.parts:
                if p.parts[-1] != 'molecule.yml':
                    playbooks.append(normpath(p))
                continue
            # hidden files are clearly not playbooks, likely config files.
            if p.parts[-1].startswith('.'):
                continue

            if is_playbook(str(p)):
                playbooks.append(normpath(p))
                continue

            _logger.info('Unknown file type: %s', normpath(p))

        _logger.info('Found roles: %s', ' '.join(role_dirs))
        _logger.info('Found playbooks: %s', ' '.join(playbooks))

        for role in role_dirs:
            lintables.append(Lintable(role, kind="role"))
        for playbook in playbooks:
            lintables.append(Lintable(playbook, kind="playbook"))

    return lintables
Exemplo n.º 9
0
def get_playbooks_and_roles(options=None) -> List[str]:  # noqa: C901
    """Find roles and playbooks."""
    if options is None:
        options = {}

    files = get_yaml_files(options)

    playbooks = []
    role_dirs = []
    role_internals = {
        'defaults',
        'files',
        'handlers',
        'meta',
        'tasks',
        'templates',
        'vars',
    }

    # detect role in repository root:
    if 'tasks/main.yml' in files or 'tasks/main.yaml' in files:
        role_dirs.append('.')

    for p in map(Path, files):

        try:
            for file_path in options.exclude_paths:
                if str(p.resolve()).startswith(str(file_path)):
                    raise FileNotFoundError(
                        f'File {file_path} matched exclusion entry: {p}')
        except FileNotFoundError as e:
            _logger.debug('Ignored %s due to: %s', p, e)
            continue

        if (next((i for i in p.parts if i.endswith('playbooks')), None)
                or 'playbook' in p.parts[-1]):
            playbooks.append(normpath(p))
            continue

        # ignore if any folder ends with _vars
        if next((i for i in p.parts if i.endswith('_vars')), None):
            continue
        elif 'roles' in p.parts or '.' in role_dirs:
            if 'tasks' in p.parts and p.parts[-1] in ['main.yaml', 'main.yml']:
                role_dirs.append(str(p.parents[1]))
            elif role_internals.intersection(p.parts):
                continue
            elif 'tests' in p.parts:
                playbooks.append(normpath(p))
        if 'molecule' in p.parts:
            if p.parts[-1] != 'molecule.yml':
                playbooks.append(normpath(p))
            continue
        # hidden files are clearly not playbooks, likely config files.
        if p.parts[-1].startswith('.'):
            continue

        if is_playbook(str(p)):
            playbooks.append(normpath(p))
            continue

        _logger.info('Unknown file type: %s', normpath(p))

    _logger.info('Found roles: %s', ' '.join(role_dirs))
    _logger.info('Found playbooks: %s', ' '.join(playbooks))

    return role_dirs + playbooks
Exemplo n.º 10
0
def test_normpath_with_path_object(path):
    assert normpath(path) == "a"
Exemplo n.º 11
0
def main(args):
    # formatter = formatters.Formatter()

    parser = optparse.OptionParser("%prog [options] [playbook.yml [playbook2 ...]]|roledirectory",
                                   version="%prog " + __version__)

    parser.add_option('-L', dest='listrules', default=False,
                      action='store_true', help="list all the rules")
    parser.add_option('-q', dest='quiet',
                      default=False,
                      action='store_true',
                      help="quieter, although not silent output")
    parser.add_option('-p', dest='parseable',
                      default=False,
                      action='store_true',
                      help="parseable output in the format of pep8")
    parser.add_option('--parseable-severity', dest='parseable_severity',
                      default=False,
                      action='store_true',
                      help="parseable output including severity of rule")
    parser.add_option('-r', action='append', dest='rulesdir',
                      default=[], type='str',
                      help="specify one or more rules directories using "
                           "one or more -r arguments. Any -r flags override "
                           "the default rules in %s, unless -R is also used."
                           % DEFAULT_RULESDIR)
    parser.add_option('-R', action='store_true',
                      default=False,
                      dest='use_default_rules',
                      help="Use default rules in %s in addition to any extra "
                           "rules directories specified with -r. There is "
                           "no need to specify this if no -r flags are used"
                           % DEFAULT_RULESDIR)
    parser.add_option('-t', dest='tags',
                      action='append',
                      default=[],
                      help="only check rules whosef id/tags match these values")
    parser.add_option('-T', dest='listtags', action='store_true',
                      help="list all the tags")
    parser.add_option('-v', dest='verbosity', action='count',
                      help="Increase verbosity level",
                      default=0)
    parser.add_option('-x', dest='skip_list', default=[], action='append',
                      help="only check rules whose id/tags do not " +
                           "match these values")
    parser.add_option('--nocolor', dest='colored',
                      default=hasattr(sys.stdout, 'isatty') and sys.stdout.isatty(),
                      action='store_false',
                      help="disable colored output")
    parser.add_option('--force-color', dest='colored',
                      action='store_true',
                      help="Try force colored output (relying on ansible's code)")
    parser.add_option('--exclude', dest='exclude_paths', action='append',
                      help='path to directories or files to skip. This option'
                           ' is repeatable.',
                      default=[])
    parser.add_option('-c', dest='config_file',
                      help='Specify configuration file to use.  Defaults to ".ansible-lint"')
    options, args = parser.parse_args(args)

    config = load_config(options.config_file)

    if config:
        if 'quiet' in config:
            options.quiet = options.quiet or config['quiet']

        if 'parseable' in config:
            options.parseable = options.parseable or config['parseable']

        if 'parseable_severity' in config:
            options.parseable_severity = options.parseable_severity or \
                                         config['parseable_severity']

        if 'use_default_rules' in config:
            options.use_default_rules = options.use_default_rules or config['use_default_rules']

        if 'verbosity' in config:
            options.verbosity = options.verbosity + config['verbosity']

        options.exclude_paths.extend(
            config.get('exclude_paths', []))

        if 'rulesdir' in config:
            options.rulesdir = options.rulesdir + config['rulesdir']

        if 'skip_list' in config:
            options.skip_list = options.skip_list + config['skip_list']

        if 'tags' in config:
            options.tags = options.tags + config['tags']

    if options.quiet:
        formatter = formatters.QuietFormatter()

    if options.parseable:
        formatter = formatters.ParseableFormatter()

    if options.parseable_severity:
        formatter = formatters.ParseableSeverityFormatter()

    # # # no args triggers auto-detection mode
    # if len(args) == 0 and not (options.listrules or options.listtags):
    #     args = get_playbooks_and_roles(options=options)

    if options.use_default_rules:
        rulesdirs = options.rulesdir + [DEFAULT_RULESDIR]
    else:
        rulesdirs = options.rulesdir or [DEFAULT_RULESDIR]

    rules = RulesCollection(rulesdirs)
    # for rulesdir in rulesdirs:
    #     rules.extend(RulesCollection.load_plugins(rulesdir))

    if options.listrules:
        print(rules)
        return 0

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

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

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

    playbooks = sorted(set(args))
    matches = list()
    checked_files = set()
    for playbook in playbooks:
        runner = Runner(playbook=playbook, rules=rules)
        matches.extend(runner.run())

    matches.sort(key=lambda x: (normpath(x.filename), x.linenumber, x.rule.id))

    return matches