Skip to content
Open
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
2 changes: 1 addition & 1 deletion craft_application/remote/worktree.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def init_repo(self) -> None:
if self._repo_dir.exists():
rmtree(self._repo_dir)

copytree(self._project_dir, self._repo_dir)
copytree(self._project_dir, self._repo_dir, ignore_dangling_symlinks=True)
Comment thread
bepri marked this conversation as resolved.

self._gitify_repository()

Expand Down
2 changes: 2 additions & 0 deletions docs/reference/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Changelog
Bug fixes
=========

- ``remote-build`` no longer raises an error when dangling symlinks are present in the
project repository.
- Ignore .spread-reuse files when deciding if a source is outdated.

7.1.0 (2026-07-07)
Expand Down
17 changes: 15 additions & 2 deletions tests/unit/remote/test_worktree.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def mock_base_directory(mocker, new_dir):
return _mock_base_directory


@pytest.fixture(autouse=True)
@pytest.fixture

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every test that needed this mock was already directly requesting it, but the autouse broke my new test

def mock_copytree(mocker):
"""Returns a mocked `shutil.copytree()`."""
return mocker.patch("craft_application.remote.worktree.copytree")
Expand Down Expand Up @@ -75,7 +75,7 @@ def test_worktree_init_clean_exception_wrapped(mock_git_repo):

@pytest.mark.usefixtures("new_dir", "mock_copytree")
def test_worktree_init_dirty(mock_base_directory, mock_git_repo):
"""Test initialization of a WorkTree with a clean git repository."""
"""Test initialization of a WorkTree with a dirty git repository."""
mock_git_repo.return_value.is_clean.return_value = False

worktree = WorkTree(app_name="test-app", build_id="test-id", project_dir=Path())
Expand All @@ -93,6 +93,19 @@ def test_worktree_init_dirty(mock_base_directory, mock_git_repo):
]


def test_worktree_init_dangling_symlinks(tmp_path: Path) -> None:
"""Test that dangling symlinks don't break the repository init."""
(tmp_path / "file").touch()
(tmp_path / "broken-link").symlink_to("not-real")
worktree = WorkTree(app_name="test-app", build_id="test-id", project_dir=tmp_path)

worktree.init_repo()

assert (worktree.repo_dir / "file").is_file()
# Broken symlinks are just ignored now
assert not (worktree.repo_dir / "broken-link").is_symlink()


@pytest.mark.usefixtures("new_dir")
def test_worktree_repo_dir():
"""Verify the `repo_dir` property."""
Expand Down
Loading