diff --git a/pyproject.toml b/pyproject.toml index bc2b4bd7..976f4767 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,6 +120,7 @@ disable = [ [tool.pytest.ini_options] # ensure we treat warnings as error filterwarnings = ["error"] +testpaths = ["test"] [tool.ruff] select = ["ALL"] diff --git a/src/ansible_compat/runtime.py b/src/ansible_compat/runtime.py index f014442c..b8dd3deb 100644 --- a/src/ansible_compat/runtime.py +++ b/src/ansible_compat/runtime.py @@ -412,7 +412,9 @@ def install_collection( ) -> None: """Install an Ansible collection. - Can accept version constraints like 'foo.bar:>=1.2.3' + Can accept arguments like: + 'foo.bar:>=1.2.3' + 'git+https://github.com/ansible-collections/ansible.posix.git,main' """ cmd = [ "ansible-galaxy", @@ -423,11 +425,18 @@ def install_collection( if force: cmd.append("--force") + if isinstance(collection, Path): + collection = str(collection) # As ansible-galaxy install is not able to automatically determine # if the range requires a pre-release, we need to manuall add the --pre # flag when needed. - matches = version_re.search(str(collection)) - if matches and CollectionVersion(matches[1]).is_prerelease: + matches = version_re.search(collection) + + if ( + not is_url(collection) + and matches + and CollectionVersion(matches[1]).is_prerelease + ): cmd.append("--pre") cpaths: list[str] = self.config.collections_paths @@ -602,7 +611,7 @@ def prepare_environment( # noqa: C901 required_version, ) self.install_collection( - f"{name}:{required_version}", + f"{name}{',' if is_url(name) else ':'}{required_version}", destination=destination, ) @@ -916,3 +925,8 @@ def search_galaxy_paths(search_dir: Path) -> list[str]: if file_path.is_file(): galaxy_paths.append(str(file_path)) return galaxy_paths + + +def is_url(name: str) -> bool: + """Return True if a dependency name looks like an URL.""" + return bool(re.match("^git[+@]", name)) diff --git a/test/collections/acme.goodies/galaxy.yml b/test/collections/acme.goodies/galaxy.yml index 901429b2..96821154 100644 --- a/test/collections/acme.goodies/galaxy.yml +++ b/test/collections/acme.goodies/galaxy.yml @@ -8,6 +8,7 @@ description: Sample collection to use with molecule dependencies: community.molecule: ">=0.1.0" # used to also test '=>' condition ansible.utils: "*" # used to also test '*' + git+https://github.com/ansible-collections/community.crypto.git: main # tests ability to install from git build_ignore: - "*.egg-info" - .DS_Store diff --git a/test/test_runtime.py b/test/test_runtime.py index 940c81f5..63017eea 100644 --- a/test/test_runtime.py +++ b/test/test_runtime.py @@ -22,7 +22,12 @@ AnsibleCompatError, InvalidPrerequisiteError, ) -from ansible_compat.runtime import CompletedProcess, Runtime, search_galaxy_paths +from ansible_compat.runtime import ( + CompletedProcess, + Runtime, + is_url, + search_galaxy_paths, +) if TYPE_CHECKING: from collections.abc import Iterator @@ -538,6 +543,13 @@ def test_install_collection(runtime: Runtime) -> None: runtime.install_collection("examples/reqs_v2/community-molecule-0.1.0.tar.gz") +def test_install_collection_git(runtime: Runtime) -> None: + """Check that valid collection installs do not fail.""" + runtime.install_collection( + "git+https://github.com/ansible-collections/ansible.posix,main", + ) + + def test_install_collection_dest(runtime: Runtime, tmp_path: pathlib.Path) -> None: """Check that valid collection to custom destination passes.""" # Since Ansible 2.15.3 there is no guarantee that this will install the collection at requested path @@ -728,6 +740,7 @@ def test_runtime_version_in_range( "ansible.posix", # from tests/requirements.yml "ansible.utils", # from galaxy.yml "community.molecule", # from galaxy.yml + "community.crypto", # from galaxy.yml as a git dependency ], id="normal", ), @@ -890,3 +903,28 @@ def test_runtime_plugins(runtime: Runtime) -> None: def test_galaxy_path(path: str, result: list[str]) -> None: """Check behavior of galaxy path search.""" assert search_galaxy_paths(Path(path)) == result + + +@pytest.mark.parametrize( + ("name", "result"), + ( + pytest.param( + "foo", + False, + id="0", + ), + pytest.param( + "git+git", + True, + id="1", + ), + pytest.param( + "git@acme.com", + True, + id="2", + ), + ), +) +def test_is_url(name: str, result: bool) -> None: + """Checks functionality of is_url.""" + assert is_url(name) == result diff --git a/tox.ini b/tox.ini index 484059e9..e9613ee7 100644 --- a/tox.ini +++ b/tox.ini @@ -71,7 +71,7 @@ setenv = PIP_DISABLE_PIP_VERSION_CHECK = 1 PIP_CONSTRAINT = {toxinidir}/requirements.txt PRE_COMMIT_COLOR = always - PYTEST_REQPASS = 89 + PYTEST_REQPASS = 93 FORCE_COLOR = 1 allowlist_externals = ansible