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
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
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
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
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
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
def test_normpath_with_path_object(path): """Ensure that relative parent dirs are normalized in paths.""" assert normpath(path) == "a"
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
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
def test_normpath_with_path_object(path): assert normpath(path) == "a"
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