From f9f6080630f1a50b42ae7d5313339a03e2ef69ca Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Wed, 17 Jan 2018 10:53:03 -0800 Subject: [PATCH] Improve handling of ansible-doc sanity errors. --- lib/ansible/cli/doc.py | 2 +- test/runner/lib/sanity/ansible_doc.py | 41 +++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index e9f3c2d5a36..99cf388721a 100644 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -163,7 +163,7 @@ class DocCLI(CLI): doc, plainexamples, returndocs, metadata = get_docstring(filename, fragment_loader, verbose=(self.options.verbosity > 0)) except: display.vvv(traceback.format_exc()) - display.error("%s %s has a documentation error formatting or is missing documentation." % (plugin_type, plugin)) + display.error("%s %s has a documentation error formatting or is missing documentation." % (plugin_type, plugin), wrap_text=False) continue if doc is not None: diff --git a/test/runner/lib/sanity/ansible_doc.py b/test/runner/lib/sanity/ansible_doc.py index c9c720779de..b4df24cbb41 100644 --- a/test/runner/lib/sanity/ansible_doc.py +++ b/test/runner/lib/sanity/ansible_doc.py @@ -1,11 +1,14 @@ """Sanity test for ansible-doc.""" from __future__ import absolute_import, print_function +import re + from lib.sanity import ( SanityMultipleVersion, SanityFailure, SanitySuccess, SanitySkipped, + SanityMessage, ) from lib.util import ( @@ -42,9 +45,7 @@ class AnsibleDocTest(SanityMultipleVersion): if not modules: return SanitySkipped(self.name, python_version=python_version) - # ansible-doc fails due to async syntax errors on Python 3.7 currently - if python_version == '3.7': - return SanitySkipped(self.name, python_version=python_version) + module_paths = dict((t.module, t.path) for t in targets.targets if t.module) env = ansible_environment(args, color=False) cmd = ['ansible-doc'] + modules @@ -57,6 +58,13 @@ class AnsibleDocTest(SanityMultipleVersion): stderr = ex.stderr status = ex.status + if stderr: + errors = stderr.strip().splitlines() + messages = [self.parse_error(e, module_paths) for e in errors] + + if messages and all(messages): + return SanityFailure(self.name, messages=messages, python_version=python_version) + if status: summary = u'%s' % SubprocessError(cmd=cmd, status=status, stderr=stderr) return SanityFailure(self.name, summary=summary, python_version=python_version) @@ -69,3 +77,30 @@ class AnsibleDocTest(SanityMultipleVersion): return SanityFailure(self.name, summary=summary, python_version=python_version) return SanitySuccess(self.name, python_version=python_version) + + @staticmethod + def parse_error(error, module_paths): + """ + :type error: str + :type module_paths: dict[str, str] + :rtype: SanityMessage | None + """ + # example error messages from lib/ansible/cli/doc.py: + # ERROR! module ping missing documentation (or could not parse documentation): expected string or buffer + # [ERROR]: module ping has a documentation error formatting or is missing documentation. + match = re.search(r'^[^ ]*ERROR[^ ]* (?P[^ ]+) (?P[^ ]+) (?P.*)$', error) + + if match: + groups = match.groupdict() + + error_type = groups['type'] + error_name = groups['name'] + error_text = groups['text'] + + if error_type == 'module' and error_name in module_paths: + return SanityMessage( + message=error_text, + path=module_paths[error_name], + ) + + return None