fix(github): pass repo parameter to GHClient for explicit PR resolution (#413)

The gh CLI was failing with "Could not resolve to a PullRequest" error
because it inferred the repository from git remotes instead of using
an explicit repository. With multiple remotes configured, the wrong
repo could be queried.

This fix passes the repo parameter through the call chain and adds
the -R flag to all PR-related gh commands, ensuring the correct
repository is always queried regardless of git remote configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Andy
2025-12-29 23:21:40 +01:00
committed by GitHub
parent a39ea49d4d
commit 4bdf7a0c5b
4 changed files with 43 additions and 2 deletions
@@ -201,13 +201,15 @@ class PRContext:
class PRContextGatherer:
"""Gathers all context needed for PR review BEFORE the AI starts."""
def __init__(self, project_dir: Path, pr_number: int):
def __init__(self, project_dir: Path, pr_number: int, repo: str | None = None):
self.project_dir = Path(project_dir)
self.pr_number = pr_number
self.repo = repo
self.gh_client = GHClient(
project_dir=self.project_dir,
default_timeout=30.0,
max_retries=3,
repo=repo,
)
async def gather(self) -> PRContext:
@@ -953,14 +955,17 @@ class FollowupContextGatherer:
project_dir: Path,
pr_number: int,
previous_review: PRReviewResult, # Forward reference
repo: str | None = None,
):
self.project_dir = Path(project_dir)
self.pr_number = pr_number
self.previous_review = previous_review
self.repo = repo
self.gh_client = GHClient(
project_dir=self.project_dir,
default_timeout=30.0,
max_retries=3,
repo=repo,
)
async def gather(self) -> FollowupReviewContext:
+32
View File
@@ -84,6 +84,7 @@ class GHClient:
default_timeout: float = 30.0,
max_retries: int = 3,
enable_rate_limiting: bool = True,
repo: str | None = None,
):
"""
Initialize GitHub CLI client.
@@ -93,11 +94,14 @@ class GHClient:
default_timeout: Default timeout in seconds for commands
max_retries: Maximum number of retry attempts
enable_rate_limiting: Whether to enforce rate limiting (default: True)
repo: Repository in 'owner/repo' format. If provided, uses -R flag
instead of inferring from git remotes.
"""
self.project_dir = Path(project_dir)
self.default_timeout = default_timeout
self.max_retries = max_retries
self.enable_rate_limiting = enable_rate_limiting
self.repo = repo
# Initialize rate limiter singleton
if enable_rate_limiting:
@@ -254,6 +258,28 @@ class GHClient:
# Should never reach here, but for type safety
raise GHCommandError(f"gh {args[0]} failed after {self.max_retries} attempts")
# =========================================================================
# Helper methods
# =========================================================================
def _add_repo_flag(self, args: list[str]) -> list[str]:
"""
Add -R flag to command args if repo is configured.
This ensures gh CLI uses the correct repository instead of
inferring from git remotes, which can fail with multiple remotes
or when working in worktrees.
Args:
args: Command arguments list
Returns:
Modified args list with -R flag if repo is set
"""
if self.repo:
return args + ["-R", self.repo]
return args
# =========================================================================
# Convenience methods for common gh commands
# =========================================================================
@@ -295,6 +321,7 @@ class GHClient:
"--json",
",".join(json_fields),
]
args = self._add_repo_flag(args)
result = await self.run(args)
return json.loads(result.stdout)
@@ -334,6 +361,7 @@ class GHClient:
"--json",
",".join(json_fields),
]
args = self._add_repo_flag(args)
result = await self.run(args)
return json.loads(result.stdout)
@@ -352,6 +380,7 @@ class GHClient:
PRTooLargeError: If PR exceeds GitHub's 20,000 line diff limit
"""
args = ["pr", "diff", str(pr_number)]
args = self._add_repo_flag(args)
try:
result = await self.run(args)
return result.stdout
@@ -396,6 +425,7 @@ class GHClient:
args.append("--comment")
args.extend(["--body", body])
args = self._add_repo_flag(args)
await self.run(args)
return 0 # gh CLI doesn't return review ID
@@ -574,6 +604,7 @@ class GHClient:
args.extend(["--subject", commit_title])
if commit_message:
args.extend(["--body", commit_message])
args = self._add_repo_flag(args)
await self.run(args)
@@ -586,6 +617,7 @@ class GHClient:
body: Comment body
"""
args = ["pr", "comment", str(pr_number), "--body", body]
args = self._add_repo_flag(args)
await self.run(args)
async def pr_get_assignees(self, pr_number: int) -> list[str]:
+4 -1
View File
@@ -129,6 +129,7 @@ class GitHubOrchestrator:
default_timeout=30.0,
max_retries=3,
enable_rate_limiting=True,
repo=config.repo,
)
# Initialize bot detector for preventing infinite loops
@@ -300,7 +301,9 @@ class GitHubOrchestrator:
try:
# Gather PR context
print("[DEBUG orchestrator] Creating context gatherer...", flush=True)
gatherer = PRContextGatherer(self.project_dir, pr_number)
gatherer = PRContextGatherer(
self.project_dir, pr_number, repo=self.config.repo
)
print("[DEBUG orchestrator] Gathering PR context...", flush=True)
pr_context = await gatherer.gather()
@@ -56,6 +56,7 @@ class GitHubProvider:
self._gh_client = GHClient(
project_dir=project_dir,
enable_rate_limiting=self.enable_rate_limiting,
repo=self._repo,
)
@property