ece306b201
Check that all yaml we ship is parsable by the pyyaml c backend. Since Ansible uses Pyyaml for docs and playbooks, if the yaml files aren't parsable, they will error out if they were used. Warn and skip yamllint if libyaml backend is not present Ignore new errors in examples until someone can fix them
136 lines
3.7 KiB
Python
136 lines
3.7 KiB
Python
"""Sanity test using yamllint."""
|
|
from __future__ import (absolute_import, division, print_function)
|
|
__metaclass__ = type
|
|
|
|
import json
|
|
import os
|
|
|
|
from .. import types as t
|
|
|
|
from ..import ansible_util
|
|
|
|
from ..sanity import (
|
|
SanitySingleVersion,
|
|
SanityMessage,
|
|
SanityFailure,
|
|
SanitySkipped,
|
|
SanitySuccess,
|
|
SANITY_ROOT,
|
|
)
|
|
|
|
from ..target import (
|
|
TestTarget,
|
|
)
|
|
|
|
from ..util import (
|
|
SubprocessError,
|
|
display,
|
|
is_subdir,
|
|
find_python,
|
|
)
|
|
|
|
from ..util_common import (
|
|
run_command,
|
|
)
|
|
|
|
from ..config import (
|
|
SanityConfig,
|
|
)
|
|
|
|
from ..data import (
|
|
data_context,
|
|
)
|
|
|
|
|
|
class YamllintTest(SanitySingleVersion):
|
|
"""Sanity test using yamllint."""
|
|
@property
|
|
def error_code(self): # type: () -> t.Optional[str]
|
|
"""Error code for ansible-test matching the format used by the underlying test program, or None if the program does not use error codes."""
|
|
return 'ansible-test'
|
|
|
|
def filter_targets(self, targets): # type: (t.List[TestTarget]) -> t.List[TestTarget]
|
|
"""Return the given list of test targets, filtered to include only those relevant for the test."""
|
|
yaml_targets = [target for target in targets if os.path.splitext(target.path)[1] in ('.yml', '.yaml')]
|
|
|
|
for plugin_type, plugin_path in sorted(data_context().content.plugin_paths.items()):
|
|
if plugin_type == 'module_utils':
|
|
continue
|
|
|
|
yaml_targets.extend([target for target in targets if
|
|
os.path.splitext(target.path)[1] == '.py' and
|
|
os.path.basename(target.path) != '__init__.py' and
|
|
is_subdir(target.path, plugin_path)])
|
|
|
|
return yaml_targets
|
|
|
|
def test(self, args, targets, python_version):
|
|
"""
|
|
:type args: SanityConfig
|
|
:type targets: SanityTargets
|
|
:type python_version: str
|
|
:rtype: TestResult
|
|
"""
|
|
ansible_util.check_pyyaml(args, python_version)
|
|
if not ansible_util.CHECK_YAML_VERSIONS[python_version]['cloader']:
|
|
display.warning("Skipping sanity test '%s' due to missing libyaml support in PyYAML."
|
|
% self.name)
|
|
return SanitySkipped(self.name)
|
|
|
|
settings = self.load_processor(args)
|
|
|
|
paths = [target.path for target in targets.include]
|
|
|
|
python = find_python(python_version)
|
|
|
|
results = self.test_paths(args, paths, python)
|
|
results = settings.process_errors(results, paths)
|
|
|
|
if results:
|
|
return SanityFailure(self.name, messages=results)
|
|
|
|
return SanitySuccess(self.name)
|
|
|
|
@staticmethod
|
|
def test_paths(args, paths, python):
|
|
"""
|
|
:type args: SanityConfig
|
|
:type paths: list[str]
|
|
:type python: str
|
|
:rtype: list[SanityMessage]
|
|
"""
|
|
cmd = [
|
|
python,
|
|
os.path.join(SANITY_ROOT, 'yamllint', 'yamllinter.py'),
|
|
]
|
|
|
|
data = '\n'.join(paths)
|
|
|
|
display.info(data, verbosity=4)
|
|
|
|
try:
|
|
stdout, stderr = run_command(args, cmd, data=data, capture=True)
|
|
status = 0
|
|
except SubprocessError as ex:
|
|
stdout = ex.stdout
|
|
stderr = ex.stderr
|
|
status = ex.status
|
|
|
|
if stderr:
|
|
raise SubprocessError(cmd=cmd, status=status, stderr=stderr, stdout=stdout)
|
|
|
|
if args.explain:
|
|
return []
|
|
|
|
results = json.loads(stdout)['messages']
|
|
|
|
results = [SanityMessage(
|
|
code=r['code'],
|
|
message=r['message'],
|
|
path=r['path'],
|
|
line=int(r['line']),
|
|
column=int(r['column']),
|
|
level=r['level'],
|
|
) for r in results]
|
|
|
|
return results
|