From dc35ae0029d7c3eba890b9260a3e802a148d5f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jelmer=20Vernoo=C4=B3?= Date: Mon, 9 Feb 2026 10:38:53 +0000 Subject: [PATCH] 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 --- tests/vcs/git/test_backend.py | 81 +++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tests/vcs/git/test_backend.py b/tests/vcs/git/test_backend.py index 2531f76d466..eb51ff347c6 100644 --- a/tests/vcs/git/test_backend.py +++ b/tests/vcs/git/test_backend.py @@ -290,3 +290,84 @@ def test_clone_existing_locked_tag(tmp_path: Path, temp_repo: TempRepoFixture) - f"Try again later or remove the {tag_ref_lock} manually" " if you are sure no other process is holding it." ) + + +@pytest.mark.skip_git_mock +def test_clone_with_lfs_files(tmp_path: Path) -> None: + """Test cloning a repository with Git LFS files (issue #8723).""" + from dulwich import porcelain + from dulwich.lfs import LFSStore + + # Create a source repository with LFS support + source_path = tmp_path / "source-repo" + source_path.mkdir() + repo = Repo.init(str(source_path)) + + # Set up LFS in the repository + lfs_dir = source_path / ".git" / "lfs" + lfs_dir.mkdir(parents=True) + lfs_store = LFSStore.create(str(lfs_dir)) + + # Configure LFS URL in the repository config + config = repo.get_config() + config.set((b"lfs",), b"url", lfs_dir.as_uri().encode()) + config.write_to_path() + + # Configure .gitattributes to track large files with LFS + gitattributes = source_path / ".gitattributes" + gitattributes.write_text("*.bin filter=lfs diff=lfs merge=lfs -text\n") + porcelain.add(repo, str(gitattributes)) + + # Create a regular file + regular_file = source_path / "regular.txt" + regular_file.write_text("This is a regular file") + porcelain.add(repo, str(regular_file)) + + # Create an LFS file with a pointer + lfs_content = b"This is a large binary file content for LFS storage" + lfs_file = source_path / "large.bin" + + # Store the actual content in LFS store and create pointer + lfs_object_id = lfs_store.write_object([lfs_content]) + lfs_pointer = ( + f"version https://git-lfs.github.com/spec/v1\n" + f"oid sha256:{lfs_object_id}\n" + f"size {len(lfs_content)}\n" + ) + lfs_file.write_text(lfs_pointer) + porcelain.add(repo, str(lfs_file)) + + # Commit the files + porcelain.commit( + repo, + message=b"Add files with LFS support", + author=b"Test ", + committer=b"Test ", + ) + + # Clone the repository + source_root_dir = tmp_path / "clone-root" + source_root_dir.mkdir() + Git.clone( + url=source_path.as_uri(), + source_root=source_root_dir, + name="clone-test", + ) + + # Verify the clone succeeded + clone_dir = source_root_dir / "clone-test" + assert (clone_dir / ".git").is_dir() + + # Verify regular file is present + assert (clone_dir / "regular.txt").exists() + assert (clone_dir / "regular.txt").read_text() == "This is a regular file" + + # Verify .gitattributes is present + assert (clone_dir / ".gitattributes").exists() + assert "filter=lfs" in (clone_dir / ".gitattributes").read_text() + + # Verify LFS file is present with actual content (not just pointer) + # The LFS system should automatically retrieve the actual content + assert (clone_dir / "large.bin").exists() + lfs_file_content = (clone_dir / "large.bin").read_bytes() + assert lfs_file_content == lfs_content