fix: three defects found by codex review of today's merged work
No P1s. All three confirmed in the code before fixing. [P2] Invites were destroyed by a transient forge error. apply_invites() popped the whole pending list BEFORE attempting the collaborator PUT, so a 502 or a timeout while someone first signed in meant they got no access and re-linking never retried -- the promise was gone. Now it peeks, and consumes each grant only after that grant actually lands. A partial failure keeps exactly the grants that failed. [P2] Snapshots lost staged-only work. build_snapshot() read HEAD into a scratch index and staged the WORKTREE, so a hunk you staged and then edited further survived only in its later worktree form. git keeps index and worktree as separate states and the backup now does too: the real index is read without being touched, and when it differs from both HEAD and the worktree it rides along as a second parent. [P3] A truncated repo listing could resolve a bare name to the WRONG repo. resolve_granted() discarded the truncation flag, so a name whose only match sat beyond the 2000-repo cap fell back to <login>/<name> and would clone that instead. Truncation now means "unknown", not "absent": it refuses and asks for the owner. A complete listing still falls back, because absence is then real. 209 tests (was 204).
This commit is contained in:
@@ -1310,5 +1310,53 @@ class TestDeviceFlowOutputIsVisible(unittest.TestCase):
|
||||
self.assertTrue(all(seen[:2]),
|
||||
"the URL and code must be printed with flush=True")
|
||||
|
||||
|
||||
class TestCodexReviewFindings(GitScenarioBase):
|
||||
"""Regressions for the three issues codex found in today's merged work."""
|
||||
|
||||
def test_staged_only_work_survives_a_snapshot(self):
|
||||
"""[P2] Stage a hunk, edit further, lose the laptop: the staged version
|
||||
must still be recoverable, not just the later worktree one."""
|
||||
self.write(self.local, "a.txt", "committed")
|
||||
run_git(self.local, "add", "-A")
|
||||
run_git(self.local, "commit", "-m", "base")
|
||||
self.write(self.local, "a.txt", "THE CAREFULLY STAGED VERSION")
|
||||
run_git(self.local, "add", "a.txt") # staged
|
||||
self.write(self.local, "a.txt", "later scratch edit") # worktree moved on
|
||||
|
||||
commit, tree = client.build_snapshot(self.local)
|
||||
|
||||
# the worktree state is the snapshot's own tree
|
||||
self.assertEqual(run_git(self.local, "show", f"{commit}:a.txt"),
|
||||
"later scratch edit")
|
||||
# ...and the staged state is reachable through the extra parent
|
||||
parents = run_git(self.local, "log", "-1", "--format=%P", commit).split()
|
||||
staged = [p for p in parents
|
||||
if run_git(self.local, "show", f"{p}:a.txt")
|
||||
== "THE CAREFULLY STAGED VERSION"]
|
||||
self.assertTrue(staged, f"staged version unreachable from {parents}")
|
||||
|
||||
def test_a_snapshot_does_not_disturb_the_index(self):
|
||||
self.write(self.local, "a.txt", "one")
|
||||
run_git(self.local, "add", "-A")
|
||||
run_git(self.local, "commit", "-m", "base")
|
||||
self.write(self.local, "a.txt", "staged")
|
||||
run_git(self.local, "add", "a.txt")
|
||||
before = run_git(self.local, "status", "--porcelain")
|
||||
client.build_snapshot(self.local)
|
||||
self.assertEqual(run_git(self.local, "status", "--porcelain"), before)
|
||||
|
||||
def test_a_truncated_listing_refuses_instead_of_guessing(self):
|
||||
"""[P3] A name that is merely beyond the page cap must not resolve to a
|
||||
different repo that happens to exist under your own account."""
|
||||
cfg = {"login": "alice", "gitea_base": "http://forge.example", "token": "t"}
|
||||
with self.assertRaises(SystemExit) as e:
|
||||
client.resolve_granted(cfg, "notes", repos=[], truncated=True)
|
||||
self.assertIn("truncated", str(e.exception))
|
||||
# a complete listing still falls back, because absence is then real
|
||||
self.assertEqual(
|
||||
client.resolve_granted(cfg, "notes", repos=[], truncated=False),
|
||||
"alice/notes")
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user