From cb1888125d6a9edbee278121332a9fdc4337d7af Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Wed, 7 Dec 2016 07:56:19 -0800 Subject: [PATCH] add metadata to doc support (#18802) fix broken module docs change doc AST id extraction to use == instead of in --- hacking/module_formatter.py | 2 +- lib/ansible/cli/doc.py | 15 ++++++++-- lib/ansible/modules/clustering/znode.py | 3 +- lib/ansible/modules/windows/win_reboot.py | 2 +- lib/ansible/utils/module_docs.py | 28 ++++++++++++++++--- test/sanity/validate-modules/validate-modules | 2 +- 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/hacking/module_formatter.py b/hacking/module_formatter.py index fd5fe3fac1d..e23994e3716 100755 --- a/hacking/module_formatter.py +++ b/hacking/module_formatter.py @@ -251,7 +251,7 @@ def process_module(module, options, env, template, outputname, module_map, alias print("rendering: %s" % module) # use ansible core library to parse out doc metadata YAML and plaintext examples - doc, examples, returndocs = module_docs.get_docstring(fname, verbose=options.verbose) + doc, examples, returndocs, metadata = module_docs.get_docstring(fname, verbose=options.verbose) # crash if module is missing documentation and not explicitly hidden from docs index if doc is None: diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index eef133803a3..08e782e30e7 100644 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -99,7 +99,7 @@ class DocCLI(CLI): continue try: - doc, plainexamples, returndocs = module_docs.get_docstring(filename, verbose=(self.options.verbosity > 0)) + doc, plainexamples, returndocs, metadata = module_docs.get_docstring(filename, verbose=(self.options.verbosity > 0)) except: display.vvv(traceback.format_exc()) display.error("module %s has a documentation error formatting or is missing documentation\nTo see exact traceback use -vvv" % module) @@ -124,6 +124,7 @@ class DocCLI(CLI): doc['now_date'] = datetime.date.today().strftime('%Y-%m-%d') doc['plainexamples'] = plainexamples doc['returndocs'] = returndocs + doc['metadata'] = metadata if self.options.show_snippet: text += self.get_snippet_text(doc) @@ -185,7 +186,7 @@ class DocCLI(CLI): continue try: - doc, plainexamples, returndocs = module_docs.get_docstring(filename) + doc, plainexamples, returndocs, metadata = module_docs.get_docstring(filename) desc = self.tty_ify(doc.get('short_description', '?')).strip() if len(desc) > linelimit: desc = desc[:linelimit] + '...' @@ -254,9 +255,19 @@ class DocCLI(CLI): text.append("%s\n" % textwrap.fill(CLI.tty_ify(desc), limit, initial_indent=" ", subsequent_indent=" ")) + # FUTURE: move deprecation to metadata-only + if 'deprecated' in doc and doc['deprecated'] is not None and len(doc['deprecated']) > 0: text.append("DEPRECATED: \n%s\n" % doc['deprecated']) + metadata = doc['metadata'] + + supported_by = metadata['supported_by'] + text.append("Supported by: %s\n" % supported_by) + + status = metadata['status'] + text.append("Status: %s\n" % ", ".join(status)) + if 'action' in doc and doc['action']: text.append(" * note: %s\n" % "This module has a corresponding action plugin.") diff --git a/lib/ansible/modules/clustering/znode.py b/lib/ansible/modules/clustering/znode.py index 0ed39428920..f0d4e7b195e 100644 --- a/lib/ansible/modules/clustering/znode.py +++ b/lib/ansible/modules/clustering/znode.py @@ -25,7 +25,8 @@ DOCUMENTATION = """ module: znode version_added: "2.0" short_description: Create, delete, retrieve, and update znodes using ZooKeeper -description: Create, delete, retrieve, and update znodes using ZooKeeper. +description: + - Create, delete, retrieve, and update znodes using ZooKeeper. options: hosts: description: diff --git a/lib/ansible/modules/windows/win_reboot.py b/lib/ansible/modules/windows/win_reboot.py index c8f179e7dd4..711f20c4815 100644 --- a/lib/ansible/modules/windows/win_reboot.py +++ b/lib/ansible/modules/windows/win_reboot.py @@ -73,7 +73,7 @@ EXAMPLES=''' reboot_timeout_sec: 3600 ''' -RETURNS=''' +RETURN=''' rebooted: description: true if the machine was rebooted returned: always diff --git a/lib/ansible/utils/module_docs.py b/lib/ansible/utils/module_docs.py index 48f705cd920..0a12cddb9af 100755 --- a/lib/ansible/utils/module_docs.py +++ b/lib/ansible/utils/module_docs.py @@ -60,6 +60,7 @@ def get_docstring(filename, verbose=False): doc = None plainexamples = None returndocs = None + metadata = None try: # Thank you, Habbie, for this bit of code :-) @@ -74,7 +75,7 @@ def get_docstring(filename, verbose=False): display.warning("Failed to assign id for %s on %s, skipping" % (t, filename)) continue - if 'DOCUMENTATION' in theid: + if 'DOCUMENTATION' == theid: doc = AnsibleLoader(child.value.s, file_name=filename).get_single_data() fragments = doc.get('extends_documentation_fragment', []) @@ -120,15 +121,34 @@ def get_docstring(filename, verbose=False): else: raise Exception("Attempt to extend a documentation fragement of unknown type") - elif 'EXAMPLES' in theid: + elif 'EXAMPLES' == theid: plainexamples = child.value.s[1:] # Skip first empty line - elif 'RETURN' in theid: + elif 'RETURN' == theid: returndocs = child.value.s[1:] + + elif 'ANSIBLE_METADATA' == theid: + metadata = child.value + if type(metadata).__name__ == 'Dict': + metadata = ast.literal_eval(child.value) + else: + display.warning("Non-dict metadata detected in %s, skipping" % filename) + metadata = dict() + except: display.error("unable to parse %s" % filename) if verbose == True: display.display("unable to parse %s" % filename) raise - return doc, plainexamples, returndocs + + if not metadata: + metadata = dict() + + # ensure metadata defaults + # FUTURE: extract this into its own class for use by runtime metadata + metadata['version'] = metadata.get('version', '1.0') + metadata['status'] = metadata.get('status', ['preview']) + metadata['supported_by'] = metadata.get('supported_by', 'community') + + return doc, plainexamples, returndocs, metadata diff --git a/test/sanity/validate-modules/validate-modules b/test/sanity/validate-modules/validate-modules index 99ee7b005fb..a12b062e61f 100755 --- a/test/sanity/validate-modules/validate-modules +++ b/test/sanity/validate-modules/validate-modules @@ -499,7 +499,7 @@ class ModuleValidator(Validator): with CaptureStd(): try: existing = module_loader.find_plugin(self.name, mod_type='.py') - existing_doc, _, _ = get_docstring(existing, verbose=True) + existing_doc, _, _, _ = get_docstring(existing, verbose=True) existing_options = existing_doc.get('options', {}) except AssertionError: fragment = doc['extends_documentation_fragment']