summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSloane Hertel <19572925+s-hertel@users.noreply.github.com>2022-04-13 12:21:55 -0400
committerGitHub <noreply@github.com>2022-04-13 11:21:55 -0500
commit8bbcfebd5c7e5efeb9c8dc173a3fa5ebceab3df5 (patch)
tree5dcde28e76aaad2025b7b4f95c6e113b2c2fa2c3
parentefbe050c29d11153253724d83c77ce343ff67c3f (diff)
downloadansible-8bbcfebd5c7e5efeb9c8dc173a3fa5ebceab3df5.tar.gz
Get git executable for collections in git repos (#77493) (#77501)
* Fix traceback installing collections from git repos if git is not installed (cherry picked from commit 477c55b0d231dcb62cfcec21fe93a8fee95b4215)
-rw-r--r--changelogs/fragments/77493-ansible-galaxy-find-git-executable-before-using.yaml2
-rw-r--r--lib/ansible/galaxy/collection/concrete_artifact_manager.py15
-rw-r--r--test/units/galaxy/test_collection_install.py29
3 files changed, 39 insertions, 7 deletions
diff --git a/changelogs/fragments/77493-ansible-galaxy-find-git-executable-before-using.yaml b/changelogs/fragments/77493-ansible-galaxy-find-git-executable-before-using.yaml
new file mode 100644
index 0000000000..835bd6a926
--- /dev/null
+++ b/changelogs/fragments/77493-ansible-galaxy-find-git-executable-before-using.yaml
@@ -0,0 +1,2 @@
+bugfixes:
+ - Fix traceback when installing a collection from a git repository and git is not installed (https://github.com/ansible/ansible/issues/77479).
diff --git a/lib/ansible/galaxy/collection/concrete_artifact_manager.py b/lib/ansible/galaxy/collection/concrete_artifact_manager.py
index 73b392f45c..5be1eaabc9 100644
--- a/lib/ansible/galaxy/collection/concrete_artifact_manager.py
+++ b/lib/ansible/galaxy/collection/concrete_artifact_manager.py
@@ -38,6 +38,7 @@ from ansible.galaxy import get_collections_galaxy_meta_info
from ansible.galaxy.dependency_resolution.dataclasses import _GALAXY_YAML
from ansible.galaxy.user_agent import user_agent
from ansible.module_utils._text import to_bytes, to_native, to_text
+from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.yaml import yaml_load
from ansible.module_utils.six.moves.urllib.error import URLError
from ansible.module_utils.six.moves.urllib.parse import urldefrag
@@ -350,11 +351,19 @@ def _extract_collection_from_git(repo_url, coll_ver, b_path):
prefix=to_bytes(name, errors='surrogate_or_strict'),
) # type: bytes
+ try:
+ git_executable = get_bin_path('git')
+ except ValueError as err:
+ raise AnsibleError(
+ "Could not find git executable to extract the collection from the Git repository `{repo_url!s}`.".
+ format(repo_url=to_native(git_url))
+ ) from err
+
# Perform a shallow clone if simply cloning HEAD
if version == 'HEAD':
- git_clone_cmd = 'git', 'clone', '--depth=1', git_url, to_text(b_checkout_path)
+ git_clone_cmd = git_executable, 'clone', '--depth=1', git_url, to_text(b_checkout_path)
else:
- git_clone_cmd = 'git', 'clone', git_url, to_text(b_checkout_path)
+ git_clone_cmd = git_executable, 'clone', git_url, to_text(b_checkout_path)
# FIXME: '--branch', version
try:
@@ -368,7 +377,7 @@ def _extract_collection_from_git(repo_url, coll_ver, b_path):
proc_err,
)
- git_switch_cmd = 'git', 'checkout', to_text(version)
+ git_switch_cmd = git_executable, 'checkout', to_text(version)
try:
subprocess.check_call(git_switch_cmd, cwd=b_checkout_path)
except subprocess.CalledProcessError as proc_err:
diff --git a/test/units/galaxy/test_collection_install.py b/test/units/galaxy/test_collection_install.py
index d4565fd59d..00e082d7cd 100644
--- a/test/units/galaxy/test_collection_install.py
+++ b/test/units/galaxy/test_collection_install.py
@@ -18,6 +18,7 @@ import yaml
from io import BytesIO, StringIO
from units.compat.mock import MagicMock
+from unittest import mock
import ansible.module_utils.six.moves.urllib.error as urllib_error
@@ -27,6 +28,7 @@ from ansible.errors import AnsibleError
from ansible.galaxy import collection, api, dependency_resolution
from ansible.galaxy.dependency_resolution.dataclasses import Candidate, Requirement
from ansible.module_utils._text import to_bytes, to_native, to_text
+from ansible.module_utils.common.process import get_bin_path
from ansible.utils import context_objects as co
from ansible.utils.display import Display
@@ -171,6 +173,22 @@ def galaxy_server():
return galaxy_api
+def test_concrete_artifact_manager_scm_no_executable(monkeypatch):
+ url = 'https://github.com/org/repo'
+ version = 'commitish'
+ mock_subprocess_check_call = MagicMock()
+ monkeypatch.setattr(collection.concrete_artifact_manager.subprocess, 'check_call', mock_subprocess_check_call)
+ mock_mkdtemp = MagicMock(return_value='')
+ monkeypatch.setattr(collection.concrete_artifact_manager, 'mkdtemp', mock_mkdtemp)
+
+ error = re.escape(
+ "Could not find git executable to extract the collection from the Git repository `https://github.com/org/repo`"
+ )
+ with mock.patch.dict(os.environ, {"PATH": ""}):
+ with pytest.raises(AnsibleError, match=error):
+ collection.concrete_artifact_manager._extract_collection_from_git(url, version, b'path')
+
+
@pytest.mark.parametrize(
'url,version,trailing_slash',
[
@@ -193,10 +211,12 @@ def test_concrete_artifact_manager_scm_cmd(url, version, trailing_slash, monkeyp
repo = 'https://github.com/org/repo'
if trailing_slash:
repo += '/'
- clone_cmd = ('git', 'clone', repo, '')
+
+ git_executable = get_bin_path('git')
+ clone_cmd = (git_executable, 'clone', repo, '')
assert mock_subprocess_check_call.call_args_list[0].args[0] == clone_cmd
- assert mock_subprocess_check_call.call_args_list[1].args[0] == ('git', 'checkout', 'commitish')
+ assert mock_subprocess_check_call.call_args_list[1].args[0] == (git_executable, 'checkout', 'commitish')
@pytest.mark.parametrize(
@@ -222,10 +242,11 @@ def test_concrete_artifact_manager_scm_cmd_shallow(url, version, trailing_slash,
repo = 'https://github.com/org/repo'
if trailing_slash:
repo += '/'
- shallow_clone_cmd = ('git', 'clone', '--depth=1', repo, '')
+ git_executable = get_bin_path('git')
+ shallow_clone_cmd = (git_executable, 'clone', '--depth=1', repo, '')
assert mock_subprocess_check_call.call_args_list[0].args[0] == shallow_clone_cmd
- assert mock_subprocess_check_call.call_args_list[1].args[0] == ('git', 'checkout', 'HEAD')
+ assert mock_subprocess_check_call.call_args_list[1].args[0] == (git_executable, 'checkout', 'HEAD')
def test_build_requirement_from_path(collection_artifact):