From 137e559d575cb2997e7e8c397f1dbf6c27896fcf Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Thu, 25 Jan 2024 21:09:05 +0100 Subject: [PATCH] refactor: drop default standards version and rename to rules --- ansiblelater/__main__.py | 32 ++-- ansiblelater/candidate.py | 159 ++++++------------ ansiblelater/{standard.py => rule.py} | 50 +++--- ansiblelater/rules/CheckBecomeUser.py | 5 +- ansiblelater/rules/CheckBracesSpaces.py | 5 +- ansiblelater/rules/CheckChangedInWhen.py | 5 +- ansiblelater/rules/CheckCommandHasChanges.py | 5 +- .../rules/CheckCommandInsteadOfArgument.py | 5 +- .../rules/CheckCommandInsteadOfModule.py | 5 +- .../rules/CheckCompareToEmptyString.py | 5 +- .../rules/CheckCompareToLiteralBool.py | 5 +- ansiblelater/rules/CheckDeprecated.py | 5 +- ansiblelater/rules/CheckDeprecatedBareVars.py | 5 +- .../rules/CheckFilePermissionMissing.py | 5 +- .../rules/CheckFilePermissionOctal.py | 5 +- ansiblelater/rules/CheckFilterSeparation.py | 5 +- ansiblelater/rules/CheckGitHasVersion.py | 5 +- ansiblelater/rules/CheckInstallUseLatest.py | 5 +- ansiblelater/rules/CheckLiteralBoolFormat.py | 5 +- ansiblelater/rules/CheckLocalAction.py | 5 +- .../rules/CheckMetaChangeFromDefault.py | 5 +- ansiblelater/rules/CheckMetaMain.py | 5 +- ansiblelater/rules/CheckNameFormat.py | 5 +- ansiblelater/rules/CheckNamedTask.py | 5 +- ansiblelater/rules/CheckNativeYaml.py | 5 +- ansiblelater/rules/CheckNestedJinja.py | 5 +- ansiblelater/rules/CheckRelativeRolePaths.py | 5 +- ansiblelater/rules/CheckScmInSrc.py | 5 +- .../rules/CheckShellInsteadCommand.py | 5 +- ansiblelater/rules/CheckTaskSeparation.py | 5 +- ansiblelater/rules/CheckUniqueNamedTask.py | 5 +- ansiblelater/rules/CheckVersion.py | 16 -- ansiblelater/rules/CheckWhenFormat.py | 5 +- ansiblelater/rules/CheckYamlColons.py | 5 +- ansiblelater/rules/CheckYamlDocumentEnd.py | 5 +- ansiblelater/rules/CheckYamlDocumentStart.py | 5 +- ansiblelater/rules/CheckYamlEmptyLines.py | 5 +- ansiblelater/rules/CheckYamlFile.py | 5 +- ansiblelater/rules/CheckYamlHasContent.py | 5 +- ansiblelater/rules/CheckYamlHyphens.py | 5 +- ansiblelater/rules/CheckYamlIndent.py | 5 +- ansiblelater/settings.py | 15 +- ansiblelater/utils/__init__.py | 7 - .../{standards_check.md => rule.md} | 7 +- docs/content/configuration/cli.md | 25 ++- docs/content/configuration/defaults.md | 15 +- docs/content/included_rules/_index.md | 3 +- docs/data/menu/main.yml | 4 +- 48 files changed, 197 insertions(+), 321 deletions(-) rename ansiblelater/{standard.py => rule.py} (84%) delete mode 100644 ansiblelater/rules/CheckVersion.py rename docs/content/build_rules/{standards_check.md => rule.md} (89%) diff --git a/ansiblelater/__main__.py b/ansiblelater/__main__.py index 28a49d3..4202008 100755 --- a/ansiblelater/__main__.py +++ b/ansiblelater/__main__.py @@ -7,8 +7,8 @@ import sys from ansiblelater import LOG, __version__, logger from ansiblelater.candidate import Candidate +from ansiblelater.rule import SingleRules from ansiblelater.settings import Settings -from ansiblelater.standard import SingleStandards def main(): @@ -22,33 +22,33 @@ def main(): parser.add_argument( "-r", "--rules-dir", - dest="rules.standards", - metavar="RULES", + dest="rules.dir", + metavar="DIR", action="append", - help="directory of standard rules", + help="directory of rules", ) parser.add_argument( "-B", - "--no-buildin", - dest="rules.buildin", + "--no-builtin", + dest="rules.builtin", action="store_false", - help="disables build-in standard rules", + help="disables built-in rules", ) parser.add_argument( - "-s", - "--standards", - dest="rules.filter", - metavar="FILTER", + "-i", + "--include-rules", + dest="rules.include_filter", + metavar="TAGS", action="append", - help="limit standards to given ID's", + help="limit rules to given id/tags", ) parser.add_argument( "-x", - "--exclude-standards", + "--exclude-rules", dest="rules.exclude_filter", - metavar="EXCLUDE_FILTER", + metavar="TAGS", action="append", - help="exclude standards by given ID's", + help="exclude rules by given it/tags", ) parser.add_argument( "-v", dest="logging.level", action="append_const", const=-1, help="increase log level" @@ -65,7 +65,7 @@ def main(): config = settings.config logger.update_logger(LOG, config["logging"]["level"], config["logging"]["json"]) - SingleStandards(config["rules"]["standards"]) + SingleRules(config["rules"]["dir"]) workers = max(multiprocessing.cpu_count() - 2, 2) p = multiprocessing.Pool(workers) diff --git a/ansiblelater/candidate.py b/ansiblelater/candidate.py index 6a326c7..1c0ecd2 100644 --- a/ansiblelater/candidate.py +++ b/ansiblelater/candidate.py @@ -3,14 +3,12 @@ import codecs import copy import os -import re from ansible.plugins.loader import module_loader -from packaging.version import Version -from ansiblelater import LOG, utils +from ansiblelater import LOG from ansiblelater.logger import flag_extra -from ansiblelater.standard import SingleStandards, StandardBase +from ansiblelater.rule import RuleBase, SingleRules class Candidate: @@ -21,7 +19,7 @@ class Candidate: bundled with necessary meta informations for rule processing. """ - def __init__(self, filename, settings={}, standards=[]): # noqa + def __init__(self, filename, settings={}, rules=[]): # noqa self.path = filename self.binary = False self.vault = False @@ -37,163 +35,114 @@ class Candidate: except UnicodeDecodeError: self.binary = True - def _get_version(self): - name = type(self).__name__ - path = self.path - version = None - config_version = self.config["rules"]["version"].strip() - - if config_version: - version_config_re = re.compile(r"([\d.]+)") - match = version_config_re.match(config_version) - if match: - version = match.group(1) - - if not self.binary: - if isinstance(self, RoleFile): - parentdir = os.path.dirname(os.path.abspath(self.path)) - while parentdir != os.path.dirname(parentdir): - meta_file = os.path.join(parentdir, "meta", "main.yml") - if os.path.exists(meta_file): - path = meta_file - break - parentdir = os.path.dirname(parentdir) - - version_file_re = re.compile(r"^# Standards:\s*([\d.]+)") - with codecs.open(path, mode="rb", encoding="utf-8") as f: - for line in f: - match = version_file_re.match(line) - if match: - version = match.group(1) - - if version: - LOG.info(f"{name} {path} declares standards version {version}") - - return version - - def _filter_standards(self): - target_standards = [] - includes = self.config["rules"]["filter"] + def _filter_rules(self): + target_rules = [] + includes = self.config["rules"]["include_filter"] excludes = self.config["rules"]["exclude_filter"] if len(includes) == 0: - includes = [s.sid for s in self.standards] + includes = [s.sid for s in self.rules] - for standard in self.standards: - if standard.sid in includes and standard.sid not in excludes: - target_standards.append(standard) + for rule in self.rules: + if rule.sid in includes and rule.sid not in excludes: + target_rules.append(rule) - return target_standards + return target_rules def review(self): errors = 0 - self.standards = SingleStandards(self.config["rules"]["standards"]).rules - self.version_config = self._get_version() - self.version = self.version_config or utils.standards_latest(self.standards) + self.rules = SingleRules(self.config["rules"]["dir"]).rules - for standard in self._filter_standards(): - if type(self).__name__.lower() not in standard.types: + for rule in self._filter_rules(): + if type(self).__name__.lower() not in rule.types: continue - result = standard.check(self, self.config) + result = rule.check(self, self.config) if not result: - LOG.error( - f"Standard '{standard.sid}' returns an empty result object. Check failed!" - ) + LOG.error(f"rule '{rule.sid}' returns an empty result object. Check failed!") continue labels = { "tag": "review", - "standard": standard.description, + "rule": rule.description, "file": self.path, "passed": True, } - if standard.sid and standard.sid.strip(): - labels["sid"] = standard.sid + if rule.sid and rule.sid.strip(): + labels["sid"] = rule.sid for err in result.errors: err_labels = copy.copy(labels) err_labels["passed"] = False - sid = self._format_id(standard.sid) + sid = self._format_id(rule.sid) path = self.path - description = standard.description + description = rule.description - if isinstance(err, StandardBase.Error): + if isinstance(err, RuleBase.Error): err_labels.update(err.to_dict()) - if not standard.version: - LOG.warning( - f"{sid}Best practice '{description}' not met:\n{path}:{err}", - extra=flag_extra(err_labels), - ) - elif Version(standard.version) > Version(self.version): - LOG.warning( - f"{sid}Future standard '{description}' not met:\n{path}:{err}", - extra=flag_extra(err_labels), - ) - else: - msg = f"{sid}Standard '{description}' not met:\n{path}:{err}" + msg = f"{sid}rule '{description}' not met:\n{path}:{err}" - if standard.sid not in self.config["rules"]["warning_filter"]: - LOG.error(msg, extra=flag_extra(err_labels)) - errors = errors + 1 - else: - LOG.warning(msg, extra=flag_extra(err_labels)) + if rule.sid not in self.config["rules"]["warning_filter"]: + LOG.error(msg, extra=flag_extra(err_labels)) + errors = errors + 1 + else: + LOG.warning(msg, extra=flag_extra(err_labels)) return errors @staticmethod - def classify(filename, settings={}, standards=[]): # noqa + def classify(filename, settings={}, rules=[]): # noqa parentdir = os.path.basename(os.path.dirname(filename)) basename = os.path.basename(filename) ext = os.path.splitext(filename)[1][1:] if parentdir in ["tasks"]: - return Task(filename, settings, standards) + return Task(filename, settings, rules) if parentdir in ["handlers"]: - return Handler(filename, settings, standards) + return Handler(filename, settings, rules) if parentdir in ["vars", "defaults"]: - return RoleVars(filename, settings, standards) + return RoleVars(filename, settings, rules) if "group_vars" in filename.split(os.sep): - return GroupVars(filename, settings, standards) + return GroupVars(filename, settings, rules) if "host_vars" in filename.split(os.sep): - return HostVars(filename, settings, standards) + return HostVars(filename, settings, rules) if parentdir in ["meta"] and "main" in basename: - return Meta(filename, settings, standards) + return Meta(filename, settings, rules) if parentdir in ["meta"] and "argument_specs" in basename: - return ArgumentSpecs(filename, settings, standards) + return ArgumentSpecs(filename, settings, rules) if parentdir in [ "library", "lookup_plugins", "callback_plugins", "filter_plugins", ] or filename.endswith(".py"): - return Code(filename, settings, standards) + return Code(filename, settings, rules) if basename == "inventory" or basename == "hosts" or parentdir in ["inventories"]: - return Inventory(filename, settings, standards) + return Inventory(filename, settings, rules) if "rolesfile" in basename or ("requirements" in basename and ext in ["yaml", "yml"]): - return Rolesfile(filename, settings, standards) + return Rolesfile(filename, settings, rules) if "Makefile" in basename: - return Makefile(filename, settings, standards) + return Makefile(filename, settings, rules) if "templates" in filename.split(os.sep) or basename.endswith(".j2"): - return Template(filename, settings, standards) + return Template(filename, settings, rules) if "files" in filename.split(os.sep): - return File(filename, settings, standards) + return File(filename, settings, rules) if basename.endswith(".yml") or basename.endswith(".yaml"): - return Playbook(filename, settings, standards) + return Playbook(filename, settings, rules) if "README" in basename: - return Doc(filename, settings, standards) + return Doc(filename, settings, rules) return None - def _format_id(self, standard_id): - sid = standard_id.strip() + def _format_id(self, rule_id): + sid = rule_id.strip() if sid: - standard_id = f"[{sid}] " + rule_id = f"[{sid}] " - return standard_id + return rule_id def __repr__(self): return f"{type(self).__name__} ({self.path})" @@ -205,8 +154,8 @@ class Candidate: class RoleFile(Candidate): """Object classified as Ansible role file.""" - def __init__(self, filename, settings={}, standards=[]): # noqa - super().__init__(filename, settings, standards) + def __init__(self, filename, settings={}, rules=[]): # noqa + super().__init__(filename, settings, rules) parentdir = os.path.dirname(os.path.abspath(filename)) while parentdir != os.path.dirname(parentdir): @@ -226,16 +175,16 @@ class Playbook(Candidate): class Task(RoleFile): """Object classified as Ansible task file.""" - def __init__(self, filename, settings={}, standards=[]): # noqa - super().__init__(filename, settings, standards) + def __init__(self, filename, settings={}, rules=[]): # noqa + super().__init__(filename, settings, rules) self.filetype = "tasks" class Handler(RoleFile): """Object classified as Ansible handler file.""" - def __init__(self, filename, settings={}, standards=[]): # noqa - super().__init__(filename, settings, standards) + def __init__(self, filename, settings={}, rules=[]): # noqa + super().__init__(filename, settings, rules) self.filetype = "handlers" diff --git a/ansiblelater/standard.py b/ansiblelater/rule.py similarity index 84% rename from ansiblelater/standard.py rename to ansiblelater/rule.py index 507117c..4bd6e71 100644 --- a/ansiblelater/standard.py +++ b/ansiblelater/rule.py @@ -1,4 +1,4 @@ -"""Standard definition.""" +"""Rule definition.""" import copy import importlib @@ -27,22 +27,21 @@ from ansiblelater.utils.yamlhelper import ( ) -class StandardMeta(type): +class RuleMeta(type): def __call__(cls, *args): mcls = type.__call__(cls, *args) mcls.sid = cls.sid mcls.description = getattr(cls, "description", "__unknown__") mcls.helptext = getattr(cls, "helptext", "") - mcls.version = getattr(cls, "version", None) mcls.types = getattr(cls, "types", []) return mcls -class StandardExtendedMeta(StandardMeta, ABCMeta): +class RuleExtendedMeta(RuleMeta, ABCMeta): pass -class StandardBase(metaclass=StandardExtendedMeta): +class RuleBase(metaclass=RuleExtendedMeta): SHELL_PIPE_CHARS = "&|<>;$\n*[]{}?" @property @@ -55,7 +54,7 @@ class StandardBase(metaclass=StandardExtendedMeta): pass def __repr__(self): - return f"Standard: {self.description} (version: {self.version}, types: {self.types})" + return f"Rule: {self.description} (types: {self.types})" @staticmethod def get_tasks(candidate, settings): # noqa @@ -69,11 +68,11 @@ class StandardBase(metaclass=StandardExtendedMeta): except LaterError as ex: e = ex.original errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True except LaterAnsibleError as e: - errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) + errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}")) candidate.faulty = True return yamllines, errors @@ -93,11 +92,11 @@ class StandardBase(metaclass=StandardExtendedMeta): except LaterError as ex: e = ex.original errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True except LaterAnsibleError as e: - errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) + errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}")) candidate.faulty = True return tasks, errors @@ -115,11 +114,11 @@ class StandardBase(metaclass=StandardExtendedMeta): except LaterError as ex: e = ex.original errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True except LaterAnsibleError as e: - errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) + errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}")) candidate.faulty = True return normalized, errors @@ -159,11 +158,11 @@ class StandardBase(metaclass=StandardExtendedMeta): except LaterError as ex: e = ex.original errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True except LaterAnsibleError as e: - errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) + errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}")) candidate.faulty = True return normalized, errors @@ -184,11 +183,11 @@ class StandardBase(metaclass=StandardExtendedMeta): except LaterError as ex: e = ex.original errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True except LaterAnsibleError as e: - errors.append(StandardBase.Error(e.line, f"syntax error: {e.message}")) + errors.append(RuleBase.Error(e.line, f"syntax error: {e.message}")) candidate.faulty = True return yamllines, errors @@ -210,7 +209,7 @@ class StandardBase(metaclass=StandardExtendedMeta): content = yaml.safe_load(f) except yaml.YAMLError as e: errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True @@ -224,14 +223,14 @@ class StandardBase(metaclass=StandardExtendedMeta): try: with open(candidate.path, encoding="utf-8") as f: for problem in linter.run(f, YamlLintConfig(options)): - errors.append(StandardBase.Error(problem.line, problem.desc)) + errors.append(RuleBase.Error(problem.line, problem.desc)) except yaml.YAMLError as e: errors.append( - StandardBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") + RuleBase.Error(e.problem_mark.line + 1, f"syntax error: {e.problem}") ) candidate.faulty = True except (TypeError, ValueError) as e: - errors.append(StandardBase.Error(None, f"yamllint error: {e}")) + errors.append(RuleBase.Error(None, f"yamllint error: {e}")) candidate.faulty = True return errors @@ -302,7 +301,7 @@ class StandardBase(metaclass=StandardExtendedMeta): return "\n".join([f"{self.candidate}:{error}" for error in self.errors]) -class StandardLoader: +class RulesLoader: def __init__(self, source): self.rules = [] @@ -331,10 +330,7 @@ class StandardLoader: def _is_plugin(self, obj): return ( - inspect.isclass(obj) - and issubclass(obj, StandardBase) - and obj is not StandardBase - and not None + inspect.isclass(obj) and issubclass(obj, RuleBase) and obj is not RuleBase and not None ) def validate(self): @@ -343,11 +339,11 @@ class StandardLoader: all_std = len(normalized_std) if all_std != unique_std: sysexit_with_message( - "Detect duplicate ID's in standards definition. Please use unique ID's only." + "Found duplicate tags in rules definition. Please use unique tags only." ) -class SingleStandards(StandardLoader, metaclass=Singleton): +class SingleRules(RulesLoader, metaclass=Singleton): """Singleton config class.""" pass diff --git a/ansiblelater/rules/CheckBecomeUser.py b/ansiblelater/rules/CheckBecomeUser.py index 3befe7a..89703c9 100644 --- a/ansiblelater/rules/CheckBecomeUser.py +++ b/ansiblelater/rules/CheckBecomeUser.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckBecomeUser(StandardBase): +class CheckBecomeUser(RuleBase): sid = "ANSIBLE0015" description = "Become should be combined with become_user" helptext = "the task has `become` enabled but `become_user` is missing" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckBracesSpaces.py b/ansiblelater/rules/CheckBracesSpaces.py index 14d3414..58f56d6 100644 --- a/ansiblelater/rules/CheckBracesSpaces.py +++ b/ansiblelater/rules/CheckBracesSpaces.py @@ -1,14 +1,13 @@ import re -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase from ansiblelater.utils import count_spaces -class CheckBracesSpaces(StandardBase): +class CheckBracesSpaces(RuleBase): sid = "ANSIBLE0004" description = "YAML should use consistent number of spaces around variables" helptext = "no suitable numbers of spaces (min: {min} max: {max})" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckChangedInWhen.py b/ansiblelater/rules/CheckChangedInWhen.py index 758dfa4..36bf9d2 100644 --- a/ansiblelater/rules/CheckChangedInWhen.py +++ b/ansiblelater/rules/CheckChangedInWhen.py @@ -18,14 +18,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckChangedInWhen(StandardBase): +class CheckChangedInWhen(RuleBase): sid = "ANSIBLE0026" description = "Use handlers instead of `when: changed`" helptext = "tasks using `when: result.changed` setting are effectively acting as a handler" - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckCommandHasChanges.py b/ansiblelater/rules/CheckCommandHasChanges.py index 758c005..21a1f18 100644 --- a/ansiblelater/rules/CheckCommandHasChanges.py +++ b/ansiblelater/rules/CheckCommandHasChanges.py @@ -1,14 +1,13 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckCommandHasChanges(StandardBase): +class CheckCommandHasChanges(RuleBase): sid = "ANSIBLE0011" description = "Commands should be idempotent" helptext = ( "commands should only read while using `changed_when` or try to be " "idempotent while using controls like `creates`, `removes` or `when`" ) - version = "0.1" types = ["playbook", "task"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckCommandInsteadOfArgument.py b/ansiblelater/rules/CheckCommandInsteadOfArgument.py index 5507f7a..756548b 100644 --- a/ansiblelater/rules/CheckCommandInsteadOfArgument.py +++ b/ansiblelater/rules/CheckCommandInsteadOfArgument.py @@ -20,14 +20,13 @@ import os -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckCommandInsteadOfArgument(StandardBase): +class CheckCommandInsteadOfArgument(RuleBase): sid = "ANSIBLE0017" description = "Commands should not be used in place of module arguments" helptext = "{exec} used in place of file modules argument {arg}" - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckCommandInsteadOfModule.py b/ansiblelater/rules/CheckCommandInsteadOfModule.py index dd836ba..e031985 100644 --- a/ansiblelater/rules/CheckCommandInsteadOfModule.py +++ b/ansiblelater/rules/CheckCommandInsteadOfModule.py @@ -1,13 +1,12 @@ import os -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckCommandInsteadOfModule(StandardBase): +class CheckCommandInsteadOfModule(RuleBase): sid = "ANSIBLE0008" description = "Commands should not be used in place of modules" helptext = "{exec} command used in place of {module} module" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckCompareToEmptyString.py b/ansiblelater/rules/CheckCompareToEmptyString.py index 025ea37..00e1e01 100644 --- a/ansiblelater/rules/CheckCompareToEmptyString.py +++ b/ansiblelater/rules/CheckCompareToEmptyString.py @@ -1,14 +1,13 @@ import re from ansiblelater.candidate import Template -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckCompareToEmptyString(StandardBase): +class CheckCompareToEmptyString(RuleBase): sid = "ANSIBLE0012" description = 'Don\'t compare to empty string ""' helptext = "use `when: var` rather than `when: var !=` (or conversely `when: not var`)" - version = "0.1" types = ["playbook", "task", "handler", "template"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckCompareToLiteralBool.py b/ansiblelater/rules/CheckCompareToLiteralBool.py index 7e3b3e7..9824c9c 100644 --- a/ansiblelater/rules/CheckCompareToLiteralBool.py +++ b/ansiblelater/rules/CheckCompareToLiteralBool.py @@ -1,14 +1,13 @@ import re from ansiblelater.candidate import Template -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckCompareToLiteralBool(StandardBase): +class CheckCompareToLiteralBool(RuleBase): sid = "ANSIBLE0013" description = "Don't compare to True or False" helptext = "use `when: var` rather than `when: var == True` (or conversely `when: not var`)" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckDeprecated.py b/ansiblelater/rules/CheckDeprecated.py index e396413..561313b 100644 --- a/ansiblelater/rules/CheckDeprecated.py +++ b/ansiblelater/rules/CheckDeprecated.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckDeprecated(StandardBase): +class CheckDeprecated(RuleBase): sid = "ANSIBLE9999" description = "Deprecated features should not be used" helptext = "'{old}' is deprecated and should not be used anymore. Use '{new}' instead." - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckDeprecatedBareVars.py b/ansiblelater/rules/CheckDeprecatedBareVars.py index 123a98a..7a66f7f 100644 --- a/ansiblelater/rules/CheckDeprecatedBareVars.py +++ b/ansiblelater/rules/CheckDeprecatedBareVars.py @@ -20,18 +20,17 @@ import os -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase from ansiblelater.utils import has_glob, has_jinja -class CheckDeprecatedBareVars(StandardBase): +class CheckDeprecatedBareVars(RuleBase): sid = "ANSIBLE0027" description = "Deprecated bare variables in loops must not be used" helptext = ( "bare var '{barevar}' in '{loop_type}' must use full var syntax '{{{{ {barevar} }}}}' " "or be converted to a list" ) - version = "0.3" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckFilePermissionMissing.py b/ansiblelater/rules/CheckFilePermissionMissing.py index 8b6b364..3ca1856 100644 --- a/ansiblelater/rules/CheckFilePermissionMissing.py +++ b/ansiblelater/rules/CheckFilePermissionMissing.py @@ -19,17 +19,16 @@ # THE SOFTWARE. import re -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckFilePermissionMissing(StandardBase): +class CheckFilePermissionMissing(RuleBase): sid = "ANSIBLE0018" description = "File permissions unset or incorrect" helptext = ( "`mode` parameter should set permissions explicitly (e.g. `mode: 0644`) " "to avoid unexpected file permissions" ) - version = "0.2" types = ["playbook", "task", "handler"] _modules = { diff --git a/ansiblelater/rules/CheckFilePermissionOctal.py b/ansiblelater/rules/CheckFilePermissionOctal.py index 96691a5..18d3dcd 100644 --- a/ansiblelater/rules/CheckFilePermissionOctal.py +++ b/ansiblelater/rules/CheckFilePermissionOctal.py @@ -18,14 +18,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckFilePermissionOctal(StandardBase): +class CheckFilePermissionOctal(RuleBase): sid = "ANSIBLE0019" description = "Octal file permissions must contain leading zero or be a string" helptext = "numeric file permissions without leading zero can behave in unexpected ways" - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckFilterSeparation.py b/ansiblelater/rules/CheckFilterSeparation.py index e754b6d..64efac2 100644 --- a/ansiblelater/rules/CheckFilterSeparation.py +++ b/ansiblelater/rules/CheckFilterSeparation.py @@ -1,13 +1,12 @@ import re -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckFilterSeparation(StandardBase): +class CheckFilterSeparation(RuleBase): sid = "ANSIBLE0016" description = "Jinja2 filters should be separated with spaces" helptext = "no suitable numbers of spaces (required: 1)" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckGitHasVersion.py b/ansiblelater/rules/CheckGitHasVersion.py index 12d8d69..5bd9f5a 100644 --- a/ansiblelater/rules/CheckGitHasVersion.py +++ b/ansiblelater/rules/CheckGitHasVersion.py @@ -18,14 +18,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckGitHasVersion(StandardBase): +class CheckGitHasVersion(RuleBase): sid = "ANSIBLE0020" description = "Git checkouts should use explicit version" helptext = "git checkouts should point to an explicit commit or tag, not `latest`" - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckInstallUseLatest.py b/ansiblelater/rules/CheckInstallUseLatest.py index 6208b5b..200fd89 100644 --- a/ansiblelater/rules/CheckInstallUseLatest.py +++ b/ansiblelater/rules/CheckInstallUseLatest.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckInstallUseLatest(StandardBase): +class CheckInstallUseLatest(RuleBase): sid = "ANSIBLE0009" description = "Package installs should use present, not latest" helptext = "package installs should use `state=present` with or without a version" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckLiteralBoolFormat.py b/ansiblelater/rules/CheckLiteralBoolFormat.py index 22af7f6..69530e8 100644 --- a/ansiblelater/rules/CheckLiteralBoolFormat.py +++ b/ansiblelater/rules/CheckLiteralBoolFormat.py @@ -1,13 +1,12 @@ import re -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckLiteralBoolFormat(StandardBase): +class CheckLiteralBoolFormat(RuleBase): sid = "ANSIBLE0014" description = "Literal bools should be consistent" helptext = "literal bools should be written as `{bools}`" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckLocalAction.py b/ansiblelater/rules/CheckLocalAction.py index c53ba99..1234ed2 100644 --- a/ansiblelater/rules/CheckLocalAction.py +++ b/ansiblelater/rules/CheckLocalAction.py @@ -1,13 +1,12 @@ # Copyright (c) 2016, Tsukinowa Inc. # Copyright (c) 2018, Ansible Project -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckLocalAction(StandardBase): +class CheckLocalAction(RuleBase): sid = "ANSIBLE0024" description = "Don't use local_action" helptext = "`delegate_to: localhost` should be used instead of `local_action`" - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckMetaChangeFromDefault.py b/ansiblelater/rules/CheckMetaChangeFromDefault.py index 4431cc3..776042e 100644 --- a/ansiblelater/rules/CheckMetaChangeFromDefault.py +++ b/ansiblelater/rules/CheckMetaChangeFromDefault.py @@ -1,14 +1,13 @@ # Copyright (c) 2018, Ansible Project from nested_lookup import nested_lookup -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckMetaChangeFromDefault(StandardBase): +class CheckMetaChangeFromDefault(RuleBase): sid = "ANSIBLE0021" description = "Roles meta/main.yml default values should be changed" helptext = "meta/main.yml default values should be changed for: `{field}`" - version = "0.2" types = ["meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckMetaMain.py b/ansiblelater/rules/CheckMetaMain.py index 56f6254..21c8b76 100644 --- a/ansiblelater/rules/CheckMetaMain.py +++ b/ansiblelater/rules/CheckMetaMain.py @@ -1,13 +1,12 @@ from nested_lookup import nested_lookup -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckMetaMain(StandardBase): +class CheckMetaMain(RuleBase): sid = "ANSIBLE0002" description = "Roles must contain suitable meta/main.yml" helptext = "file should contain `{key}` key" - version = "0.1" types = ["meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckNameFormat.py b/ansiblelater/rules/CheckNameFormat.py index d3ff5ae..85c1974 100644 --- a/ansiblelater/rules/CheckNameFormat.py +++ b/ansiblelater/rules/CheckNameFormat.py @@ -1,13 +1,12 @@ from collections import defaultdict -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckNameFormat(StandardBase): +class CheckNameFormat(RuleBase): sid = "ANSIBLE0007" description = "Name of tasks and handlers must be formatted" helptext = "name '{name}' should start with uppercase" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckNamedTask.py b/ansiblelater/rules/CheckNamedTask.py index 6829211..9ee85f8 100644 --- a/ansiblelater/rules/CheckNamedTask.py +++ b/ansiblelater/rules/CheckNamedTask.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckNamedTask(StandardBase): +class CheckNamedTask(RuleBase): sid = "ANSIBLE0006" description = "Tasks and handlers must be named" helptext = "module '{module}' used without or empty `name` attribute" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckNativeYaml.py b/ansiblelater/rules/CheckNativeYaml.py index 03bf908..df6760d 100644 --- a/ansiblelater/rules/CheckNativeYaml.py +++ b/ansiblelater/rules/CheckNativeYaml.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckNativeYaml(StandardBase): +class CheckNativeYaml(RuleBase): sid = "LINT0008" description = "Use YAML format for tasks and handlers rather than key=value" helptext = "task arguments appear to be in key value rather than YAML format" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckNestedJinja.py b/ansiblelater/rules/CheckNestedJinja.py index af5f17f..ff6616c 100644 --- a/ansiblelater/rules/CheckNestedJinja.py +++ b/ansiblelater/rules/CheckNestedJinja.py @@ -21,17 +21,16 @@ # THE SOFTWARE. import re -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckNestedJinja(StandardBase): +class CheckNestedJinja(RuleBase): sid = "ANSIBLE0023" description = "Don't use nested Jinja2 pattern" helptext = ( "there should not be any nested jinja pattern " "like `{{ list_one + {{ list_two | max }} }}`" ) - version = "0.2" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckRelativeRolePaths.py b/ansiblelater/rules/CheckRelativeRolePaths.py index 8b9cc3e..6682347 100644 --- a/ansiblelater/rules/CheckRelativeRolePaths.py +++ b/ansiblelater/rules/CheckRelativeRolePaths.py @@ -1,13 +1,12 @@ # Copyright (c) 2016, Tsukinowa Inc. # Copyright (c) 2018, Ansible Project -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckRelativeRolePaths(StandardBase): +class CheckRelativeRolePaths(RuleBase): sid = "ANSIBLE0025" description = "Don't use a relative path in a role" helptext = "`copy` and `template` modules don't need relative path for `src`" - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckScmInSrc.py b/ansiblelater/rules/CheckScmInSrc.py index 519a7ec..b1b666c 100644 --- a/ansiblelater/rules/CheckScmInSrc.py +++ b/ansiblelater/rules/CheckScmInSrc.py @@ -1,13 +1,12 @@ from ansible.parsing.yaml.objects import AnsibleMapping -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckScmInSrc(StandardBase): +class CheckScmInSrc(RuleBase): sid = "ANSIBLE0005" description = "Use `scm:` key rather than `src: scm+url`" helptext = "usage of `src: scm+url` not recommended" - version = "0.1" types = ["rolesfile"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckShellInsteadCommand.py b/ansiblelater/rules/CheckShellInsteadCommand.py index 28c8ec4..4f26a83 100644 --- a/ansiblelater/rules/CheckShellInsteadCommand.py +++ b/ansiblelater/rules/CheckShellInsteadCommand.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckShellInsteadCommand(StandardBase): +class CheckShellInsteadCommand(RuleBase): sid = "ANSIBLE0010" description = "Shell should only be used when essential" helptext = "shell should only be used when piping, redirecting or chaining commands" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckTaskSeparation.py b/ansiblelater/rules/CheckTaskSeparation.py index a44f160..2d60479 100644 --- a/ansiblelater/rules/CheckTaskSeparation.py +++ b/ansiblelater/rules/CheckTaskSeparation.py @@ -1,14 +1,13 @@ import re from collections import defaultdict -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckTaskSeparation(StandardBase): +class CheckTaskSeparation(RuleBase): sid = "ANSIBLE0001" description = "Single tasks should be separated by empty line" helptext = "missing task separation (required: 1 empty line)" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckUniqueNamedTask.py b/ansiblelater/rules/CheckUniqueNamedTask.py index 55210d4..5e7ff00 100644 --- a/ansiblelater/rules/CheckUniqueNamedTask.py +++ b/ansiblelater/rules/CheckUniqueNamedTask.py @@ -1,13 +1,12 @@ from collections import defaultdict -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckUniqueNamedTask(StandardBase): +class CheckUniqueNamedTask(RuleBase): sid = "ANSIBLE0003" description = "Tasks and handlers must be uniquely named within a single file" helptext = "name '{name}' appears multiple times" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckVersion.py b/ansiblelater/rules/CheckVersion.py deleted file mode 100644 index 61cee24..0000000 --- a/ansiblelater/rules/CheckVersion.py +++ /dev/null @@ -1,16 +0,0 @@ -from ansiblelater.standard import StandardBase - - -class CheckVersion(StandardBase): - sid = "ANSIBLE9998" - description = "Standards version should be pinned" - helptext = "Standards version not set. Using latest standards version {version}" - types = ["task", "handler", "rolevars", "meta", "template", "file", "playbook"] - - def check(self, candidate, settings): # noqa - errors = [] - - if not candidate.version_config: - errors.append(self.Error(None, self.helptext.format(version=candidate.version))) - - return self.Result(candidate.path, errors) diff --git a/ansiblelater/rules/CheckWhenFormat.py b/ansiblelater/rules/CheckWhenFormat.py index 44307b0..15d8d24 100644 --- a/ansiblelater/rules/CheckWhenFormat.py +++ b/ansiblelater/rules/CheckWhenFormat.py @@ -1,13 +1,12 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckWhenFormat(StandardBase): +class CheckWhenFormat(RuleBase): sid = "ANSIBLE0022" description = "Don't use Jinja2 in when" helptext = ( "`when` is a raw Jinja2 expression, redundant {{ }} " "should be removed from variable(s)" ) - version = "0.2" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlColons.py b/ansiblelater/rules/CheckYamlColons.py index 54fc842..c32cc68 100644 --- a/ansiblelater/rules/CheckYamlColons.py +++ b/ansiblelater/rules/CheckYamlColons.py @@ -1,10 +1,9 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlColons(StandardBase): +class CheckYamlColons(RuleBase): sid = "LINT0005" description = "YAML should use consistent number of spaces around colons" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlDocumentEnd.py b/ansiblelater/rules/CheckYamlDocumentEnd.py index 5aaa9f5..e333d51 100644 --- a/ansiblelater/rules/CheckYamlDocumentEnd.py +++ b/ansiblelater/rules/CheckYamlDocumentEnd.py @@ -1,10 +1,9 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlDocumentEnd(StandardBase): +class CheckYamlDocumentEnd(RuleBase): sid = "LINT0009" description = "YAML should contain document end marker" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlDocumentStart.py b/ansiblelater/rules/CheckYamlDocumentStart.py index d4f22ce..d795a81 100644 --- a/ansiblelater/rules/CheckYamlDocumentStart.py +++ b/ansiblelater/rules/CheckYamlDocumentStart.py @@ -1,10 +1,9 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlDocumentStart(StandardBase): +class CheckYamlDocumentStart(RuleBase): sid = "LINT0004" description = "YAML should contain document start marker" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlEmptyLines.py b/ansiblelater/rules/CheckYamlEmptyLines.py index 48ca448..dc8376c 100644 --- a/ansiblelater/rules/CheckYamlEmptyLines.py +++ b/ansiblelater/rules/CheckYamlEmptyLines.py @@ -1,10 +1,9 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlEmptyLines(StandardBase): +class CheckYamlEmptyLines(RuleBase): sid = "LINT0001" description = "YAML should not contain unnecessarily empty lines" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlFile.py b/ansiblelater/rules/CheckYamlFile.py index 42714fc..c26cf90 100644 --- a/ansiblelater/rules/CheckYamlFile.py +++ b/ansiblelater/rules/CheckYamlFile.py @@ -1,13 +1,12 @@ import os -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlFile(StandardBase): +class CheckYamlFile(RuleBase): sid = "LINT0006" description = "Roles file should be in yaml format" helptext = "file does not have a .yml extension" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlHasContent.py b/ansiblelater/rules/CheckYamlHasContent.py index b943fd2..e0c0126 100644 --- a/ansiblelater/rules/CheckYamlHasContent.py +++ b/ansiblelater/rules/CheckYamlHasContent.py @@ -1,11 +1,10 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlHasContent(StandardBase): +class CheckYamlHasContent(RuleBase): sid = "LINT0007" description = "Files should contain useful content" helptext = "the file appears to have no useful content" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "defaults", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlHyphens.py b/ansiblelater/rules/CheckYamlHyphens.py index c6dae26..f45c3a3 100644 --- a/ansiblelater/rules/CheckYamlHyphens.py +++ b/ansiblelater/rules/CheckYamlHyphens.py @@ -1,10 +1,9 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlHyphens(StandardBase): +class CheckYamlHyphens(RuleBase): sid = "LINT0003" description = "YAML should use consistent number of spaces after hyphens" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/rules/CheckYamlIndent.py b/ansiblelater/rules/CheckYamlIndent.py index 525bed5..8f74b57 100644 --- a/ansiblelater/rules/CheckYamlIndent.py +++ b/ansiblelater/rules/CheckYamlIndent.py @@ -1,10 +1,9 @@ -from ansiblelater.standard import StandardBase +from ansiblelater.rule import RuleBase -class CheckYamlIndent(StandardBase): +class CheckYamlIndent(RuleBase): sid = "LINT0002" description = "YAML should not contain unnecessarily empty lines" - version = "0.1" types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"] def check(self, candidate, settings): diff --git a/ansiblelater/settings.py b/ansiblelater/settings.py index 6d51bbe..530b747 100644 --- a/ansiblelater/settings.py +++ b/ansiblelater/settings.py @@ -104,13 +104,13 @@ class Settings: if f not in defaults["ansible"]["custom_modules"]: defaults["ansible"]["custom_modules"].append(f) - if defaults["rules"]["buildin"]: - defaults["rules"]["standards"].append( + if defaults["rules"]["builtin"]: + defaults["rules"]["dir"].append( os.path.join(resource_filename("ansiblelater", "rules")) ) - defaults["rules"]["standards"] = [ - os.path.relpath(os.path.normpath(p)) for p in defaults["rules"]["standards"] + defaults["rules"]["dir"] = [ + os.path.relpath(os.path.normpath(p)) for p in defaults["rules"]["dir"] ] return defaults @@ -118,9 +118,9 @@ class Settings: def _get_defaults(self): defaults = { "rules": { - "buildin": True, - "standards": [], - "filter": [], + "builtin": True, + "dir": [], + "include_filter": [], "exclude_filter": [], "warning_filter": [ "ANSIBLE9999", @@ -128,7 +128,6 @@ class Settings: ], "ignore_dotfiles": True, "exclude_files": [], - "version": "", }, "logging": { "level": "WARNING", diff --git a/ansiblelater/utils/__init__.py b/ansiblelater/utils/__init__.py index dc79be4..9b81e61 100644 --- a/ansiblelater/utils/__init__.py +++ b/ansiblelater/utils/__init__.py @@ -6,7 +6,6 @@ import sys from contextlib import suppress import yaml -from packaging.version import Version from ansiblelater import logger @@ -35,12 +34,6 @@ def count_spaces(c_string): return (leading_spaces, trailing_spaces) -def standards_latest(standards): - return max( - [standard.version for standard in standards if standard.version] or ["0.1"], key=Version - ) - - def lines_ranges(lines_spec): if not lines_spec: return None diff --git a/docs/content/build_rules/standards_check.md b/docs/content/build_rules/rule.md similarity index 89% rename from docs/content/build_rules/standards_check.md rename to docs/content/build_rules/rule.md index cc885b9..8b224ea 100644 --- a/docs/content/build_rules/standards_check.md +++ b/docs/content/build_rules/rule.md @@ -1,18 +1,17 @@ --- -title: Minimal standard checks +title: Write a rule --- -A typical standards check will look like: +A typical rule check will look like: {{< highlight Python "linenos=table" >}} -class CheckBecomeUser(StandardBase): +class CheckBecomeUser(RuleBase): sid = "ANSIBLE0015" description = "Become should be combined with become_user" helptext = "the task has `become` enabled but `become_user` is missing" - version = "0.1" types = ["playbook", "task", "handler"] def check(self, candidate, settings): diff --git a/docs/content/configuration/cli.md b/docs/content/configuration/cli.md index b5fbcd1..aa571c5 100644 --- a/docs/content/configuration/cli.md +++ b/docs/content/configuration/cli.md @@ -8,28 +8,27 @@ You can get all available CLI options by running `ansible-later --help`: {{< highlight Shell "linenos=table" >}} $ ansible-later --help -usage: ansible-later [-h] [-c CONFIG_FILE] [-r RULES.STANDARDS] - [-s RULES.FILTER] [-v] [-q] [--version] - [rules.files [rules.files ...]] +usage: ansible-later [-h] [-c CONFIG] [-r DIR] [-B] [-i TAGS] [-x TAGS] [-v] [-q] [-V] [rules.files ...] Validate Ansible files against best practice guideline positional arguments: rules.files -optional arguments: +options: -h, --help show this help message and exit - -c CONFIG_FILE, --config CONFIG_FILE - location of configuration file - -r RULES.STANDARDS, --rules RULES.STANDARDS - location of standards rules - -s RULES.FILTER, --standards RULES.FILTER - limit standards to given ID's - -x RULES.EXCLUDE_FILTER, --exclude-standards RULES.EXCLUDE_FILTER - exclude standards by given ID's + -c CONFIG, --config CONFIG + path to configuration file + -r DIR, --rules-dir DIR + directory of rules + -B, --no-builtin disables built-in rules + -i TAGS, --include-rules TAGS + limit rules to given id/tags + -x TAGS, --exclude-rules TAGS + exclude rules by given it/tags -v increase log level -q decrease log level - --version show program's version number and exit + -V, --version show program's version number and exit {{< /highlight >}} diff --git a/docs/content/configuration/defaults.md b/docs/content/configuration/defaults.md index 03d94b0..da6372a 100644 --- a/docs/content/configuration/defaults.md +++ b/docs/content/configuration/defaults.md @@ -58,8 +58,8 @@ logging: # Global settings for all defined rules rules: - # Disable build-in rules if required - buildin: True + # Disable built-in rules if required + builtin: True # List of files to exclude exclude_files: [] @@ -75,8 +75,7 @@ rules: exclude_filter: [] # List of rule ID's that should be displayed as a warning instead of an error. By default, - # only rules whose version is higher than the current default version are marked as warnings. - # This list allows to degrade errors to warnings for each rule. + # no rules are marked as warnings. This list allows to degrade errors to warnings for each rule. warning_filter: - "ANSIBLE9999" - "ANSIBLE9998" @@ -85,12 +84,8 @@ rules: # You can disable this setting and handle dotfiles by yourself with `exclude_files`. ignore_dotfiles: True - # List of directories to load standard rules from (defaults to build-in) - standards: [] - - # Standard version to use. Standard version set in a roles meta file - # or playbook will takes precedence. - version: + # List of directories to load rules from (defaults to built-in) + dir: [] # Block to control included yamllint rules. # See https://yamllint.readthedocs.io/en/stable/rules.html diff --git a/docs/content/included_rules/_index.md b/docs/content/included_rules/_index.md index a7cc1a9..b8c32aa 100644 --- a/docs/content/included_rules/_index.md +++ b/docs/content/included_rules/_index.md @@ -2,7 +2,7 @@ title: Included rules --- -Reviews are useless without some rules or standards to check against. ansible-later comes with a set of built-in checks, which are explained in the following table. +Reviews are useless without some rules to check against. `ansible-later` comes with a set of built-in checks, which are explained in the following table. | Rule | ID | Description | Parameter | | ----------------------------- | ----------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------- | @@ -42,5 +42,4 @@ Reviews are useless without some rules or standards to check against. ansible-la | CheckRelativeRolePaths | ANSIBLE0025 | Don't use a relative path in a role. | | | CheckChangedInWhen | ANSIBLE0026 | Use handlers instead of `when: changed`. | | | CheckChangedInWhen | ANSIBLE0027 | Deprecated bare variables in loops must not be used. | | -| CheckVersion | ANSIBLE9998 | Standards version should be pinned. | | | CheckDeprecated | ANSIBLE9999 | Deprecated features of `ansible-later` should not be used. | | diff --git a/docs/data/menu/main.yml b/docs/data/menu/main.yml index 196c80d..9974da2 100644 --- a/docs/data/menu/main.yml +++ b/docs/data/menu/main.yml @@ -23,5 +23,5 @@ main: sub: - name: Candidates ref: "/build_rules/candidates" - - name: Standards checks - ref: "/build_rules/standards_check" + - name: Rules + ref: "/build_rules/rule"