Skip to content

Commit dc35ae0

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. Fixes #8723
1 parent a84cd0f commit dc35ae0

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

tests/vcs/git/test_backend.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,84 @@ def test_clone_existing_locked_tag(tmp_path: Path, temp_repo: TempRepoFixture) -
290290
f"Try again later or remove the {tag_ref_lock} manually"
291291
" if you are sure no other process is holding it."
292292
)
293+
294+
295+
@pytest.mark.skip_git_mock
296+
def test_clone_with_lfs_files(tmp_path: Path) -> None:
297+
"""Test cloning a repository with Git LFS files (issue #8723)."""
298+
from dulwich import porcelain
299+
from dulwich.lfs import LFSStore
300+
301+
# Create a source repository with LFS support
302+
source_path = tmp_path / "source-repo"
303+
source_path.mkdir()
304+
repo = Repo.init(str(source_path))
305+
306+
# Set up LFS in the repository
307+
lfs_dir = source_path / ".git" / "lfs"
308+
lfs_dir.mkdir(parents=True)
309+
lfs_store = LFSStore.create(str(lfs_dir))
310+
311+
# Configure LFS URL in the repository config
312+
config = repo.get_config()
313+
config.set((b"lfs",), b"url", lfs_dir.as_uri().encode())
314+
config.write_to_path()
315+
316+
# Configure .gitattributes to track large files with LFS
317+
gitattributes = source_path / ".gitattributes"
318+
gitattributes.write_text("*.bin filter=lfs diff=lfs merge=lfs -text\n")
319+
porcelain.add(repo, str(gitattributes))
320+
321+
# Create a regular file
322+
regular_file = source_path / "regular.txt"
323+
regular_file.write_text("This is a regular file")
324+
porcelain.add(repo, str(regular_file))
325+
326+
# Create an LFS file with a pointer
327+
lfs_content = b"This is a large binary file content for LFS storage"
328+
lfs_file = source_path / "large.bin"
329+
330+
# Store the actual content in LFS store and create pointer
331+
lfs_object_id = lfs_store.write_object([lfs_content])
332+
lfs_pointer = (
333+
f"version https://git-lfs.github.com/spec/v1\n"
334+
f"oid sha256:{lfs_object_id}\n"
335+
f"size {len(lfs_content)}\n"
336+
)
337+
lfs_file.write_text(lfs_pointer)
338+
porcelain.add(repo, str(lfs_file))
339+
340+
# Commit the files
341+
porcelain.commit(
342+
repo,
343+
message=b"Add files with LFS support",
344+
author=b"Test <test@example.com>",
345+
committer=b"Test <test@example.com>",
346+
)
347+
348+
# Clone the repository
349+
source_root_dir = tmp_path / "clone-root"
350+
source_root_dir.mkdir()
351+
Git.clone(
352+
url=source_path.as_uri(),
353+
source_root=source_root_dir,
354+
name="clone-test",
355+
)
356+
357+
# Verify the clone succeeded
358+
clone_dir = source_root_dir / "clone-test"
359+
assert (clone_dir / ".git").is_dir()
360+
361+
# Verify regular file is present
362+
assert (clone_dir / "regular.txt").exists()
363+
assert (clone_dir / "regular.txt").read_text() == "This is a regular file"
364+
365+
# Verify .gitattributes is present
366+
assert (clone_dir / ".gitattributes").exists()
367+
assert "filter=lfs" in (clone_dir / ".gitattributes").read_text()
368+
369+
# Verify LFS file is present with actual content (not just pointer)
370+
# The LFS system should automatically retrieve the actual content
371+
assert (clone_dir / "large.bin").exists()
372+
lfs_file_content = (clone_dir / "large.bin").read_bytes()
373+
assert lfs_file_content == lfs_content

0 commit comments

Comments
 (0)