diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index bc1b51c038..f7dd572756 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -25,17 +25,17 @@ jobs: - tox_env: lint - tox_env: docs - tox_env: py36 - PREFIX: PYTEST_REQPASS=449 + PREFIX: PYTEST_REQPASS=448 - tox_env: py37 - PREFIX: PYTEST_REQPASS=449 + PREFIX: PYTEST_REQPASS=448 - tox_env: py38 - PREFIX: PYTEST_REQPASS=449 + PREFIX: PYTEST_REQPASS=448 - tox_env: py39 - PREFIX: PYTEST_REQPASS=449 + PREFIX: PYTEST_REQPASS=448 - tox_env: py36-devel - PREFIX: PYTEST_REQPASS=449 + PREFIX: PYTEST_REQPASS=448 - tox_env: py39-devel - PREFIX: PYTEST_REQPASS=449 + PREFIX: PYTEST_REQPASS=448 - tox_env: packaging - tox_env: eco - tox_env: dockerfile diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f911387278..c8a2995206 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -54,7 +54,7 @@ repos: entry: mypy src/ pass_filenames: false additional_dependencies: - - ansible-lint>=5.1.2 + - ansible-compat>=0.3.0 - click>=8.0.1 - enrich>=1.2.5 - importlib-metadata>=4.6.1 diff --git a/setup.cfg b/setup.cfg index d5f4787191..7c1e542d0c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -66,7 +66,7 @@ setup_requires = # These are required in actual runtime: install_requires = - ansible-lint >= 5.1.1 # only for the prerun functionality + ansible-compat >= 0.3.0 cerberus >= 1.3.1, !=1.3.3, !=1.3.4 click >= 8.0, < 9 click-help-colors >= 0.9 diff --git a/src/molecule/command/base.py b/src/molecule/command/base.py index d32f57c7de..b85b0324ab 100644 --- a/src/molecule/command/base.py +++ b/src/molecule/command/base.py @@ -28,7 +28,6 @@ from typing import Any, Callable import click -from ansiblelint.prerun import prepare_environment from click_help_colors import HelpColorsCommand, HelpColorsGroup import molecule.scenarios @@ -109,7 +108,7 @@ def execute_cmdline_scenarios(scenario_name, args, command_args, ansible_args=() if scenario.config.config["prerun"]: LOG.info("Performing prerun...") - prepare_environment() + scenario.config.runtime.prepare_environment() if command_args.get("subcommand") == "reset": LOG.info("Removing %s" % scenario.ephemeral_directory) diff --git a/src/molecule/config.py b/src/molecule/config.py index 0c1bfc41b7..ab5cc85960 100644 --- a/src/molecule/config.py +++ b/src/molecule/config.py @@ -23,10 +23,12 @@ import functools import logging import os +import warnings from typing import Callable, MutableMapping, TypeVar from uuid import uuid4 -from ansiblelint.config import ansible_version +from ansible_compat.runtime import Runtime +from packaging.version import Version from molecule import api, interpolation, platforms, scenario, state, util from molecule.dependency import ansible_galaxy, shell @@ -51,6 +53,16 @@ def cache(func: Callable[..., T]) -> T: return functools.lru_cache()(func) # type: ignore +@cache +def ansible_version() -> Version: + """Retrieve Ansible version.""" + warnings.warn( + "molecule.config.ansible_version is deprecated, will be removed in the future.", + category=DeprecationWarning, + ) + return Runtime().version + + # https://stackoverflow.com/questions/16017397/injecting-function-call-after-init-with-decorator # noqa class NewInitCaller(type): """NewInitCaller.""" @@ -102,6 +114,7 @@ def __init__(self, molecule_file: str, args={}, command_args={}, ansible_args=() self._action = None self._run_uuid = str(uuid4()) self.project_directory = os.getenv("MOLECULE_PROJECT_DIRECTORY", os.getcwd()) + self.runtime = Runtime(isolated=True) def after_init(self): self.config = self._reget_config() @@ -115,7 +128,7 @@ def write(self) -> None: def ansible_collections_path(self): """Return collection path variable for current version of Ansible.""" # https://github.com/ansible/ansible/pull/70007 - if ansible_version() >= ansible_version("2.10.0.dev0"): + if self.runtime.version >= Version("2.10.0.dev0"): return "ANSIBLE_COLLECTIONS_PATH" else: return "ANSIBLE_COLLECTIONS_PATHS" diff --git a/src/molecule/dependency/base.py b/src/molecule/dependency/base.py index 6e0fb78c35..8b6eedaaae 100644 --- a/src/molecule/dependency/base.py +++ b/src/molecule/dependency/base.py @@ -110,10 +110,6 @@ def default_env(self): # pragma: no cover :return: dict """ env = util.merge_dicts(os.environ, self._config.env) - # inject ephemeral_directory on top of path - env[self._config.ansible_collections_path] = os.path.join( - self._config.scenario.ephemeral_directory, "collections" - ) return env @property diff --git a/src/molecule/provisioner/ansible.py b/src/molecule/provisioner/ansible.py index 734429cb3f..72ac636640 100644 --- a/src/molecule/provisioner/ansible.py +++ b/src/molecule/provisioner/ansible.py @@ -457,7 +457,6 @@ def default_env(self): *os.environ.get("ANSIBLE_ROLES_PATH", "").split(":"), ] ), - self._config.ansible_collections_path: ":".join(collections_path_list), "ANSIBLE_LIBRARY": ":".join(self._get_modules_directories()), "ANSIBLE_FILTER_PLUGINS": ":".join( [ diff --git a/src/molecule/shell.py b/src/molecule/shell.py index 4c5de77cd9..27c789f06e 100644 --- a/src/molecule/shell.py +++ b/src/molecule/shell.py @@ -24,12 +24,13 @@ import click import pkg_resources +from ansible_compat.runtime import Runtime import molecule from molecule import command, logger from molecule.api import drivers from molecule.command.base import click_group_ex -from molecule.config import MOLECULE_DEBUG, MOLECULE_VERBOSITY, ansible_version +from molecule.config import MOLECULE_DEBUG, MOLECULE_VERBOSITY from molecule.console import console from molecule.util import do_report, lookup_config_file @@ -59,9 +60,8 @@ def print_version(ctx, param, value): color = "bright_yellow" if v.is_prerelease else "green" msg = f"molecule [{color}]{v}[/] using python [repr.number]{sys.version_info[0]}.{sys.version_info[1]}[/] \n" - msg += ( - f" [repr.attrib_name]ansible[/][dim]:[/][repr.number]{ansible_version()}[/]" - ) + runtime = Runtime() + msg += f" [repr.attrib_name]ansible[/][dim]:[/][repr.number]{runtime.version}[/]" for driver in drivers(): msg += f"\n [repr.attrib_name]{str(driver)}[/][dim]:[/][repr.number]{driver.version}[/][dim] from {driver.module}[/]" if driver.required_collections: diff --git a/src/molecule/test/functional/conftest.py b/src/molecule/test/functional/conftest.py index 46c5003131..d94104f783 100644 --- a/src/molecule/test/functional/conftest.py +++ b/src/molecule/test/functional/conftest.py @@ -28,9 +28,10 @@ import pexpect import pkg_resources import pytest +from ansible_compat.runtime import Runtime +from packaging.version import Version from molecule import logger, util -from molecule.config import ansible_version from molecule.test.conftest import change_dir_to, molecule_directory from molecule.text import strip_ansi_color from molecule.util import run_command @@ -257,4 +258,5 @@ def supports_docker() -> bool: def min_ansible(version: str) -> bool: """Ensure current Ansible is newer than a given a minimal one.""" - return ansible_version() >= ansible_version(version) + runtime = Runtime() + return bool(runtime.version >= Version(version)) diff --git a/src/molecule/test/unit/conftest.py b/src/molecule/test/unit/conftest.py index 90a128979f..baea801e10 100644 --- a/src/molecule/test/unit/conftest.py +++ b/src/molecule/test/unit/conftest.py @@ -24,7 +24,7 @@ import shutil from pathlib import Path from subprocess import CompletedProcess -from typing import Any, Tuple +from typing import Any, Generator, Tuple from uuid import uuid4 import pytest @@ -145,15 +145,19 @@ def molecule_file_fixture( @pytest.fixture def config_instance( molecule_file_fixture: str, molecule_data, request -) -> config.Config: +) -> Generator[config.Config, None, None]: mdc = copy.deepcopy(molecule_data) if hasattr(request, "param"): mdc = util.merge_dicts(mdc, request.getfixturevalue(request.param)) - write_molecule_file(molecule_file_fixture, mdc) + pytest.helpers.write_molecule_file(molecule_file_fixture, mdc) + + _environ = dict(os.environ) c = config.Config(molecule_file_fixture) c.command_args = {"subcommand": "test"} - - return c + yield c + # restore environ which can be modified by Config() + os.environ.clear() + os.environ.update(_environ) # Mocks diff --git a/src/molecule/test/unit/provisioner/test_ansible.py b/src/molecule/test/unit/provisioner/test_ansible.py index 0bdde7d13d..ea3f294e84 100644 --- a/src/molecule/test/unit/provisioner/test_ansible.py +++ b/src/molecule/test/unit/provisioner/test_ansible.py @@ -134,18 +134,6 @@ def test_default_env_property(_instance): assert "ANSIBLE_FILTER_PLUGINS" in _instance.env -def test_default_env_property_collections_path(config_instance): - config_instance.project_directory = ( - "/some/path/ansible_collections/namespace/collection/but/not/really" - "/ansible_collections/other_ns/other_name/and/some/more/segments" - ) - - env = ansible.Ansible(config_instance).default_env - - paths = env[config_instance.ansible_collections_path].split(":") - assert "/some/path/ansible_collections/namespace/collection/but/not/really" in paths - - def test_name_property(_instance): assert "ansible" == _instance.name