reuse_refs_check: sibling repos beside the MAIN clone for a worktree (R-1114)
gates / gates (push) Successful in 6m43s
gates / gates (push) Successful in 6m43s
FELHOM_WORKSPACE (set by felhom-controller's runner) names where the sibling repos are; the worktree's own main clone is skipped. Unset: unchanged. Test red-proved both ways. Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
1 parent
796c373a3a
commit
0314b8e7cf
3 files changed
+54
-2
No files matched your search
@@ -1,3 +1,11 @@
|
|||||||
|
## 2026-10-17 — reuse_refs_check.py: sibling repos beside the MAIN clone, for a worktree (R-1114)
|
||||||
|
|
||||||
|
`find_siblings` reads `FELHOM_WORKSPACE` when set — felhom-controller's runner sets it to the main clone's parent
|
||||||
|
(`controller/scripts/shared_scripts.py`) — and skips the worktree's own main clone, so a path deleted in the worktree
|
||||||
|
never resolves in the main clone. Unset, nothing changes (the other three runners). Test
|
||||||
|
`test_worktree_searches_the_workspace_not_its_own_main_clone`, red-proved both ways (no env → the sibling is not found;
|
||||||
|
no skip → the main clone is searched).
|
||||||
|
|
||||||
## 2026-10-16 — build-hub.sh 1.25.0: a version number is pushed once (R-1098)
|
## 2026-10-16 — build-hub.sh 1.25.0: a version number is pushed once (R-1098)
|
||||||
|
|
||||||
`scripts/build-hub.sh` refuses `--push`/`--multiarch` of a tag the registry already has, and refuses when the registry
|
`scripts/build-hub.sh` refuses `--push`/`--multiarch` of a tag the registry already has, and refuses when the registry
|
||||||
|
|||||||
@@ -115,13 +115,33 @@ def index_for(root):
|
|||||||
return _index_cache[root]
|
return _index_cache[root]
|
||||||
|
|
||||||
|
|
||||||
|
def _main_clone_of_worktree(root):
|
||||||
|
"""The main clone of a linked worktree (its `.git` FILE reads `gitdir: <main>/.git/worktrees/<name>`), else None."""
|
||||||
|
try:
|
||||||
|
with open(os.path.join(root, ".git")) as fh:
|
||||||
|
line = fh.readline().strip()
|
||||||
|
except OSError: # a directory (a main clone) or absent
|
||||||
|
return None
|
||||||
|
if not line.startswith("gitdir:"):
|
||||||
|
return None
|
||||||
|
gitdir = os.path.realpath(line[len("gitdir:"):].strip())
|
||||||
|
head, tail = os.path.split(os.path.dirname(gitdir)) # <main>/.git, "worktrees"
|
||||||
|
if tail != "worktrees" or os.path.basename(head) != ".git":
|
||||||
|
return None
|
||||||
|
return os.path.dirname(head)
|
||||||
|
|
||||||
|
|
||||||
def find_siblings(root):
|
def find_siblings(root):
|
||||||
"""Immediate sibling dirs of <root> that are themselves git working trees. One level only.
|
"""Immediate sibling dirs of <root> that are themselves git working trees. One level only.
|
||||||
|
|
||||||
Returns (list_of_paths, error_message_or_None). A sibling repo that is simply absent is NEVER
|
Returns (list_of_paths, error_message_or_None). A sibling repo that is simply absent is NEVER
|
||||||
a failure — a clone in isolation must still be able to check itself.
|
a failure — a clone in isolation must still be able to check itself.
|
||||||
"""
|
"""
|
||||||
parent = os.path.dirname(os.path.abspath(root))
|
# FELHOM_WORKSPACE (R-1114): set by felhom-controller's runner to the MAIN clone's parent when <root> is a
|
||||||
|
# worktree outside git/ (its own parent holds other worktrees, not the sibling repos). The main clone of
|
||||||
|
# <root> itself is then skipped: a path deleted in the worktree must not resolve in the main clone.
|
||||||
|
parent = os.environ.get("FELHOM_WORKSPACE") or os.path.dirname(os.path.abspath(root))
|
||||||
|
own_main = _main_clone_of_worktree(root)
|
||||||
try:
|
try:
|
||||||
entries = sorted(os.listdir(parent))
|
entries = sorted(os.listdir(parent))
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
@@ -129,7 +149,7 @@ def find_siblings(root):
|
|||||||
sibs = []
|
sibs = []
|
||||||
for e in entries:
|
for e in entries:
|
||||||
p = os.path.join(parent, e)
|
p = os.path.join(parent, e)
|
||||||
if os.path.abspath(p) == os.path.abspath(root):
|
if os.path.abspath(p) == os.path.abspath(root) or (own_main and os.path.realpath(p) == own_main):
|
||||||
continue
|
continue
|
||||||
if os.path.isdir(p) and os.path.exists(os.path.join(p, ".git")):
|
if os.path.isdir(p) and os.path.exists(os.path.join(p, ".git")):
|
||||||
sibs.append(p)
|
sibs.append(p)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
SCRIPT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "reuse_refs_check.py")
|
SCRIPT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "reuse_refs_check.py")
|
||||||
|
|
||||||
@@ -119,6 +120,29 @@ class ReuseRefsCheckTest(unittest.TestCase):
|
|||||||
self.assertEqual(rc, 0, out)
|
self.assertEqual(rc, 0, out)
|
||||||
self.assertIn("cross-repo", out)
|
self.assertIn("cross-repo", out)
|
||||||
|
|
||||||
|
# ── R-1114: a worktree outside git/ searches the workspace, never its own main clone ──
|
||||||
|
def test_worktree_searches_the_workspace_not_its_own_main_clone(self):
|
||||||
|
ws = os.path.join(self.tmp, "git")
|
||||||
|
main = os.path.join(ws, "mainrepo")
|
||||||
|
os.makedirs(os.path.join(main, ".git", "worktrees", "b3"))
|
||||||
|
write(os.path.join(main, "only", "in", "main.go"), "package in\n")
|
||||||
|
shared = os.path.join(ws, "felhom.eu")
|
||||||
|
os.makedirs(os.path.join(shared, ".git"))
|
||||||
|
write(os.path.join(shared, "scripts", "x.py"), "# gate\n")
|
||||||
|
wt = os.path.join(self.tmp, "wt", "b3")
|
||||||
|
write(os.path.join(wt, ".git"), "gitdir: %s\n" % os.path.join(main, ".git", "worktrees", "b3"))
|
||||||
|
write(os.path.join(wt, "REUSE.md"), "run `felhom.eu/scripts/x.py`\n")
|
||||||
|
rc, out = self.run_check(wt)
|
||||||
|
self.assertNotEqual(rc, 0, "without FELHOM_WORKSPACE the worktree's own parent holds no felhom.eu:\n" + out)
|
||||||
|
with mock.patch.dict(os.environ, {"FELHOM_WORKSPACE": ws}):
|
||||||
|
rc, out = self.run_check(wt)
|
||||||
|
self.assertEqual(rc, 0, out)
|
||||||
|
self.assertNotIn("mainrepo", out.split("siblings searched:")[-1]) # its own main clone is skipped
|
||||||
|
# a path that exists only in the main clone (deleted in the worktree) must NOT resolve there
|
||||||
|
write(os.path.join(wt, "REUSE.md"), "see `only/in/main.go`\n")
|
||||||
|
rc, out = self.run_check(wt)
|
||||||
|
self.assertNotEqual(rc, 0, out)
|
||||||
|
|
||||||
def test_non_git_sibling_is_not_searched(self):
|
def test_non_git_sibling_is_not_searched(self):
|
||||||
plain = os.path.join(self.tmp, "notarepo") # no .git — not a repo, must not resolve
|
plain = os.path.join(self.tmp, "notarepo") # no .git — not a repo, must not resolve
|
||||||
write(os.path.join(plain, "pkg", "x.go"), "package pkg\n")
|
write(os.path.join(plain, "pkg", "x.go"), "package pkg\n")
|
||||||
|
|||||||
Reference in new issue
Block a user