mirror of
https://github.com/thegeeklab/ansible-later.git
synced 2024-11-24 22:00:40 +00:00
refactor: drop default standards version and rename to rules (#752)
BREAKING CHANGE: The option to define a `Standards` version has been removed. Every new rule that is added on upcoming releases is activated by default and will also create errors if triggered. The behavior of rules can be controlled by the existing `rules.exclude_filter` or `rules.warning_filter` options. BREAKING CHANGE: The option `rules.buildin` has been renamed to `rules.builtin`. BREAKING CHANGE: The option `rules.standards` has been renamed to `rules.dir`. BREAKING CHANGE: The option `rules.filter` has been renamed to `rules.include_filter`.
This commit is contained in:
parent
d360de2125
commit
2df48598ec
@ -7,8 +7,8 @@ import sys
|
|||||||
|
|
||||||
from ansiblelater import LOG, __version__, logger
|
from ansiblelater import LOG, __version__, logger
|
||||||
from ansiblelater.candidate import Candidate
|
from ansiblelater.candidate import Candidate
|
||||||
|
from ansiblelater.rule import SingleRules
|
||||||
from ansiblelater.settings import Settings
|
from ansiblelater.settings import Settings
|
||||||
from ansiblelater.standard import SingleStandards
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -22,33 +22,33 @@ def main():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-r",
|
"-r",
|
||||||
"--rules-dir",
|
"--rules-dir",
|
||||||
dest="rules.standards",
|
dest="rules.dir",
|
||||||
metavar="RULES",
|
metavar="DIR",
|
||||||
action="append",
|
action="append",
|
||||||
help="directory of standard rules",
|
help="directory of rules",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-B",
|
"-B",
|
||||||
"--no-buildin",
|
"--no-builtin",
|
||||||
dest="rules.buildin",
|
dest="rules.builtin",
|
||||||
action="store_false",
|
action="store_false",
|
||||||
help="disables build-in standard rules",
|
help="disables built-in rules",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-s",
|
"-i",
|
||||||
"--standards",
|
"--include-rules",
|
||||||
dest="rules.filter",
|
dest="rules.include_filter",
|
||||||
metavar="FILTER",
|
metavar="TAGS",
|
||||||
action="append",
|
action="append",
|
||||||
help="limit standards to given ID's",
|
help="limit rules to given id/tags",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-x",
|
"-x",
|
||||||
"--exclude-standards",
|
"--exclude-rules",
|
||||||
dest="rules.exclude_filter",
|
dest="rules.exclude_filter",
|
||||||
metavar="EXCLUDE_FILTER",
|
metavar="TAGS",
|
||||||
action="append",
|
action="append",
|
||||||
help="exclude standards by given ID's",
|
help="exclude rules by given it/tags",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", dest="logging.level", action="append_const", const=-1, help="increase log level"
|
"-v", dest="logging.level", action="append_const", const=-1, help="increase log level"
|
||||||
@ -65,7 +65,7 @@ def main():
|
|||||||
config = settings.config
|
config = settings.config
|
||||||
|
|
||||||
logger.update_logger(LOG, config["logging"]["level"], config["logging"]["json"])
|
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)
|
workers = max(multiprocessing.cpu_count() - 2, 2)
|
||||||
p = multiprocessing.Pool(workers)
|
p = multiprocessing.Pool(workers)
|
||||||
|
@ -3,14 +3,12 @@
|
|||||||
import codecs
|
import codecs
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
from ansible.plugins.loader import module_loader
|
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.logger import flag_extra
|
||||||
from ansiblelater.standard import SingleStandards, StandardBase
|
from ansiblelater.rule import RuleBase, SingleRules
|
||||||
|
|
||||||
|
|
||||||
class Candidate:
|
class Candidate:
|
||||||
@ -21,7 +19,7 @@ class Candidate:
|
|||||||
bundled with necessary meta informations for rule processing.
|
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.path = filename
|
||||||
self.binary = False
|
self.binary = False
|
||||||
self.vault = False
|
self.vault = False
|
||||||
@ -37,107 +35,58 @@ class Candidate:
|
|||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
self.binary = True
|
self.binary = True
|
||||||
|
|
||||||
def _get_version(self):
|
def _filter_rules(self):
|
||||||
name = type(self).__name__
|
target_rules = []
|
||||||
path = self.path
|
includes = self.config["rules"]["include_filter"]
|
||||||
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"]
|
|
||||||
excludes = self.config["rules"]["exclude_filter"]
|
excludes = self.config["rules"]["exclude_filter"]
|
||||||
|
|
||||||
if len(includes) == 0:
|
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:
|
for rule in self.rules:
|
||||||
if standard.sid in includes and standard.sid not in excludes:
|
if rule.sid in includes and rule.sid not in excludes:
|
||||||
target_standards.append(standard)
|
target_rules.append(rule)
|
||||||
|
|
||||||
return target_standards
|
return target_rules
|
||||||
|
|
||||||
def review(self):
|
def review(self):
|
||||||
errors = 0
|
errors = 0
|
||||||
self.standards = SingleStandards(self.config["rules"]["standards"]).rules
|
self.rules = SingleRules(self.config["rules"]["dir"]).rules
|
||||||
self.version_config = self._get_version()
|
|
||||||
self.version = self.version_config or utils.standards_latest(self.standards)
|
|
||||||
|
|
||||||
for standard in self._filter_standards():
|
for rule in self._filter_rules():
|
||||||
if type(self).__name__.lower() not in standard.types:
|
if type(self).__name__.lower() not in rule.types:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result = standard.check(self, self.config)
|
result = rule.check(self, self.config)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
LOG.error(
|
LOG.error(f"rule '{rule.sid}' returns an empty result object. Check failed!")
|
||||||
f"Standard '{standard.sid}' returns an empty result object. Check failed!"
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
"tag": "review",
|
"tag": "review",
|
||||||
"standard": standard.description,
|
"rule": rule.description,
|
||||||
"file": self.path,
|
"file": self.path,
|
||||||
"passed": True,
|
"passed": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
if standard.sid and standard.sid.strip():
|
if rule.sid and rule.sid.strip():
|
||||||
labels["sid"] = standard.sid
|
labels["sid"] = rule.sid
|
||||||
|
|
||||||
for err in result.errors:
|
for err in result.errors:
|
||||||
err_labels = copy.copy(labels)
|
err_labels = copy.copy(labels)
|
||||||
err_labels["passed"] = False
|
err_labels["passed"] = False
|
||||||
|
|
||||||
sid = self._format_id(standard.sid)
|
sid = self._format_id(rule.sid)
|
||||||
path = self.path
|
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())
|
err_labels.update(err.to_dict())
|
||||||
|
|
||||||
if not standard.version:
|
msg = f"{sid}rule '{description}' not met:\n{path}:{err}"
|
||||||
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}"
|
|
||||||
|
|
||||||
if standard.sid not in self.config["rules"]["warning_filter"]:
|
if rule.sid not in self.config["rules"]["warning_filter"]:
|
||||||
LOG.error(msg, extra=flag_extra(err_labels))
|
LOG.error(msg, extra=flag_extra(err_labels))
|
||||||
errors = errors + 1
|
errors = errors + 1
|
||||||
else:
|
else:
|
||||||
@ -146,54 +95,54 @@ class Candidate:
|
|||||||
return errors
|
return errors
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def classify(filename, settings={}, standards=[]): # noqa
|
def classify(filename, settings={}, rules=[]): # noqa
|
||||||
parentdir = os.path.basename(os.path.dirname(filename))
|
parentdir = os.path.basename(os.path.dirname(filename))
|
||||||
basename = os.path.basename(filename)
|
basename = os.path.basename(filename)
|
||||||
ext = os.path.splitext(filename)[1][1:]
|
ext = os.path.splitext(filename)[1][1:]
|
||||||
|
|
||||||
if parentdir in ["tasks"]:
|
if parentdir in ["tasks"]:
|
||||||
return Task(filename, settings, standards)
|
return Task(filename, settings, rules)
|
||||||
if parentdir in ["handlers"]:
|
if parentdir in ["handlers"]:
|
||||||
return Handler(filename, settings, standards)
|
return Handler(filename, settings, rules)
|
||||||
if parentdir in ["vars", "defaults"]:
|
if parentdir in ["vars", "defaults"]:
|
||||||
return RoleVars(filename, settings, standards)
|
return RoleVars(filename, settings, rules)
|
||||||
if "group_vars" in filename.split(os.sep):
|
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):
|
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:
|
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:
|
if parentdir in ["meta"] and "argument_specs" in basename:
|
||||||
return ArgumentSpecs(filename, settings, standards)
|
return ArgumentSpecs(filename, settings, rules)
|
||||||
if parentdir in [
|
if parentdir in [
|
||||||
"library",
|
"library",
|
||||||
"lookup_plugins",
|
"lookup_plugins",
|
||||||
"callback_plugins",
|
"callback_plugins",
|
||||||
"filter_plugins",
|
"filter_plugins",
|
||||||
] or filename.endswith(".py"):
|
] or filename.endswith(".py"):
|
||||||
return Code(filename, settings, standards)
|
return Code(filename, settings, rules)
|
||||||
if basename == "inventory" or basename == "hosts" or parentdir in ["inventories"]:
|
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"]):
|
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:
|
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"):
|
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):
|
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"):
|
if basename.endswith(".yml") or basename.endswith(".yaml"):
|
||||||
return Playbook(filename, settings, standards)
|
return Playbook(filename, settings, rules)
|
||||||
if "README" in basename:
|
if "README" in basename:
|
||||||
return Doc(filename, settings, standards)
|
return Doc(filename, settings, rules)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _format_id(self, standard_id):
|
def _format_id(self, rule_id):
|
||||||
sid = standard_id.strip()
|
sid = rule_id.strip()
|
||||||
if sid:
|
if sid:
|
||||||
standard_id = f"[{sid}] "
|
rule_id = f"[{sid}] "
|
||||||
|
|
||||||
return standard_id
|
return rule_id
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{type(self).__name__} ({self.path})"
|
return f"{type(self).__name__} ({self.path})"
|
||||||
@ -205,8 +154,8 @@ class Candidate:
|
|||||||
class RoleFile(Candidate):
|
class RoleFile(Candidate):
|
||||||
"""Object classified as Ansible role file."""
|
"""Object classified as Ansible role file."""
|
||||||
|
|
||||||
def __init__(self, filename, settings={}, standards=[]): # noqa
|
def __init__(self, filename, settings={}, rules=[]): # noqa
|
||||||
super().__init__(filename, settings, standards)
|
super().__init__(filename, settings, rules)
|
||||||
|
|
||||||
parentdir = os.path.dirname(os.path.abspath(filename))
|
parentdir = os.path.dirname(os.path.abspath(filename))
|
||||||
while parentdir != os.path.dirname(parentdir):
|
while parentdir != os.path.dirname(parentdir):
|
||||||
@ -226,16 +175,16 @@ class Playbook(Candidate):
|
|||||||
class Task(RoleFile):
|
class Task(RoleFile):
|
||||||
"""Object classified as Ansible task file."""
|
"""Object classified as Ansible task file."""
|
||||||
|
|
||||||
def __init__(self, filename, settings={}, standards=[]): # noqa
|
def __init__(self, filename, settings={}, rules=[]): # noqa
|
||||||
super().__init__(filename, settings, standards)
|
super().__init__(filename, settings, rules)
|
||||||
self.filetype = "tasks"
|
self.filetype = "tasks"
|
||||||
|
|
||||||
|
|
||||||
class Handler(RoleFile):
|
class Handler(RoleFile):
|
||||||
"""Object classified as Ansible handler file."""
|
"""Object classified as Ansible handler file."""
|
||||||
|
|
||||||
def __init__(self, filename, settings={}, standards=[]): # noqa
|
def __init__(self, filename, settings={}, rules=[]): # noqa
|
||||||
super().__init__(filename, settings, standards)
|
super().__init__(filename, settings, rules)
|
||||||
self.filetype = "handlers"
|
self.filetype = "handlers"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"""Standard definition."""
|
"""Rule definition."""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import importlib
|
import importlib
|
||||||
@ -27,22 +27,21 @@ from ansiblelater.utils.yamlhelper import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class StandardMeta(type):
|
class RuleMeta(type):
|
||||||
def __call__(cls, *args):
|
def __call__(cls, *args):
|
||||||
mcls = type.__call__(cls, *args)
|
mcls = type.__call__(cls, *args)
|
||||||
mcls.sid = cls.sid
|
mcls.sid = cls.sid
|
||||||
mcls.description = getattr(cls, "description", "__unknown__")
|
mcls.description = getattr(cls, "description", "__unknown__")
|
||||||
mcls.helptext = getattr(cls, "helptext", "")
|
mcls.helptext = getattr(cls, "helptext", "")
|
||||||
mcls.version = getattr(cls, "version", None)
|
|
||||||
mcls.types = getattr(cls, "types", [])
|
mcls.types = getattr(cls, "types", [])
|
||||||
return mcls
|
return mcls
|
||||||
|
|
||||||
|
|
||||||
class StandardExtendedMeta(StandardMeta, ABCMeta):
|
class RuleExtendedMeta(RuleMeta, ABCMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StandardBase(metaclass=StandardExtendedMeta):
|
class RuleBase(metaclass=RuleExtendedMeta):
|
||||||
SHELL_PIPE_CHARS = "&|<>;$\n*[]{}?"
|
SHELL_PIPE_CHARS = "&|<>;$\n*[]{}?"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -55,7 +54,7 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Standard: {self.description} (version: {self.version}, types: {self.types})"
|
return f"Rule: {self.description} (types: {self.types})"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_tasks(candidate, settings): # noqa
|
def get_tasks(candidate, settings): # noqa
|
||||||
@ -69,11 +68,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
e = ex.original
|
e = ex.original
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
except LaterAnsibleError as e:
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
return yamllines, errors
|
return yamllines, errors
|
||||||
@ -93,11 +92,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
e = ex.original
|
e = ex.original
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
except LaterAnsibleError as e:
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
return tasks, errors
|
return tasks, errors
|
||||||
@ -115,11 +114,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
e = ex.original
|
e = ex.original
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
except LaterAnsibleError as e:
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
return normalized, errors
|
return normalized, errors
|
||||||
@ -159,11 +158,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
e = ex.original
|
e = ex.original
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
except LaterAnsibleError as e:
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
return normalized, errors
|
return normalized, errors
|
||||||
@ -184,11 +183,11 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
e = ex.original
|
e = ex.original
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
except LaterAnsibleError as e:
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
return yamllines, errors
|
return yamllines, errors
|
||||||
@ -210,7 +209,7 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
content = yaml.safe_load(f)
|
content = yaml.safe_load(f)
|
||||||
except yaml.YAMLError as e:
|
except yaml.YAMLError as e:
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
@ -224,14 +223,14 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
try:
|
try:
|
||||||
with open(candidate.path, encoding="utf-8") as f:
|
with open(candidate.path, encoding="utf-8") as f:
|
||||||
for problem in linter.run(f, YamlLintConfig(options)):
|
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:
|
except yaml.YAMLError as e:
|
||||||
errors.append(
|
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
|
candidate.faulty = True
|
||||||
except (TypeError, ValueError) as e:
|
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
|
candidate.faulty = True
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
@ -302,7 +301,7 @@ class StandardBase(metaclass=StandardExtendedMeta):
|
|||||||
return "\n".join([f"{self.candidate}:{error}" for error in self.errors])
|
return "\n".join([f"{self.candidate}:{error}" for error in self.errors])
|
||||||
|
|
||||||
|
|
||||||
class StandardLoader:
|
class RulesLoader:
|
||||||
def __init__(self, source):
|
def __init__(self, source):
|
||||||
self.rules = []
|
self.rules = []
|
||||||
|
|
||||||
@ -331,10 +330,7 @@ class StandardLoader:
|
|||||||
|
|
||||||
def _is_plugin(self, obj):
|
def _is_plugin(self, obj):
|
||||||
return (
|
return (
|
||||||
inspect.isclass(obj)
|
inspect.isclass(obj) and issubclass(obj, RuleBase) and obj is not RuleBase and not None
|
||||||
and issubclass(obj, StandardBase)
|
|
||||||
and obj is not StandardBase
|
|
||||||
and not None
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -343,11 +339,11 @@ class StandardLoader:
|
|||||||
all_std = len(normalized_std)
|
all_std = len(normalized_std)
|
||||||
if all_std != unique_std:
|
if all_std != unique_std:
|
||||||
sysexit_with_message(
|
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."""
|
"""Singleton config class."""
|
||||||
|
|
||||||
pass
|
pass
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckBecomeUser(StandardBase):
|
class CheckBecomeUser(RuleBase):
|
||||||
sid = "ANSIBLE0015"
|
sid = "ANSIBLE0015"
|
||||||
description = "Become should be combined with become_user"
|
description = "Become should be combined with become_user"
|
||||||
helptext = "the task has `become` enabled but `become_user` is missing"
|
helptext = "the task has `become` enabled but `become_user` is missing"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
from ansiblelater.utils import count_spaces
|
from ansiblelater.utils import count_spaces
|
||||||
|
|
||||||
|
|
||||||
class CheckBracesSpaces(StandardBase):
|
class CheckBracesSpaces(RuleBase):
|
||||||
sid = "ANSIBLE0004"
|
sid = "ANSIBLE0004"
|
||||||
description = "YAML should use consistent number of spaces around variables"
|
description = "YAML should use consistent number of spaces around variables"
|
||||||
helptext = "no suitable numbers of spaces (min: {min} max: {max})"
|
helptext = "no suitable numbers of spaces (min: {min} max: {max})"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -18,14 +18,13 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckChangedInWhen(StandardBase):
|
class CheckChangedInWhen(RuleBase):
|
||||||
sid = "ANSIBLE0026"
|
sid = "ANSIBLE0026"
|
||||||
description = "Use handlers instead of `when: changed`"
|
description = "Use handlers instead of `when: changed`"
|
||||||
helptext = "tasks using `when: result.changed` setting are effectively acting as a handler"
|
helptext = "tasks using `when: result.changed` setting are effectively acting as a handler"
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckCommandHasChanges(StandardBase):
|
class CheckCommandHasChanges(RuleBase):
|
||||||
sid = "ANSIBLE0011"
|
sid = "ANSIBLE0011"
|
||||||
description = "Commands should be idempotent"
|
description = "Commands should be idempotent"
|
||||||
helptext = (
|
helptext = (
|
||||||
"commands should only read while using `changed_when` or try to be "
|
"commands should only read while using `changed_when` or try to be "
|
||||||
"idempotent while using controls like `creates`, `removes` or `when`"
|
"idempotent while using controls like `creates`, `removes` or `when`"
|
||||||
)
|
)
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task"]
|
types = ["playbook", "task"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -20,14 +20,13 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckCommandInsteadOfArgument(StandardBase):
|
class CheckCommandInsteadOfArgument(RuleBase):
|
||||||
sid = "ANSIBLE0017"
|
sid = "ANSIBLE0017"
|
||||||
description = "Commands should not be used in place of module arguments"
|
description = "Commands should not be used in place of module arguments"
|
||||||
helptext = "{exec} used in place of file modules argument {arg}"
|
helptext = "{exec} used in place of file modules argument {arg}"
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckCommandInsteadOfModule(StandardBase):
|
class CheckCommandInsteadOfModule(RuleBase):
|
||||||
sid = "ANSIBLE0008"
|
sid = "ANSIBLE0008"
|
||||||
description = "Commands should not be used in place of modules"
|
description = "Commands should not be used in place of modules"
|
||||||
helptext = "{exec} command used in place of {module} module"
|
helptext = "{exec} command used in place of {module} module"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.candidate import Template
|
from ansiblelater.candidate import Template
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckCompareToEmptyString(StandardBase):
|
class CheckCompareToEmptyString(RuleBase):
|
||||||
sid = "ANSIBLE0012"
|
sid = "ANSIBLE0012"
|
||||||
description = 'Don\'t compare to empty string ""'
|
description = 'Don\'t compare to empty string ""'
|
||||||
helptext = "use `when: var` rather than `when: var !=` (or conversely `when: not var`)"
|
helptext = "use `when: var` rather than `when: var !=` (or conversely `when: not var`)"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "template"]
|
types = ["playbook", "task", "handler", "template"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.candidate import Template
|
from ansiblelater.candidate import Template
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckCompareToLiteralBool(StandardBase):
|
class CheckCompareToLiteralBool(RuleBase):
|
||||||
sid = "ANSIBLE0013"
|
sid = "ANSIBLE0013"
|
||||||
description = "Don't compare to True or False"
|
description = "Don't compare to True or False"
|
||||||
helptext = "use `when: var` rather than `when: var == True` (or conversely `when: not var`)"
|
helptext = "use `when: var` rather than `when: var == True` (or conversely `when: not var`)"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckDeprecated(StandardBase):
|
class CheckDeprecated(RuleBase):
|
||||||
sid = "ANSIBLE9999"
|
sid = "ANSIBLE9999"
|
||||||
description = "Deprecated features should not be used"
|
description = "Deprecated features should not be used"
|
||||||
helptext = "'{old}' is deprecated and should not be used anymore. Use '{new}' instead."
|
helptext = "`{old}` is deprecated and should not be used anymore. Use `{new}` instead."
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -20,18 +20,17 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
from ansiblelater.utils import has_glob, has_jinja
|
from ansiblelater.utils import has_glob, has_jinja
|
||||||
|
|
||||||
|
|
||||||
class CheckDeprecatedBareVars(StandardBase):
|
class CheckDeprecatedBareVars(RuleBase):
|
||||||
sid = "ANSIBLE0027"
|
sid = "ANSIBLE0027"
|
||||||
description = "Deprecated bare variables in loops must not be used"
|
description = "Deprecated bare variables in loops must not be used"
|
||||||
helptext = (
|
helptext = (
|
||||||
"bare var '{barevar}' in '{loop_type}' must use full var syntax '{{{{ {barevar} }}}}' "
|
"bare var '{barevar}' in '{loop_type}' must use full var syntax '{{{{ {barevar} }}}}' "
|
||||||
"or be converted to a list"
|
"or be converted to a list"
|
||||||
)
|
)
|
||||||
version = "0.3"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -19,17 +19,16 @@
|
|||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckFilePermissionMissing(StandardBase):
|
class CheckFilePermissionMissing(RuleBase):
|
||||||
sid = "ANSIBLE0018"
|
sid = "ANSIBLE0018"
|
||||||
description = "File permissions unset or incorrect"
|
description = "File permissions unset or incorrect"
|
||||||
helptext = (
|
helptext = (
|
||||||
"`mode` parameter should set permissions explicitly (e.g. `mode: 0644`) "
|
"`mode` parameter should set permissions explicitly (e.g. `mode: 0644`) "
|
||||||
"to avoid unexpected file permissions"
|
"to avoid unexpected file permissions"
|
||||||
)
|
)
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
_modules = {
|
_modules = {
|
||||||
|
@ -18,14 +18,13 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckFilePermissionOctal(StandardBase):
|
class CheckFilePermissionOctal(RuleBase):
|
||||||
sid = "ANSIBLE0019"
|
sid = "ANSIBLE0019"
|
||||||
description = "Octal file permissions must contain leading zero or be a string"
|
description = "Octal file permissions must contain leading zero or be a string"
|
||||||
helptext = "numeric file permissions without leading zero can behave in unexpected ways"
|
helptext = "numeric file permissions without leading zero can behave in unexpected ways"
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckFilterSeparation(StandardBase):
|
class CheckFilterSeparation(RuleBase):
|
||||||
sid = "ANSIBLE0016"
|
sid = "ANSIBLE0016"
|
||||||
description = "Jinja2 filters should be separated with spaces"
|
description = "Jinja2 filters should be separated with spaces"
|
||||||
helptext = "no suitable numbers of spaces (required: 1)"
|
helptext = "no suitable numbers of spaces (required: 1)"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -18,14 +18,13 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckGitHasVersion(StandardBase):
|
class CheckGitHasVersion(RuleBase):
|
||||||
sid = "ANSIBLE0020"
|
sid = "ANSIBLE0020"
|
||||||
description = "Git checkouts should use explicit version"
|
description = "Git checkouts should use explicit version"
|
||||||
helptext = "git checkouts should point to an explicit commit or tag, not `latest`"
|
helptext = "git checkouts should point to an explicit commit or tag, not `latest`"
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckInstallUseLatest(StandardBase):
|
class CheckInstallUseLatest(RuleBase):
|
||||||
sid = "ANSIBLE0009"
|
sid = "ANSIBLE0009"
|
||||||
description = "Package installs should use present, not latest"
|
description = "Package installs should use present, not latest"
|
||||||
helptext = "package installs should use `state=present` with or without a version"
|
helptext = "package installs should use `state=present` with or without a version"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckLiteralBoolFormat(StandardBase):
|
class CheckLiteralBoolFormat(RuleBase):
|
||||||
sid = "ANSIBLE0014"
|
sid = "ANSIBLE0014"
|
||||||
description = "Literal bools should be consistent"
|
description = "Literal bools should be consistent"
|
||||||
helptext = "literal bools should be written as `{bools}`"
|
helptext = "literal bools should be written as `{bools}`"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
|
# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
|
||||||
# Copyright (c) 2018, Ansible Project
|
# Copyright (c) 2018, Ansible Project
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckLocalAction(StandardBase):
|
class CheckLocalAction(RuleBase):
|
||||||
sid = "ANSIBLE0024"
|
sid = "ANSIBLE0024"
|
||||||
description = "Don't use local_action"
|
description = "Don't use local_action"
|
||||||
helptext = "`delegate_to: localhost` should be used instead of `local_action`"
|
helptext = "`delegate_to: localhost` should be used instead of `local_action`"
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
# Copyright (c) 2018, Ansible Project
|
# Copyright (c) 2018, Ansible Project
|
||||||
from nested_lookup import nested_lookup
|
from nested_lookup import nested_lookup
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckMetaChangeFromDefault(StandardBase):
|
class CheckMetaChangeFromDefault(RuleBase):
|
||||||
sid = "ANSIBLE0021"
|
sid = "ANSIBLE0021"
|
||||||
description = "Roles meta/main.yml default values should be changed"
|
description = "Roles meta/main.yml default values should be changed"
|
||||||
helptext = "meta/main.yml default values should be changed for: `{field}`"
|
helptext = "meta/main.yml default values should be changed for: `{field}`"
|
||||||
version = "0.2"
|
|
||||||
types = ["meta"]
|
types = ["meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
from nested_lookup import nested_lookup
|
from nested_lookup import nested_lookup
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckMetaMain(StandardBase):
|
class CheckMetaMain(RuleBase):
|
||||||
sid = "ANSIBLE0002"
|
sid = "ANSIBLE0002"
|
||||||
description = "Roles must contain suitable meta/main.yml"
|
description = "Roles must contain suitable meta/main.yml"
|
||||||
helptext = "file should contain `{key}` key"
|
helptext = "file should contain `{key}` key"
|
||||||
version = "0.1"
|
|
||||||
types = ["meta"]
|
types = ["meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckNameFormat(StandardBase):
|
class CheckNameFormat(RuleBase):
|
||||||
sid = "ANSIBLE0007"
|
sid = "ANSIBLE0007"
|
||||||
description = "Name of tasks and handlers must be formatted"
|
description = "Name of tasks and handlers must be formatted"
|
||||||
helptext = "name '{name}' should start with uppercase"
|
helptext = "name `{name}` should start with uppercase"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckNamedTask(StandardBase):
|
class CheckNamedTask(RuleBase):
|
||||||
sid = "ANSIBLE0006"
|
sid = "ANSIBLE0006"
|
||||||
description = "Tasks and handlers must be named"
|
description = "Tasks and handlers must be named"
|
||||||
helptext = "module '{module}' used without or empty `name` attribute"
|
helptext = "module `{module}` used without or empty `name` attribute"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckNativeYaml(StandardBase):
|
class CheckNativeYaml(RuleBase):
|
||||||
sid = "LINT0008"
|
sid = "LINT0008"
|
||||||
description = "Use YAML format for tasks and handlers rather than key=value"
|
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"
|
helptext = "task arguments appear to be in key value rather than YAML format"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -21,17 +21,16 @@
|
|||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckNestedJinja(StandardBase):
|
class CheckNestedJinja(RuleBase):
|
||||||
sid = "ANSIBLE0023"
|
sid = "ANSIBLE0023"
|
||||||
description = "Don't use nested Jinja2 pattern"
|
description = "Don't use nested Jinja2 pattern"
|
||||||
helptext = (
|
helptext = (
|
||||||
"there should not be any nested jinja pattern "
|
"there should not be any nested jinja pattern "
|
||||||
"like `{{ list_one + {{ list_two | max }} }}`"
|
"like `{{ list_one + {{ list_two | max }} }}`"
|
||||||
)
|
)
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
|
# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
|
||||||
# Copyright (c) 2018, Ansible Project
|
# Copyright (c) 2018, Ansible Project
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckRelativeRolePaths(StandardBase):
|
class CheckRelativeRolePaths(RuleBase):
|
||||||
sid = "ANSIBLE0025"
|
sid = "ANSIBLE0025"
|
||||||
description = "Don't use a relative path in a role"
|
description = "Don't use a relative path in a role"
|
||||||
helptext = "`copy` and `template` modules don't need relative path for `src`"
|
helptext = "`copy` and `template` modules don't need relative path for `src`"
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
from ansible.parsing.yaml.objects import AnsibleMapping
|
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"
|
sid = "ANSIBLE0005"
|
||||||
description = "Use `scm:` key rather than `src: scm+url`"
|
description = "Use `scm:` key rather than `src: scm+url`"
|
||||||
helptext = "usage of `src: scm+url` not recommended"
|
helptext = "usage of `src: scm+url` not recommended"
|
||||||
version = "0.1"
|
|
||||||
types = ["rolesfile"]
|
types = ["rolesfile"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckShellInsteadCommand(StandardBase):
|
class CheckShellInsteadCommand(RuleBase):
|
||||||
sid = "ANSIBLE0010"
|
sid = "ANSIBLE0010"
|
||||||
description = "Shell should only be used when essential"
|
description = "Shell should only be used when essential"
|
||||||
helptext = "shell should only be used when piping, redirecting or chaining commands"
|
helptext = "shell should only be used when piping, redirecting or chaining commands"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import re
|
import re
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckTaskSeparation(StandardBase):
|
class CheckTaskSeparation(RuleBase):
|
||||||
sid = "ANSIBLE0001"
|
sid = "ANSIBLE0001"
|
||||||
description = "Single tasks should be separated by empty line"
|
description = "Single tasks should be separated by empty line"
|
||||||
helptext = "missing task separation (required: 1 empty line)"
|
helptext = "missing task separation (required: 1 empty line)"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckUniqueNamedTask(StandardBase):
|
class CheckUniqueNamedTask(RuleBase):
|
||||||
sid = "ANSIBLE0003"
|
sid = "ANSIBLE0003"
|
||||||
description = "Tasks and handlers must be uniquely named within a single file"
|
description = "Tasks and handlers must be uniquely named within a single file"
|
||||||
helptext = "name '{name}' appears multiple times"
|
helptext = "name `{name}` appears multiple times"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -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)
|
|
@ -1,13 +1,12 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckWhenFormat(StandardBase):
|
class CheckWhenFormat(RuleBase):
|
||||||
sid = "ANSIBLE0022"
|
sid = "ANSIBLE0022"
|
||||||
description = "Don't use Jinja2 in when"
|
description = "Don't use Jinja2 in when"
|
||||||
helptext = (
|
helptext = (
|
||||||
"`when` is a raw Jinja2 expression, redundant {{ }} " "should be removed from variable(s)"
|
"`when` is a raw Jinja2 expression, redundant {{ }} " "should be removed from variable(s)"
|
||||||
)
|
)
|
||||||
version = "0.2"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlColons(StandardBase):
|
class CheckYamlColons(RuleBase):
|
||||||
sid = "LINT0005"
|
sid = "LINT0005"
|
||||||
description = "YAML should use consistent number of spaces around colons"
|
description = "YAML should use consistent number of spaces around colons"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlDocumentEnd(StandardBase):
|
class CheckYamlDocumentEnd(RuleBase):
|
||||||
sid = "LINT0009"
|
sid = "LINT0009"
|
||||||
description = "YAML should contain document end marker"
|
description = "YAML should contain document end marker"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlDocumentStart(StandardBase):
|
class CheckYamlDocumentStart(RuleBase):
|
||||||
sid = "LINT0004"
|
sid = "LINT0004"
|
||||||
description = "YAML should contain document start marker"
|
description = "YAML should contain document start marker"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlEmptyLines(StandardBase):
|
class CheckYamlEmptyLines(RuleBase):
|
||||||
sid = "LINT0001"
|
sid = "LINT0001"
|
||||||
description = "YAML should not contain unnecessarily empty lines"
|
description = "YAML should not contain unnecessarily empty lines"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlFile(StandardBase):
|
class CheckYamlFile(RuleBase):
|
||||||
sid = "LINT0006"
|
sid = "LINT0006"
|
||||||
description = "Roles file should be in yaml format"
|
description = "Roles file should be in yaml format"
|
||||||
helptext = "file does not have a .yml extension"
|
helptext = "file does not have a .yml extension"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlHasContent(StandardBase):
|
class CheckYamlHasContent(RuleBase):
|
||||||
sid = "LINT0007"
|
sid = "LINT0007"
|
||||||
description = "Files should contain useful content"
|
description = "Files should contain useful content"
|
||||||
helptext = "the file appears to have no useful content"
|
helptext = "the file appears to have no useful content"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "defaults", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "defaults", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlHyphens(StandardBase):
|
class CheckYamlHyphens(RuleBase):
|
||||||
sid = "LINT0003"
|
sid = "LINT0003"
|
||||||
description = "YAML should use consistent number of spaces after hyphens"
|
description = "YAML should use consistent number of spaces after hyphens"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from ansiblelater.standard import StandardBase
|
from ansiblelater.rule import RuleBase
|
||||||
|
|
||||||
|
|
||||||
class CheckYamlIndent(StandardBase):
|
class CheckYamlIndent(RuleBase):
|
||||||
sid = "LINT0002"
|
sid = "LINT0002"
|
||||||
description = "YAML should not contain unnecessarily empty lines"
|
description = "YAML should not contain unnecessarily empty lines"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
types = ["playbook", "task", "handler", "rolevars", "hostvars", "groupvars", "meta"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
||||||
|
@ -104,13 +104,13 @@ class Settings:
|
|||||||
if f not in defaults["ansible"]["custom_modules"]:
|
if f not in defaults["ansible"]["custom_modules"]:
|
||||||
defaults["ansible"]["custom_modules"].append(f)
|
defaults["ansible"]["custom_modules"].append(f)
|
||||||
|
|
||||||
if defaults["rules"]["buildin"]:
|
if defaults["rules"]["builtin"]:
|
||||||
defaults["rules"]["standards"].append(
|
defaults["rules"]["dir"].append(
|
||||||
os.path.join(resource_filename("ansiblelater", "rules"))
|
os.path.join(resource_filename("ansiblelater", "rules"))
|
||||||
)
|
)
|
||||||
|
|
||||||
defaults["rules"]["standards"] = [
|
defaults["rules"]["dir"] = [
|
||||||
os.path.relpath(os.path.normpath(p)) for p in defaults["rules"]["standards"]
|
os.path.relpath(os.path.normpath(p)) for p in defaults["rules"]["dir"]
|
||||||
]
|
]
|
||||||
|
|
||||||
return defaults
|
return defaults
|
||||||
@ -118,9 +118,9 @@ class Settings:
|
|||||||
def _get_defaults(self):
|
def _get_defaults(self):
|
||||||
defaults = {
|
defaults = {
|
||||||
"rules": {
|
"rules": {
|
||||||
"buildin": True,
|
"builtin": True,
|
||||||
"standards": [],
|
"dir": [],
|
||||||
"filter": [],
|
"include_filter": [],
|
||||||
"exclude_filter": [],
|
"exclude_filter": [],
|
||||||
"warning_filter": [
|
"warning_filter": [
|
||||||
"ANSIBLE9999",
|
"ANSIBLE9999",
|
||||||
@ -128,7 +128,6 @@ class Settings:
|
|||||||
],
|
],
|
||||||
"ignore_dotfiles": True,
|
"ignore_dotfiles": True,
|
||||||
"exclude_files": [],
|
"exclude_files": [],
|
||||||
"version": "",
|
|
||||||
},
|
},
|
||||||
"logging": {
|
"logging": {
|
||||||
"level": "WARNING",
|
"level": "WARNING",
|
||||||
|
@ -6,7 +6,6 @@ import sys
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from packaging.version import Version
|
|
||||||
|
|
||||||
from ansiblelater import logger
|
from ansiblelater import logger
|
||||||
|
|
||||||
@ -35,12 +34,6 @@ def count_spaces(c_string):
|
|||||||
return (leading_spaces, trailing_spaces)
|
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):
|
def lines_ranges(lines_spec):
|
||||||
if not lines_spec:
|
if not lines_spec:
|
||||||
return None
|
return None
|
||||||
|
@ -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:
|
||||||
|
|
||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
<!-- spellchecker-disable -->
|
<!-- spellchecker-disable -->
|
||||||
{{< highlight Python "linenos=table" >}}
|
{{< highlight Python "linenos=table" >}}
|
||||||
class CheckBecomeUser(StandardBase):
|
class CheckBecomeUser(RuleBase):
|
||||||
|
|
||||||
sid = "ANSIBLE0015"
|
sid = "ANSIBLE0015"
|
||||||
description = "Become should be combined with become_user"
|
description = "Become should be combined with become_user"
|
||||||
helptext = "the task has `become` enabled but `become_user` is missing"
|
helptext = "the task has `become` enabled but `become_user` is missing"
|
||||||
version = "0.1"
|
|
||||||
types = ["playbook", "task", "handler"]
|
types = ["playbook", "task", "handler"]
|
||||||
|
|
||||||
def check(self, candidate, settings):
|
def check(self, candidate, settings):
|
@ -8,28 +8,27 @@ You can get all available CLI options by running `ansible-later --help`:
|
|||||||
<!-- spellchecker-disable -->
|
<!-- spellchecker-disable -->
|
||||||
{{< highlight Shell "linenos=table" >}}
|
{{< highlight Shell "linenos=table" >}}
|
||||||
$ ansible-later --help
|
$ ansible-later --help
|
||||||
usage: ansible-later [-h] [-c CONFIG_FILE] [-r RULES.STANDARDS]
|
usage: ansible-later [-h] [-c CONFIG] [-r DIR] [-B] [-i TAGS] [-x TAGS] [-v] [-q] [-V] [rules.files ...]
|
||||||
[-s RULES.FILTER] [-v] [-q] [--version]
|
|
||||||
[rules.files [rules.files ...]]
|
|
||||||
|
|
||||||
Validate Ansible files against best practice guideline
|
Validate Ansible files against best practice guideline
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
rules.files
|
rules.files
|
||||||
|
|
||||||
optional arguments:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-c CONFIG_FILE, --config CONFIG_FILE
|
-c CONFIG, --config CONFIG
|
||||||
location of configuration file
|
path to configuration file
|
||||||
-r RULES.STANDARDS, --rules RULES.STANDARDS
|
-r DIR, --rules-dir DIR
|
||||||
location of standards rules
|
directory of rules
|
||||||
-s RULES.FILTER, --standards RULES.FILTER
|
-B, --no-builtin disables built-in rules
|
||||||
limit standards to given ID's
|
-i TAGS, --include-rules TAGS
|
||||||
-x RULES.EXCLUDE_FILTER, --exclude-standards RULES.EXCLUDE_FILTER
|
limit rules to given id/tags
|
||||||
exclude standards by given ID's
|
-x TAGS, --exclude-rules TAGS
|
||||||
|
exclude rules by given it/tags
|
||||||
-v increase log level
|
-v increase log level
|
||||||
-q decrease log level
|
-q decrease log level
|
||||||
--version show program's version number and exit
|
-V, --version show program's version number and exit
|
||||||
{{< /highlight >}}
|
{{< /highlight >}}
|
||||||
<!-- spellchecker-enable -->
|
<!-- spellchecker-enable -->
|
||||||
<!-- prettier-ignore-end -->
|
<!-- prettier-ignore-end -->
|
||||||
|
@ -58,8 +58,8 @@ logging:
|
|||||||
|
|
||||||
# Global settings for all defined rules
|
# Global settings for all defined rules
|
||||||
rules:
|
rules:
|
||||||
# Disable build-in rules if required
|
# Disable built-in rules if required
|
||||||
buildin: True
|
builtin: True
|
||||||
|
|
||||||
# List of files to exclude
|
# List of files to exclude
|
||||||
exclude_files: []
|
exclude_files: []
|
||||||
@ -75,8 +75,7 @@ rules:
|
|||||||
exclude_filter: []
|
exclude_filter: []
|
||||||
|
|
||||||
# List of rule ID's that should be displayed as a warning instead of an error. By default,
|
# 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.
|
# no rules are marked as warnings. This list allows to degrade errors to warnings for each rule.
|
||||||
# This list allows to degrade errors to warnings for each rule.
|
|
||||||
warning_filter:
|
warning_filter:
|
||||||
- "ANSIBLE9999"
|
- "ANSIBLE9999"
|
||||||
- "ANSIBLE9998"
|
- "ANSIBLE9998"
|
||||||
@ -85,12 +84,8 @@ rules:
|
|||||||
# You can disable this setting and handle dotfiles by yourself with `exclude_files`.
|
# You can disable this setting and handle dotfiles by yourself with `exclude_files`.
|
||||||
ignore_dotfiles: True
|
ignore_dotfiles: True
|
||||||
|
|
||||||
# List of directories to load standard rules from (defaults to build-in)
|
# List of directories to load rules from (defaults to built-in)
|
||||||
standards: []
|
dir: []
|
||||||
|
|
||||||
# Standard version to use. Standard version set in a roles meta file
|
|
||||||
# or playbook will takes precedence.
|
|
||||||
version:
|
|
||||||
|
|
||||||
# Block to control included yamllint rules.
|
# Block to control included yamllint rules.
|
||||||
# See https://yamllint.readthedocs.io/en/stable/rules.html
|
# See https://yamllint.readthedocs.io/en/stable/rules.html
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
title: Included rules
|
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 |
|
| 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. | |
|
| CheckRelativeRolePaths | ANSIBLE0025 | Don't use a relative path in a role. | |
|
||||||
| CheckChangedInWhen | ANSIBLE0026 | Use handlers instead of `when: changed`. | |
|
| CheckChangedInWhen | ANSIBLE0026 | Use handlers instead of `when: changed`. | |
|
||||||
| CheckChangedInWhen | ANSIBLE0027 | Deprecated bare variables in loops must not be used. | |
|
| 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. | |
|
| CheckDeprecated | ANSIBLE9999 | Deprecated features of `ansible-later` should not be used. | |
|
||||||
|
@ -23,5 +23,5 @@ main:
|
|||||||
sub:
|
sub:
|
||||||
- name: Candidates
|
- name: Candidates
|
||||||
ref: "/build_rules/candidates"
|
ref: "/build_rules/candidates"
|
||||||
- name: Standards checks
|
- name: Rules
|
||||||
ref: "/build_rules/standards_check"
|
ref: "/build_rules/rule"
|
||||||
|
Loading…
Reference in New Issue
Block a user