Skip to content

Commit 06d272b

Browse files
author
Jacob Mages-Haskins
committed
AIML-150 Fix finding the PR for Copilot
1 parent 70d0b95 commit 06d272b

File tree

4 files changed

+205
-95
lines changed

4 files changed

+205
-95
lines changed

src/git_handler.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ def reset_issue(issue_number: int, remediation_label: str) -> bool:
759759
return False
760760

761761

762-
def find_open_pr_for_issue(issue_number: int) -> dict:
762+
def find_open_pr_for_issue(issue_number: int, issue_title: str) -> dict:
763763
"""
764764
Finds an open pull request associated with the given issue number.
765765
Specifically looks for PRs with branch names matching the pattern 'copilot/fix-{issue_number}'
@@ -805,8 +805,21 @@ def find_open_pr_for_issue(issue_number: int) -> dict:
805805
pr_list_output = run_command(claude_pr_list_command, env=gh_env, check=False)
806806

807807
if not pr_list_output or pr_list_output.strip() == "[]":
808-
debug_log(f"No open PRs found for issue #{issue_number} with either Copilot or Claude branch pattern")
809-
return None
808+
copilot_issue_title_search_pattern = f"in:title \"[WIP] {issue_title}\""
809+
copilot_issue_title_list_command = [
810+
"gh", "pr", "list",
811+
"--repo", config.GITHUB_REPOSITORY,
812+
"--state", "open",
813+
"--search", copilot_issue_title_search_pattern,
814+
"--limit", "1",
815+
"--json", "number,url,title,headRefName,baseRefName,state"
816+
]
817+
818+
pr_list_output = run_command(copilot_issue_title_list_command, env=gh_env, check=False)
819+
820+
if not pr_list_output or pr_list_output.strip() == "[]":
821+
debug_log(f"No open PRs found for issue #{issue_number} with either Copilot or Claude branch pattern")
822+
return None
810823

811824
prs_data = json.loads(pr_list_output)
812825

@@ -926,7 +939,7 @@ def get_issue_comments(issue_number: int, author: str = None) -> List[dict]:
926939
Returns:
927940
List[dict]: A list of comment data dictionaries or empty list if no comments or error
928941
"""
929-
author_log = f"and author: {author}" if author else ""
942+
author_log = f"and author: {author}" if author else ""
930943
debug_log(f"Getting comments for issue #{issue_number} {author_log}")
931944
gh_env = get_gh_env()
932945
author_filter = f"| map(select(.author.login == \"{author}\")) " if author else ""
@@ -1098,7 +1111,11 @@ def get_claude_workflow_run_id() -> int:
10981111
debug_log("Getting in-progress Claude workflow run ID")
10991112

11001113
gh_env = get_gh_env()
1101-
jq_filter = 'map(select(.event == "issues" or .event == "issue_comment") | select(.status == "in_progress") | select(.conclusion != "skipped")) | sort_by(.createdAt) | reverse | .[0]'
1114+
jq_filter = (
1115+
'map(select(.event == "issues" or .event == "issue_comment") | '
1116+
'select(.status == "in_progress") | select(.conclusion != "skipped")) | '
1117+
'sort_by(.createdAt) | reverse | .[0]'
1118+
)
11021119
workflow_command = [
11031120
"gh", "run", "list",
11041121
"--repo", config.GITHUB_REPOSITORY,

src/github/external_coding_agent.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,13 @@ def generate_fixes(self, vuln_uuid: str, remediation_id: str, vuln_title: str, i
193193
# Proceed with PR polling for all agent types
194194

195195
# Poll for PR creation by the external agent
196-
log(f"Waiting for external agent to create a PR for issue #{issue_number}")
196+
log(f"Waiting for external agent to create a PR for issue #{issue_number}, '{issue_title}'")
197197

198198
# Poll for a PR to be created by the external agent (100 attempts, 5 seconds apart = ~8.3 minutes max)
199-
pr_info = self._process_external_coding_agent_run(issue_number, remediation_id, vulnerability_label, remediation_label, is_existing_issue, max_attempts=100, sleep_seconds=5)
199+
pr_info = self._process_external_coding_agent_run(
200+
issue_number, issue_title, remediation_id, vulnerability_label,
201+
remediation_label, is_existing_issue, max_attempts=100, sleep_seconds=5
202+
)
200203

201204
log("\n::endgroup::")
202205
if pr_info:
@@ -215,7 +218,7 @@ def generate_fixes(self, vuln_uuid: str, remediation_id: str, vuln_title: str, i
215218
telemetry_handler.update_telemetry("resultInfo.failureCategory", FailureCategory.AGENT_FAILURE.name)
216219
return False
217220

218-
def _process_external_coding_agent_run(self, issue_number: int, remediation_id: str, vulnerability_label: str,
221+
def _process_external_coding_agent_run(self, issue_number: int, issue_title: str, remediation_id: str, vulnerability_label: str,
219222
remediation_label: str, is_existing_issue: bool,
220223
max_attempts: int = 100, sleep_seconds: int = 5) -> Optional[dict]:
221224
"""
@@ -246,7 +249,7 @@ def _process_external_coding_agent_run(self, issue_number: int, remediation_id:
246249
pr_info = self._process_claude_workflow_run(issue_number, remediation_id)
247250
else:
248251
# GitHub Copilot agent
249-
pr_info = git_handler.find_open_pr_for_issue(issue_number)
252+
pr_info = git_handler.find_open_pr_for_issue(issue_number, issue_title)
250253

251254
if pr_info:
252255
pr_number = pr_info.get("number")
@@ -288,7 +291,6 @@ def _process_external_coding_agent_run(self, issue_number: int, remediation_id:
288291
log(f"No PR found for issue #{issue_number} after {max_attempts} polling attempts", is_error=True)
289292
return None
290293

291-
292294
def _process_claude_workflow_run(self, issue_number: int, remediation_id: str,) -> Optional[dict]:
293295
"""
294296
Process the Claude Code workflow run and extract PR information from Claude's comment
@@ -307,13 +309,13 @@ def _process_claude_workflow_run(self, issue_number: int, remediation_id: str,)
307309

308310
if not workflow_run_id:
309311
# If no workflow run ID found yet, continue polling
310-
debug_log(f"Claude workflow_run_id not found, checking again...")
312+
debug_log("Claude workflow_run_id not found, checking again...")
311313
return None
312314

313315
# Get all issue comments to find the latest comment author.login
314316
issue_comments = git_handler.get_issue_comments(issue_number)
315317
if not issue_comments or len(issue_comments) == 0:
316-
debug_log(f"No comments added to issue, checking again...")
318+
debug_log("No comments added to issue, checking again...")
317319
return None
318320

319321
author_login = issue_comments[0].get("author", {}).get("login", '')
@@ -364,8 +366,8 @@ def _process_claude_workflow_run(self, issue_number: int, remediation_id: str,)
364366
debug_log(f"Claude create PR returned url: {pr_url}")
365367

366368
if not pr_url:
367-
log(f"Failed to create PR for Claude Code fix", is_error=True)
368-
reason = f"Could not create Claude PR due to processing issues"
369+
log("Failed to create PR for Claude Code fix", is_error=True)
370+
reason = "Could not create Claude PR due to processing issues"
369371
self._update_telemetry_and_exit_claude_agent_failure(reason, remediation_id, issue_number)
370372

371373
# Extract PR number from URL
@@ -396,8 +398,7 @@ def _process_claude_workflow_run(self, issue_number: int, remediation_id: str,)
396398
self._update_telemetry_and_exit_claude_agent_failure(msg, remediation_id, issue_number)
397399
return None
398400

399-
400-
def _process_claude_comment_body(self, comment_body: str, remediation_id: str, issue_number: int) -> dict:
401+
def _process_claude_comment_body(self, comment_body: str, remediation_id: str, issue_number: int) -> dict: # noqa: C901
401402
"""
402403
Process Claude's comment body to extract PR information. Returning the pr_title
403404
and pr_body are required for this method to be successful and to create the PR.
@@ -499,7 +500,6 @@ def _process_claude_comment_body(self, comment_body: str, remediation_id: str, i
499500
"pr_body": contrast_pr_body
500501
}
501502

502-
503503
def _get_claude_head_branch(self, head_branch_from_url: str,
504504
comment_body: str,
505505
issue_number: int,
@@ -547,8 +547,8 @@ def _get_claude_head_branch(self, head_branch_from_url: str,
547547

548548
# Final check - if no branch could be found by any method, fail gracefully
549549
if not head_branch:
550-
log(f"Could not determine claude branch name using any available method", is_error=True)
551-
reason = f"Could not extract Claude head_branch needed for PR creation"
550+
log("Could not determine claude branch name using any available method", is_error=True)
551+
reason = "Could not extract Claude head_branch needed for PR creation"
552552
self._update_telemetry_and_exit_claude_agent_failure(reason, remediation_id, issue_number)
553553

554554
return head_branch

0 commit comments

Comments
 (0)