mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-17 00:43:29 -05:00
fix: block a pin bump when git history is unreadable
realign_prose read a failing git log as an empty history and stopped silently at an unreadable revision, so the stale-prose check answered "nothing to move" and let --bump-commit through. It now reports such citations to read again instead of passing them.
This commit is contained in:
1 parent
03784eeceb
commit
24f7ade261
2 files changed
+55
-9
No files matched your search
+35
-9
@@ -2688,15 +2688,29 @@ def _set_pin(text: str, document: dict, field: str, value: str, after: str) -> s
|
||||
return insert_after_line(text, after, f'{field}: "{value}"')
|
||||
|
||||
|
||||
def _git_history(path: Path) -> list[str]:
|
||||
"""Commits touching the profile, newest first, empty outside a repo."""
|
||||
result = subprocess.run(
|
||||
["git", "log", "--format=%H", "--", path.name],
|
||||
cwd=path.parent, capture_output=True, text=True, check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return []
|
||||
return result.stdout.split()
|
||||
def _git_history(path: Path) -> list[str] | None:
|
||||
"""Commits touching the profile, newest first; None when git cannot say.
|
||||
|
||||
An untracked profile has no history. A git that fails (no repository,
|
||||
dubious ownership, git missing) has not answered, and reading that as
|
||||
"nothing written under an older pin" let a bump through.
|
||||
"""
|
||||
def git(*argv: str) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(
|
||||
["git", *argv], cwd=path.parent, capture_output=True, text=True, check=False,
|
||||
)
|
||||
|
||||
try:
|
||||
result = git("log", "--format=%H", "--", path.name)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.split()
|
||||
# A repository with no commit yet holds nothing written earlier.
|
||||
inside = git("rev-parse", "--is-inside-work-tree")
|
||||
if inside.stdout.strip() == "true" and git("rev-parse", "-q", "--verify", "HEAD").returncode:
|
||||
return []
|
||||
except OSError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def _git_file_at(path: Path, sha: str) -> dict | None:
|
||||
@@ -2936,6 +2950,8 @@ def realign_prose(
|
||||
and document[f"{field}_commit"]
|
||||
]
|
||||
history = _git_history(path)
|
||||
if history is None:
|
||||
return [f"read again: {path.name}: git history unreadable"]
|
||||
if not history:
|
||||
return []
|
||||
|
||||
@@ -2944,11 +2960,15 @@ def realign_prose(
|
||||
alive = dict.fromkeys(fields, True)
|
||||
intro: dict[str, str | None] = dict.fromkeys(fields)
|
||||
revisions: list[tuple[str, dict]] = []
|
||||
# Fields whose writing pin lies past a revision that cannot be read:
|
||||
# where their text came in is unknown, so they are not moved.
|
||||
unknown: dict[str, str] = {}
|
||||
for sha in history:
|
||||
if not any(alive.values()):
|
||||
break
|
||||
past = _git_file_at(path, sha)
|
||||
if past is None:
|
||||
unknown = {field: sha for field, live in alive.items() if live}
|
||||
break
|
||||
revisions.append((sha, past))
|
||||
values = _scalar_values(past)
|
||||
@@ -2963,6 +2983,12 @@ def realign_prose(
|
||||
messages: list[str] = []
|
||||
jobs: list[tuple[Citation, dict]] = []
|
||||
for citation in citations:
|
||||
if citation.field in unknown:
|
||||
messages.append(
|
||||
f"read again: {citation.field}: {citation.ref} "
|
||||
f"(revision {unknown[citation.field][:8]} unreadable)"
|
||||
)
|
||||
continue
|
||||
intro_sha = intro.get(citation.field)
|
||||
if intro_sha is None:
|
||||
# The scalar is not committed yet: written now, under this pin.
|
||||
|
||||
@@ -2283,6 +2283,9 @@ class TestWriteDryRun(unittest.TestCase):
|
||||
self.dir = Path(self.tmp.name)
|
||||
self.path = self.dir / "p.yml"
|
||||
self.path.write_text(SAMPLE, encoding="utf-8")
|
||||
# Profiles live in a repository: git answers "no history" for an
|
||||
# untracked file, where outside one it answers nothing at all.
|
||||
subprocess.run(["git", "init", "-q"], cwd=self.dir, check=True)
|
||||
|
||||
def tearDown(self):
|
||||
self.tmp.cleanup()
|
||||
@@ -3589,6 +3592,23 @@ class TestRealignProse(unittest.TestCase):
|
||||
self.assertTrue(any("would recale" in m for m in messages))
|
||||
self.assertIn("(a.c:10)", self.path.read_text())
|
||||
|
||||
def test_an_unreadable_history_blocks_rather_than_passes(self):
|
||||
"""git failing (no repository, dubious ownership) read as "nothing
|
||||
written under an older pin" and let a bump through."""
|
||||
self.path.write_text(PROSE_SAMPLE, encoding="utf-8")
|
||||
messages = profile_sync.realign_prose(self.path, self.tmp.name, dry_run=True)
|
||||
self.assertEqual(messages, ["read again: p.yml: git history unreadable"])
|
||||
|
||||
def test_an_unreadable_revision_stops_the_move(self):
|
||||
self._repo_with_advanced_pin()
|
||||
self.files[("oldpin", "a.c")] = ["x"] * 9 + ["subject"]
|
||||
self.files[("pin", "a.c")] = ["x"] * 13 + ["subject"]
|
||||
with mock.patch.object(profile_sync, "_git_file_at", return_value=None):
|
||||
messages = profile_sync.realign_prose(self.path, self.tmp.name)
|
||||
self.assertTrue(messages)
|
||||
self.assertTrue(all(m.startswith("read again: notes:") for m in messages))
|
||||
self.assertIn("(a.c:10)", self.path.read_text())
|
||||
|
||||
def test_scalar_written_at_the_current_pin_is_left_alone(self):
|
||||
self._git("init", "-q")
|
||||
self._git("config", "user.email", "t@t")
|
||||
|
||||
Reference in new issue
Block a user