diff --git a/CHANGELOG.md b/CHANGELOG.md index 637f76c7..b5a0fde4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,6 +172,8 @@ per-file diff commands. against the upstream repo (https and ssh forms, optional `.git` suffix), and an undeterminable checkout assumes upstream. Tests only, no `framework_version` bump. +- **Upstream companion commands retain the selected refs** (#591) - generated follow-up commands now preserve custom base and head references instead of silently comparing the defaults. + - **`linkedin-search` and `freehire-search` reject invalid `--format` flags with `BAD_ARG`** (#555, `.agents/skills/linkedin-search/cli/src/cli.ts`, `.agents/skills/freehire-search/cli/src/cli.ts`) - unrecognized `--format` flags previously fell back silently to `"json"` with exit code 0, masking diff --git a/tests/test_upstream_crossrefs.py b/tests/test_upstream_crossrefs.py new file mode 100644 index 00000000..c7d1fe75 --- /dev/null +++ b/tests/test_upstream_crossrefs.py @@ -0,0 +1,67 @@ +"""Companion commands must inspect the same selected upstream ref.""" +import re +import shlex +import shutil +import subprocess +import sys +import unittest +from pathlib import Path + +from tests.test_check_upstream_updates import UpstreamCheckerRepoFixture, FRONTMATTER + + +class CompanionRefTests(UpstreamCheckerRepoFixture): + branch_name = "release/next" + + def setUp(self): + super().setUp() + source = Path(__file__).resolve().parent.parent + shutil.copy(source / "tools/upstream_triage.py", self.root / "tools/upstream_triage.py") + self.remote = "forks/template" + self.branch = self.branch_name + # A local remote permits the real companion CLI's normal fetch without + # contacting a service. The selected branch differs from master. + self.add_remote(self.remote, str(self.root)) + self.git("update-ref", f"refs/remotes/{self.remote}/master", "HEAD") + agents = self.root / "AGENTS.md" + agents.write_text(FRONTMATTER.replace("1.0.0", "2.0.0"), encoding="utf-8") + self.git("add", "AGENTS.md") + self.git("commit", "-qm", "update next-release methodology") + self.git("branch", self.branch) + self.git("update-ref", f"refs/remotes/{self.remote}/{self.branch}", "HEAD") + self.git("reset", "--hard", "HEAD~1") + + def git(self, *args): + return subprocess.run(["git", *args], cwd=self.root, check=True, capture_output=True) + + def follow(self, command): + argv = shlex.split(command) + argv[0] = sys.executable + result = subprocess.run(argv, cwd=self.root, capture_output=True, text=True, encoding="utf-8") + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + return result.stdout + + def test_version_checker_companion_uses_selected_remote_and_branch(self): + result = self.run_checker("--remote", self.remote, "--branch", self.branch) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("[UPDATE]", result.stdout) + command = result.stdout.split("run: ", 1)[1].strip() + companion = self.follow(command) + self.assertIn(f"{self.remote}/{self.branch}", companion) + self.assertIn("**1** worth reviewing", companion) + + def test_triage_companion_uses_selected_remote_and_branch(self): + result = subprocess.run( + [sys.executable, "tools/upstream_triage.py", "--remote", self.remote, "--branch", self.branch], + cwd=self.root, capture_output=True, text=True, encoding="utf-8", + ) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("**1** worth reviewing", result.stdout) + command = re.search(r"run `(python tools/check_upstream_updates.py [^`]+)`", result.stdout).group(1) + companion = self.follow(command) + self.assertIn(f"{self.remote}/{self.branch}", companion) + self.assertIn("[UPDATE]", companion) + + +class QuotedCompanionRefTests(CompanionRefTests): + branch_name = "release'next" diff --git a/tools/check_upstream_updates.py b/tools/check_upstream_updates.py index d5271546..4dd8c9db 100755 --- a/tools/check_upstream_updates.py +++ b/tools/check_upstream_updates.py @@ -15,6 +15,7 @@ from __future__ import annotations import argparse import os import re +import shlex import subprocess import sys from pathlib import Path @@ -189,7 +190,7 @@ def main() -> int: # answers "which upstream commits deserve review". Point at the companion. print( f"\nFor commit-level triage of upstream commits, run: " - f"python3 tools/upstream_triage.py --remote {remote}" + f"python3 tools/upstream_triage.py --remote {shlex.quote(remote)} --branch {shlex.quote(args.branch)}" ) return 0 diff --git a/tools/upstream_triage.py b/tools/upstream_triage.py index 4de0f800..986de66e 100755 --- a/tools/upstream_triage.py +++ b/tools/upstream_triage.py @@ -33,6 +33,7 @@ the upstream ref is unavailable, so a scheduled job degrades gracefully. from __future__ import annotations import argparse +import shlex import subprocess import sys @@ -149,7 +150,7 @@ def main() -> int: behind = rev_list(f"HEAD..{ref}") if not behind: print(f"Up to date with `{ref}`. Nothing to review. :white_check_mark:") - _print_crossref(ref) + _print_crossref(args.remote, args.branch) return 0 fork_only = rev_list(f"{ref}..HEAD") @@ -235,15 +236,15 @@ def main() -> int: lines.append("_None._") print("\n".join(lines)) - _print_crossref(ref) + _print_crossref(args.remote, args.branch) return 0 -def _print_crossref(ref: str) -> None: +def _print_crossref(remote: str, branch: str) -> None: print() print( "_For personalized-file version stamps (which methodology files changed), " - f"run `python tools/check_upstream_updates.py --remote {ref.split('/')[0]}`._" + f"run `python tools/check_upstream_updates.py --remote {shlex.quote(remote)} --branch {shlex.quote(branch)}`._" )