diff --git a/src/ansible_compat/constants.py b/src/ansible_compat/constants.py index 857c4e5a..9c2fa9b5 100644 --- a/src/ansible_compat/constants.py +++ b/src/ansible_compat/constants.py @@ -14,7 +14,7 @@ INVALID_PREREQUISITES_RC = 10 MSG_INVALID_FQRL = """\ -Computed fully qualified role name of %s does not follow current galaxy requirements. +Computed fully qualified role name of {0} does not follow current galaxy requirements. Please edit meta/main.yml and assure we can correctly determine full role name: galaxy_info: diff --git a/src/ansible_compat/runtime.py b/src/ansible_compat/runtime.py index 5a0361c5..b3625715 100644 --- a/src/ansible_compat/runtime.py +++ b/src/ansible_compat/runtime.py @@ -240,7 +240,9 @@ def prepare_environment( if not offline: self.install_requirements("requirements.yml") - for req in pathlib.Path(".").glob("molecule/*/requirements.yml"): + for req in pathlib.Path(self.project_dir).glob( + "molecule/*/requirements.yml" + ): self.install_requirements(str(req)) for name, min_version in required_collections.items(): @@ -249,9 +251,8 @@ def prepare_environment( destination=f"{self.cache_dir}/collections" if self.cache_dir else None, ) - _install_galaxy_role(self.project_dir) - # _perform_mockings() self._prepare_ansible_paths() + _install_galaxy_role(self.project_dir) def require_collection( # noqa: C901 self, @@ -362,13 +363,14 @@ def _install_galaxy_role(project_dir: str, role_name_check: int = 0) -> None: 1: warn if name is not compliant 2: bypass any name checking """ - if not os.path.exists("meta/main.yml"): + meta_filename = os.path.join(project_dir, 'meta', 'main.yml') + if not os.path.exists(meta_filename): return - yaml = yaml_from_file("meta/main.yml") + yaml = yaml_from_file(meta_filename) if 'galaxy_info' not in yaml: return - fqrn = _get_role_fqrn(yaml['galaxy_info']) + fqrn = _get_role_fqrn(yaml['galaxy_info'], project_dir) if role_name_check in [0, 1]: if not re.match(r"[a-z0-9][a-z0-9_]+\.[a-z][a-z0-9_]+$", fqrn): @@ -385,7 +387,7 @@ def _install_galaxy_role(project_dir: str, role_name_check: int = 0) -> None: role_name = _get_galaxy_role_name(yaml['galaxy_info']) fqrn = f"{role_namespace}{role_name}" else: - fqrn = pathlib.Path(".").absolute().name + fqrn = pathlib.Path(project_dir).absolute().name path = pathlib.Path(f"{get_cache_dir(project_dir)}/roles") path.mkdir(parents=True, exist_ok=True) link_path = path / fqrn @@ -402,13 +404,15 @@ def _install_galaxy_role(project_dir: str, role_name_check: int = 0) -> None: ) -def _get_role_fqrn(galaxy_infos: Dict[str, Any]) -> str: +def _get_role_fqrn(galaxy_infos: Dict[str, Any], project_dir: str) -> str: """Compute role fqrn.""" role_namespace = _get_galaxy_role_ns(galaxy_infos) role_name = _get_galaxy_role_name(galaxy_infos) if len(role_name) == 0: - role_name = pathlib.Path(".").absolute().name - role_name = re.sub(r'(ansible-|ansible-role-)', '', role_name) + role_name = pathlib.Path(project_dir).absolute().name + role_name = re.sub(r'(ansible-|ansible-role-)', '', role_name).split( + ".", maxsplit=2 + )[-1] return f"{role_namespace}{role_name}" @@ -441,7 +445,7 @@ def _get_galaxy_role_ns(galaxy_infos: Dict[str, Any]) -> str: ) # if there's a space in the name space, it's likely author name # and not the galaxy login, so act as if there was no namespace - if re.match(r"^\w+ \w+", role_namespace): + if not role_namespace or re.match(r"^\w+ \w+", role_namespace): role_namespace = "" else: role_namespace = f"{role_namespace}." diff --git a/test/roles/acme.sample2/meta/main.yml b/test/roles/acme.sample2/meta/main.yml new file mode 100644 index 00000000..b682a846 --- /dev/null +++ b/test/roles/acme.sample2/meta/main.yml @@ -0,0 +1,16 @@ +--- +dependencies: [] + +galaxy_info: + # role_name is missing in order to test deduction from folder name + author: acme + description: ACME sample role + company: "ACME LTD" + license: MIT + min_ansible_version: "2.9" + platforms: + - name: Debian + versions: + - any + galaxy_tags: + - samples diff --git a/test/roles/ansible-role-sample/meta/main.yml b/test/roles/ansible-role-sample/meta/main.yml new file mode 100644 index 00000000..bfddeb7b --- /dev/null +++ b/test/roles/ansible-role-sample/meta/main.yml @@ -0,0 +1,16 @@ +--- +dependencies: [] + +galaxy_info: + role_name: sample + author: acme + description: ACME sample role + company: "ACME LTD" + license: MIT + min_ansible_version: "2.9" + platforms: + - name: Debian + versions: + - any + galaxy_tags: + - samples diff --git a/test/roles/sample3/meta/main.yml b/test/roles/sample3/meta/main.yml new file mode 100644 index 00000000..f4797883 --- /dev/null +++ b/test/roles/sample3/meta/main.yml @@ -0,0 +1,16 @@ +--- +dependencies: [] + +galaxy_info: + # role_name is missing in order to test deduction from folder name + author: acme + description: ACME samble role + company: "ACME LTD" + license: MIT + min_ansible_version: "2.9" + platforms: + - name: Debian + versions: + - any + galaxy_tags: + - samples diff --git a/test/test_runtime.py b/test/test_runtime.py index c58e6f04..cc8c10bd 100644 --- a/test/test_runtime.py +++ b/test/test_runtime.py @@ -87,6 +87,34 @@ def test_runtime_version_fail_cli(mocker: MockerFixture) -> None: runtime.version # pylint: disable=pointless-statement +@pytest.mark.parametrize( + ("folder", "role_name"), + ( + ("ansible-role-sample", "acme.sample"), + ("acme.sample2", "acme.sample2"), + ("sample3", "acme.sample3"), + ), + ids=("sample", "sample2", "sample3"), +) +def test_runtime_install_role( + caplog: pytest.LogCaptureFixture, folder: str, role_name: str +) -> None: + """Checks that we can install roles.""" + caplog.set_level(logging.INFO) + project_dir = os.path.join(os.path.dirname(__file__), "roles", folder) + runtime = Runtime(isolated=True, project_dir=project_dir) + runtime.prepare_environment() + assert ( + "symlink to current repository in order to enable Ansible to find the role" + in caplog.text + ) + # check that role appears as installed now + result = runtime.exec(["ansible-galaxy", "list"]) + assert result.returncode == 0, result + assert role_name in result.stdout + runtime.clean() + + def test_runtime_install_requirements_missing_file() -> None: """Check that missing requirements file is ignored.""" # Do not rely on this behavior, it may be removed in the future diff --git a/tox.ini b/tox.ini index 0bff9af3..93359440 100644 --- a/tox.ini +++ b/tox.ini @@ -45,7 +45,7 @@ setenv = PIP_DISABLE_PIP_VERSION_CHECK = 1 PIP_CONSTRAINT = {toxinidir}/constraints.txt PRE_COMMIT_COLOR = always - PYTEST_REQPASS = 35 + PYTEST_REQPASS = 38 FORCE_COLOR = 1 allowlist_externals = sh