Skip to content

Commit 36a97bf

Browse files
committed
Add test for Git LFS repository cloning
Verifies that Poetry can successfully clone Git repositories that use Git Large File Storage (LFS) and that LFS files are properly retrieved with their actual content rather than just pointer files. This test uses dulwich's built-in LFS support to create a repository with LFS files and verifies that cloning works correctly without requiring manual configuration. Note that while LFS support works in Dulwich >=1, the tests specifically rely on it being able to use locally cloned LFS stores, which requires dulwich 1.2.1. Fixes #8723
1 parent e9d6150 commit 36a97bf

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pytest-cov = ">=4.0"
7979
pytest-mock = ">=3.9"
8080
pytest-randomly = ">=3.12"
8181
pytest-xdist = { version = ">=3.1", extras = ["psutil"] }
82+
dulwich = ">=1.2.1"
8283

8384
[tool.poetry.group.typing.dependencies]
8485
mypy = ">=1.8.0"

tests/vcs/git/test_backend.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,3 +453,79 @@ def test_clone_legacy_strips_ref_prefixes(
453453

454454
mock_clone.assert_called_once()
455455
mock_checkout.assert_called_once_with(expected_checkout, target)
456+
457+
458+
@pytest.mark.skip_git_mock
459+
def test_clone_with_lfs_files(tmp_path: Path) -> None:
460+
"""Test cloning a repository with Git LFS files (issue #8723)."""
461+
from dulwich import porcelain
462+
from dulwich.lfs import LFSStore
463+
464+
# Create a source repository with LFS support
465+
source_path = tmp_path / "source-repo"
466+
source_path.mkdir()
467+
repo = Repo.init(str(source_path))
468+
469+
# Set up LFS in the repository
470+
lfs_dir = source_path / ".git" / "lfs"
471+
lfs_dir.mkdir(parents=True)
472+
lfs_store = LFSStore.create(str(lfs_dir))
473+
474+
# Configure .gitattributes to track large files with LFS
475+
gitattributes = source_path / ".gitattributes"
476+
gitattributes.write_text("*.bin filter=lfs diff=lfs merge=lfs -text\n")
477+
porcelain.add(repo, str(gitattributes))
478+
479+
# Create a regular file
480+
regular_file = source_path / "regular.txt"
481+
regular_file.write_text("This is a regular file")
482+
porcelain.add(repo, str(regular_file))
483+
484+
# Create an LFS file with a pointer
485+
lfs_content = b"This is a large binary file content for LFS storage"
486+
lfs_file = source_path / "large.bin"
487+
488+
# Store the actual content in LFS store and create pointer
489+
lfs_object_id = lfs_store.write_object([lfs_content])
490+
lfs_pointer = (
491+
f"version https://git-lfs.github.com/spec/v1\n"
492+
f"oid sha256:{lfs_object_id}\n"
493+
f"size {len(lfs_content)}\n"
494+
)
495+
lfs_file.write_text(lfs_pointer)
496+
porcelain.add(repo, str(lfs_file))
497+
498+
# Commit the files
499+
porcelain.commit(
500+
repo,
501+
message=b"Add files with LFS support",
502+
author=b"Test <test@example.com>",
503+
committer=b"Test <test@example.com>",
504+
)
505+
506+
# Clone the repository
507+
source_root_dir = tmp_path / "clone-root"
508+
source_root_dir.mkdir()
509+
Git.clone(
510+
url=source_path.as_uri(),
511+
source_root=source_root_dir,
512+
name="clone-test",
513+
)
514+
515+
# Verify the clone succeeded
516+
clone_dir = source_root_dir / "clone-test"
517+
assert (clone_dir / ".git").is_dir()
518+
519+
# Verify regular file is present
520+
assert (clone_dir / "regular.txt").exists()
521+
assert (clone_dir / "regular.txt").read_text() == "This is a regular file"
522+
523+
# Verify .gitattributes is present
524+
assert (clone_dir / ".gitattributes").exists()
525+
assert "filter=lfs" in (clone_dir / ".gitattributes").read_text()
526+
527+
# Verify LFS file is present with actual content (not just pointer)
528+
# The LFS system should automatically retrieve the actual content
529+
assert (clone_dir / "large.bin").exists()
530+
lfs_file_content = (clone_dir / "large.bin").read_bytes()
531+
assert lfs_file_content == lfs_content

0 commit comments

Comments
 (0)