summaryrefslogtreecommitdiffstats
path: root/test/sanity
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-14 20:03:01 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-14 20:03:01 +0000
commita453ac31f3428614cceb99027f8efbdb9258a40b (patch)
treef61f87408f32a8511cbd91799f9cececb53e0374 /test/sanity
parentInitial commit. (diff)
downloadansible-a453ac31f3428614cceb99027f8efbdb9258a40b.tar.xz
ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.zip
Adding upstream version 2.10.7+merged+base+2.10.8+dfsg.upstream/2.10.7+merged+base+2.10.8+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/sanity')
-rw-r--r--test/sanity/code-smell/configure-remoting-ps1.json4
-rwxr-xr-xtest/sanity/code-smell/configure-remoting-ps1.py54
-rw-r--r--test/sanity/code-smell/deprecated-config.json10
-rwxr-xr-xtest/sanity/code-smell/deprecated-config.py102
-rw-r--r--test/sanity/code-smell/deprecated-config.requirements.txt2
-rw-r--r--test/sanity/code-smell/docs-build.json6
-rwxr-xr-xtest/sanity/code-smell/docs-build.py155
-rw-r--r--test/sanity/code-smell/docs-build.requirements.txt6
-rw-r--r--test/sanity/code-smell/no-unwanted-files.json7
-rwxr-xr-xtest/sanity/code-smell/no-unwanted-files.py47
-rw-r--r--test/sanity/code-smell/obsolete-files.json17
-rwxr-xr-xtest/sanity/code-smell/obsolete-files.py19
-rw-r--r--test/sanity/code-smell/package-data.json6
-rwxr-xr-xtest/sanity/code-smell/package-data.py379
-rw-r--r--test/sanity/code-smell/package-data.requirements.txt10
-rw-r--r--test/sanity/code-smell/release-names.json4
-rwxr-xr-xtest/sanity/code-smell/release-names.py50
-rw-r--r--test/sanity/code-smell/release-names.requirements.txt1
-rw-r--r--test/sanity/code-smell/required-and-default-attributes.json9
-rwxr-xr-xtest/sanity/code-smell/required-and-default-attributes.py21
-rw-r--r--test/sanity/code-smell/skip.txt2
-rw-r--r--test/sanity/code-smell/test-constraints.json9
-rwxr-xr-xtest/sanity/code-smell/test-constraints.py21
-rw-r--r--test/sanity/code-smell/update-bundled.json8
-rwxr-xr-xtest/sanity/code-smell/update-bundled.py165
-rw-r--r--test/sanity/code-smell/update-bundled.requirements.txt1
-rw-r--r--test/sanity/ignore.txt427
27 files changed, 1542 insertions, 0 deletions
diff --git a/test/sanity/code-smell/configure-remoting-ps1.json b/test/sanity/code-smell/configure-remoting-ps1.json
new file mode 100644
index 00000000..593b765d
--- /dev/null
+++ b/test/sanity/code-smell/configure-remoting-ps1.json
@@ -0,0 +1,4 @@
+{
+ "no_targets": true,
+ "output": "path-message"
+}
diff --git a/test/sanity/code-smell/configure-remoting-ps1.py b/test/sanity/code-smell/configure-remoting-ps1.py
new file mode 100755
index 00000000..51dff20c
--- /dev/null
+++ b/test/sanity/code-smell/configure-remoting-ps1.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+
+
+def main():
+ # required by external automated processes and should not be moved, renamed or converted to a symbolic link
+ original = 'examples/scripts/ConfigureRemotingForAnsible.ps1'
+ # required to be packaged with ansible-test and must match the original file, but cannot be a symbolic link
+ # the packaged version is needed to run tests when ansible-test has been installed
+ # keeping the packaged version identical to the original makes sure tests cover both files
+ packaged = 'test/lib/ansible_test/_data/setup/ConfigureRemotingForAnsible.ps1'
+
+ copy_valid = False
+
+ if os.path.isfile(original) and os.path.isfile(packaged):
+ with open(original, 'rb') as original_file:
+ original_content = original_file.read()
+
+ with open(packaged, 'rb') as packaged_file:
+ packaged_content = packaged_file.read()
+
+ if original_content == packaged_content:
+ copy_valid = True
+
+ if not copy_valid:
+ print('%s: must be an exact copy of "%s"' % (packaged, original))
+
+ for path in [original, packaged]:
+ directory = path
+
+ while True:
+ directory = os.path.dirname(directory)
+
+ if not directory:
+ break
+
+ if not os.path.isdir(directory):
+ print('%s: must be a directory' % directory)
+
+ if os.path.islink(directory):
+ print('%s: cannot be a symbolic link' % directory)
+
+ if not os.path.isfile(path):
+ print('%s: must be a file' % path)
+
+ if os.path.islink(path):
+ print('%s: cannot be a symbolic link' % path)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/deprecated-config.json b/test/sanity/code-smell/deprecated-config.json
new file mode 100644
index 00000000..4a884860
--- /dev/null
+++ b/test/sanity/code-smell/deprecated-config.json
@@ -0,0 +1,10 @@
+{
+ "all_targets": true,
+ "output": "path-message",
+ "extensions": [
+ ".py"
+ ],
+ "prefixes": [
+ "lib/ansible/"
+ ]
+}
diff --git a/test/sanity/code-smell/deprecated-config.py b/test/sanity/code-smell/deprecated-config.py
new file mode 100755
index 00000000..08e93c36
--- /dev/null
+++ b/test/sanity/code-smell/deprecated-config.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# (c) 2018, Matt Martz <matt@sivel.net>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import mmap
+import os
+import re
+import sys
+
+from distutils.version import StrictVersion
+
+import yaml
+
+import ansible.config
+
+from ansible.plugins.loader import fragment_loader
+from ansible.release import __version__ as ansible_version
+from ansible.utils.plugin_docs import get_docstring
+
+DOC_RE = re.compile(b'^DOCUMENTATION', flags=re.M)
+ANSIBLE_MAJOR = StrictVersion('.'.join(ansible_version.split('.')[:2]))
+
+
+def find_deprecations(obj, path=None):
+ if not isinstance(obj, (list, dict)):
+ return
+
+ try:
+ items = obj.items()
+ except AttributeError:
+ items = enumerate(obj)
+
+ for key, value in items:
+ if path is None:
+ this_path = []
+ else:
+ this_path = path[:]
+
+ this_path.append(key)
+
+ if key != 'deprecated':
+ for result in find_deprecations(value, path=this_path):
+ yield result
+ else:
+ try:
+ version = value['version']
+ this_path.append('version')
+ except KeyError:
+ version = value['removed_in']
+ this_path.append('removed_in')
+ if StrictVersion(version) <= ANSIBLE_MAJOR:
+ yield (this_path, version)
+
+
+def main():
+ plugins = []
+ for path in sys.argv[1:] or sys.stdin.read().splitlines():
+ with open(path, 'rb') as f:
+ try:
+ mm_file = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
+ except ValueError:
+ continue
+ if DOC_RE.search(mm_file):
+ plugins.append(path)
+ mm_file.close()
+
+ for plugin in plugins:
+ data = {}
+ data['doc'], data['examples'], data['return'], data['metadata'] = get_docstring(plugin, fragment_loader)
+ for result in find_deprecations(data['doc']):
+ print(
+ '%s: %s is scheduled for removal in %s' % (plugin, '.'.join(str(i) for i in result[0][:-2]), result[1])
+ )
+
+ base = os.path.join(os.path.dirname(ansible.config.__file__), 'base.yml')
+ with open(base) as f:
+ data = yaml.safe_load(f)
+
+ for result in find_deprecations(data):
+ print('%s: %s is scheduled for removal in %s' % (base, '.'.join(str(i) for i in result[0][:-2]), result[1]))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/deprecated-config.requirements.txt b/test/sanity/code-smell/deprecated-config.requirements.txt
new file mode 100644
index 00000000..cfefdeec
--- /dev/null
+++ b/test/sanity/code-smell/deprecated-config.requirements.txt
@@ -0,0 +1,2 @@
+jinja2 # ansible-base requirement
+pyyaml
diff --git a/test/sanity/code-smell/docs-build.json b/test/sanity/code-smell/docs-build.json
new file mode 100644
index 00000000..0218bfc5
--- /dev/null
+++ b/test/sanity/code-smell/docs-build.json
@@ -0,0 +1,6 @@
+{
+ "intercept": true,
+ "disabled": true,
+ "no_targets": true,
+ "output": "path-line-column-message"
+}
diff --git a/test/sanity/code-smell/docs-build.py b/test/sanity/code-smell/docs-build.py
new file mode 100755
index 00000000..80eca15f
--- /dev/null
+++ b/test/sanity/code-smell/docs-build.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+def main():
+ base_dir = os.getcwd() + os.path.sep
+ docs_dir = os.path.abspath('docs/docsite')
+
+ # TODO: Remove this temporary hack to constrain 'cryptography' when we have
+ # a better story for dealing with it.
+ tmpfd, tmp = tempfile.mkstemp()
+ requirements_txt = os.path.join(base_dir, 'requirements.txt')
+ shutil.copy2(requirements_txt, tmp)
+ lines = []
+ with open(requirements_txt, 'r') as f:
+ for line in f.readlines():
+ if line.strip() == 'cryptography':
+ line = 'cryptography < 3.4\n'
+ lines.append(line)
+
+ with open(requirements_txt, 'w') as f:
+ f.writelines(lines)
+
+ try:
+ cmd = ['make', 'core_singlehtmldocs']
+ sphinx = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=docs_dir)
+ stdout, stderr = sphinx.communicate()
+ finally:
+ shutil.move(tmp, requirements_txt)
+
+ stdout = stdout.decode('utf-8')
+ stderr = stderr.decode('utf-8')
+
+ if sphinx.returncode != 0:
+ sys.stderr.write("Command '%s' failed with status code: %d\n" % (' '.join(cmd), sphinx.returncode))
+
+ if stdout.strip():
+ stdout = simplify_stdout(stdout)
+
+ sys.stderr.write("--> Standard Output\n")
+ sys.stderr.write("%s\n" % stdout.strip())
+
+ if stderr.strip():
+ sys.stderr.write("--> Standard Error\n")
+ sys.stderr.write("%s\n" % stderr.strip())
+
+ sys.exit(1)
+
+ with open('docs/docsite/rst_warnings', 'r') as warnings_fd:
+ output = warnings_fd.read().strip()
+ lines = output.splitlines()
+
+ known_warnings = {
+ 'block-quote-missing-blank-line': r'^Block quote ends without a blank line; unexpected unindent.$',
+ 'literal-block-lex-error': r'^Could not lex literal_block as "[^"]*". Highlighting skipped.$',
+ 'duplicate-label': r'^duplicate label ',
+ 'undefined-label': r'undefined label: ',
+ 'unknown-document': r'unknown document: ',
+ 'toc-tree-missing-document': r'toctree contains reference to nonexisting document ',
+ 'reference-target-not-found': r'[^ ]* reference target not found: ',
+ 'not-in-toc-tree': r"document isn't included in any toctree$",
+ 'unexpected-indentation': r'^Unexpected indentation.$',
+ 'definition-list-missing-blank-line': r'^Definition list ends without a blank line; unexpected unindent.$',
+ 'explicit-markup-missing-blank-line': r'Explicit markup ends without a blank line; unexpected unindent.$',
+ 'toc-tree-glob-pattern-no-match': r"^toctree glob pattern '[^']*' didn't match any documents$",
+ 'unknown-interpreted-text-role': '^Unknown interpreted text role "[^"]*".$',
+ }
+
+ for line in lines:
+ match = re.search('^(?P<path>[^:]+):((?P<line>[0-9]+):)?((?P<column>[0-9]+):)? (?P<level>WARNING|ERROR): (?P<message>.*)$', line)
+
+ if not match:
+ path = 'docs/docsite/rst/index.rst'
+ lineno = 0
+ column = 0
+ code = 'unknown'
+ message = line
+
+ # surface unknown lines while filtering out known lines to avoid excessive output
+ print('%s:%d:%d: %s: %s' % (path, lineno, column, code, message))
+ continue
+
+ path = match.group('path')
+ lineno = int(match.group('line') or 0)
+ column = int(match.group('column') or 0)
+ level = match.group('level').lower()
+ message = match.group('message')
+
+ path = os.path.abspath(path)
+
+ if path.startswith(base_dir):
+ path = path[len(base_dir):]
+
+ if path.startswith('rst/'):
+ path = 'docs/docsite/' + path # fix up paths reported relative to `docs/docsite/`
+
+ if level == 'warning':
+ code = 'warning'
+
+ for label, pattern in known_warnings.items():
+ if re.search(pattern, message):
+ code = label
+ break
+ else:
+ code = 'error'
+
+ print('%s:%d:%d: %s: %s' % (path, lineno, column, code, message))
+
+
+def simplify_stdout(value):
+ """Simplify output by omitting earlier 'rendering: ...' messages."""
+ lines = value.strip().splitlines()
+
+ rendering = []
+ keep = []
+
+ def truncate_rendering():
+ """Keep last rendering line (if any) with a message about omitted lines as needed."""
+ if not rendering:
+ return
+
+ notice = rendering[-1]
+
+ if len(rendering) > 1:
+ notice += ' (%d previous rendering line(s) omitted)' % (len(rendering) - 1)
+
+ keep.append(notice)
+ # Could change to rendering.clear() if we do not support python2
+ rendering[:] = []
+
+ for line in lines:
+ if line.startswith('rendering: '):
+ rendering.append(line)
+ continue
+
+ truncate_rendering()
+ keep.append(line)
+
+ truncate_rendering()
+
+ result = '\n'.join(keep)
+
+ return result
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/docs-build.requirements.txt b/test/sanity/code-smell/docs-build.requirements.txt
new file mode 100644
index 00000000..5e458795
--- /dev/null
+++ b/test/sanity/code-smell/docs-build.requirements.txt
@@ -0,0 +1,6 @@
+jinja2
+pyyaml
+sphinx
+sphinx-notfound-page
+straight.plugin
+antsibull
diff --git a/test/sanity/code-smell/no-unwanted-files.json b/test/sanity/code-smell/no-unwanted-files.json
new file mode 100644
index 00000000..7a89ebbe
--- /dev/null
+++ b/test/sanity/code-smell/no-unwanted-files.json
@@ -0,0 +1,7 @@
+{
+ "include_symlinks": true,
+ "prefixes": [
+ "lib/"
+ ],
+ "output": "path-message"
+}
diff --git a/test/sanity/code-smell/no-unwanted-files.py b/test/sanity/code-smell/no-unwanted-files.py
new file mode 100755
index 00000000..bff09152
--- /dev/null
+++ b/test/sanity/code-smell/no-unwanted-files.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+"""Prevent unwanted files from being added to the source tree."""
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import sys
+
+
+def main():
+ """Main entry point."""
+ paths = sys.argv[1:] or sys.stdin.read().splitlines()
+
+ allowed_extensions = (
+ '.cs',
+ '.ps1',
+ '.psm1',
+ '.py',
+ )
+
+ skip_paths = set([
+ 'lib/ansible/config/ansible_builtin_runtime.yml', # not included in the sanity ignore file since it won't exist until after migration
+ ])
+
+ skip_directories = (
+ 'lib/ansible/galaxy/data/',
+ )
+
+ for path in paths:
+ if path in skip_paths:
+ continue
+
+ if any(path.startswith(skip_directory) for skip_directory in skip_directories):
+ continue
+
+ if path.startswith('lib/') and not path.startswith('lib/ansible/'):
+ print('%s: all "lib" content must reside in the "lib/ansible" directory' % path)
+ continue
+
+ ext = os.path.splitext(path)[1]
+
+ if ext not in allowed_extensions:
+ print('%s: extension must be one of: %s' % (path, ', '.join(allowed_extensions)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/obsolete-files.json b/test/sanity/code-smell/obsolete-files.json
new file mode 100644
index 00000000..02d39204
--- /dev/null
+++ b/test/sanity/code-smell/obsolete-files.json
@@ -0,0 +1,17 @@
+{
+ "include_symlinks": true,
+ "prefixes": [
+ "test/runner/",
+ "test/sanity/ansible-doc/",
+ "test/sanity/compile/",
+ "test/sanity/import/",
+ "test/sanity/pep8/",
+ "test/sanity/pslint/",
+ "test/sanity/pylint/",
+ "test/sanity/rstcheck/",
+ "test/sanity/shellcheck/",
+ "test/sanity/validate-modules/",
+ "test/sanity/yamllint/"
+ ],
+ "output": "path-message"
+}
diff --git a/test/sanity/code-smell/obsolete-files.py b/test/sanity/code-smell/obsolete-files.py
new file mode 100755
index 00000000..e9ddc8a5
--- /dev/null
+++ b/test/sanity/code-smell/obsolete-files.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"""Prevent files from being added to directories that are now obsolete."""
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import sys
+
+
+def main():
+ """Main entry point."""
+ paths = sys.argv[1:] or sys.stdin.read().splitlines()
+
+ for path in paths:
+ print('%s: directory "%s/" is obsolete and should not contain any files' % (path, os.path.dirname(path)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/package-data.json b/test/sanity/code-smell/package-data.json
new file mode 100644
index 00000000..2b8a5326
--- /dev/null
+++ b/test/sanity/code-smell/package-data.json
@@ -0,0 +1,6 @@
+{
+ "intercept": true,
+ "disabled": true,
+ "all_targets": true,
+ "output": "path-message"
+}
diff --git a/test/sanity/code-smell/package-data.py b/test/sanity/code-smell/package-data.py
new file mode 100755
index 00000000..ca5f5ef5
--- /dev/null
+++ b/test/sanity/code-smell/package-data.py
@@ -0,0 +1,379 @@
+#!/usr/bin/env python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import contextlib
+import fnmatch
+import glob
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+
+
+def assemble_files_to_ship(complete_file_list):
+ """
+ This looks for all files which should be shipped in the sdist
+ """
+ # All files which are in the repository except these:
+ ignore_patterns = (
+ # Developer-only tools
+ '.azure-pipelines/*',
+ '.github/*',
+ '.github/*/*',
+ 'changelogs/fragments/*',
+ 'hacking/backport/*',
+ 'hacking/shippable/*',
+ 'hacking/tests/*',
+ 'hacking/ticket_stubs/*',
+ 'test/sanity/code-smell/botmeta.*',
+ 'test/utils/*',
+ 'test/utils/*/*',
+ 'test/utils/*/*/*',
+ '.git*',
+ )
+ ignore_files = frozenset((
+ # Developer-only tools
+ 'changelogs/config.yaml',
+ 'hacking/README.md',
+ 'hacking/ansible-profile',
+ 'hacking/cgroup_perf_recap_graph.py',
+ 'hacking/create_deprecated_issues.py',
+ 'hacking/deprecated_issue_template.md',
+ 'hacking/fix_test_syntax.py',
+ 'hacking/get_library.py',
+ 'hacking/metadata-tool.py',
+ 'hacking/report.py',
+ 'hacking/return_skeleton_generator.py',
+ 'hacking/test-module',
+ 'hacking/test-module.py',
+ 'test/support/README.md',
+ '.cherry_picker.toml',
+ '.mailmap',
+ # Generated as part of a build step
+ 'docs/docsite/rst/conf.py',
+ 'docs/docsite/rst/index.rst',
+ # Possibly should be included
+ 'examples/scripts/uptime.py',
+ 'examples/scripts/my_test.py',
+ 'examples/scripts/my_test_info.py',
+ 'examples/scripts/my_test_facts.py',
+ 'examples/DOCUMENTATION.yml',
+ 'examples/play.yml',
+ 'examples/hosts.yaml',
+ 'examples/hosts.yml',
+ 'examples/inventory_script_schema.json',
+ 'examples/plugin_filters.yml',
+ 'hacking/env-setup',
+ 'hacking/env-setup.fish',
+ 'MANIFEST',
+ ))
+
+ # These files are generated and then intentionally added to the sdist
+
+ # Manpages
+ manpages = ['docs/man/man1/ansible.1']
+ for dirname, dummy, files in os.walk('bin'):
+ for filename in files:
+ path = os.path.join(dirname, filename)
+ if os.path.islink(path):
+ if os.readlink(path) == 'ansible':
+ manpages.append('docs/man/man1/%s.1' % filename)
+
+ # Misc
+ misc_generated_files = [
+ 'SYMLINK_CACHE.json',
+ 'PKG-INFO',
+ ]
+
+ shipped_files = manpages + misc_generated_files
+
+ for path in complete_file_list:
+ if path not in ignore_files:
+ for ignore in ignore_patterns:
+ if fnmatch.fnmatch(path, ignore):
+ break
+ else:
+ shipped_files.append(path)
+
+ return shipped_files
+
+
+def assemble_files_to_install(complete_file_list):
+ """
+ This looks for all of the files which should show up in an installation of ansible
+ """
+ ignore_patterns = tuple()
+
+ pkg_data_files = []
+ for path in complete_file_list:
+
+ if path.startswith("lib/ansible"):
+ prefix = 'lib'
+ elif path.startswith("test/lib/ansible_test"):
+ prefix = 'test/lib'
+ else:
+ continue
+
+ for ignore in ignore_patterns:
+ if fnmatch.fnmatch(path, ignore):
+ break
+ else:
+ pkg_data_files.append(os.path.relpath(path, prefix))
+
+ return pkg_data_files
+
+
+@contextlib.contextmanager
+def clean_repository(file_list):
+ """Copy the repository to clean it of artifacts"""
+ # Create a tempdir that will be the clean repo
+ with tempfile.TemporaryDirectory() as repo_root:
+ directories = set((repo_root + os.path.sep,))
+
+ for filename in file_list:
+ # Determine if we need to create the directory
+ directory = os.path.dirname(filename)
+ dest_dir = os.path.join(repo_root, directory)
+ if dest_dir not in directories:
+ os.makedirs(dest_dir)
+
+ # Keep track of all the directories that now exist
+ path_components = directory.split(os.path.sep)
+ path = repo_root
+ for component in path_components:
+ path = os.path.join(path, component)
+ if path not in directories:
+ directories.add(path)
+
+ # Copy the file
+ shutil.copy2(filename, dest_dir, follow_symlinks=False)
+
+ yield repo_root
+
+
+def create_sdist(tmp_dir):
+ """Create an sdist in the repository"""
+ create = subprocess.Popen(
+ ['make', 'snapshot', 'SDIST_DIR=%s' % tmp_dir],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
+
+ stderr = create.communicate()[1]
+
+ if create.returncode != 0:
+ raise Exception('make snapshot failed:\n%s' % stderr)
+
+ # Determine path to sdist
+ tmp_dir_files = os.listdir(tmp_dir)
+
+ if not tmp_dir_files:
+ raise Exception('sdist was not created in the temp dir')
+ elif len(tmp_dir_files) > 1:
+ raise Exception('Unexpected extra files in the temp dir')
+
+ return os.path.join(tmp_dir, tmp_dir_files[0])
+
+
+def extract_sdist(sdist_path, tmp_dir):
+ """Untar the sdist"""
+ # Untar the sdist from the tmp_dir
+ with tarfile.open(os.path.join(tmp_dir, sdist_path), 'r|*') as sdist:
+ sdist.extractall(path=tmp_dir)
+
+ # Determine the sdist directory name
+ sdist_filename = os.path.basename(sdist_path)
+ tmp_dir_files = os.listdir(tmp_dir)
+ try:
+ tmp_dir_files.remove(sdist_filename)
+ except ValueError:
+ # Unexpected could not find original sdist in temp dir
+ raise
+
+ if len(tmp_dir_files) > 1:
+ raise Exception('Unexpected extra files in the temp dir')
+ elif len(tmp_dir_files) < 1:
+ raise Exception('sdist extraction did not occur i nthe temp dir')
+
+ return os.path.join(tmp_dir, tmp_dir_files[0])
+
+
+def install_sdist(tmp_dir, sdist_dir):
+ """Install the extracted sdist into the temporary directory"""
+ install = subprocess.Popen(
+ ['python', 'setup.py', 'install', '--root=%s' % tmp_dir],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ cwd=os.path.join(tmp_dir, sdist_dir),
+ )
+
+ stdout, stderr = install.communicate()
+
+ if install.returncode != 0:
+ raise Exception('sdist install failed:\n%s' % stderr)
+
+ # Determine the prefix for the installed files
+ match = re.search('^creating (%s/.*?/(?:site|dist)-packages)/ansible$' %
+ tmp_dir, stdout, flags=re.M)
+ return match.group(1)
+
+
+def check_sdist_contains_expected(sdist_dir, to_ship_files):
+ """Check that the files we expect to ship are present in the sdist"""
+ results = []
+ for filename in to_ship_files:
+ path = os.path.join(sdist_dir, filename)
+ if not os.path.exists(path):
+ results.append('%s: File was not added to sdist' % filename)
+
+ # Also changelog
+ changelog_files = glob.glob(os.path.join(sdist_dir, 'changelogs/CHANGELOG-v2.[0-9]*.rst'))
+ if not changelog_files:
+ results.append('changelogs/CHANGELOG-v2.*.rst: Changelog file was not added to the sdist')
+ elif len(changelog_files) > 1:
+ results.append('changelogs/CHANGELOG-v2.*.rst: Too many changelog files: %s'
+ % changelog_files)
+
+ return results
+
+
+def check_sdist_files_are_wanted(sdist_dir, to_ship_files):
+ """Check that all files in the sdist are desired"""
+ results = []
+ for dirname, dummy, files in os.walk(sdist_dir):
+ dirname = os.path.relpath(dirname, start=sdist_dir)
+ if dirname == '.':
+ dirname = ''
+
+ for filename in files:
+ path = os.path.join(dirname, filename)
+ if path not in to_ship_files:
+ if fnmatch.fnmatch(path, 'changelogs/CHANGELOG-v2.[0-9]*.rst'):
+ # changelog files are expected
+ continue
+
+ # FIXME: ansible-test doesn't pass the paths of symlinks to us so we aren't
+ # checking those
+ if not os.path.islink(os.path.join(sdist_dir, path)):
+ results.append('%s: File in sdist was not in the repository' % path)
+
+ return results
+
+
+def check_installed_contains_expected(install_dir, to_install_files):
+ """Check that all the files we expect to be installed are"""
+ results = []
+ for filename in to_install_files:
+ path = os.path.join(install_dir, filename)
+ if not os.path.exists(path):
+ results.append('%s: File not installed' % os.path.join('lib', filename))
+
+ return results
+
+
+EGG_RE = re.compile('ansible[^/]+\\.egg-info/(PKG-INFO|SOURCES.txt|'
+ 'dependency_links.txt|not-zip-safe|requires.txt|top_level.txt)$')
+
+
+def check_installed_files_are_wanted(install_dir, to_install_files):
+ """Check that all installed files were desired"""
+ results = []
+
+ for dirname, dummy, files in os.walk(install_dir):
+ dirname = os.path.relpath(dirname, start=install_dir)
+ if dirname == '.':
+ dirname = ''
+
+ for filename in files:
+ # If this is a byte code cache, look for the python file's name
+ directory = dirname
+ if filename.endswith('.pyc') or filename.endswith('.pyo'):
+ # Remove the trailing "o" or c"
+ filename = filename[:-1]
+
+ if directory.endswith('%s__pycache__' % os.path.sep):
+ # Python3 byte code cache, look for the basename of
+ # __pycache__/__init__.cpython-36.py
+ segments = filename.rsplit('.', 2)
+ if len(segments) >= 3:
+ filename = '.'.join((segments[0], segments[2]))
+ directory = os.path.dirname(directory)
+
+ path = os.path.join(directory, filename)
+
+ # Test that the file was listed for installation
+ if path not in to_install_files:
+ # FIXME: ansible-test doesn't pass the paths of symlinks to us so we
+ # aren't checking those
+ if not os.path.islink(os.path.join(install_dir, path)):
+ if not EGG_RE.match(path):
+ results.append('%s: File was installed but was not supposed to be' % path)
+
+ return results
+
+
+def _find_symlinks():
+ symlink_list = []
+ for dirname, directories, filenames in os.walk('.'):
+ for filename in filenames:
+ path = os.path.join(dirname, filename)
+ # Strip off "./" from the front
+ path = path[2:]
+ if os.path.islink(path):
+ symlink_list.append(path)
+
+ return symlink_list
+
+
+def main():
+ """All of the files in the repository"""
+ complete_file_list = []
+ for path in sys.argv[1:] or sys.stdin.read().splitlines():
+ complete_file_list.append(path)
+
+ # ansible-test isn't currently passing symlinks to us so construct those ourselves for now
+ for filename in _find_symlinks():
+ if filename not in complete_file_list:
+ # For some reason ansible-test is passing us lib/ansible/module_utils/ansible_release.py
+ # which is a symlink even though it doesn't pass any others
+ complete_file_list.append(filename)
+
+ # We may run this after docs sanity tests so get a clean repository to run in
+ with clean_repository(complete_file_list) as clean_repo_dir:
+ os.chdir(clean_repo_dir)
+
+ to_ship_files = assemble_files_to_ship(complete_file_list)
+ to_install_files = assemble_files_to_install(complete_file_list)
+
+ results = []
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ sdist_path = create_sdist(tmp_dir)
+ sdist_dir = extract_sdist(sdist_path, tmp_dir)
+
+ # Check that the files that are supposed to be in the sdist are there
+ results.extend(check_sdist_contains_expected(sdist_dir, to_ship_files))
+
+ # Check that the files that are in the sdist are in the repository
+ results.extend(check_sdist_files_are_wanted(sdist_dir, to_ship_files))
+
+ # install the sdist
+ install_dir = install_sdist(tmp_dir, sdist_dir)
+
+ # Check that the files that are supposed to be installed are there
+ results.extend(check_installed_contains_expected(install_dir, to_install_files))
+
+ # Check that the files that are installed are supposed to be installed
+ results.extend(check_installed_files_are_wanted(install_dir, to_install_files))
+
+ for message in results:
+ print(message)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/package-data.requirements.txt b/test/sanity/code-smell/package-data.requirements.txt
new file mode 100644
index 00000000..5d74c715
--- /dev/null
+++ b/test/sanity/code-smell/package-data.requirements.txt
@@ -0,0 +1,10 @@
+docutils
+jinja2
+packaging
+pyyaml # ansible-base requirement
+rstcheck
+setuptools > 39.2
+straight.plugin
+
+# changelog build requires python 3.6+
+antsibull-changelog ; python_version >= '3.6'
diff --git a/test/sanity/code-smell/release-names.json b/test/sanity/code-smell/release-names.json
new file mode 100644
index 00000000..593b765d
--- /dev/null
+++ b/test/sanity/code-smell/release-names.json
@@ -0,0 +1,4 @@
+{
+ "no_targets": true,
+ "output": "path-message"
+}
diff --git a/test/sanity/code-smell/release-names.py b/test/sanity/code-smell/release-names.py
new file mode 100755
index 00000000..f8003320
--- /dev/null
+++ b/test/sanity/code-smell/release-names.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# (c) 2019, Ansible Project
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+"""
+Test that the release name is present in the list of used up release names
+"""
+
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from yaml import safe_load
+
+from ansible.release import __codename__
+
+
+def main():
+ """Entrypoint to the script"""
+
+ with open('.github/RELEASE_NAMES.yml') as f:
+ releases = safe_load(f.read())
+
+ # Why this format? The file's sole purpose is to be read by a human when they need to know
+ # which release names have already been used. So:
+ # 1) It's easier for a human to find the release names when there's one on each line
+ # 2) It helps keep other people from using the file and then asking for new features in it
+ for name in (r.split(maxsplit=1)[1] for r in releases):
+ if __codename__ == name:
+ break
+ else:
+ print('.github/RELEASE_NAMES.yml: Current codename was not present in the file')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/release-names.requirements.txt b/test/sanity/code-smell/release-names.requirements.txt
new file mode 100644
index 00000000..c3726e8b
--- /dev/null
+++ b/test/sanity/code-smell/release-names.requirements.txt
@@ -0,0 +1 @@
+pyyaml
diff --git a/test/sanity/code-smell/required-and-default-attributes.json b/test/sanity/code-smell/required-and-default-attributes.json
new file mode 100644
index 00000000..dd9ac7b1
--- /dev/null
+++ b/test/sanity/code-smell/required-and-default-attributes.json
@@ -0,0 +1,9 @@
+{
+ "prefixes": [
+ "lib/ansible/"
+ ],
+ "extensions": [
+ ".py"
+ ],
+ "output": "path-line-column-message"
+}
diff --git a/test/sanity/code-smell/required-and-default-attributes.py b/test/sanity/code-smell/required-and-default-attributes.py
new file mode 100755
index 00000000..5ef410bd
--- /dev/null
+++ b/test/sanity/code-smell/required-and-default-attributes.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import re
+import sys
+
+
+def main():
+ for path in sys.argv[1:] or sys.stdin.read().splitlines():
+ with open(path, 'r') as path_fd:
+ for line, text in enumerate(path_fd.readlines()):
+ match = re.search(r'(FieldAttribute.*(default|required).*(default|required))', text)
+
+ if match:
+ print('%s:%d:%d: use only one of `default` or `required` with `FieldAttribute`' % (
+ path, line + 1, match.start(1) + 1))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/skip.txt b/test/sanity/code-smell/skip.txt
new file mode 100644
index 00000000..6fb327b3
--- /dev/null
+++ b/test/sanity/code-smell/skip.txt
@@ -0,0 +1,2 @@
+deprecated-config.py # disabled by default, to be enabled by the release manager after branching
+update-bundled.py # disabled by default, to be enabled by the release manager after branching
diff --git a/test/sanity/code-smell/test-constraints.json b/test/sanity/code-smell/test-constraints.json
new file mode 100644
index 00000000..69b07bf3
--- /dev/null
+++ b/test/sanity/code-smell/test-constraints.json
@@ -0,0 +1,9 @@
+{
+ "prefixes": [
+ "test/lib/ansible_test/_data/requirements/"
+ ],
+ "extensions": [
+ ".txt"
+ ],
+ "output": "path-line-column-message"
+}
diff --git a/test/sanity/code-smell/test-constraints.py b/test/sanity/code-smell/test-constraints.py
new file mode 100755
index 00000000..e8b9c795
--- /dev/null
+++ b/test/sanity/code-smell/test-constraints.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import re
+import sys
+
+
+def main():
+ for path in sys.argv[1:] or sys.stdin.read().splitlines():
+ with open(path, 'r') as path_fd:
+ for line, text in enumerate(path_fd.readlines()):
+ match = re.search(r'^[^;#]*?([<>=])(?!.*sanity_ok.*)', text)
+
+ if match:
+ print('%s:%d:%d: put constraints in `test/lib/ansible_test/_data/requirements/constraints.txt`' % (
+ path, line + 1, match.start(1) + 1))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/update-bundled.json b/test/sanity/code-smell/update-bundled.json
new file mode 100644
index 00000000..379bf4d7
--- /dev/null
+++ b/test/sanity/code-smell/update-bundled.json
@@ -0,0 +1,8 @@
+{
+ "all_targets": true,
+ "ignore_self": true,
+ "extensions": [
+ ".py"
+ ],
+ "output": "path-message"
+}
diff --git a/test/sanity/code-smell/update-bundled.py b/test/sanity/code-smell/update-bundled.py
new file mode 100755
index 00000000..121e225f
--- /dev/null
+++ b/test/sanity/code-smell/update-bundled.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# (c) 2018, Ansible Project
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+"""
+This test checks whether the libraries we're bundling are out of date and need to be synced with
+a newer upstream release.
+"""
+
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import fnmatch
+import json
+import re
+import sys
+from distutils.version import LooseVersion
+
+import packaging.specifiers
+
+from ansible.module_utils.urls import open_url
+
+
+BUNDLED_RE = re.compile(b'\\b_BUNDLED_METADATA\\b')
+
+
+def get_bundled_libs(paths):
+ """
+ Return the set of known bundled libraries
+
+ :arg paths: The paths which the test has been instructed to check
+ :returns: The list of all files which we know to contain bundled libraries. If a bundled
+ library consists of multiple files, this should be the file which has metadata included.
+ """
+ bundled_libs = set()
+ for filename in fnmatch.filter(paths, 'lib/ansible/compat/*/__init__.py'):
+ bundled_libs.add(filename)
+
+ bundled_libs.add('lib/ansible/module_utils/distro/__init__.py')
+ bundled_libs.add('lib/ansible/module_utils/six/__init__.py')
+ bundled_libs.add('lib/ansible/module_utils/compat/ipaddress.py')
+ # backports.ssl_match_hostname should be moved to its own file in the future
+ bundled_libs.add('lib/ansible/module_utils/urls.py')
+
+ return bundled_libs
+
+
+def get_files_with_bundled_metadata(paths):
+ """
+ Search for any files which have bundled metadata inside of them
+
+ :arg paths: Iterable of filenames to search for metadata inside of
+ :returns: A set of pathnames which contained metadata
+ """
+
+ with_metadata = set()
+ for path in paths:
+ with open(path, 'rb') as f:
+ body = f.read()
+
+ if BUNDLED_RE.search(body):
+ with_metadata.add(path)
+
+ return with_metadata
+
+
+def get_bundled_metadata(filename):
+ """
+ Retrieve the metadata about a bundled library from a python file
+
+ :arg filename: The filename to look inside for the metadata
+ :raises ValueError: If we're unable to extract metadata from the file
+ :returns: The metadata from the python file
+ """
+ with open(filename, 'r') as module:
+ for line in module:
+ if line.strip().startswith('_BUNDLED_METADATA'):
+ data = line[line.index('{'):].strip()
+ break
+ else:
+ raise ValueError('Unable to check bundled library for update. Please add'
+ ' _BUNDLED_METADATA dictionary to the library file with'
+ ' information on pypi name and bundled version.')
+ metadata = json.loads(data)
+ return metadata
+
+
+def get_latest_applicable_version(pypi_data, constraints=None):
+ """Get the latest pypi version of the package that we allow
+
+ :arg pypi_data: Pypi information about the data as returned by
+ ``https://pypi.org/pypi/{pkg_name}/json``
+ :kwarg constraints: version constraints on what we're allowed to use as specified by
+ the bundled metadata
+ :returns: The most recent version on pypi that are allowed by ``constraints``
+ """
+ latest_version = "0"
+ if constraints:
+ version_specification = packaging.specifiers.SpecifierSet(constraints)
+ for version in pypi_data['releases']:
+ if version in version_specification:
+ if LooseVersion(version) > LooseVersion(latest_version):
+ latest_version = version
+ else:
+ latest_version = pypi_data['info']['version']
+
+ return latest_version
+
+
+def main():
+ """Entrypoint to the script"""
+
+ paths = sys.argv[1:] or sys.stdin.read().splitlines()
+
+ bundled_libs = get_bundled_libs(paths)
+ files_with_bundled_metadata = get_files_with_bundled_metadata(paths)
+
+ for filename in files_with_bundled_metadata.difference(bundled_libs):
+ print('{0}: ERROR: File contains _BUNDLED_METADATA but needs to be added to'
+ ' test/sanity/code-smell/update-bundled.py'.format(filename))
+
+ for filename in bundled_libs:
+ try:
+ metadata = get_bundled_metadata(filename)
+ except ValueError as e:
+ print('{0}: ERROR: {1}'.format(filename, e))
+ continue
+ except (IOError, OSError) as e:
+ if e.errno == 2:
+ print('{0}: ERROR: {1}. Perhaps the bundled library has been removed'
+ ' or moved and the bundled library test needs to be modified as'
+ ' well?'.format(filename, e))
+
+ pypi_fh = open_url('https://pypi.org/pypi/{0}/json'.format(metadata['pypi_name']))
+ pypi_data = json.loads(pypi_fh.read().decode('utf-8'))
+
+ constraints = metadata.get('version_constraints', None)
+ latest_version = get_latest_applicable_version(pypi_data, constraints)
+
+ if LooseVersion(metadata['version']) < LooseVersion(latest_version):
+ print('{0}: UPDATE {1} from {2} to {3} {4}'.format(
+ filename,
+ metadata['pypi_name'],
+ metadata['version'],
+ latest_version,
+ 'https://pypi.org/pypi/{0}/json'.format(metadata['pypi_name'])))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/sanity/code-smell/update-bundled.requirements.txt b/test/sanity/code-smell/update-bundled.requirements.txt
new file mode 100644
index 00000000..748809f7
--- /dev/null
+++ b/test/sanity/code-smell/update-bundled.requirements.txt
@@ -0,0 +1 @@
+packaging
diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt
new file mode 100644
index 00000000..5275f076
--- /dev/null
+++ b/test/sanity/ignore.txt
@@ -0,0 +1,427 @@
+docs/bin/find-plugin-refs.py future-import-boilerplate
+docs/bin/find-plugin-refs.py metaclass-boilerplate
+docs/docsite/_extensions/pygments_lexer.py future-import-boilerplate
+docs/docsite/_extensions/pygments_lexer.py metaclass-boilerplate
+docs/docsite/_themes/sphinx_rtd_theme/__init__.py future-import-boilerplate
+docs/docsite/_themes/sphinx_rtd_theme/__init__.py metaclass-boilerplate
+docs/docsite/rst/dev_guide/testing/sanity/no-smart-quotes.rst no-smart-quotes
+examples/play.yml shebang
+examples/scripts/my_test.py shebang # example module but not in a normal module location
+examples/scripts/my_test_facts.py shebang # example module but not in a normal module location
+examples/scripts/my_test_info.py shebang # example module but not in a normal module location
+examples/scripts/ConfigureRemotingForAnsible.ps1 pslint:PSCustomUseLiteralPath
+examples/scripts/upgrade_to_ps3.ps1 pslint:PSCustomUseLiteralPath
+examples/scripts/upgrade_to_ps3.ps1 pslint:PSUseApprovedVerbs
+hacking/build-ansible.py shebang # only run by release engineers, Python 3.6+ required
+hacking/build_library/build_ansible/announce.py compile-2.6!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/announce.py compile-2.7!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/announce.py compile-3.5!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/commands.py compile-2.6!skip # release and docs process only, 3.6+ required
+hacking/build_library/build_ansible/commands.py compile-2.7!skip # release and docs process only, 3.6+ required
+hacking/build_library/build_ansible/commands.py compile-3.5!skip # release and docs process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/dump_config.py compile-2.6!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/dump_config.py compile-2.7!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/dump_config.py compile-3.5!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/dump_keywords.py compile-2.6!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/dump_keywords.py compile-2.7!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/dump_keywords.py compile-3.5!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/generate_man.py compile-2.6!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/generate_man.py compile-2.7!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/generate_man.py compile-3.5!skip # docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/porting_guide.py compile-2.6!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/porting_guide.py compile-2.7!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/porting_guide.py compile-3.5!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/release_announcement.py compile-2.6!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/release_announcement.py compile-2.7!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/release_announcement.py compile-3.5!skip # release process only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/update_intersphinx.py compile-2.6!skip # release process and docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/update_intersphinx.py compile-2.7!skip # release process and docs build only, 3.6+ required
+hacking/build_library/build_ansible/command_plugins/update_intersphinx.py compile-3.5!skip # release process and docs build only, 3.6+ required
+hacking/fix_test_syntax.py future-import-boilerplate
+hacking/fix_test_syntax.py metaclass-boilerplate
+hacking/get_library.py future-import-boilerplate
+hacking/get_library.py metaclass-boilerplate
+hacking/report.py future-import-boilerplate
+hacking/report.py metaclass-boilerplate
+hacking/return_skeleton_generator.py future-import-boilerplate
+hacking/return_skeleton_generator.py metaclass-boilerplate
+hacking/test-module.py future-import-boilerplate
+hacking/test-module.py metaclass-boilerplate
+hacking/tests/gen_distribution_version_testcase.py future-import-boilerplate
+hacking/tests/gen_distribution_version_testcase.py metaclass-boilerplate
+lib/ansible/cli/console.py pylint:blacklisted-name
+lib/ansible/cli/scripts/ansible_cli_stub.py shebang
+lib/ansible/cli/scripts/ansible_connection_cli_stub.py shebang
+lib/ansible/config/base.yml no-unwanted-files
+lib/ansible/executor/playbook_executor.py pylint:blacklisted-name
+lib/ansible/executor/powershell/async_watchdog.ps1 pslint:PSCustomUseLiteralPath
+lib/ansible/executor/powershell/async_wrapper.ps1 pslint:PSCustomUseLiteralPath
+lib/ansible/executor/powershell/exec_wrapper.ps1 pslint:PSCustomUseLiteralPath
+lib/ansible/executor/task_queue_manager.py pylint:blacklisted-name
+lib/ansible/galaxy/collection.py compile-2.6!skip # 'ansible-galaxy collection' requires 2.7+
+lib/ansible/module_utils/compat/_selectors2.py future-import-boilerplate # ignore bundled
+lib/ansible/module_utils/compat/_selectors2.py metaclass-boilerplate # ignore bundled
+lib/ansible/module_utils/compat/_selectors2.py pylint:blacklisted-name
+lib/ansible/module_utils/distro/__init__.py empty-init # breaks namespacing, bundled, do not override
+lib/ansible/module_utils/distro/_distro.py future-import-boilerplate # ignore bundled
+lib/ansible/module_utils/distro/_distro.py metaclass-boilerplate # ignore bundled
+lib/ansible/module_utils/distro/_distro.py no-assert
+lib/ansible/module_utils/distro/_distro.py pep8!skip # bundled code we don't want to modify
+lib/ansible/module_utils/facts/__init__.py empty-init # breaks namespacing, deprecate and eventually remove
+lib/ansible/module_utils/facts/network/linux.py pylint:blacklisted-name
+lib/ansible/module_utils/facts/system/distribution.py pylint:ansible-bad-function
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.ArgvParser.psm1 pslint:PSUseApprovedVerbs
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 pslint:PSProvideCommentHelp # need to agree on best format for comment location
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 pslint:PSUseApprovedVerbs
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.FileUtil.psm1 pslint:PSCustomUseLiteralPath
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.FileUtil.psm1 pslint:PSProvideCommentHelp
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1 pslint:PSCustomUseLiteralPath
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1 pslint:PSUseApprovedVerbs
+lib/ansible/module_utils/powershell/Ansible.ModuleUtils.LinkUtil.psm1 pslint:PSUseApprovedVerbs
+lib/ansible/module_utils/pycompat24.py no-get-exception
+lib/ansible/module_utils/six/__init__.py empty-init # breaks namespacing, bundled, do not override
+lib/ansible/module_utils/six/__init__.py future-import-boilerplate # ignore bundled
+lib/ansible/module_utils/six/__init__.py metaclass-boilerplate # ignore bundled
+lib/ansible/module_utils/six/__init__.py no-basestring
+lib/ansible/module_utils/six/__init__.py no-dict-iteritems
+lib/ansible/module_utils/six/__init__.py no-dict-iterkeys
+lib/ansible/module_utils/six/__init__.py no-dict-itervalues
+lib/ansible/module_utils/six/__init__.py replace-urlopen
+lib/ansible/module_utils/urls.py pylint:blacklisted-name
+lib/ansible/module_utils/urls.py replace-urlopen
+lib/ansible/modules/command.py validate-modules:doc-default-does-not-match-spec # _uses_shell is undocumented
+lib/ansible/modules/command.py validate-modules:doc-missing-type
+lib/ansible/modules/command.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/command.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/command.py validate-modules:undocumented-parameter
+lib/ansible/modules/expect.py validate-modules:doc-missing-type
+lib/ansible/modules/assemble.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/blockinfile.py validate-modules:doc-choices-do-not-match-spec
+lib/ansible/modules/blockinfile.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/copy.py pylint:blacklisted-name
+lib/ansible/modules/copy.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/copy.py validate-modules:doc-type-does-not-match-spec
+lib/ansible/modules/copy.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/copy.py validate-modules:undocumented-parameter
+lib/ansible/modules/file.py pylint:ansible-bad-function
+lib/ansible/modules/file.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/file.py validate-modules:undocumented-parameter
+lib/ansible/modules/find.py use-argspec-type-path # fix needed
+lib/ansible/modules/lineinfile.py validate-modules:doc-choices-do-not-match-spec
+lib/ansible/modules/lineinfile.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/lineinfile.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/replace.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/stat.py validate-modules:doc-default-does-not-match-spec # get_md5 is undocumented
+lib/ansible/modules/stat.py validate-modules:parameter-invalid
+lib/ansible/modules/stat.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/stat.py validate-modules:undocumented-parameter
+lib/ansible/modules/unarchive.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/unarchive.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/get_url.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/uri.py pylint:blacklisted-name
+lib/ansible/modules/uri.py validate-modules:doc-required-mismatch
+lib/ansible/modules/uri.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/uri.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/pip.py pylint:blacklisted-name
+lib/ansible/modules/pip.py validate-modules:doc-elements-mismatch
+lib/ansible/modules/pip.py validate-modules:invalid-ansiblemodule-schema
+lib/ansible/modules/apt.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/apt.py validate-modules:parameter-invalid
+lib/ansible/modules/apt.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/apt.py validate-modules:undocumented-parameter
+lib/ansible/modules/apt_key.py validate-modules:mutually_exclusive-unknown
+lib/ansible/modules/apt_key.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/apt_key.py validate-modules:undocumented-parameter
+lib/ansible/modules/apt_repository.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/apt_repository.py validate-modules:parameter-invalid
+lib/ansible/modules/apt_repository.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/apt_repository.py validate-modules:undocumented-parameter
+lib/ansible/modules/dnf.py validate-modules:doc-missing-type
+lib/ansible/modules/dnf.py validate-modules:doc-required-mismatch
+lib/ansible/modules/dnf.py validate-modules:parameter-invalid
+lib/ansible/modules/dnf.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/dnf.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/dpkg_selections.py validate-modules:doc-missing-type
+lib/ansible/modules/dpkg_selections.py validate-modules:doc-required-mismatch
+lib/ansible/modules/package_facts.py validate-modules:doc-choices-do-not-match-spec
+lib/ansible/modules/package_facts.py validate-modules:doc-missing-type
+lib/ansible/modules/package_facts.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/rpm_key.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/yum.py pylint:blacklisted-name
+lib/ansible/modules/yum.py validate-modules:doc-missing-type
+lib/ansible/modules/yum.py validate-modules:parameter-invalid
+lib/ansible/modules/yum.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/yum.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/yum_repository.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/yum_repository.py validate-modules:doc-missing-type
+lib/ansible/modules/yum_repository.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/yum_repository.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/yum_repository.py validate-modules:undocumented-parameter
+lib/ansible/modules/git.py pylint:blacklisted-name
+lib/ansible/modules/git.py use-argspec-type-path
+lib/ansible/modules/git.py validate-modules:doc-missing-type
+lib/ansible/modules/git.py validate-modules:doc-required-mismatch
+lib/ansible/modules/git.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/git.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/subversion.py validate-modules:doc-required-mismatch
+lib/ansible/modules/subversion.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/subversion.py validate-modules:undocumented-parameter
+lib/ansible/modules/getent.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/hostname.py validate-modules:invalid-ansiblemodule-schema
+lib/ansible/modules/hostname.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/iptables.py pylint:blacklisted-name
+lib/ansible/modules/iptables.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/service.py validate-modules:nonexistent-parameter-documented
+lib/ansible/modules/service.py validate-modules:use-run-command-not-popen
+lib/ansible/modules/setup.py validate-modules:doc-missing-type
+lib/ansible/modules/setup.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/setup.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/systemd.py validate-modules:parameter-invalid
+lib/ansible/modules/systemd.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/systemd.py validate-modules:return-syntax-error
+lib/ansible/modules/sysvinit.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/sysvinit.py validate-modules:parameter-type-not-in-doc
+lib/ansible/modules/sysvinit.py validate-modules:return-syntax-error
+lib/ansible/modules/user.py validate-modules:doc-default-does-not-match-spec
+lib/ansible/modules/user.py validate-modules:doc-default-incompatible-type
+lib/ansible/modules/user.py validate-modules:parameter-list-no-elements
+lib/ansible/modules/user.py validate-modules:use-run-command-not-popen
+lib/ansible/modules/async_status.py use-argspec-type-path
+lib/ansible/modules/async_status.py validate-modules!skip
+lib/ansible/modules/async_wrapper.py ansible-doc!skip # not an actual module
+lib/ansible/modules/async_wrapper.py pylint:ansible-bad-function
+lib/ansible/modules/async_wrapper.py use-argspec-type-path
+lib/ansible/modules/wait_for.py validate-modules:parameter-list-no-elements
+lib/ansible/parsing/vault/__init__.py pylint:blacklisted-name
+lib/ansible/playbook/base.py pylint:blacklisted-name
+lib/ansible/playbook/collectionsearch.py required-and-default-attributes # https://github.com/ansible/ansible/issues/61460
+lib/ansible/playbook/helpers.py pylint:blacklisted-name
+lib/ansible/playbook/role/__init__.py pylint:blacklisted-name
+lib/ansible/plugins/action/normal.py action-plugin-docs # default action plugin for modules without a dedicated action plugin
+lib/ansible/plugins/cache/base.py ansible-doc!skip # not a plugin, but a stub for backwards compatibility
+lib/ansible/plugins/lookup/sequence.py pylint:blacklisted-name
+lib/ansible/plugins/strategy/__init__.py pylint:blacklisted-name
+lib/ansible/plugins/strategy/linear.py pylint:blacklisted-name
+lib/ansible/vars/hostvars.py pylint:blacklisted-name
+test/integration/targets/ansible-runner/files/adhoc_example1.py future-import-boilerplate
+test/integration/targets/ansible-runner/files/adhoc_example1.py metaclass-boilerplate
+test/integration/targets/ansible-runner/files/playbook_example1.py future-import-boilerplate
+test/integration/targets/ansible-runner/files/playbook_example1.py metaclass-boilerplate
+test/integration/targets/ansible-test/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import
+test/integration/targets/ansible-test/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import-from
+test/integration/targets/ansible-test/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py pylint:ansible-bad-function
+test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/filter/check_pylint.py pylint:blacklisted-name
+test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/modules/hello.py pylint:relative-beyond-top-level
+test/integration/targets/ansible-test/ansible_collections/ns/col/tests/unit/plugins/module_utils/test_my_util.py pylint:relative-beyond-top-level
+test/integration/targets/ansible-test/ansible_collections/ns/col/tests/unit/plugins/modules/test_hello.py pylint:relative-beyond-top-level
+test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/modules/hello.py pylint:relative-beyond-top-level
+test/integration/targets/ansible-test-docker/ansible_collections/ns/col/tests/unit/plugins/module_utils/test_my_util.py pylint:relative-beyond-top-level
+test/integration/targets/ansible-test-docker/ansible_collections/ns/col/tests/unit/plugins/modules/test_hello.py pylint:relative-beyond-top-level
+test/integration/targets/async_fail/library/async_test.py future-import-boilerplate
+test/integration/targets/async_fail/library/async_test.py metaclass-boilerplate
+test/integration/targets/collections_plugin_namespace/collection_root/ansible_collections/my_ns/my_col/plugins/lookup/lookup_no_future_boilerplate.py future-import-boilerplate
+test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/my_util2.py pylint:relative-beyond-top-level
+test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/my_util3.py pylint:relative-beyond-top-level
+test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/my_module.py pylint:relative-beyond-top-level
+test/integration/targets/expect/files/test_command.py future-import-boilerplate
+test/integration/targets/expect/files/test_command.py metaclass-boilerplate
+test/integration/targets/gathering_facts/library/bogus_facts shebang
+test/integration/targets/gathering_facts/library/facts_one shebang
+test/integration/targets/gathering_facts/library/facts_two shebang
+test/integration/targets/get_url/files/testserver.py future-import-boilerplate
+test/integration/targets/get_url/files/testserver.py metaclass-boilerplate
+test/integration/targets/group/files/gidget.py future-import-boilerplate
+test/integration/targets/group/files/gidget.py metaclass-boilerplate
+test/integration/targets/ignore_unreachable/fake_connectors/bad_exec.py future-import-boilerplate
+test/integration/targets/ignore_unreachable/fake_connectors/bad_exec.py metaclass-boilerplate
+test/integration/targets/ignore_unreachable/fake_connectors/bad_put_file.py future-import-boilerplate
+test/integration/targets/ignore_unreachable/fake_connectors/bad_put_file.py metaclass-boilerplate
+test/integration/targets/json_cleanup/library/bad_json shebang
+test/integration/targets/incidental_win_dsc/files/xTestDsc/1.0.0/DSCResources/ANSIBLE_xSetReboot/ANSIBLE_xSetReboot.psm1 pslint!skip
+test/integration/targets/incidental_win_dsc/files/xTestDsc/1.0.0/DSCResources/ANSIBLE_xTestResource/ANSIBLE_xTestResource.psm1 pslint!skip
+test/integration/targets/incidental_win_dsc/files/xTestDsc/1.0.0/xTestDsc.psd1 pslint!skip
+test/integration/targets/incidental_win_dsc/files/xTestDsc/1.0.1/DSCResources/ANSIBLE_xTestResource/ANSIBLE_xTestResource.psm1 pslint!skip
+test/integration/targets/incidental_win_dsc/files/xTestDsc/1.0.1/xTestDsc.psd1 pslint!skip
+test/integration/targets/incidental_win_ping/library/win_ping_syntax_error.ps1 pslint!skip
+test/integration/targets/incidental_win_reboot/templates/post_reboot.ps1 pslint!skip
+test/integration/targets/lookup_ini/lookup-8859-15.ini no-smart-quotes
+test/integration/targets/module_precedence/lib_with_extension/a.ini shebang
+test/integration/targets/module_precedence/lib_with_extension/ping.ini shebang
+test/integration/targets/module_precedence/lib_with_extension/ping.py future-import-boilerplate
+test/integration/targets/module_precedence/lib_with_extension/ping.py metaclass-boilerplate
+test/integration/targets/module_precedence/multiple_roles/bar/library/ping.py future-import-boilerplate
+test/integration/targets/module_precedence/multiple_roles/bar/library/ping.py metaclass-boilerplate
+test/integration/targets/module_precedence/multiple_roles/foo/library/ping.py future-import-boilerplate
+test/integration/targets/module_precedence/multiple_roles/foo/library/ping.py metaclass-boilerplate
+test/integration/targets/module_precedence/roles_with_extension/foo/library/a.ini shebang
+test/integration/targets/module_precedence/roles_with_extension/foo/library/ping.ini shebang
+test/integration/targets/module_precedence/roles_with_extension/foo/library/ping.py future-import-boilerplate
+test/integration/targets/module_precedence/roles_with_extension/foo/library/ping.py metaclass-boilerplate
+test/integration/targets/module_utils/library/test.py future-import-boilerplate
+test/integration/targets/module_utils/library/test.py metaclass-boilerplate
+test/integration/targets/module_utils/library/test_env_override.py future-import-boilerplate
+test/integration/targets/module_utils/library/test_env_override.py metaclass-boilerplate
+test/integration/targets/module_utils/library/test_failure.py future-import-boilerplate
+test/integration/targets/module_utils/library/test_failure.py metaclass-boilerplate
+test/integration/targets/module_utils/library/test_override.py future-import-boilerplate
+test/integration/targets/module_utils/library/test_override.py metaclass-boilerplate
+test/integration/targets/module_utils/module_utils/bar0/foo.py pylint:blacklisted-name
+test/integration/targets/module_utils/module_utils/foo.py pylint:blacklisted-name
+test/integration/targets/module_utils/module_utils/sub/bar/__init__.py pylint:blacklisted-name
+test/integration/targets/module_utils/module_utils/sub/bar/bar.py pylint:blacklisted-name
+test/integration/targets/module_utils/module_utils/yak/zebra/foo.py pylint:blacklisted-name
+test/integration/targets/old_style_modules_posix/library/helloworld.sh shebang
+test/integration/targets/pause/test-pause.py future-import-boilerplate
+test/integration/targets/pause/test-pause.py metaclass-boilerplate
+test/integration/targets/pip/files/ansible_test_pip_chdir/__init__.py future-import-boilerplate
+test/integration/targets/pip/files/ansible_test_pip_chdir/__init__.py metaclass-boilerplate
+test/integration/targets/pip/files/setup.py future-import-boilerplate
+test/integration/targets/pip/files/setup.py metaclass-boilerplate
+test/integration/targets/run_modules/library/test.py future-import-boilerplate
+test/integration/targets/run_modules/library/test.py metaclass-boilerplate
+test/integration/targets/script/files/no_shebang.py future-import-boilerplate
+test/integration/targets/script/files/no_shebang.py metaclass-boilerplate
+test/integration/targets/service/files/ansible_test_service.py future-import-boilerplate
+test/integration/targets/service/files/ansible_test_service.py metaclass-boilerplate
+test/integration/targets/setup_rpm_repo/files/create-repo.py future-import-boilerplate
+test/integration/targets/setup_rpm_repo/files/create-repo.py metaclass-boilerplate
+test/integration/targets/template/files/encoding_1252_utf-8.expected no-smart-quotes
+test/integration/targets/template/files/encoding_1252_windows-1252.expected no-smart-quotes
+test/integration/targets/template/files/foo.dos.txt line-endings
+test/integration/targets/template/role_filter/filter_plugins/myplugin.py future-import-boilerplate
+test/integration/targets/template/role_filter/filter_plugins/myplugin.py metaclass-boilerplate
+test/integration/targets/template/templates/encoding_1252.j2 no-smart-quotes
+test/integration/targets/infra/library/test.py future-import-boilerplate
+test/integration/targets/infra/library/test.py metaclass-boilerplate
+test/integration/targets/unicode/unicode.yml no-smart-quotes
+test/integration/targets/uri/files/testserver.py future-import-boilerplate
+test/integration/targets/uri/files/testserver.py metaclass-boilerplate
+test/integration/targets/var_precedence/ansible-var-precedence-check.py future-import-boilerplate
+test/integration/targets/var_precedence/ansible-var-precedence-check.py metaclass-boilerplate
+test/integration/targets/builtin_vars_prompt/test-vars_prompt.py future-import-boilerplate
+test/integration/targets/builtin_vars_prompt/test-vars_prompt.py metaclass-boilerplate
+test/integration/targets/vault/test-vault-client.py future-import-boilerplate
+test/integration/targets/vault/test-vault-client.py metaclass-boilerplate
+test/integration/targets/wait_for/files/testserver.py future-import-boilerplate
+test/integration/targets/wait_for/files/testserver.py metaclass-boilerplate
+test/integration/targets/want_json_modules_posix/library/helloworld.py future-import-boilerplate
+test/integration/targets/want_json_modules_posix/library/helloworld.py metaclass-boilerplate
+test/integration/targets/win_exec_wrapper/library/test_fail.ps1 pslint:PSCustomUseLiteralPath
+test/integration/targets/win_exec_wrapper/tasks/main.yml no-smart-quotes # We are explicitly testing smart quote support for env vars
+test/integration/targets/win_fetch/tasks/main.yml no-smart-quotes # We are explictly testing smart quotes in the file name to fetch
+test/integration/targets/win_module_utils/library/legacy_only_new_way_win_line_ending.ps1 line-endings # Explicitly tests that we still work with Windows line endings
+test/integration/targets/win_module_utils/library/legacy_only_old_way_win_line_ending.ps1 line-endings # Explicitly tests that we still work with Windows line endings
+test/integration/targets/win_script/files/test_script.ps1 pslint:PSAvoidUsingWriteHost # Keep
+test/integration/targets/win_script/files/test_script_creates_file.ps1 pslint:PSAvoidUsingCmdletAliases
+test/integration/targets/win_script/files/test_script_removes_file.ps1 pslint:PSCustomUseLiteralPath
+test/integration/targets/win_script/files/test_script_with_args.ps1 pslint:PSAvoidUsingWriteHost # Keep
+test/integration/targets/win_script/files/test_script_with_splatting.ps1 pslint:PSAvoidUsingWriteHost # Keep
+test/integration/targets/windows-minimal/library/win_ping_syntax_error.ps1 pslint!skip
+test/lib/ansible_test/_data/requirements/constraints.txt test-constraints
+test/lib/ansible_test/_data/requirements/integration.cloud.azure.txt test-constraints
+test/lib/ansible_test/_data/requirements/sanity.ps1 pslint:PSCustomUseLiteralPath # Uses wildcards on purpose
+test/lib/ansible_test/_data/sanity/pylint/plugins/string_format.py use-compat-six
+test/lib/ansible_test/_data/setup/ConfigureRemotingForAnsible.ps1 pslint:PSCustomUseLiteralPath
+test/lib/ansible_test/_data/setup/windows-httptester.ps1 pslint:PSCustomUseLiteralPath
+test/support/integration/plugins/module_utils/azure_rm_common.py future-import-boilerplate
+test/support/integration/plugins/module_utils/azure_rm_common.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/azure_rm_common_rest.py future-import-boilerplate
+test/support/integration/plugins/module_utils/azure_rm_common_rest.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/cloud.py future-import-boilerplate
+test/support/integration/plugins/module_utils/cloud.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/compat/ipaddress.py future-import-boilerplate
+test/support/integration/plugins/module_utils/compat/ipaddress.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/compat/ipaddress.py no-unicode-literals
+test/support/integration/plugins/module_utils/database.py future-import-boilerplate
+test/support/integration/plugins/module_utils/database.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/mysql.py future-import-boilerplate
+test/support/integration/plugins/module_utils/mysql.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/network/common/utils.py future-import-boilerplate
+test/support/integration/plugins/module_utils/network/common/utils.py metaclass-boilerplate
+test/support/integration/plugins/module_utils/postgres.py future-import-boilerplate
+test/support/integration/plugins/module_utils/postgres.py metaclass-boilerplate
+test/support/integration/plugins/modules/lvg.py pylint:blacklisted-name
+test/support/integration/plugins/modules/synchronize.py pylint:blacklisted-name
+test/support/integration/plugins/modules/timezone.py pylint:blacklisted-name
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/doc_fragments/netconf.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/doc_fragments/netconf.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/doc_fragments/network_agnostic.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/doc_fragments/network_agnostic.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/compat/ipaddress.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/compat/ipaddress.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/compat/ipaddress.py no-unicode-literals
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/compat/ipaddress.py pep8:E203
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/cfg/base.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/cfg/base.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/config.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/config.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/facts/facts.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/facts/facts.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/network.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/network.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/parsing.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/parsing.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/utils.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/utils.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/netconf/netconf.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/netconf/netconf.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/restconf/restconf.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/restconf/restconf.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_command.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_command.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_config.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_config.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_config.py pep8:E501
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/doc_fragments/vyos.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/doc_fragments/vyos.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/module_utils/network/vyos/vyos.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/module_utils/network/vyos/vyos.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_command.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_command.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_command.py pep8:E231
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_command.py pylint:blacklisted-name
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_config.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_config.py metaclass-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_facts.py future-import-boilerplate
+test/support/network-integration/collections/ansible_collections/vyos/vyos/plugins/modules/vyos_facts.py metaclass-boilerplate
+test/support/windows-integration/plugins/modules/async_status.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/setup.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_copy.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_dsc.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_feature.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_find.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_lineinfile.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_regedit.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_security_policy.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_shell.ps1 pslint!skip
+test/support/windows-integration/plugins/modules/win_wait_for.ps1 pslint!skip
+test/units/executor/test_play_iterator.py pylint:blacklisted-name
+test/units/module_utils/basic/test_deprecate_warn.py pylint:ansible-deprecated-no-version
+test/units/module_utils/basic/test_deprecate_warn.py pylint:ansible-deprecated-version
+test/units/module_utils/basic/test_run_command.py pylint:blacklisted-name
+test/units/module_utils/urls/fixtures/multipart.txt line-endings # Fixture for HTTP tests that use CRLF
+test/units/module_utils/urls/test_Request.py replace-urlopen
+test/units/module_utils/urls/test_fetch_url.py replace-urlopen
+test/units/modules/test_apt.py pylint:blacklisted-name
+test/units/modules/test_known_hosts.py pylint:ansible-bad-function
+test/units/parsing/vault/test_vault.py pylint:blacklisted-name
+test/units/playbook/role/test_role.py pylint:blacklisted-name
+test/units/plugins/test_plugins.py pylint:blacklisted-name
+test/units/template/test_templar.py pylint:blacklisted-name
+test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/module_utils/my_util.py future-import-boilerplate # test expects no boilerplate
+test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/module_utils/my_util.py metaclass-boilerplate # test expects no boilerplate
+test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/action/my_action.py pylint:relative-beyond-top-level
+test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/modules/__init__.py empty-init # testing that collections don't need inits
+test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/__init__.py empty-init # testing that collections don't need inits
+test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/ansible/__init__.py empty-init # testing that collections don't need inits
+test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/testns/__init__.py empty-init # testing that collections don't need inits
+test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/testns/testcoll/__init__.py empty-init # testing that collections don't need inits
+test/units/utils/collection_loader/test_collection_loader.py pylint:undefined-variable # magic runtime local var splatting
+test/utils/shippable/check_matrix.py replace-urlopen
+test/utils/shippable/timing.py shebang