Add several new doc<->arg_spec checks (#36247)
* Add several new doc<->arg_spec checks. See #18183 * Update ignore.txt for validate-modules
This commit is contained in:
parent
77fa41795e
commit
50adc5409b
4 changed files with 2958 additions and 7 deletions
|
@ -110,6 +110,9 @@ Errors
|
|||
321 ``Exception`` attempting to import module for ``argument_spec`` introspection
|
||||
322 argument is listed in the argument_spec, but not documented in the module
|
||||
323 argument is listed in DOCUMENTATION.options, but not accepted by the module
|
||||
324 Value for "default" from the argument_spec does not match the documentation
|
||||
325 argument_spec defines type="bool" but documentation does not
|
||||
326 Value for "choices" from the argument_spec does not match the documentation
|
||||
..
|
||||
--------- -------------------
|
||||
**4xx** **Syntax**
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -45,7 +45,7 @@ from module_args import AnsibleModuleImportError, get_argument_spec
|
|||
|
||||
from schema import doc_schema, metadata_1_1_schema, return_schema
|
||||
|
||||
from utils import CaptureStd, parse_yaml
|
||||
from utils import CaptureStd, compare_unordered_lists, maybe_convert_bool, parse_yaml
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
from ansible.module_utils.six import PY3, with_metaclass
|
||||
|
@ -1058,6 +1058,34 @@ class ModuleValidator(Validator):
|
|||
'should not be marked as required' % arg)
|
||||
)
|
||||
|
||||
doc_default = docs.get('options', {}).get(arg, {}).get('default', None)
|
||||
if data.get('type') == 'bool':
|
||||
doc_default = maybe_convert_bool(doc_default)
|
||||
if 'default' in data and data['default'] != doc_default:
|
||||
self.reporter.error(
|
||||
path=self.object_path,
|
||||
code=324,
|
||||
msg=('Value for "default" from the argument_spec (%r) for "%s" does not match the '
|
||||
'documentation (%r)' % (data['default'], arg, doc_default))
|
||||
)
|
||||
|
||||
doc_type = docs.get('options', {}).get(arg, {}).get('type', 'str')
|
||||
if 'type' in data and data['type'] == 'bool' and doc_type != 'bool':
|
||||
self.reporter.error(
|
||||
path=self.object_path,
|
||||
code=325,
|
||||
msg='argument_spec for "%s" defines type="bool" but documentation does not' % (arg,)
|
||||
)
|
||||
|
||||
doc_choices = docs.get('options', {}).get(arg, {}).get('choices', [])
|
||||
if not compare_unordered_lists(data.get('choices', []), doc_choices):
|
||||
self.reporter.error(
|
||||
path=self.object_path,
|
||||
code=326,
|
||||
msg=('Value for "choices" from the argument_spec (%r) for "%s" does not match the '
|
||||
'documentation (%r)' % (data.get('choices', []), arg, doc_choices))
|
||||
)
|
||||
|
||||
if docs:
|
||||
try:
|
||||
add_fragments(docs, self.object_path, fragment_loader=fragment_loader)
|
||||
|
|
|
@ -25,6 +25,7 @@ import yaml
|
|||
import yaml.reader
|
||||
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
|
||||
|
||||
class AnsibleTextIOWrapper(TextIOWrapper):
|
||||
|
@ -114,3 +115,24 @@ def parse_yaml(value, lineno, module, name, load_all=False):
|
|||
})
|
||||
|
||||
return data, errors, traces
|
||||
|
||||
|
||||
def maybe_convert_bool(value):
|
||||
"""Safe conversion to boolean, catching TypeError and returning the original result
|
||||
|
||||
Only used in doc<->arg_spec comparisons
|
||||
"""
|
||||
try:
|
||||
return boolean(value)
|
||||
except TypeError:
|
||||
return value
|
||||
|
||||
|
||||
def compare_unordered_lists(a, b):
|
||||
"""Safe list comparisons
|
||||
|
||||
Supports:
|
||||
- unordered lists
|
||||
- unhashable elements
|
||||
"""
|
||||
return len(a) == len(b) and all(x in b for x in a)
|
||||
|
|
Loading…
Reference in a new issue