diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b201462dd23..052a07058fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -598,3 +598,16 @@ repos: - -e - lint-tests-pre-commit - -- + + - repo: https://github.com/saltstack/salt-nox-pre-commit + rev: master + hooks: + - id: nox-py2 + alias: check-docs + name: Check Docs + files: ^(salt/.*\.py|doc/ref/.*\.rst)$ + args: + - -e + - invoke-pre-commit + - -- + - docs.check diff --git a/tasks/__init__.py b/tasks/__init__.py index 45e4eb3be5c..ce53de9faf8 100644 --- a/tasks/__init__.py +++ b/tasks/__init__.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- from invoke import Collection # pylint: disable=3rd-party-module-not-gated +from . import docs ns = Collection() +docs = Collection.from_module(docs, name="docs") +ns.add_collection(docs, name="docs") diff --git a/tasks/docs.py b/tasks/docs.py new file mode 100644 index 00000000000..5ef31cedf89 --- /dev/null +++ b/tasks/docs.py @@ -0,0 +1,459 @@ +# -*- coding: utf-8 -*- +""" + tasks.docstrings + ~~~~~~~~~~~~~~~~ + + Check salt code base for for missing or wrong docstrings +""" + +import ast +import collections +import os +import pathlib +import re + +from invoke import task # pylint: disable=3rd-party-module-not-gated +from tasks import utils + +CODE_DIR = pathlib.Path(__file__).resolve().parent.parent +DOCS_DIR = CODE_DIR / "doc" +SALT_CODE_DIR = CODE_DIR / "salt" + +os.chdir(str(CODE_DIR)) + +python_module_to_doc_path = {} +doc_path_to_python_module = {} + + +check_paths = ( + "salt/auth", + "salt/beacons", + "salt/cache", + "salt/cloud", + "salt/engine", + "salt/executors", + "salt/fileserver", + "salt/grains", + "salt/modules", + "salt/netapi", + "salt/output", + "salt/pillar", + "salt/proxy", + "salt/queues", + "salt/renderers", + "salt/returners", + "salt/roster", + "salt/runners", + "salt/sdb", + "salt/serializers", + "salt/states", + "salt/thorium", + "salt/tokens", + "salt/tops", + "salt/wheel", +) +exclude_paths = ( + "salt/cloud/cli.py", + "salt/cloud/exceptions.py", + "salt/cloud/libcloudfuncs.py", +) + + +def build_path_cache(): + """ + Build a python module to doc module cache + """ + + for path in SALT_CODE_DIR.rglob("*.py"): + path = path.resolve().relative_to(CODE_DIR) + strpath = str(path) + if strpath.endswith("__init__.py"): + continue + if not strpath.startswith(check_paths): + continue + if strpath.startswith(exclude_paths): + continue + + parts = list(path.parts) + stub_path = DOCS_DIR / "ref" + # Remove salt from parts + parts.pop(0) + # Remove the package from parts + package = parts.pop(0) + # Remove the module from parts + module = parts.pop() + + if package == "cloud": + package = "clouds" + if package == "fileserver": + package = "file_server" + if package == "netapi": + # These are handled differently + if not parts: + # This is rest_wsgi + stub_path = ( + stub_path + / package + / "all" + / str(path).replace(".py", ".rst").replace(os.sep, ".") + ) + else: + # rest_cherrypy, rest_tornado + subpackage = parts.pop(0) + stub_path = ( + stub_path + / package + / "all" + / "salt.netapi.{}.rst".format(subpackage) + ) + else: + stub_path = ( + stub_path + / package + / "all" + / str(path).replace(".py", ".rst").replace(os.sep, ".") + ) + stub_path = stub_path.relative_to(CODE_DIR) + python_module_to_doc_path[path] = stub_path + doc_path_to_python_module[stub_path] = path + + +build_path_cache() + + +def build_file_list(files, extension): + # Unfortunately invoke does not support nargs. + # We migth have been passed --files="foo.py bar.py" + # Turn that into a list of paths + _files = [] + for path in files: + if not path: + continue + for spath in path.split(): + if not spath.endswith(extension): + continue + _files.append(spath) + if not _files: + _files = CODE_DIR.rglob("*{}".format(extension)) + else: + _files = [pathlib.Path(fname) for fname in _files] + _files = [path.relative_to(CODE_DIR) for path in _files] + return _files + + +def build_python_module_paths(files): + _files = [] + for path in build_file_list(files, ".py"): + strpath = str(path) + if strpath.endswith("__init__.py"): + continue + if not strpath.startswith(check_paths): + continue + if strpath.startswith(exclude_paths): + continue + _files.append(path) + return _files + + +def build_docs_paths(files): + return build_file_list(files, ".rst") + + +@task(iterable=["files"], positional=["files"]) +def check_inline_markup(ctx, files): + """ + Check docstring for :doc: usage + + We should not be using the ``:doc:`` inline markup option when + cross-referencing locations. Use ``:ref:`` or ``:mod:`` instead. + + This task checks for reference to ``:doc:`` usage. + + See Issue #12788 for more information. + + https://github.com/saltstack/salt/issues/12788 + """ + # CD into Salt's repo root directory + ctx.cd(CODE_DIR) + + files = build_python_module_paths(files) + + exitcode = 0 + for path in files: + module = ast.parse(path.read_text(), filename=str(path)) + funcdefs = [node for node in module.body if isinstance(node, ast.FunctionDef)] + for funcdef in funcdefs: + docstring = ast.get_docstring(funcdef, clean=True) + if not docstring: + continue + if ":doc:" in docstring: + utils.error( + "The {} function in {} contains ':doc:' usage", funcdef.name, path + ) + exitcode += 1 + utils.exit_invoke(exitcode) + + +@task(iterable=["files"]) +def check_stubs(ctx, files): + # CD into Salt's repo root directory + ctx.cd(CODE_DIR) + + files = build_python_module_paths(files) + + exitcode = 0 + for path in files: + strpath = str(path) + if strpath.endswith("__init__.py"): + continue + if not strpath.startswith(check_paths): + continue + if strpath.startswith(exclude_paths): + continue + stub_path = python_module_to_doc_path[path] + if not stub_path.exists(): + exitcode += 1 + utils.error( + "The module at {} does not have a sphinx stub at {}", path, stub_path + ) + utils.exit_invoke(exitcode) + + +@task(iterable=["files"]) +def check_virtual(ctx, files): + """ + Check if .rst files for each module contains the text ".. _virtual" + indicating it is a virtual doc page, and, in case a module exists by + the same name, it's going to be shaddowed and not accessible + """ + exitcode = 0 + files = build_docs_paths(files) + for path in files: + if path.name == "index.rst": + continue + contents = path.read_text() + if ".. _virtual-" in contents: + try: + python_module = doc_path_to_python_module[path] + utils.error( + "The doc file at {} indicates that it's virtual, yet, there's a python module " + "at {} that will shaddow it.", + path, + python_module, + ) + exitcode += 1 + except KeyError: + # This is what we're expecting + continue + utils.exit_invoke(exitcode) + + +@task(iterable=["files"]) +def check_module_indexes(ctx, files): + exitcode = 0 + files = build_docs_paths(files) + for path in files: + if path.name != "index.rst": + continue + contents = path.read_text() + if ".. autosummary::" not in contents: + continue + module_index_block = re.search( + r""" + \.\.\s+autosummary::\s*\n + (\s+:[a-z]+:.*\n)* + (\s*\n)+ + (?P(\s*[a-z0-9_\.]+\s*\n)+) + """, + contents, + flags=re.VERBOSE, + ) + + if not module_index_block: + continue + + module_index = re.findall( + r"""\s*([a-z0-9_\.]+)\s*\n""", module_index_block.group("mods") + ) + if module_index != sorted(module_index): + exitcode += 1 + utils.error( + "The autosummary mods in {} are not properly sorted. Please sort them.", + path, + ) + + module_index_duplicates = [ + mod for mod, count in collections.Counter(module_index).items() if count > 1 + ] + if module_index_duplicates: + exitcode += 1 + utils.error( + "Module index {} contains duplicates: {}", path, module_index_duplicates + ) + # Let's check if all python modules are included in the index + path_parts = list(path.parts) + # drop doc + path_parts.pop(0) + # drop ref + path_parts.pop(0) + # drop "index.rst" + path_parts.pop() + # drop "all" + path_parts.pop() + package = path_parts.pop(0) + if package == "clouds": + package = "cloud" + if package == "file_server": + package = "fileserver" + if package == "configuration": + package = "log" + path_parts = ["handlers"] + python_package = SALT_CODE_DIR.joinpath(package, *path_parts).relative_to( + CODE_DIR + ) + modules = set() + for module in python_package.rglob("*.py"): + if package == "netapi": + if module.stem == "__init__": + continue + if len(module.parts) > 4: + continue + if len(module.parts) > 3: + modules.add(module.parent.stem) + else: + modules.add(module.stem) + elif package == "cloud": + if len(module.parts) < 4: + continue + if module.name == "__init__.py": + continue + modules.add(module.stem) + elif package == "modules": + if len(module.parts) > 3: + # salt.modules.inspeclib + if module.name == "__init__.py": + modules.add(module.parent.stem) + continue + modules.add("{}.{}".format(module.parent.stem, module.stem)) + continue + if module.name == "__init__.py": + continue + modules.add(module.stem) + elif module.name == "__init__.py": + continue + elif module.name != "__init__.py": + modules.add(module.stem) + + missing_modules_in_index = set(modules) - set(module_index) + if missing_modules_in_index: + exitcode += 1 + utils.error( + "The module index at {} is missing the following modules: {}", + path, + ", ".join(missing_modules_in_index), + ) + extra_modules_in_index = set(module_index) - set(modules) + if extra_modules_in_index: + exitcode += 1 + utils.error( + "The module index at {} has extra modules(non existing): {}", + path, + ", ".join(extra_modules_in_index), + ) + utils.exit_invoke(exitcode) + + +@task(iterable=["files"]) +def check_stray(ctx, files): + exitcode = 0 + exclude_paths = ( + DOCS_DIR / "_inc", + DOCS_DIR / "ref" / "cli" / "_includes", + DOCS_DIR / "ref" / "cli", + DOCS_DIR / "ref" / "configuration", + DOCS_DIR / "ref" / "file_server" / "backends.rst", + DOCS_DIR / "ref" / "file_server" / "environments.rst", + DOCS_DIR / "ref" / "file_server" / "file_roots.rst", + DOCS_DIR / "ref" / "internals", + DOCS_DIR / "ref" / "modules" / "all" / "salt.modules.inspectlib.rst", + DOCS_DIR / "ref" / "peer.rst", + DOCS_DIR / "ref" / "publisheracl.rst", + DOCS_DIR / "ref" / "python-api.rst", + DOCS_DIR / "ref" / "states" / "aggregate.rst", + DOCS_DIR / "ref" / "states" / "altering_states.rst", + DOCS_DIR / "ref" / "states" / "backup_mode.rst", + DOCS_DIR / "ref" / "states" / "compiler_ordering.rst", + DOCS_DIR / "ref" / "states" / "extend.rst", + DOCS_DIR / "ref" / "states" / "failhard.rst", + DOCS_DIR / "ref" / "states" / "global_state_arguments.rst", + DOCS_DIR / "ref" / "states" / "highstate.rst", + DOCS_DIR / "ref" / "states" / "include.rst", + DOCS_DIR / "ref" / "states" / "layers.rst", + DOCS_DIR / "ref" / "states" / "master_side.rst", + DOCS_DIR / "ref" / "states" / "ordering.rst", + DOCS_DIR / "ref" / "states" / "parallel.rst", + DOCS_DIR / "ref" / "states" / "providers.rst", + DOCS_DIR / "ref" / "states" / "requisites.rst", + DOCS_DIR / "ref" / "states" / "startup.rst", + DOCS_DIR / "ref" / "states" / "testing.rst", + DOCS_DIR / "ref" / "states" / "top.rst", + DOCS_DIR / "ref" / "states" / "vars.rst", + DOCS_DIR / "ref" / "states" / "writing.rst", + DOCS_DIR / "topics", + ) + exclude_paths = tuple([str(p.relative_to(CODE_DIR)) for p in exclude_paths]) + files = build_docs_paths(files) + for path in files: + if not str(path).startswith(str((DOCS_DIR / "ref").relative_to(CODE_DIR))): + continue + if str(path).startswith(exclude_paths): + continue + if path.name in ("index.rst", "glossary.rst", "faq.rst", "README.rst"): + continue + try: + python_module = doc_path_to_python_module[path] + except KeyError: + contents = path.read_text() + if ".. _virtual-" in contents: + continue + exitcode += 1 + utils.error( + "The doc at {} doesn't have a corresponding python module an is considered a stray " + "doc. Please remove it.", + path, + ) + utils.exit_invoke(exitcode) + + +@task(iterable=["files"]) +def check(ctx, files): + try: + utils.info("Checking inline :doc: markup") + check_inline_markup(ctx, files) + except SystemExit as exc: + if exc.code != 0: + raise + try: + utils.info("Checking python module stubs") + check_stubs(ctx, files) + except SystemExit as exc: + if exc.code != 0: + raise + try: + utils.info("Checking virtual modules") + check_virtual(ctx, files) + except SystemExit as exc: + if exc.code != 0: + raise + try: + utils.info("Checking doc module indexes") + check_module_indexes(ctx, files) + except SystemExit as exc: + if exc.code != 0: + raise + try: + utils.info("Checking stray docs") + check_stray(ctx, files) + except SystemExit as exc: + if exc.code != 0: + raise diff --git a/tasks/utils.py b/tasks/utils.py index 50cfa7f98e0..045f5fe9f05 100644 --- a/tasks/utils.py +++ b/tasks/utils.py @@ -2,6 +2,7 @@ """ tasks.utils ~~~~~~~~~~~ + Invoke utilities """ diff --git a/tests/unit/test_doc.py b/tests/unit/test_doc.py deleted file mode 100644 index 3905bcd7408..00000000000 --- a/tests/unit/test_doc.py +++ /dev/null @@ -1,601 +0,0 @@ -# -*- coding: utf-8 -*- -""" - tests.unit.doc_test - ~~~~~~~~~~~~~~~~~~~~ -""" - -# Import Python libs -from __future__ import absolute_import - -import collections -import logging -import os -import re - -# Import Salt libs -import salt.modules.cmdmod -import salt.utils.files -import salt.utils.platform -from tests.support.runtests import RUNTIME_VARS - -# Import Salt Testing libs -from tests.support.unit import TestCase, skipIf - -log = logging.getLogger(__name__) - - -class DocTestCase(TestCase): - """ - Unit test case for testing doc files and strings. - """ - - @skipIf(True, "SLOWTEST skip") - def test_check_for_doc_inline_markup(self): - """ - We should not be using the ``:doc:`` inline markup option when - cross-referencing locations. Use ``:ref:`` or ``:mod:`` instead. - - This test checks for reference to ``:doc:`` usage. - - See Issue #12788 for more information. - - https://github.com/saltstack/salt/issues/12788 - """ - salt_dir = RUNTIME_VARS.CODE_DIR - - if salt.utils.platform.is_windows(): - if salt.utils.path.which("bash"): - # Use grep from git-bash when it exists. - cmd = "bash -c 'grep -r :doc: ./salt/" - grep_call = salt.modules.cmdmod.run_stdout(cmd=cmd, cwd=salt_dir).split( - os.linesep - ) - os_sep = "/" - else: - # No grep in Windows, use findstr - # findstr in windows doesn't prepend 'Binary` to binary files, so - # use the '/P' switch to skip files with unprintable characters - cmd = 'findstr /C:":doc:" /S /P {0}\\*'.format(salt_dir) - grep_call = salt.modules.cmdmod.run_stdout(cmd=cmd).split(os.linesep) - os_sep = os.sep - else: - salt_dir += "/" - cmd = "grep -r :doc: " + salt_dir - grep_call = salt.modules.cmdmod.run_stdout(cmd=cmd).split(os.linesep) - os_sep = os.sep - - test_ret = {} - for line in grep_call: - # Skip any .pyc files that may be present - if line.startswith("Binary"): - continue - - # Only split on colons not followed by a '\' as is the case with - # Windows Drives - regex = re.compile(r":(?!\\)") - try: - key, val = regex.split(line, 1) - except ValueError: - log.error("Could not split line: %s", line) - continue - - # Don't test man pages, this file, the tox or nox virtualenv files, - # the page that documents to not use ":doc:", the doc/conf.py file - # or the artifacts directory on nox CI test runs - if ( - "man" in key - or ".tox{}".format(os_sep) in key - or ".nox{}".format(os_sep) in key - or "ext{}".format(os_sep) in key - or "artifacts{}".format(os_sep) in key - or key.endswith("test_doc.py") - or key.endswith(os_sep.join(["doc", "conf.py"])) - or key.endswith(os_sep.join(["conventions", "documentation.rst"])) - or key.endswith( - os_sep.join(["doc", "topics", "releases", "2016.11.2.rst"]) - ) - or key.endswith( - os_sep.join(["doc", "topics", "releases", "2016.11.3.rst"]) - ) - or key.endswith( - os_sep.join(["doc", "topics", "releases", "2016.3.5.rst"]) - ) - ): - continue - - # Set up test return dict - if test_ret.get(key) is None: - test_ret[key] = [val.strip()] - else: - test_ret[key].append(val.strip()) - - # Allow test results to show files with :doc: ref, rather than truncating - self.maxDiff = None - - # test_ret should be empty, otherwise there are :doc: references present - self.assertEqual(test_ret, {}) - - def _check_doc_files(self, module_skip, module_dir, doc_skip, module_doc_dir): - """ - Ensure various salt modules have associated documentation - """ - - salt_dir = RUNTIME_VARS.CODE_DIR - - # Build list of module files - module_files = [] - skip_module_files = module_skip - full_module_dir = os.path.join(salt_dir, *module_dir) - for file in os.listdir(full_module_dir): - if file.endswith(".py"): - module_name = os.path.splitext(file)[0] - if module_name not in skip_module_files: - module_files.append(module_name) - # Capture modules in subdirectories like inspectlib and rest_cherrypy - elif ( - os.path.isdir(os.path.join(full_module_dir, file)) - and not file.startswith("_") - and os.path.isfile(os.path.join(full_module_dir, file, "__init__.py")) - ): - module_name = file - if module_name not in skip_module_files: - module_files.append(module_name) - - # Build list of documentation files - module_docs = [] - skip_doc_files = doc_skip - full_module_doc_dir = os.path.join(salt_dir, *module_doc_dir) - doc_prefix = ".".join(module_dir) + "." - for file in os.listdir(full_module_doc_dir): - if file.endswith(".rst"): - doc_name = os.path.splitext(file)[0] - if doc_name.startswith(doc_prefix): - doc_name = doc_name[len(doc_prefix) :] - if doc_name not in skip_doc_files: - module_docs.append(doc_name) - - module_index_file = os.path.join(full_module_doc_dir, "index.rst") - with salt.utils.files.fopen(module_index_file, "rb") as fp: - module_index_contents = fp.read().decode("utf-8") - - module_index_block = re.search( - r""" - \.\.\s+autosummary::\s*\n - (\s+:[a-z]+:.*\n)* - (\s*\n)+ - (?P(\s*[a-z0-9_\.]+\s*\n)+) - """, - module_index_contents, - flags=re.VERBOSE, - ) - - module_index = re.findall( - r"""\s*([a-z0-9_\.]+)\s*\n""", module_index_block.group("mods") - ) - - # Check that every module has associated documentation file - for module in module_files: - self.assertIn( - module, - module_docs, - "module file {0} is missing documentation in {1}".format( - module, full_module_doc_dir - ), - ) - - # Check that every module is listed in the index file - self.assertIn( - module, - module_index, - "module file {0} is missing in {1}".format(module, module_index_file), - ) - - # Check if .rst file for this module contains the text - # ".. _virtual" indicating it is a virtual doc page - full_module_doc_name = os.path.join( - full_module_doc_dir, doc_prefix + module + ".rst" - ) - with salt.utils.files.fopen(full_module_doc_name) as rst_file: - rst_text = rst_file.read() - virtual_string = 'module file "{0}" is also a virtual doc page {1} and is not accessible' - self.assertNotIn( - ".. _virtual", - rst_text, - virtual_string.format(module, doc_prefix + module + ".rst"), - ) - - for doc_file in module_docs: - self.assertIn( - doc_file, - module_files, - "Doc file {0} is missing associated module in {1}".format( - doc_file, full_module_dir - ), - ) - # Check that a module index is sorted - sorted_module_index = sorted(module_index) - self.assertEqual( - module_index, - sorted_module_index, - msg="Module index is not sorted: {}".format(module_index_file), - ) - - # Check for duplicates inside of a module index - module_index_duplicates = [ - mod for mod, count in collections.Counter(module_index).items() if count > 1 - ] - if module_index_duplicates: - self.fail( - "Module index {0} contains duplicates: {1}".format( - module_index_file, module_index_duplicates - ) - ) - - # Check for stray module docs - # Do not check files listed in doc_skip - stray_modules = set(module_index).difference(module_files + doc_skip) - if stray_modules: - self.fail( - "Stray module names {0} in the doc index {1}".format( - sorted(list(stray_modules)), module_index_file - ) - ) - stray_modules = set(module_docs).difference(module_files) - if stray_modules: - self.fail( - "Stray module doc files {0} in the doc folder {1}".format( - sorted(list(stray_modules)), full_module_doc_dir - ) - ) - - def test_auth_doc_files(self): - """ - Ensure auth modules have associated documentation - - doc example: doc/ref/auth/all/salt.auth.rest.rst - auth module example: salt/auth/rest.py - """ - - skip_files = ["__init__"] - module_dir = ["salt", "auth"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "auth", "all"] - self._check_doc_files(skip_files, module_dir, skip_doc_files, doc_dir) - - def test_beacon_doc_files(self): - """ - Ensure beacon modules have associated documentation - - doc example: doc/ref/beacons/all/salt.beacon.rest.rst - beacon module example: salt/beacons/rest.py - """ - - skip_files = ["__init__"] - module_dir = ["salt", "beacons"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "beacons", "all"] - self._check_doc_files(skip_files, module_dir, skip_doc_files, doc_dir) - - def test_cache_doc_files(self): - """ - Ensure cache modules have associated documentation - - doc example: doc/ref/cache/all/salt.cache.consul.rst - cache module example: salt/cache/consul.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "cache"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "cache", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_cloud_doc_files(self): - """ - Ensure cloud modules have associated documentation - - doc example: doc/ref/clouds/all/salt.cloud.gce.rst - cloud module example: salt/cloud/clouds/gce.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "cloud", "clouds"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "clouds", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_engine_doc_files(self): - """ - Ensure engine modules have associated documentation - - doc example: doc/ref/engines/all/salt.engines.docker_events.rst - engine module example: salt/engines/docker_events.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "engines"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "engines", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_executors_doc_files(self): - """ - Ensure executor modules have associated documentation - - doc example: doc/ref/executors/all/salt.executors.docker.rst - engine module example: salt/executors/docker.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "executors"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "executors", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_fileserver_doc_files(self): - """ - Ensure fileserver modules have associated documentation - - doc example: doc/ref/fileserver/all/salt.fileserver.gitfs.rst - module example: salt/fileserver/gitfs.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "fileserver"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "file_server", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_grain_doc_files(self): - """ - Ensure grain modules have associated documentation - - doc example: doc/ref/grains/all/salt.grains.core.rst - module example: salt/grains/core.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "grains"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "grains", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_module_doc_files(self): - """ - Ensure modules have associated documentation - - doc example: doc/ref/modules/all/salt.modules.zabbix.rst - execution module example: salt/modules/zabbix.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "modules"] - skip_doc_files = [ - "index", - "group", - "inspectlib.collector", - "inspectlib.dbhandle", - "inspectlib.entities", - "inspectlib.exceptions", - "inspectlib.fsdb", - "inspectlib.kiwiproc", - "inspectlib.query", - "kernelpkg", - "pkg", - "user", - "service", - "shadow", - "sysctl", - ] - doc_dir = ["doc", "ref", "modules", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_netapi_doc_files(self): - """ - Ensure netapi modules have associated documentation - - doc example: doc/ref/netapi/all/salt.netapi.rest_cherrypy.rst - module example: salt/netapi/rest_cherrypy - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "netapi"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "netapi", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_output_doc_files(self): - """ - Ensure output modules have associated documentation - - doc example: doc/ref/output/all/salt.output.highstate.rst - module example: salt/output/highstate.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "output"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "output", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_pillar_doc_files(self): - """ - Ensure pillar modules have associated documentation - - doc example: doc/ref/pillar/all/salt.pillar.cobbler.rst - module example: salt/pillar/cobbler.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "pillar"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "pillar", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_proxy_doc_files(self): - """ - Ensure proxy modules have associated documentation - - doc example: doc/ref/proxy/all/salt.proxy.docker.rst - module example: salt/proxy/docker.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "proxy"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "proxy", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_queues_doc_files(self): - """ - Ensure queue modules have associated documentation - - doc example: doc/ref/queues/all/salt.queues.sqlite_queue.rst - module example: salt/queues/sqlite_queue.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "queues"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "queues", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_renderers_doc_files(self): - """ - Ensure render modules have associated documentation - - doc example: doc/ref/renderers/all/salt.renderers.json.rst - module example: salt/renderers/json.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "renderers"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "renderers", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_returners_doc_files(self): - """ - Ensure return modules have associated documentation - - doc example: doc/ref/returners/all/salt.returners.cassandra_return.rst - module example: salt/returners/cassandra_return.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "returners"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "returners", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_runners_doc_files(self): - """ - Ensure runner modules have associated documentation - - doc example: doc/ref/runners/all/salt.runners.auth.rst - module example: salt/runners/auth.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "runners"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "runners", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_sdb_doc_files(self): - """ - Ensure sdb modules have associated documentation - - doc example: doc/ref/sdb/all/salt.sdb.rest.rst - module example: salt/sdb/rest.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "sdb"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "sdb", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_serializers_doc_files(self): - """ - Ensure serializer modules have associated documentation - - doc example: doc/ref/serializers/all/salt.serializers.yaml.rst - module example: salt/serializers/yaml.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "serializers"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "serializers", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_states_doc_files(self): - """ - Ensure states have associated documentation - - doc example: doc/ref/states/all/salt.states.zabbix_host.rst - module example: salt/states/zabbix_host.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "states"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "states", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_thorium_doc_files(self): - """ - Ensure thorium modules have associated documentation - - doc example: doc/ref/thorium/all/salt.thorium.calc.rst - module example: salt/thorium/calc.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "thorium"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "thorium", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_token_doc_files(self): - """ - Ensure token modules have associated documentation - - doc example: doc/ref/tokens/all/salt.tokens.localfs.rst - module example: salt/tokens/localfs.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "tokens"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "tokens", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_tops_doc_files(self): - """ - Ensure top modules have associated documentation - - doc example: doc/ref/tops/all/salt.tops.saltclass.rst - module example: salt/tops/saltclass.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "tops"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "tops", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir) - - def test_wheel_doc_files(self): - """ - Ensure wheel modules have associated documentation - - doc example: doc/ref/wheel/all/salt.wheel.key.rst - module example: salt/wheel/key.py - """ - - skip_module_files = ["__init__"] - module_dir = ["salt", "wheel"] - skip_doc_files = ["index", "all"] - doc_dir = ["doc", "ref", "wheel", "all"] - self._check_doc_files(skip_module_files, module_dir, skip_doc_files, doc_dir)