Get git executable for collections in git repos (#77493)

* Fix traceback installing collections from git repos if git is not installed
pull/77503/head
Sloane Hertel 3 years ago committed by GitHub
parent eef0a1cef9
commit 477c55b0d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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).

@ -30,6 +30,7 @@ from ansible.galaxy import get_collections_galaxy_meta_info
from ansible.galaxy.dependency_resolution.dataclasses import _GALAXY_YAML from ansible.galaxy.dependency_resolution.dataclasses import _GALAXY_YAML
from ansible.galaxy.user_agent import user_agent from ansible.galaxy.user_agent import user_agent
from ansible.module_utils._text import to_bytes, to_native, to_text 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.common.yaml import yaml_load
from ansible.module_utils.six import raise_from from ansible.module_utils.six import raise_from
from ansible.module_utils.urls import open_url from ansible.module_utils.urls import open_url
@ -393,11 +394,19 @@ def _extract_collection_from_git(repo_url, coll_ver, b_path):
prefix=to_bytes(name, errors='surrogate_or_strict'), prefix=to_bytes(name, errors='surrogate_or_strict'),
) # type: bytes ) # 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 # Perform a shallow clone if simply cloning HEAD
if version == '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: 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 # FIXME: '--branch', version
try: try:
@ -411,7 +420,7 @@ def _extract_collection_from_git(repo_url, coll_ver, b_path):
proc_err, proc_err,
) )
git_switch_cmd = 'git', 'checkout', to_text(version) git_switch_cmd = git_executable, 'checkout', to_text(version)
try: try:
subprocess.check_call(git_switch_cmd, cwd=b_checkout_path) subprocess.check_call(git_switch_cmd, cwd=b_checkout_path)
except subprocess.CalledProcessError as proc_err: except subprocess.CalledProcessError as proc_err:

@ -18,6 +18,7 @@ import yaml
from io import BytesIO, StringIO from io import BytesIO, StringIO
from mock import MagicMock, patch from mock import MagicMock, patch
from unittest import mock
import ansible.module_utils.six.moves.urllib.error as urllib_error 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 import collection, api, dependency_resolution
from ansible.galaxy.dependency_resolution.dataclasses import Candidate, Requirement 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._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 import context_objects as co
from ansible.utils.display import Display from ansible.utils.display import Display
@ -172,6 +174,22 @@ def galaxy_server():
return galaxy_api 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( @pytest.mark.parametrize(
'url,version,trailing_slash', 'url,version,trailing_slash',
[ [
@ -194,10 +212,12 @@ def test_concrete_artifact_manager_scm_cmd(url, version, trailing_slash, monkeyp
repo = 'https://github.com/org/repo' repo = 'https://github.com/org/repo'
if trailing_slash: if trailing_slash:
repo += '/' 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[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( @pytest.mark.parametrize(
@ -223,10 +243,11 @@ def test_concrete_artifact_manager_scm_cmd_shallow(url, version, trailing_slash,
repo = 'https://github.com/org/repo' repo = 'https://github.com/org/repo'
if trailing_slash: if trailing_slash:
repo += '/' 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[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): def test_build_requirement_from_path(collection_artifact):

Loading…
Cancel
Save