fix(upstream-triage): suggest dependent cherry-picks in ancestry order (#574)

This commit is contained in:
Rudy Mizrahi Celekli authored and GitHub committed 2026-10-17 20:04:06 +02:00
1 parent 2697fa46fb
commit 1b22a38d3f
3 files changed
+31 -2

No files matched your search

+5
View File
@@ -68,6 +68,11 @@ per-file diff commands.
### Fixed ### Fixed
- **Upstream triage emits cherry-pick suggestions in dependency order**
(`tools/upstream_triage.py`) - ready-to-run commands now list ancestors before
descendants, so a follow-up patch is not suggested before the change it edits.
The report tables remain newest first; the tool still executes no Git mutations.
- **`/upskill` and `/notion-sync` now name the field ranked entries actually carry when joining - **`/upskill` and `/notion-sync` now name the field ranked entries actually carry when joining
them to tracker rows** (`.claude/skills/upskill/SKILL.md` Step 3, `.claude/commands/notion-sync.md` them to tracker rows** (`.claude/skills/upskill/SKILL.md` Step 3, `.claude/commands/notion-sync.md`
Step 2, `tests/test_upskill_skill.py`, `tests/test_notion_sync_command.py`) - both said to match Step 2, `tests/test_upskill_skill.py`, `tests/test_notion_sync_command.py`) - both said to match
+23
View File
@@ -137,6 +137,29 @@ class AlreadyAppliedTests(TriageRepoFixture):
self.assertIn("**1** worth reviewing", result.stdout) self.assertIn("**1** worth reviewing", result.stdout)
class SuggestedCherryPickOrderTests(TriageRepoFixture):
def test_suggested_commands_apply_dependent_changes_in_ancestry_order(self):
self.write("kept.py", "print('first upstream change')\n")
first = self.commit("Introduce shared behavior")
self.write("kept.py", "print('second upstream change')\n")
second = self.commit("Refine shared behavior")
self.set_upstream_to_head()
git(self.root, "reset", "--hard", "HEAD~2")
self.write("fork_only.txt", "fork customization\n")
self.commit("Customize fork")
result = self.run_triage()
self.assertEqual(result.returncode, 0, result.stderr)
commands = [line.split(" #", 1)[0].split() for line in result.stdout.splitlines()
if line.startswith("git cherry-pick ")]
self.assertEqual(len(commands), 2, result.stdout)
for command in commands:
replay = subprocess.run(command, cwd=self.root, capture_output=True, text=True)
self.assertEqual(replay.returncode, 0, replay.stdout + replay.stderr)
self.assertEqual([command[2] for command in commands], [first, second])
self.assertEqual((self.root / "kept.py").read_text(), "print('second upstream change')\n")
class WontPortTests(TriageRepoFixture): class WontPortTests(TriageRepoFixture):
def test_listed_sha_is_excluded(self): def test_listed_sha_is_excluded(self):
self.write("kept.py", "print('rejected feature')\n") self.write("kept.py", "print('rejected feature')\n")
+3 -2
View File
@@ -56,7 +56,7 @@ def git(*args: str) -> str:
def rev_list(range_spec: str) -> list[str]: def rev_list(range_spec: str) -> list[str]:
out = git("rev-list", "--no-merges", range_spec).strip() out = git("rev-list", "--no-merges", "--topo-order", range_spec).strip()
return out.splitlines() if out else [] return out.splitlines() if out else []
@@ -203,7 +203,8 @@ def main() -> int:
lines.append("<details><summary>Ready-to-run cherry-picks (review each before running)</summary>") lines.append("<details><summary>Ready-to-run cherry-picks (review each before running)</summary>")
lines.append("") lines.append("")
lines.append("```bash") lines.append("```bash")
for short, sha, subj, _ in review: # Report rows stay newest first; commands must apply ancestors first.
for short, sha, subj, _ in reversed(review):
lines.append(f"git cherry-pick {sha} # {subj}") lines.append(f"git cherry-pick {sha} # {subj}")
lines.append("```") lines.append("```")
lines.append("") lines.append("")