mirror of
https://github.com/thegeeklab/ansible-later.git
synced 2024-11-26 06:40:42 +00:00
fix json logging and add file exclude options
This commit is contained in:
parent
fa14538f20
commit
2b574970c2
@ -1,14 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ansiblelater import __version__
|
from ansiblelater import LOG, __version__, logger
|
||||||
from ansiblelater import LOG
|
from ansiblelater.command import base, candidates
|
||||||
from ansiblelater import logger
|
|
||||||
from ansiblelater.command import base
|
|
||||||
from ansiblelater.command import candidates
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -5,18 +5,12 @@ import codecs
|
|||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
import ansible
|
from ansiblelater import LOG, utils
|
||||||
|
|
||||||
from ansiblelater import LOG
|
|
||||||
from ansiblelater import utils
|
|
||||||
from ansiblelater.logger import flag_extra
|
|
||||||
from ansiblelater.command.review import Error
|
from ansiblelater.command.review import Error
|
||||||
from ansiblelater.exceptions import ( # noqa
|
from ansiblelater.exceptions import LaterAnsibleError, LaterError # noqa
|
||||||
LaterError, LaterAnsibleError
|
from ansiblelater.logger import flag_extra
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Ansible 2.4 import of module loader
|
# Ansible 2.4 import of module loader
|
||||||
@ -114,8 +108,8 @@ class Candidate(object):
|
|||||||
result = standard.check(self, settings.config)
|
result = standard.check(self, settings.config)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
utils.sysexit_with_message("Standard '%s' returns an empty result object." %
|
utils.sysexit_with_message("Standard '{}' returns an empty result object.".format(
|
||||||
(standard.check.__name__))
|
standard.check.__name__))
|
||||||
|
|
||||||
labels = {"tag": "review", "standard": standard.name, "file": self.path, "passed": True}
|
labels = {"tag": "review", "standard": standard.name, "file": self.path, "passed": True}
|
||||||
|
|
||||||
@ -128,13 +122,16 @@ class Candidate(object):
|
|||||||
|
|
||||||
if not standard.version:
|
if not standard.version:
|
||||||
LOG.warn("{id}Best practice '{name}' not met:\n{path}:{error}".format(
|
LOG.warn("{id}Best practice '{name}' not met:\n{path}:{error}".format(
|
||||||
id=standard.id, name=standard.name, path=self.path, error=err), extra=flag_extra(err_labels))
|
id=standard.id, name=standard.name, path=self.path, error=err),
|
||||||
|
extra=flag_extra(err_labels))
|
||||||
elif LooseVersion(standard.version) > LooseVersion(self.version):
|
elif LooseVersion(standard.version) > LooseVersion(self.version):
|
||||||
LOG.warn("{id}Future standard '{name}' not met:\n{path}:{error}".format(
|
LOG.warn("{id}Future standard '{name}' not met:\n{path}:{error}".format(
|
||||||
id=standard.id, name=standard.name, path=self.path, error=err), extra=flag_extra(err_labels))
|
id=standard.id, name=standard.name, path=self.path, error=err),
|
||||||
|
extra=flag_extra(err_labels))
|
||||||
else:
|
else:
|
||||||
LOG.error("{id}Standard '{name}' not met:\n{path}:{error}".format(
|
LOG.error("{id}Standard '{name}' not met:\n{path}:{error}".format(
|
||||||
id=standard.id, name=standard.name, path=self.path, error=err), extra=flag_extra(err_labels))
|
id=standard.id, name=standard.name, path=self.path, error=err),
|
||||||
|
extra=flag_extra(err_labels))
|
||||||
errors = errors + 1
|
errors = errors + 1
|
||||||
if not result.errors:
|
if not result.errors:
|
||||||
if not standard.version:
|
if not standard.version:
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
"""Review candidates."""
|
"""Review candidates."""
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
|
|
||||||
@ -44,5 +41,3 @@ class Result(object):
|
|||||||
def message(self):
|
def message(self):
|
||||||
return "\n".join(["{0}:{1}".format(self.candidate, error)
|
return "\n".join(["{0}:{1}".format(self.candidate, error)
|
||||||
for error in self.errors])
|
for error in self.errors])
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,10 +7,7 @@ class LaterError(Exception):
|
|||||||
"""Generic exception for later."""
|
"""Generic exception for later."""
|
||||||
|
|
||||||
def __init__(self, msg, original):
|
def __init__(self, msg, original):
|
||||||
"""
|
"""Initialize new exception."""
|
||||||
Initialize new exception.
|
|
||||||
|
|
||||||
"""
|
|
||||||
super(LaterError, self).__init__(msg + (": %s" % original))
|
super(LaterError, self).__init__(msg + (": %s" % original))
|
||||||
self.original = original
|
self.original = original
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
from six import iteritems
|
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean as to_bool
|
from ansible.module_utils.parsing.convert_bool import boolean as to_bool
|
||||||
from pythonjsonlogger import jsonlogger
|
from pythonjsonlogger import jsonlogger
|
||||||
|
from six import iteritems
|
||||||
|
|
||||||
CONSOLE_FORMAT = "%(levelname)s: %(message)s"
|
CONSOLE_FORMAT = "%(levelname)s: %(message)s"
|
||||||
JSON_FORMAT = "(levelname) (asctime)"
|
JSON_FORMAT = "(asctime) (levelname) (message)"
|
||||||
|
|
||||||
|
|
||||||
def _should_do_markup():
|
def _should_do_markup():
|
||||||
@ -24,13 +24,6 @@ def _should_do_markup():
|
|||||||
|
|
||||||
colorama.init(autoreset=True, strip=not _should_do_markup())
|
colorama.init(autoreset=True, strip=not _should_do_markup())
|
||||||
|
|
||||||
clashing_keywords = {key for key in dir(logging.LogRecord(None, None, "", 0, "", (), None, None)) if "__" not in key}
|
|
||||||
additional_clashing_keywords = {
|
|
||||||
"message",
|
|
||||||
"asctime"
|
|
||||||
}
|
|
||||||
clashing_keywords = clashing_keywords.union(additional_clashing_keywords)
|
|
||||||
|
|
||||||
|
|
||||||
def flag_extra(kwargs):
|
def flag_extra(kwargs):
|
||||||
"""Ensure kwargs not conflict with the logging module."""
|
"""Ensure kwargs not conflict with the logging module."""
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
"""Global settings object definition."""
|
"""Global settings object definition."""
|
||||||
|
|
||||||
|
import copy
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import anyconfig
|
import anyconfig
|
||||||
from appdirs import AppDirs
|
from appdirs import AppDirs
|
||||||
|
from globmatch import glob_match
|
||||||
from jsonschema._utils import format_as_index
|
from jsonschema._utils import format_as_index
|
||||||
from pkg_resources import resource_filename
|
from pkg_resources import resource_filename
|
||||||
|
|
||||||
from ansiblelater import logger, utils
|
from ansiblelater import utils
|
||||||
|
|
||||||
config_dir = AppDirs("ansible-later").user_config_dir
|
config_dir = AppDirs("ansible-later").user_config_dir
|
||||||
default_config_file = os.path.join(config_dir, "config.yml")
|
default_config_file = os.path.join(config_dir, "config.yml")
|
||||||
@ -37,6 +39,7 @@ class Settings(object):
|
|||||||
self.args = self._set_args(args)
|
self.args = self._set_args(args)
|
||||||
self.config = self._get_config()
|
self.config = self._get_config()
|
||||||
self.schema = None
|
self.schema = None
|
||||||
|
self._update_filelist()
|
||||||
|
|
||||||
def _set_args(self, args):
|
def _set_args(self, args):
|
||||||
self.config_file = args.get("config_file") or default_config_file
|
self.config_file = args.get("config_file") or default_config_file
|
||||||
@ -80,6 +83,8 @@ class Settings(object):
|
|||||||
"rules": {
|
"rules": {
|
||||||
"standards": rules_dir,
|
"standards": rules_dir,
|
||||||
"filter": [],
|
"filter": [],
|
||||||
|
"ignore_dotfiles": True,
|
||||||
|
"exclude_files": []
|
||||||
},
|
},
|
||||||
"logging": {
|
"logging": {
|
||||||
"level": logging.WARN,
|
"level": logging.WARN,
|
||||||
@ -98,7 +103,7 @@ class Settings(object):
|
|||||||
filelist = []
|
filelist = []
|
||||||
for root, dirs, files in os.walk("."):
|
for root, dirs, files in os.walk("."):
|
||||||
for filename in files:
|
for filename in files:
|
||||||
filelist.append(os.path.join(root, filename))
|
filelist.append(os.path.relpath(os.path.normpath(os.path.join(root, filename))))
|
||||||
else:
|
else:
|
||||||
filelist = args["rules"]["files"]
|
filelist = args["rules"]["files"]
|
||||||
|
|
||||||
@ -114,3 +119,16 @@ class Settings(object):
|
|||||||
schema=format_as_index(list(e.relative_schema_path)[:-1])
|
schema=format_as_index(list(e.relative_schema_path)[:-1])
|
||||||
)
|
)
|
||||||
utils.sysexit_with_message("{schema}: {msg}".format(schema=schema_error, msg=e.message))
|
utils.sysexit_with_message("{schema}: {msg}".format(schema=schema_error, msg=e.message))
|
||||||
|
|
||||||
|
def _update_filelist(self):
|
||||||
|
files = self.config["rules"]["files"]
|
||||||
|
excludes = self.config["rules"]["exclude_files"]
|
||||||
|
ignore_dotfiles = self.config["rules"]["ignore_dotfiles"]
|
||||||
|
|
||||||
|
if ignore_dotfiles:
|
||||||
|
excludes.append(".")
|
||||||
|
|
||||||
|
valid = copy.copy(files)
|
||||||
|
for item in valid:
|
||||||
|
if glob_match(item, excludes):
|
||||||
|
files.remove(item)
|
||||||
|
@ -28,4 +28,3 @@ class Standard(object):
|
|||||||
def __repr__(self): # noqa
|
def __repr__(self): # noqa
|
||||||
return "Standard: %s (version: %s, types: %s)" % (
|
return "Standard: %s (version: %s, types: %s)" % (
|
||||||
self.name, self.version, self.types)
|
self.name, self.version, self.types)
|
||||||
|
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import importlib
|
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import re
|
import re
|
||||||
import colorama
|
import sys
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from distutils.version import LooseVersion
|
|
||||||
from ansiblelater import logger
|
from ansiblelater import logger
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean as to_bool
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ConfigParser as configparser
|
import ConfigParser as configparser # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import configparser
|
import configparser # noqa
|
||||||
|
|
||||||
|
|
||||||
LOG = logger.get_logger(__name__)
|
LOG = logger.get_logger(__name__)
|
||||||
@ -67,19 +64,13 @@ def is_line_in_ranges(line, ranges):
|
|||||||
return not ranges or any([line in r for r in ranges])
|
return not ranges or any([line in r for r in ranges])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_config(config_file):
|
|
||||||
config = configparser.RawConfigParser({'standards': None})
|
|
||||||
config.read(config_file)
|
|
||||||
|
|
||||||
return Settings(config, config_file)
|
|
||||||
|
|
||||||
|
|
||||||
def safe_load(string):
|
def safe_load(string):
|
||||||
"""
|
"""
|
||||||
Parse the provided string returns a dict.
|
Parse the provided string returns a dict.
|
||||||
|
|
||||||
:param string: A string to be parsed.
|
:param string: A string to be parsed.
|
||||||
:return: dict
|
:returns: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return yaml.safe_load(string) or {}
|
return yaml.safe_load(string) or {}
|
||||||
@ -88,12 +79,14 @@ def safe_load(string):
|
|||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def open_file(filename, mode='r'):
|
def open_file(filename, mode="r"):
|
||||||
"""
|
"""
|
||||||
Open the provide file safely and returns a file type.
|
Open the provide file safely and returns a file type.
|
||||||
|
|
||||||
:param filename: A string containing an absolute path to the file to open.
|
:param filename: A string containing an absolute path to the file to open.
|
||||||
:param mode: A string describing the way in which the file will be used.
|
:param mode: A string describing the way in which the file will be used.
|
||||||
:return: file type
|
:returns: file type
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with open(filename, mode) as stream:
|
with open(filename, mode) as stream:
|
||||||
yield stream
|
yield stream
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
import codecs
|
import codecs
|
||||||
import yaml
|
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import yaml
|
||||||
from yamllint import linter
|
from yamllint import linter
|
||||||
from yamllint.config import YamlLintConfig
|
from yamllint.config import YamlLintConfig
|
||||||
# Workaround for import errors with ansble 2.1 and 2.3
|
|
||||||
from ansible.parsing.dataloader import DataLoader
|
|
||||||
from ansiblelater.command.review import Error
|
from ansiblelater.command.review import Error
|
||||||
from .yamlhelper import normalize_task
|
from ansiblelater.exceptions import LaterAnsibleError, LaterError
|
||||||
from .yamlhelper import action_tasks
|
|
||||||
from .yamlhelper import parse_yaml_linenumbers
|
from .yamlhelper import (action_tasks, normalize_task, normalized_yaml,
|
||||||
from .yamlhelper import normalized_yaml
|
parse_yaml_linenumbers)
|
||||||
from ansiblelater.exceptions import LaterError, LaterAnsibleError
|
|
||||||
|
|
||||||
|
|
||||||
def get_tasks(candidate, settings):
|
def get_tasks(candidate, settings):
|
||||||
errors = []
|
errors = []
|
||||||
try:
|
try:
|
||||||
with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
|
with codecs.open(candidate.path, mode="rb", encoding="utf-8") as f:
|
||||||
yamllines = parse_yaml_linenumbers(f, candidate.path)
|
yamllines = parse_yaml_linenumbers(f, candidate.path)
|
||||||
|
|
||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
@ -33,7 +31,7 @@ def get_action_tasks(candidate, settings):
|
|||||||
tasks = []
|
tasks = []
|
||||||
errors = []
|
errors = []
|
||||||
try:
|
try:
|
||||||
with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
|
with codecs.open(candidate.path, mode="rb", encoding="utf-8") as f:
|
||||||
yamllines = parse_yaml_linenumbers(f, candidate.path)
|
yamllines = parse_yaml_linenumbers(f, candidate.path)
|
||||||
|
|
||||||
if yamllines:
|
if yamllines:
|
||||||
@ -65,19 +63,20 @@ def get_normalized_tasks(candidate, settings):
|
|||||||
normalized = []
|
normalized = []
|
||||||
errors = []
|
errors = []
|
||||||
try:
|
try:
|
||||||
with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
|
with codecs.open(candidate.path, mode="rb", encoding="utf-8") as f:
|
||||||
yamllines = parse_yaml_linenumbers(f, candidate.path)
|
yamllines = parse_yaml_linenumbers(f, candidate.path)
|
||||||
|
|
||||||
if yamllines:
|
if yamllines:
|
||||||
tasks = action_tasks(yamllines, candidate)
|
tasks = action_tasks(yamllines, candidate)
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
# An empty `tags` block causes `None` to be returned if
|
# An empty `tags` block causes `None` to be returned if
|
||||||
# the `or []` is not present - `task.get('tags', [])`
|
# the `or []` is not present - `task.get("tags", [])`
|
||||||
# does not suffice.
|
# does not suffice.
|
||||||
if 'skip_ansible_lint' in (task.get('tags') or []):
|
if "skip_ansible_lint" in (task.get("tags") or []):
|
||||||
# No need to normalize_task if we are skipping it.
|
# No need to normalize_task if we are skipping it.
|
||||||
continue
|
continue
|
||||||
normalized.append(normalize_task(task, candidate.path, settings["ansible"]["custom_modules"]))
|
normalized.append(
|
||||||
|
normalize_task(task, candidate.path, settings["ansible"]["custom_modules"]))
|
||||||
|
|
||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
e = ex.original
|
e = ex.original
|
||||||
@ -112,7 +111,7 @@ def get_raw_yaml(candidate, settings):
|
|||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
|
with codecs.open(candidate.path, mode="rb", encoding="utf-8") as f:
|
||||||
content = yaml.safe_load(f)
|
content = yaml.safe_load(f)
|
||||||
|
|
||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
@ -125,7 +124,7 @@ def get_raw_yaml(candidate, settings):
|
|||||||
def run_yamllint(candidate, settings, options="extends: default"):
|
def run_yamllint(candidate, settings, options="extends: default"):
|
||||||
errors = []
|
errors = []
|
||||||
try:
|
try:
|
||||||
with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
|
with codecs.open(candidate.path, mode="rb", encoding="utf-8") as f:
|
||||||
for problem in linter.run(f, YamlLintConfig(options)):
|
for problem in linter.run(f, YamlLintConfig(options)):
|
||||||
errors.append(Error(problem.line, problem.desc))
|
errors.append(Error(problem.line, problem.desc))
|
||||||
except LaterError as ex:
|
except LaterError as ex:
|
||||||
|
Loading…
Reference in New Issue
Block a user