Skip to content

Commit e1ca5b3

Browse files
authored
pass and init proxy settings in dulwich and pygit2 (#378)
* pass and init proxy settings in dulwich and pygit2 * add tests, fix more methods in dulwich * lint * debug tests * drop pytest socket * fix windows path to gitconfig
1 parent 37b5958 commit e1ca5b3

File tree

5 files changed

+108
-10
lines changed

5 files changed

+108
-10
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,4 @@ dmypy.json
138138
cython_debug/
139139

140140
.DS_Store
141+
.vscode/

pyproject.toml

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ tests = [
4848
"pytest-mock",
4949
"pytest-sugar",
5050
"pytest-test-utils>=0.1.0,<0.2",
51+
"proxy.py",
5152
]
5253
dev = [
5354
"mypy==1.11.2",
@@ -73,6 +74,7 @@ markers = [
7374
]
7475
asyncio_mode = "auto"
7576

77+
7678
[tool.coverage.run]
7779
branch = true
7880
source = ["scmrepo", "tests"]

src/scmrepo/git/backend/dulwich/__init__.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
Union,
1717
)
1818

19+
from dulwich.config import ConfigFile, StackedConfig
1920
from funcy import cached_property, reraise
2021

2122
from scmrepo.exceptions import AuthError, CloneError, InvalidRemote, RevError, SCMError
@@ -27,7 +28,7 @@
2728

2829
if TYPE_CHECKING:
2930
from dulwich.client import SSHVendor
30-
from dulwich.config import ConfigFile, StackedConfig
31+
from dulwich.config import ConfigFile
3132
from dulwich.repo import Repo
3233

3334
from scmrepo.git.objects import GitCommit
@@ -579,7 +580,8 @@ def iter_remote_refs(self, url: str, base: Optional[str] = None, **kwargs):
579580

580581
try:
581582
_remote, location = get_remote_repo(self.repo, url)
582-
client, path = get_transport_and_path(location, **kwargs)
583+
_config = kwargs.pop("config", StackedConfig.default())
584+
client, path = get_transport_and_path(location, config=_config, **kwargs)
583585
except Exception as exc:
584586
raise InvalidRemote(url) from exc
585587

@@ -616,7 +618,8 @@ def push_refspecs( # noqa: C901
616618

617619
try:
618620
_remote, location = get_remote_repo(self.repo, url)
619-
client, path = get_transport_and_path(location, **kwargs)
621+
_config = kwargs.pop("config", StackedConfig.default())
622+
client, path = get_transport_and_path(location, config=_config, **kwargs)
620623
except Exception as exc:
621624
raise SCMError(f"'{url}' is not a valid Git remote or URL") from exc
622625

@@ -723,7 +726,8 @@ def determine_wants(
723726

724727
with reraise(Exception, SCMError(f"'{url}' is not a valid Git remote or URL")):
725728
_remote, location = get_remote_repo(self.repo, url)
726-
client, path = get_transport_and_path(location, **kwargs)
729+
_config = kwargs.pop("config", StackedConfig.default())
730+
client, path = get_transport_and_path(location, config=_config, **kwargs)
727731

728732
with reraise(
729733
(NotGitRepository, KeyError),
@@ -909,6 +913,7 @@ def validate_git_remote(self, url: str, **kwargs):
909913

910914
try:
911915
_, location = get_remote_repo(self.repo, url)
916+
_config = kwargs.pop("config", StackedConfig.default())
912917
client, path = get_transport_and_path(location, **kwargs)
913918
except Exception as exc:
914919
raise InvalidRemote(url) from exc

src/scmrepo/git/backend/pygit2/__init__.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -701,15 +701,13 @@ def _default_status(
701701
remote_refs: dict[str, Oid] = (
702702
{
703703
head["name"]: head["oid"]
704-
for head in remote.ls_remotes(callbacks=cb)
704+
for head in remote.ls_remotes(callbacks=cb, proxy=True)
705705
}
706706
if not force
707707
else {}
708708
)
709709
remote.fetch(
710-
refspecs=refspecs,
711-
callbacks=cb,
712-
message="fetch",
710+
refspecs=refspecs, callbacks=cb, message="fetch", proxy=True
713711
)
714712

715713
result: dict[str, SyncStatus] = {}

tests/test_git.py

+94-2
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,41 @@
11
import os
22
import shutil
3+
from pathlib import Path
34
from typing import Any, Optional
45

56
import pytest
67
from asyncssh import SFTPClient
78
from asyncssh.connection import SSHClientConnection
89
from dulwich.client import LocalGitClient
910
from git import Repo as GitPythonRepo
11+
from proxy import TestCase as ProxyTestCase
1012
from pygit2 import GitError
1113
from pygit2.remotes import Remote
1214
from pytest_mock import MockerFixture
1315
from pytest_test_utils import TempDirFactory, TmpDir
1416
from pytest_test_utils.matchers import Matcher
1517

16-
from scmrepo.exceptions import InvalidRemote, MergeConflictError, RevError, SCMError
17-
from scmrepo.git import Git
18+
from scmrepo.exceptions import (
19+
InvalidRemote,
20+
MergeConflictError,
21+
RevError,
22+
SCMError,
23+
)
24+
from scmrepo.git import Git, GitBackends
1825
from scmrepo.git.objects import GitTag
1926

2027
from .conftest import backends
2128

2229
# pylint: disable=redefined-outer-name,unused-argument,protected-access
2330

2431

32+
BAD_PROXY_CONFIG = """[http]
33+
proxy = "http://bad-proxy.dvc.org"
34+
[https]
35+
proxy = "http://bad-proxy.dvc.org"
36+
"""
37+
38+
2539
@pytest.fixture
2640
def submodule_dir(tmp_dir: TmpDir, scm: Git):
2741
scm.commit("init")
@@ -941,6 +955,84 @@ def test_clone(
941955
assert fobj.read().strip() == "foo"
942956

943957

958+
@pytest.fixture
959+
def proxy_server():
960+
class _ProxyServer(ProxyTestCase):
961+
pass
962+
963+
_ProxyServer.setUpClass()
964+
yield f"http://{_ProxyServer.PROXY.flags.hostname}:{_ProxyServer.PROXY.flags.port}"
965+
_ProxyServer.tearDownClass()
966+
967+
968+
def test_clone_proxy_server(proxy_server: str, scm: Git, git: Git, tmp_dir: TmpDir):
969+
url = "https://github.com/iterative/dvcyaml-schema"
970+
971+
p = (
972+
Path(os.environ["HOME"] if "HOME" in os.environ else os.environ["USERPROFILE"])
973+
/ ".gitconfig"
974+
)
975+
p.write_text(BAD_PROXY_CONFIG)
976+
with pytest.raises(Exception): # noqa: PT011, B017
977+
git.clone(url, "dir")
978+
979+
mock_config_content = f"""[http]\n
980+
proxy = {proxy_server}
981+
[https]
982+
proxy = {proxy_server}
983+
"""
984+
985+
p.write_text(mock_config_content)
986+
git.clone(url, "dir")
987+
988+
989+
def test_iter_remote_refs_proxy_server(proxy_server: str, scm: Git, tmp_dir: TmpDir):
990+
url = "https://github.com/iterative/dvcyaml-schema"
991+
git = GitBackends.DEFAULT["dulwich"](".")
992+
993+
p = (
994+
Path(os.environ["HOME"] if "HOME" in os.environ else os.environ["USERPROFILE"])
995+
/ ".gitconfig"
996+
)
997+
p.write_text(BAD_PROXY_CONFIG)
998+
with pytest.raises(Exception): # noqa: PT011, B017
999+
list(git.iter_remote_refs(url))
1000+
1001+
mock_config_content = f"""[http]
1002+
proxy = {proxy_server}
1003+
[https]
1004+
proxy = {proxy_server}
1005+
"""
1006+
1007+
p.write_text(mock_config_content)
1008+
res = list(git.iter_remote_refs(url))
1009+
assert res
1010+
1011+
1012+
@pytest.mark.skip_git_backend("gitpython")
1013+
def test_fetch_refspecs_proxy_server(
1014+
proxy_server: str, scm: Git, git: Git, tmp_dir: TmpDir
1015+
):
1016+
url = "https://github.com/iterative/dvcyaml-schema"
1017+
1018+
p = (
1019+
Path(os.environ["HOME"] if "HOME" in os.environ else os.environ["USERPROFILE"])
1020+
/ ".gitconfig"
1021+
)
1022+
p.write_text(BAD_PROXY_CONFIG)
1023+
with pytest.raises(Exception): # noqa: PT011, B017
1024+
git.fetch_refspecs(url, ["refs/heads/master:refs/heads/master"])
1025+
1026+
mock_config_content = f"""[http]
1027+
proxy = {proxy_server}
1028+
[https]
1029+
proxy = {proxy_server}
1030+
"""
1031+
1032+
p.write_text(mock_config_content)
1033+
git.fetch_refspecs(url, "refs/heads/master:refs/heads/master")
1034+
1035+
9441036
@pytest.mark.skip_git_backend("pygit2")
9451037
def test_fetch(tmp_dir: TmpDir, scm: Git, git: Git, tmp_dir_factory: TempDirFactory):
9461038
tmp_dir.gen("foo", "foo")

0 commit comments

Comments
 (0)