diff --git a/docs/docsite/rst/dev_guide/testing_validate-modules.rst b/docs/docsite/rst/dev_guide/testing_validate-modules.rst index fdd3e98c78..2499410487 100644 --- a/docs/docsite/rst/dev_guide/testing_validate-modules.rst +++ b/docs/docsite/rst/dev_guide/testing_validate-modules.rst @@ -132,6 +132,8 @@ Errors +---------+--------------------------------------------------------------------------------------------------------------------------------------------+ | 318 | Module deprecated, but DOCUMENTATION.deprecated is missing | +---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 319 | ``RETURN`` fragments missing or invalid | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +---------+--------------------------------------------------------------------------------------------------------------------------------------------+ | **4xx** | **Syntax** | +---------+--------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/test/sanity/validate-modules/schema.py b/test/sanity/validate-modules/schema.py index ffef4922a8..008e53bc06 100644 --- a/test/sanity/validate-modules/schema.py +++ b/test/sanity/validate-modules/schema.py @@ -57,6 +57,30 @@ option_schema = Schema( # for example in Python 3: {str: option_schema} list_dict_option_schema = [{str_type: option_schema} for str_type in string_types] + +def return_schema(data): + + return_schema_dict = { + Required('description'): Any(list, *string_types), + Required('returned'): Any(*string_types), + Required('type'): Any('string', 'list', 'boolean', 'dict', 'complex', 'bool', 'float', 'int', 'dictionary', 'str'), + 'sample': Any(None, list, dict, int, float, *string_types), + 'example': Any(None, list, dict, int, float, *string_types) + } + if isinstance(data, dict): + if 'type' in data and (data['type'] == 'complex'): + # This will just check if the schema has a 'contains' value. + # It won't recursively validate the contents of the 'contains' field + additional_schema = { + Required('contains'): Any(dict, list, *string_types) + } + return_schema_dict.update(additional_schema) + + return Schema( + return_schema_dict, + extra=PREVENT_EXTRA + ) + def doc_schema(module_name): if module_name.startswith('_'): module_name = module_name[1:] @@ -77,6 +101,7 @@ def doc_schema(module_name): extra=PREVENT_EXTRA ) + def metadata_schema(deprecated): valid_status = Any('stableinterface', 'preview', 'deprecated', 'removed') if deprecated: @@ -94,7 +119,7 @@ def metadata_schema(deprecated): # Things to add soon #################### -# 1) Validate RETURN, including `contains` if `type: complex` +# 1) Recursively validate `type: complex` fields # This will improve documentation, though require fair amount of module tidyup # Possible Future Enhancements diff --git a/test/sanity/validate-modules/validate-modules b/test/sanity/validate-modules/validate-modules index 3f3f8bbc7e..717b7b9537 100755 --- a/test/sanity/validate-modules/validate-modules +++ b/test/sanity/validate-modules/validate-modules @@ -41,7 +41,7 @@ from ansible.utils.plugin_docs import BLACKLIST, get_docstring from module_args import get_argument_spec -from schema import doc_schema, option_schema, metadata_schema +from schema import doc_schema, option_schema, metadata_schema, return_schema from utils import CaptureStd, parse_yaml from voluptuous.humanize import humanize_error @@ -696,9 +696,13 @@ class ModuleValidator(Validator): else: self.warnings.append((312, 'No RETURN provided')) else: - _, errors, traces = parse_yaml(doc_info['RETURN']['value'], + data, errors, traces = parse_yaml(doc_info['RETURN']['value'], doc_info['RETURN']['lineno'], self.name, 'RETURN') + + if data: + for ret_key in data: + self._validate_docs_schema(data[ret_key], return_schema(data[ret_key]), 'RETURN.%s' % ret_key, 319) self.errors.extend([(313, error) for error in errors]) self.traces.extend(traces)