ansible-test - Update import test and sanity requirements. (#76308)

* Add script to freeze sanity requirements.
* Declare sanity test requirements and freeze
* Use pinned requirements for import.plugin test.
* Expand scope of import test for ansible-core.
* Add ignores for galaxy import errors.
* Update test-constraints sanity test.
pull/76310/head
Matt Clay 3 years ago committed by GitHub
parent 21ac52435b
commit bb63c97c16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -29,10 +29,10 @@ recursive-include packaging *
recursive-include test/ansible_test *.py Makefile recursive-include test/ansible_test *.py Makefile
recursive-include test/integration * recursive-include test/integration *
recursive-include test/lib/ansible_test/config *.yml *.template recursive-include test/lib/ansible_test/config *.yml *.template
recursive-include test/lib/ansible_test/_data *.cfg *.ini *.ps1 *.txt *.yml coveragerc recursive-include test/lib/ansible_test/_data *.cfg *.in *.ini *.ps1 *.txt *.yml coveragerc
recursive-include test/lib/ansible_test/_util *.cfg *.json *.ps1 *.psd1 *.py *.sh *.txt *.yml recursive-include test/lib/ansible_test/_util *.cfg *.json *.ps1 *.psd1 *.py *.sh *.txt *.yml
recursive-include test/lib/ansible_test/_util/controller/sanity/validate-modules validate-modules recursive-include test/lib/ansible_test/_util/controller/sanity/validate-modules validate-modules
recursive-include test/sanity *.json *.py *.txt recursive-include test/sanity *.in *.json *.py *.txt
recursive-include test/support *.py *.ps1 *.psm1 *.cs recursive-include test/support *.py *.ps1 *.psm1 *.cs
exclude test/sanity/code-smell/botmeta.* exclude test/sanity/code-smell/botmeta.*
exclude test/sanity/code-smell/release-names.* exclude test/sanity/code-smell/release-names.*
@ -46,4 +46,5 @@ include changelogs/changelog.yaml
recursive-include hacking/build_library *.py recursive-include hacking/build_library *.py
include hacking/build-ansible.py include hacking/build-ansible.py
include hacking/test-module.py include hacking/test-module.py
include hacking/update-sanity-requirements.py
include bin/* include bin/*

@ -0,0 +1,4 @@
minor_changes:
- ansible-test - Declare public dependencies of ansible-core and use to limit unguarded imports in plugins.
- ansible-test - Requirements for the plugin import test are now frozen.
- ansible-test - Update sanity test requirements.

@ -60,9 +60,15 @@ Ansible allows the following unchecked imports from these specific directories:
* ansible-core: * ansible-core:
* For ``lib/ansible/modules/`` and ``lib/ansible/module_utils/``, unchecked imports are only allowed from the Python standard library; * For ``lib/ansible/modules/`` and ``lib/ansible/module_utils/``, unchecked imports are only allowed from the Python standard library;
* For ``lib/ansible/plugins/``, unchecked imports are only allowed from the Python standard library, from dependencies of ansible-core, and from ansible-core itself; * For ``lib/ansible/plugins/``, unchecked imports are only allowed from the Python standard library, from public dependencies of ansible-core, and from ansible-core itself;
* collections: * collections:
* For ``plugins/modules/`` and ``plugins/module_utils/``, unchecked imports are only allowed from the Python standard library; * For ``plugins/modules/`` and ``plugins/module_utils/``, unchecked imports are only allowed from the Python standard library;
* For other directories in ``plugins/`` (see `the community collection requirements <https://github.com/ansible-collections/overview/blob/main/collection_requirements.rst#modules-plugins>`_ for a list), unchecked imports are only allowed from the Python standard library, from dependencies of ansible-core, and from ansible-core itself. * For other directories in ``plugins/`` (see `the community collection requirements <https://github.com/ansible-collections/overview/blob/main/collection_requirements.rst#modules-plugins>`_ for a list), unchecked imports are only allowed from the Python standard library, from public dependencies of ansible-core, and from ansible-core itself.
Public dependencies of ansible-core are:
* Jinja2
* PyYAML
* MarkupSafe (as a dependency of Jinja2)

@ -0,0 +1,112 @@
#!/usr/bin/env python
# PYTHON_ARGCOMPLETE_OK
"""Generate frozen sanity test requirements from source requirements files."""
from __future__ import annotations
import argparse
import dataclasses
import pathlib
import subprocess
import tempfile
import typing as t
import venv
try:
import argcomplete
except ImportError:
argcomplete = None
FILE = pathlib.Path(__file__).resolve()
ROOT = FILE.parent.parent
SELF = FILE.relative_to(ROOT)
@dataclasses.dataclass(frozen=True)
class SanityTest:
name: str
requirements_path: pathlib.Path
source_path: pathlib.Path
def freeze_requirements(self) -> None:
with tempfile.TemporaryDirectory() as venv_dir:
venv.create(venv_dir, with_pip=True)
python = pathlib.Path(venv_dir, 'bin', 'python')
pip = [python, '-m', 'pip', '--disable-pip-version-check']
env = dict()
pip_freeze = subprocess.run(pip + ['freeze'], env=env, check=True, capture_output=True, text=True)
if pip_freeze.stdout:
raise Exception(f'Initial virtual environment is not empty:\n{pip_freeze.stdout}')
subprocess.run(pip + ['install', 'wheel'], env=env, check=True) # make bdist_wheel available during pip install
subprocess.run(pip + ['install', '-r', self.source_path], env=env, check=True)
pip_freeze = subprocess.run(pip + ['freeze'], env=env, check=True, capture_output=True, text=True)
requirements = f'# edit "{self.source_path.name}" and generate with: {SELF} --test {self.name}\n{pip_freeze.stdout}'
with open(self.requirements_path, 'w') as requirement_file:
requirement_file.write(requirements)
@staticmethod
def create(path: pathlib.Path) -> SanityTest:
return SanityTest(
name=path.stem.replace('sanity.', '').replace('.requirements', ''),
requirements_path=path,
source_path=path.with_suffix('.in'),
)
def main() -> None:
tests = find_tests()
parser = argparse.ArgumentParser()
parser.add_argument(
'--test',
metavar='TEST',
dest='test_names',
action='append',
choices=[test.name for test in tests],
help='test requirements to update'
)
if argcomplete:
argcomplete.autocomplete(parser)
args = parser.parse_args()
test_names: set[str] = set(args.test_names or [])
tests = [test for test in tests if test.name in test_names] if test_names else tests
for test in tests:
print(f'===[ {test.name} ]===')
test.freeze_requirements()
def find_tests() -> t.List[SanityTest]:
globs = (
'test/lib/ansible_test/_data/requirements/sanity.*.txt',
'test/sanity/code-smell/*.requirements.txt',
)
tests: t.List[SanityTest] = []
for glob in globs:
tests.extend(get_tests(pathlib.Path(glob)))
return sorted(tests, key=lambda test: test.name)
def get_tests(glob: pathlib.Path) -> t.List[SanityTest]:
path = pathlib.Path(ROOT, glob.parent)
pattern = glob.name
return [SanityTest.create(item) for item in path.glob(pattern)]
if __name__ == '__main__':
main()

@ -0,0 +1,3 @@
jinja2 # ansible-core requirement
packaging # ansible-core requirement
pyyaml # ansible-core requirement

@ -1,7 +1,6 @@
jinja2 == 3.0.1 # ansible-core requirement # edit "sanity.ansible-doc.in" and generate with: hacking/update-sanity-requirements.py --test ansible-doc
pyyaml == 5.4.1 # ansible-core requirement Jinja2==3.0.3
packaging == 21.0 # ansible-doc requirement MarkupSafe==2.0.1
packaging==21.2
# dependencies pyparsing==2.4.7
MarkupSafe == 2.0.1 PyYAML==6.0
pyparsing == 2.4.7

@ -0,0 +1,2 @@
antsibull-changelog
docutils < 0.18 # match version required by sphinx in the docs-build sanity test

@ -1,9 +1,8 @@
antsibull-changelog == 0.9.0 # edit "sanity.changelog.in" and generate with: hacking/update-sanity-requirements.py --test changelog
antsibull-changelog==0.12.0
# dependencies docutils==0.17.1
pyyaml == 5.4.1 packaging==21.2
docutils == 0.17.1 pyparsing==2.4.7
packaging == 21.0 PyYAML==6.0
pyparsing == 2.4.7 rstcheck==3.3.1
rstcheck == 3.3.1 semantic-version==2.8.5
semantic-version == 2.8.5

@ -0,0 +1 @@
pyyaml # needed for yaml_to_json.py

@ -0,0 +1,2 @@
jinja2 # ansible-core requirement
pyyaml # ansible-core requirement

@ -0,0 +1,4 @@
# edit "sanity.import.plugin.in" and generate with: hacking/update-sanity-requirements.py --test import.plugin
Jinja2==3.0.3
MarkupSafe==2.0.1
PyYAML==6.0

@ -1 +1,2 @@
pyyaml == 5.4.1 # needed for yaml_to_json.py # edit "sanity.import.in" and generate with: hacking/update-sanity-requirements.py --test import
PyYAML==6.0

@ -1 +1,2 @@
pyyaml == 5.4.1 # edit "sanity.integration-aliases.in" and generate with: hacking/update-sanity-requirements.py --test integration-aliases
PyYAML==6.0

@ -1 +1,2 @@
pycodestyle == 2.6.0 # edit "sanity.pep8.in" and generate with: hacking/update-sanity-requirements.py --test pep8
pycodestyle==2.8.0

@ -0,0 +1,2 @@
pylint == 2.9.3 # currently vetted version
pyyaml # needed for collection_detail.py

@ -1,10 +1,9 @@
pylint == 2.9.3 # edit "sanity.pylint.in" and generate with: hacking/update-sanity-requirements.py --test pylint
pyyaml == 5.4.1 # needed for collection_detail.py astroid==2.6.6
isort==5.10.1
# dependencies lazy-object-proxy==1.6.0
astroid == 2.6.6 mccabe==0.6.1
isort == 5.9.3 pylint==2.9.3
lazy-object-proxy == 1.6.0 PyYAML==6.0
mccabe == 0.6.1 toml==0.10.2
toml == 0.10.2 wrapt==1.12.1
wrapt == 1.12.1

@ -1,2 +1,3 @@
pyyaml == 5.4.1 # edit "sanity.runtime-metadata.in" and generate with: hacking/update-sanity-requirements.py --test runtime-metadata
voluptuous == 0.12.1 PyYAML==6.0
voluptuous==0.12.2

@ -0,0 +1,3 @@
jinja2 # ansible-core requirement
pyyaml # needed for collection_detail.py
voluptuous

@ -1,6 +1,5 @@
jinja2 == 3.0.1 # ansible-core requirement # edit "sanity.validate-modules.in" and generate with: hacking/update-sanity-requirements.py --test validate-modules
pyyaml == 5.4.1 # needed for collection_detail.py Jinja2==3.0.3
voluptuous == 0.12.1 MarkupSafe==2.0.1
PyYAML==6.0
# dependencies voluptuous==0.12.2
MarkupSafe == 2.0.1

@ -1,5 +1,4 @@
yamllint == 1.26.0 # edit "sanity.yamllint.in" and generate with: hacking/update-sanity-requirements.py --test yamllint
pathspec==0.9.0
# dependencies PyYAML==6.0
pathspec == 0.9.0 yamllint==1.26.3
pyyaml == 5.4.1

@ -242,7 +242,7 @@ def command_sanity(args): # type: (SanityConfig) -> None
elif isinstance(test, SanitySingleVersion): elif isinstance(test, SanitySingleVersion):
# single version sanity tests use the controller python # single version sanity tests use the controller python
test_profile = host_state.controller_profile test_profile = host_state.controller_profile
virtualenv_python = create_sanity_virtualenv(args, test_profile.python, test.name, context=test.name) virtualenv_python = create_sanity_virtualenv(args, test_profile.python, test.name)
if virtualenv_python: if virtualenv_python:
virtualenv_yaml = check_sanity_virtualenv_yaml(virtualenv_python) virtualenv_yaml = check_sanity_virtualenv_yaml(virtualenv_python)
@ -1077,10 +1077,8 @@ def create_sanity_virtualenv(
args, # type: SanityConfig args, # type: SanityConfig
python, # type: PythonConfig python, # type: PythonConfig
name, # type: str name, # type: str
ansible=False, # type: bool
coverage=False, # type: bool coverage=False, # type: bool
minimize=False, # type: bool minimize=False, # type: bool
context=None, # type: t.Optional[str]
): # type: (...) -> t.Optional[VirtualPythonConfig] ): # type: (...) -> t.Optional[VirtualPythonConfig]
"""Return an existing sanity virtual environment matching the requested parameters or create a new one.""" """Return an existing sanity virtual environment matching the requested parameters or create a new one."""
commands = collect_requirements( # create_sanity_virtualenv() commands = collect_requirements( # create_sanity_virtualenv()
@ -1088,13 +1086,11 @@ def create_sanity_virtualenv(
controller=True, controller=True,
virtualenv=False, virtualenv=False,
command=None, command=None,
# used by import tests ansible=False,
ansible=ansible, cryptography=False,
cryptography=ansible,
coverage=coverage, coverage=coverage,
minimize=minimize, minimize=minimize,
# used by non-import tests sanity=name,
sanity=context,
) )
if commands: if commands:

@ -87,8 +87,17 @@ class ImportTest(SanityMultipleVersion):
"""Sanity test for proper import exception handling.""" """Sanity test for proper import exception handling."""
def filter_targets(self, targets): # type: (t.List[TestTarget]) -> t.List[TestTarget] def filter_targets(self, targets): # type: (t.List[TestTarget]) -> t.List[TestTarget]
"""Return the given list of test targets, filtered to include only those relevant for the test.""" """Return the given list of test targets, filtered to include only those relevant for the test."""
if data_context().content.is_ansible:
# all of ansible-core must pass the import test, not just plugins/modules
# modules/module_utils will be tested using the module context
# everything else will be tested using the plugin context
paths = ['lib/ansible']
else:
# only plugins/modules must pass the import test for collections
paths = list(data_context().content.plugin_paths.values())
return [target for target in targets if os.path.splitext(target.path)[1] == '.py' and return [target for target in targets if os.path.splitext(target.path)[1] == '.py' and
any(is_subdir(target.path, path) for path in data_context().content.plugin_paths.values())] any(is_subdir(target.path, path) for path in paths)]
@property @property
def needs_pypi(self): # type: () -> bool def needs_pypi(self): # type: () -> bool
@ -112,9 +121,9 @@ class ImportTest(SanityMultipleVersion):
messages = [] messages = []
for import_type, test, controller in ( for import_type, test in (
('module', _get_module_test(True), False), ('module', _get_module_test(True)),
('plugin', _get_module_test(False), True), ('plugin', _get_module_test(False)),
): ):
if import_type == 'plugin' and python.version in REMOTE_ONLY_PYTHON_VERSIONS: if import_type == 'plugin' and python.version in REMOTE_ONLY_PYTHON_VERSIONS:
continue continue
@ -124,7 +133,7 @@ class ImportTest(SanityMultipleVersion):
if not data and not args.prime_venvs: if not data and not args.prime_venvs:
continue continue
virtualenv_python = create_sanity_virtualenv(args, python, f'{self.name}.{import_type}', ansible=controller, coverage=args.coverage, minimize=True) virtualenv_python = create_sanity_virtualenv(args, python, f'{self.name}.{import_type}', coverage=args.coverage, minimize=True)
if not virtualenv_python: if not virtualenv_python:
display.warning(f'Skipping sanity test "{self.name}" on Python {python.version} due to missing virtual environment support.') display.warning(f'Skipping sanity test "{self.name}" on Python {python.version} due to missing virtual environment support.')
@ -143,7 +152,7 @@ class ImportTest(SanityMultipleVersion):
) )
if data_context().content.collection: if data_context().content.collection:
external_python = create_sanity_virtualenv(args, args.controller_python, self.name, context=self.name) external_python = create_sanity_virtualenv(args, args.controller_python, self.name)
env.update( env.update(
SANITY_COLLECTION_FULL_NAME=data_context().content.collection.full_name, SANITY_COLLECTION_FULL_NAME=data_context().content.collection.full_name,

@ -1,2 +1,3 @@
pyyaml == 5.4.1 # edit "botmeta.requirements.in" and generate with: hacking/update-sanity-requirements.py --test botmeta
voluptuous == 0.12.1 PyYAML==6.0
voluptuous==0.12.2

@ -0,0 +1,2 @@
jinja2 # ansible-core requirement
pyyaml

@ -1,5 +1,4 @@
jinja2 == 3.0.1 # ansible-core requirement # edit "deprecated-config.requirements.in" and generate with: hacking/update-sanity-requirements.py --test deprecated-config
pyyaml == 5.4.1 Jinja2==3.0.3
MarkupSafe==2.0.1
# dependencies PyYAML==6.0
MarkupSafe == 2.0.1

@ -0,0 +1,8 @@
jinja2
pyyaml
resolvelib < 0.6.0
sphinx == 4.2.0
sphinx-notfound-page
sphinx-ansible-theme
straight.plugin
antsibull

@ -1,50 +1,50 @@
jinja2 == 3.0.1 # edit "docs-build.requirements.in" and generate with: hacking/update-sanity-requirements.py --test docs-build
pyyaml == 5.4.1 aiofiles==0.7.0
resolvelib == 0.5.4 aiohttp==3.8.0
sphinx == 2.1.2 aiosignal==1.2.0
sphinx-notfound-page == 0.7.1 alabaster==0.7.12
sphinx-ansible-theme == 0.8.0 ansible-pygments==0.1.0
straight.plugin == 1.5.0 antsibull==0.39.2
antsibull == 0.26.0 antsibull-changelog==0.12.0
async-timeout==4.0.1
# dependencies asyncio-pool==0.5.2
MarkupSafe == 2.0.1 attrs==21.2.0
aiofiles == 0.7.0 Babel==2.9.1
aiohttp == 3.7.4.post0 certifi==2021.10.8
alabaster == 0.7.12 charset-normalizer==2.0.7
ansible-pygments == 0.1.0 docutils==0.17.1
antsibull-changelog == 0.9.0 frozenlist==1.2.0
async-timeout == 3.0.1 idna==3.3
asyncio-pool == 0.5.2 imagesize==1.3.0
attrs == 21.2.0 Jinja2==3.0.3
babel == 2.9.1 MarkupSafe==2.0.1
certifi == 2021.5.30 multidict==5.2.0
chardet == 4.0.0 packaging==21.2
charset-normalizer == 2.0.5 perky==0.5.5
docutils == 0.17.1 pydantic==1.8.2
idna == 2.5 Pygments==2.10.0
imagesize == 1.2.0 pyparsing==2.4.7
multidict == 5.1.0 pytz==2021.3
packaging == 21.0 PyYAML==6.0
perky == 0.5.5 requests==2.26.0
pydantic == 1.8.2 resolvelib==0.5.4
pygments == 2.10.0 rstcheck==3.3.1
pyparsing == 2.4.7 semantic-version==2.8.5
pytz == 2021.1 sh==1.14.2
requests == 2.26.0 six==1.16.0
rstcheck == 3.3.1 snowballstemmer==2.1.0
semantic-version == 2.8.5 Sphinx==4.2.0
sh == 1.14.2 sphinx-ansible-theme==0.8.0
six == 1.16.0 sphinx-notfound-page==0.8
snowballstemmer == 2.1.0 sphinx-rtd-theme==1.0.0
sphinx-rtd-theme == 1.0.0 sphinxcontrib-applehelp==1.0.2
sphinxcontrib-applehelp == 1.0.2 sphinxcontrib-devhelp==1.0.2
sphinxcontrib-devhelp == 1.0.2 sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-htmlhelp == 2.0.0 sphinxcontrib-jsmath==1.0.1
sphinxcontrib-jsmath == 1.0.1 sphinxcontrib-qthelp==1.0.3
sphinxcontrib-qthelp == 1.0.3 sphinxcontrib-serializinghtml==1.1.5
sphinxcontrib-serializinghtml == 1.1.5 straight.plugin==1.5.0
twiggy == 0.5.1 Twiggy==0.5.1
typing-extensions == 3.10.0.2 typing-extensions==3.10.0.2
urllib3 == 1.26.6 urllib3==1.26.7
yarl == 1.6.3 yarl==1.7.2

@ -0,0 +1,7 @@
docutils < 0.18 # match version required by sphinx in the docs-build sanity test
jinja2
pyyaml # ansible-core requirement
resolvelib < 0.6.0
rstcheck
straight.plugin
antsibull-changelog

@ -1,13 +1,12 @@
docutils == 0.17.1 # edit "package-data.requirements.in" and generate with: hacking/update-sanity-requirements.py --test package-data
jinja2 == 3.0.1 antsibull-changelog==0.12.0
packaging == 21.0 docutils==0.17.1
pyyaml == 5.4.1 # ansible-core requirement Jinja2==3.0.3
resolvelib == 0.5.4 # ansible-core requirement MarkupSafe==2.0.1
rstcheck == 3.3.1 packaging==21.2
straight.plugin == 1.5.0 pyparsing==2.4.7
antsibull-changelog == 0.9.0 PyYAML==6.0
resolvelib==0.5.4
# dependencies rstcheck==3.3.1
MarkupSafe == 2.0.1 semantic-version==2.8.5
pyparsing == 2.4.7 straight.plugin==1.5.0
semantic-version == 2.8.5

@ -1 +1,2 @@
pyyaml == 5.4.1 # edit "release-names.requirements.in" and generate with: hacking/update-sanity-requirements.py --test release-names
PyYAML==6.0

@ -0,0 +1,3 @@
sphinx == 4.2.0 # required for full rstcheck functionality, installed first to get the correct docutils version
rstcheck
jinja2 # ansible-core requirement

@ -1,27 +1,25 @@
rstcheck == 3.3.1 # edit "rstcheck.requirements.in" and generate with: hacking/update-sanity-requirements.py --test rstcheck
sphinx == 2.1.2 # required for full functionality alabaster==0.7.12
Babel==2.9.1
# dependencies certifi==2021.10.8
Jinja2 == 3.0.1 charset-normalizer==2.0.7
MarkupSafe == 2.0.1 docutils==0.17.1
Pygments == 2.10.0 idna==3.3
alabaster == 0.7.12 imagesize==1.3.0
babel == 2.9.1 Jinja2==3.0.3
certifi == 2021.5.30 MarkupSafe==2.0.1
charset-normalizer == 2.0.5 packaging==21.2
docutils == 0.17.1 Pygments==2.10.0
idna == 2.5 pyparsing==2.4.7
imagesize == 1.2.0 pytz==2021.3
packaging == 21.0 requests==2.26.0
pyparsing == 2.4.7 rstcheck==3.3.1
pytz == 2021.1 snowballstemmer==2.1.0
requests == 2.26.0 Sphinx==4.2.0
rstcheck == 3.3.1 sphinxcontrib-applehelp==1.0.2
snowballstemmer == 2.1.0 sphinxcontrib-devhelp==1.0.2
sphinxcontrib-applehelp == 1.0.2 sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-devhelp == 1.0.2 sphinxcontrib-jsmath==1.0.1
sphinxcontrib-htmlhelp == 2.0.0 sphinxcontrib-qthelp==1.0.3
sphinxcontrib-jsmath == 1.0.1 sphinxcontrib-serializinghtml==1.1.5
sphinxcontrib-qthelp == 1.0.3 urllib3==1.26.7
sphinxcontrib-serializinghtml == 1.1.5
urllib3 == 1.26.6

@ -1,6 +1,7 @@
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
import os
import re import re
import sys import sys
@ -21,6 +22,11 @@ def main():
non_sanity_requirements = set() non_sanity_requirements = set()
for path, requirements in requirements.items(): for path, requirements in requirements.items():
filename = os.path.basename(path)
is_sanity = filename.startswith('sanity.') or filename.endswith('.requirements.txt')
is_constraints = path == constraints_path
for lineno, line, requirement in requirements: for lineno, line, requirement in requirements:
if not requirement: if not requirement:
print('%s:%d:%d: cannot parse requirement: %s' % (path, lineno, 1, line)) print('%s:%d:%d: cannot parse requirement: %s' % (path, lineno, 1, line))
@ -28,14 +34,10 @@ def main():
name = requirement.group('name').lower() name = requirement.group('name').lower()
raw_constraints = requirement.group('constraints') raw_constraints = requirement.group('constraints')
raw_markers = requirement.group('markers')
constraints = raw_constraints.strip() constraints = raw_constraints.strip()
markers = raw_markers.strip()
comment = requirement.group('comment') comment = requirement.group('comment')
is_sanity = path.startswith('test/lib/ansible_test/_data/requirements/sanity.') or path.startswith('test/sanity/code-smell/')
is_pinned = re.search('^ *== *[0-9.]+(\\.post[0-9]+)?$', constraints) is_pinned = re.search('^ *== *[0-9.]+(\\.post[0-9]+)?$', constraints)
is_constraints = path == constraints_path
if is_sanity: if is_sanity:
sanity = frozen_sanity.setdefault(name, []) sanity = frozen_sanity.setdefault(name, [])
@ -43,20 +45,19 @@ def main():
elif not is_constraints: elif not is_constraints:
non_sanity_requirements.add(name) non_sanity_requirements.add(name)
if is_sanity:
if not is_pinned:
# sanity test requirements must be pinned
print('%s:%d:%d: sanity test requirement (%s%s) must be frozen (use `==`)' % (path, lineno, 1, name, raw_constraints))
continue
if constraints and not is_constraints: if constraints and not is_constraints:
allow_constraints = 'sanity_ok' in comment allow_constraints = 'sanity_ok' in comment
if is_sanity and is_pinned and not markers:
allow_constraints = True # sanity tests can use frozen requirements without markers
if not allow_constraints: if not allow_constraints:
if is_sanity: # keeping constraints for tests other than sanity tests in one file helps avoid conflicts
# sanity test requirements which need constraints should be frozen to maintain consistent test results print('%s:%d:%d: put the constraint (%s%s) in `%s`' % (path, lineno, 1, name, raw_constraints, constraints_path))
# use of anything other than frozen constraints will make evaluation of conflicts extremely difficult
print('%s:%d:%d: sanity test constraint (%s%s) must be frozen (use `==`)' % (path, lineno, 1, name, raw_constraints))
else:
# keeping constraints for tests other than sanity tests in one file helps avoid conflicts
print('%s:%d:%d: put the constraint (%s%s) in `%s`' % (path, lineno, 1, name, raw_constraints, constraints_path))
for name, requirements in frozen_sanity.items(): for name, requirements in frozen_sanity.items():
if len(set(req[3].group('constraints').strip() for req in requirements)) != 1: if len(set(req[3].group('constraints').strip() for req in requirements)) != 1:

@ -1,4 +1,3 @@
packaging == 21.0 # edit "update-bundled.requirements.in" and generate with: hacking/update-sanity-requirements.py --test update-bundled
packaging==21.2
# dependencies pyparsing==2.4.7
pyparsing == 2.4.7

@ -4,6 +4,39 @@ docs/docsite/rst/locales/ja/LC_MESSAGES/dev_guide.po no-smart-quotes # Translat
examples/scripts/ConfigureRemotingForAnsible.ps1 pslint:PSCustomUseLiteralPath examples/scripts/ConfigureRemotingForAnsible.ps1 pslint:PSCustomUseLiteralPath
examples/scripts/upgrade_to_ps3.ps1 pslint:PSCustomUseLiteralPath examples/scripts/upgrade_to_ps3.ps1 pslint:PSCustomUseLiteralPath
examples/scripts/upgrade_to_ps3.ps1 pslint:PSUseApprovedVerbs examples/scripts/upgrade_to_ps3.ps1 pslint:PSUseApprovedVerbs
lib/ansible/cli/galaxy.py import-3.8 # unguarded indirect resolvelib import
lib/ansible/galaxy/collection/__init__.py import-3.8 # unguarded resolvelib import
lib/ansible/galaxy/collection/concrete_artifact_manager.py import-3.8 # unguarded resolvelib import
lib/ansible/galaxy/collection/galaxy_api_proxy.py import-3.8 # unguarded resolvelib imports
lib/ansible/galaxy/dependency_resolution/__init__.py import-3.8 # circular imports
lib/ansible/galaxy/dependency_resolution/dataclasses.py import-3.8 # circular imports
lib/ansible/galaxy/dependency_resolution/errors.py import-3.8 # circular imports
lib/ansible/galaxy/dependency_resolution/providers.py import-3.8 # circular imports
lib/ansible/galaxy/dependency_resolution/reporters.py import-3.8 # circular imports
lib/ansible/galaxy/dependency_resolution/resolvers.py import-3.8 # circular imports
lib/ansible/galaxy/dependency_resolution/versioning.py import-3.8 # circular imports
lib/ansible/cli/galaxy.py import-3.9 # unguarded indirect resolvelib import
lib/ansible/galaxy/collection/__init__.py import-3.9 # unguarded resolvelib import
lib/ansible/galaxy/collection/concrete_artifact_manager.py import-3.9 # unguarded resolvelib import
lib/ansible/galaxy/collection/galaxy_api_proxy.py import-3.9 # unguarded resolvelib imports
lib/ansible/galaxy/dependency_resolution/__init__.py import-3.9 # circular imports
lib/ansible/galaxy/dependency_resolution/dataclasses.py import-3.9 # circular imports
lib/ansible/galaxy/dependency_resolution/errors.py import-3.9 # circular imports
lib/ansible/galaxy/dependency_resolution/providers.py import-3.9 # circular imports
lib/ansible/galaxy/dependency_resolution/reporters.py import-3.9 # circular imports
lib/ansible/galaxy/dependency_resolution/resolvers.py import-3.9 # circular imports
lib/ansible/galaxy/dependency_resolution/versioning.py import-3.9 # circular imports
lib/ansible/cli/galaxy.py import-3.10 # unguarded indirect resolvelib import
lib/ansible/galaxy/collection/__init__.py import-3.10 # unguarded resolvelib import
lib/ansible/galaxy/collection/concrete_artifact_manager.py import-3.10 # unguarded resolvelib import
lib/ansible/galaxy/collection/galaxy_api_proxy.py import-3.10 # unguarded resolvelib imports
lib/ansible/galaxy/dependency_resolution/__init__.py import-3.10 # circular imports
lib/ansible/galaxy/dependency_resolution/dataclasses.py import-3.10 # circular imports
lib/ansible/galaxy/dependency_resolution/errors.py import-3.10 # circular imports
lib/ansible/galaxy/dependency_resolution/providers.py import-3.10 # circular imports
lib/ansible/galaxy/dependency_resolution/reporters.py import-3.10 # circular imports
lib/ansible/galaxy/dependency_resolution/resolvers.py import-3.10 # circular imports
lib/ansible/galaxy/dependency_resolution/versioning.py import-3.10 # circular imports
lib/ansible/cli/scripts/ansible_connection_cli_stub.py shebang lib/ansible/cli/scripts/ansible_connection_cli_stub.py shebang
lib/ansible/config/base.yml no-unwanted-files lib/ansible/config/base.yml no-unwanted-files
lib/ansible/executor/playbook_executor.py pylint:disallowed-name lib/ansible/executor/playbook_executor.py pylint:disallowed-name

Loading…
Cancel
Save