Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/poetry/vcs/git/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from pathlib import Path
from subprocess import CalledProcessError
from typing import TYPE_CHECKING
from urllib.parse import urljoin

from dulwich import porcelain
from dulwich.client import HTTPUnauthorized
Expand Down Expand Up @@ -331,16 +332,24 @@ def _clone_submodules(cls, repo: Repo) -> None:
repo_root = Path(repo.path)
modules_config = repo_root.joinpath(".gitmodules")

# A relative URL by definition starts with ../ or ./
relative_submodule_regex = re.compile(r"^\.{1,2}/")

if modules_config.exists():
config = ConfigFile.from_path(str(modules_config))

url: bytes
path: bytes
submodules = parse_submodules(config)

for path, url, name in submodules:
path_relative = Path(path.decode("utf-8"))
path_absolute = repo_root.joinpath(path_relative)

url_string = url.decode("utf-8")
if relative_submodule_regex.search(url_string):
url_string = urljoin(f"{Git.get_remote_url(repo)}/", url_string)

source_root = path_absolute.parent
source_root.mkdir(parents=True, exist_ok=True)

Expand All @@ -357,7 +366,7 @@ def _clone_submodules(cls, repo: Repo) -> None:
continue

cls.clone(
url=url.decode("utf-8"),
url=url_string,
source_root=source_root,
name=path_relative.name,
revision=revision,
Expand Down
24 changes: 24 additions & 0 deletions tests/integration/test_utils_vcs_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,30 @@ def test_git_clone_clones_submodules(source_url: str) -> None:
assert len(list(submodule_package_directory.glob("*"))) > 1


def test_git_clone_clones_submodules_with_relative_urls(source_url: str) -> None:
with Git.clone(url=source_url, branch="relative_submodule") as repo:
submodule_package_directory = (
Path(repo.path) / "submodules" / "relative-url-submodule"
)

assert submodule_package_directory.exists()
assert submodule_package_directory.joinpath("README.md").exists()
assert len(list(submodule_package_directory.glob("*"))) > 1


def test_git_clone_clones_submodules_with_relative_urls_and_explicit_base(
source_url: str,
) -> None:
with Git.clone(url=source_url, branch="relative_submodule") as repo:
submodule_package_directory = (
Path(repo.path) / "submodules" / "relative-url-submodule-with-base"
)

assert submodule_package_directory.exists()
assert submodule_package_directory.joinpath("README.md").exists()
assert len(list(submodule_package_directory.glob("*"))) > 1


def test_system_git_fallback_on_http_401(
mocker: MockerFixture,
source_url: str,
Expand Down