fix(issue-21): PR #29 review R1-R3 - untracked-safe cleanliness checks; a worktree gets its own venv
R1/R2: `git status --porcelain` honours status.showUntrackedFiles, so a `no` setting in a submodule (or the worktree) hid untracked files from the checks that justify worktree_remove.sh's single --force and from the review snapshot guard (_dirty_submodules), which then approved content it never captured. All three checks (lib_py/worktree.py, worktree_remove.sh, runner._dirty_submodules) now pass --untracked-files=all. The source tree's own snapshot was already safe: `git add -A` ignores that setting. R3: worktree_prepare.sh no longer links .venv to the control root's. It creates the worktree's own venv with the control root's interpreter and installs requirements*.txt; a leftover link is refused (exit 1), a control root without an interpreter is a warning (VENV=skipped); VENV= is printed. Tests: w1 (real venv, kept on re-run), w1b (link refused / skipped), w6e parametrised over the hidden setting for the post-stop recheck, w6e2 (hidden untracked file in the submodule and in the worktree blocks the removal), l17 untracked-hidden / during-hidden (guard refuses before the first review; a mid-round hidden file makes the round stale). Each new case fails without the fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
1 parent
90a289da44
commit
08db1da9d5
9 files changed
+107
-29
No files matched your search
@@ -417,28 +417,37 @@ def _add_submodule(wt: Path, tmp_path: Path) -> None:
|
||||
_git(wt, "commit", "-q", "-m", "add sm")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("when", ["before", "before-ignored", "untracked", "during"])
|
||||
@pytest.mark.parametrize("when", ["before", "before-ignored", "untracked", "untracked-hidden", "during", "during-hidden"])
|
||||
def test_l17_dirty_submodule_is_refused_or_makes_the_round_stale(wt_repo, monkeypatch, tmp_path, capsys, when):
|
||||
"""The -hidden variants (PR #29 review R2): status.showUntrackedFiles=no in
|
||||
the submodule must not let an untracked file past the snapshot guard,
|
||||
neither before the first review nor when it appears mid-round."""
|
||||
main, wt = wt_repo
|
||||
base = _impl(wt)
|
||||
_add_submodule(wt, tmp_path)
|
||||
if when == "before-ignored": # no ignore setting hides the dirty content
|
||||
_git(wt, "config", "submodule.sm.ignore", "all")
|
||||
_git(wt, "config", "diff.ignoreSubmodules", "all")
|
||||
if when.endswith("-hidden"):
|
||||
_git(wt / "sm", "config", "status.showUntrackedFiles", "no")
|
||||
|
||||
def dirty(*_):
|
||||
(wt / "sm" / "x.txt").write_text("unreviewed work\n")
|
||||
|
||||
def untracked(*_):
|
||||
(wt / "sm" / "new.txt").write_text("untracked in the submodule\n")
|
||||
|
||||
if when.startswith("before"):
|
||||
dirty()
|
||||
elif when == "untracked":
|
||||
(wt / "sm" / "new.txt").write_text("untracked in the submodule\n")
|
||||
elif when.startswith("untracked"):
|
||||
untracked()
|
||||
on_review = {"during": dirty, "during-hidden": untracked}.get(when)
|
||||
rc, calls, r = _drive(monkeypatch, tmp_path, ["--worktree", str(wt), "--base", base, "--review-only"],
|
||||
on_review=dirty if when == "during" else None)
|
||||
on_review=on_review)
|
||||
assert rc == 1 and _sidecars(main) == []
|
||||
err = capsys.readouterr().err
|
||||
assert "submodule(s) with uncommitted or untracked content: sm" in err
|
||||
if when == "during":
|
||||
if when.startswith("during"):
|
||||
assert len(_reviews(calls)) == 1 and r._rounds[0]["stale"] is True
|
||||
else:
|
||||
assert _reviews(calls) == [], "refused before any review"
|
||||
|
||||
Reference in new issue
Block a user