diff --git a/test/sanity/validate-modules/README.rst b/test/sanity/validate-modules/README.rst index 1c39c5b9cc5..b94173d28f2 100644 --- a/test/sanity/validate-modules/README.rst +++ b/test/sanity/validate-modules/README.rst @@ -19,53 +19,137 @@ Help .. code:: shell - usage: validate-modules [-h] [-w] [--exclude EXCLUDE] modules + usage: validate-modules [-h] [-w] [--exclude EXCLUDE] [--arg-spec] + [--base-branch BASE_BRANCH] [--format {json,plain}] + [--output OUTPUT] + modules [modules ...] positional arguments: - modules Path to module or module directory + modules Path to module or module directory optional arguments: - -h, --help show this help message and exit - -w, --warnings Show warnings - --exclude EXCLUDE RegEx exclusion pattern - -Current Validations -=================== - -Modules + -h, --help show this help message and exit + -w, --warnings Show warnings + --exclude EXCLUDE RegEx exclusion pattern + --arg-spec Analyze module argument spec + --base-branch BASE_BRANCH + Used in determining if new options were added + --format {json,plain} + Output format. Default: "plain" + --output OUTPUT Output location, use "-" for stdout. Default "-" + +Codes ~~~~~~~ Errors ^^^^^^ -#. Interpreter line is not ``#!/usr/bin/python`` -#. ``main()`` not at the bottom of the file -#. Module does not import ``ansible.module_utils.basic`` -#. Missing ``DOCUMENTATION`` -#. Documentation is invalid YAML -#. Invalid schema for ``DOCUMENTATION`` -#. Missing ``EXAMPLES`` -#. Invalid Python Syntax -#. Tabbed indentation -#. Use of ``sys.exit()`` instead of ``exit_json`` or ``fail_json`` -#. Missing GPLv3 license header in module -#. PowerShell module missing ``WANT_JSON`` -#. PowerShell module missing ``POWERSHELL_COMMON`` -#. New modules have the correct ``version_added`` -#. New arguments have the correct ``version_added`` -#. Modules should not import requests, instead use ``ansible.module_utils.urls`` -#. Missing ``RETURN`` for new modules -#. Use of ``type()`` for type comparison instead of ``isinstance()`` ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| code | sample message | ++=========+============================================================================================================================================+ +| **1xx** | **Locations** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 101 | Interpreter line is not ``#!/usr/bin/python`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 102 | Interpreter line is not ``#!powershell`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 103 | Did not find a call to ``main()`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 104 | Call to ``main()`` not the last line | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 105 | GPLv3 license header not found | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 106 | Import found before documentation variables. All imports must appear below ``DOCUMENTATION``/``EXAMPLES``/``RETURN``/``ANSIBLE_METADATA`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| **2xx** | **Imports** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 201 | Did not find a ``module_utils`` import | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 203 | ``requests`` import found, should use ``ansible.module_utils.urls`` instead | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 204 | ``boto`` import found, new modules should use ``boto3`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 205 | ``sys.exit()`` call found. Should be ``exit_json``/``fail_json`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 206 | ``WANT_JSON`` not found in module | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 207 | ``REPLACER_WINDOWS`` not found in module | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| **3xx** | **Documentation** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 301 | No ``DOCUMENTATION`` provided | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 302 | ``DOCUMENTATION`` is not valid YAML | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 303 | ``DOCUMENTATION`` fragment missing | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 304 | Unknown ``DOCUMENTATION`` error | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 305 | Invalid ``DOCUMENTATION`` schema | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 306 | Module level ``version_added`` is not a valid version number | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 307 | Module level ``version_added`` is incorrect | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 308 | ``version_added`` for new option is not a valid version number | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 309 | ``version_added`` for new option is incorrect | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 310 | No ``EXAMPLES`` provided | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 311 | ``EXAMPLES`` is not valid YAML | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 312 | No ``RETURN`` documentation provided | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 313 | ``RETURN`` is not valid YAML | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 314 | No ``ANSIBLE_METADATA`` provided | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 315 | ``ANSIBLE_METADATA`` is not valid YAML | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 316 | Invalid ``ANSIBLE_METADATA`` schema | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 317 | option is marked as required but specifies a default. Arguments with a default should not be marked as required | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| **4xx** | **Syntax** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 401 | Python ``SyntaxError`` while parsing module | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 402 | Indentation contains tabs | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 403 | Type comparison using ``type()`` found. Use ``isinstance()`` instead | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| **5xx** | **Naming** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 501 | Official Ansible modules must have a ``.py`` extension for python modules or a ``.ps1`` for powershell modules | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 502 | Ansible module subdirectories must contain an ``__init__.py`` | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 503 | Missing python documentation file | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ Warnings ^^^^^^^^ -#. Try/Except ``HAS_`` expression missing -#. Missing ``RETURN`` for existing modules -#. ``import json`` found -#. Module contains duplicate globals from basic.py - -Module Directories (Python Packages) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#. Missing ``__init__.py`` ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| code | sample message | ++=========+============================================================================================================================================+ +| **2xx** | **Imports** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 291 | Try/Except ``HAS_`` expression missing | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 292 | Did not find ``ansible.module_utils.basic`` import | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| **3xx** | **Documentation** | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 312 | No ``RETURN`` documentation provided for legacy module | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 391 | Unknown pre-existing ``DOCUMENTATION`` error | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ +| 392 | Pre-existing ``DOCUMENTATION`` fragment missing | ++---------+--------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/test/sanity/validate-modules/validate-modules b/test/sanity/validate-modules/validate-modules index e99f6656b31..2cc44e817ea 100755 --- a/test/sanity/validate-modules/validate-modules +++ b/test/sanity/validate-modules/validate-modules @@ -22,18 +22,20 @@ from __future__ import print_function import abc import argparse import ast +import json import os import re import subprocess import sys import tempfile +from collections import OrderedDict +from contextlib import contextmanager from distutils.version import StrictVersion from fnmatch import fnmatch from ansible import __version__ as ansible_version from ansible.executor.module_common import REPLACER_WINDOWS -from ansible.plugins import module_loader from ansible.utils.module_docs import BLACKLIST_MODULES, get_docstring from module_args import get_argument_spec @@ -50,16 +52,93 @@ TYPE_REGEX = re.compile(r'.*(if|or)(\s+[^"\']*|\s+)(?