From 019972f9ebe66e49aa6561d7e0195388acd61610 Mon Sep 17 00:00:00 2001 From: abuzarmahmood Date: Wed, 23 Jul 2025 00:10:08 +0000 Subject: [PATCH 1/4] feat: implement catch_log label detection and log parsing feature Co-authored-by: aider (gpt-4o) --- src/git_utils.py | 53 +++++++++++++++++++++++++++++++++++++++++++ src/response_agent.py | 5 ++++ src/triggers.py | 13 +++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/git_utils.py b/src/git_utils.py index 2489c6b..424c3e8 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -20,8 +20,40 @@ from github.Issue import Issue from github.Repository import Repository import os +import requests +import os from github.IssueComment import IssueComment + +def fetch_and_parse_github_actions_log(issue: Issue) -> str: + """ + Fetch and parse the GitHub Actions log for errors or tracebacks. + + Args: + issue: The GitHub issue to fetch logs for. + + Returns: + A string containing the parsed error or traceback. + """ + repo = issue.repository + workflow_runs = repo.get_workflow_runs(event='pull_request', branch=issue.pull_request.head.ref) + + if workflow_runs.total_count == 0: + return "No workflow runs found for this pull request." + + latest_run = workflow_runs[0] + logs_url = latest_run.logs_url + + headers = {'Authorization': f'token {os.getenv("GITHUB_TOKEN")}'} + response = requests.get(logs_url, headers=headers) + + if response.status_code != 200: + return f"Failed to fetch logs: {response.status_code} {response.reason}" + + logs = response.text + return parse_github_action_logs(logs) + + # Determine base directory src_dir = os.path.dirname(os.path.abspath(__file__)) base_dir = os.path.dirname(src_dir) @@ -90,6 +122,27 @@ def get_open_issues(repo: Repository) -> List[Issue]: return list(repo.get_issues(state='open', sort='created', direction='asc')) +def parse_github_action_logs(logs: str) -> str: + """ + Parse GitHub Actions logs for errors or tracebacks. + + Args: + logs: The logs from a GitHub Actions workflow run. + + Returns: + A string containing the parsed error or traceback messages. + """ + error_lines = [] + for line in logs.splitlines(): + if "error" in line.lower() or "traceback" in line.lower(): + error_lines.append(line) + + if not error_lines: + return "No errors or tracebacks found in logs." + + return "\n".join(error_lines) + + def get_issue_comments(issue: Issue) -> List[IssueComment]: """Get all comments for a specific issue or pull request, ignoring Graphite-related comments""" # Text to identify Graphite-related comments diff --git a/src/response_agent.py b/src/response_agent.py index eeb4bfc..dc434b6 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -1001,6 +1001,11 @@ def process_issue( print(f"Processing {entity_type} #{issue_or_pr.number}") try: + if triggers.has_catch_log_label(issue_or_pr): + parsed_log = git_utils.fetch_and_parse_github_actions_log(issue_or_pr) + write_issue_response(issue_or_pr, f"Error log:\n```\n{parsed_log}\n```") + return True, None + has_bot_mention = triggers.has_blech_bot_tag(issue_or_pr) \ or '[ blech_bot ]' in (issue_or_pr.title or '').lower() if not has_bot_mention: diff --git a/src/triggers.py b/src/triggers.py index a0ef1cb..b81a79f 100644 --- a/src/triggers.py +++ b/src/triggers.py @@ -21,6 +21,19 @@ def has_blech_bot_tag(issue: Issue) -> bool: return any(label.name == "blech_bot" for label in issue.labels) +def has_catch_log_label(issue: Issue) -> bool: + """ + Check if the issue has the 'catch_log' label + + Args: + issue: The GitHub issue to check + + Returns: + True if the issue has the 'catch_log' label, False otherwise + """ + return any(label.name == "catch_log" for label in issue.labels) + + def has_generate_edit_command_trigger(issue: Issue) -> bool: """ Check if the issue comments contain the trigger for generate_edit_command From 9c5fcfd324395be74fa5b5047d173d2f929caf5e Mon Sep 17 00:00:00 2001 From: abuzarmahmood Date: Wed, 23 Jul 2025 00:10:15 +0000 Subject: [PATCH 2/4] fix: import git_utils to resolve undefined name error in response_agent.py Co-authored-by: aider (gpt-4o) --- src/response_agent.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/response_agent.py b/src/response_agent.py index dc434b6..b096a3a 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -24,6 +24,7 @@ import bot_tools import os +import src.git_utils as git_utils from src.git_utils import ( get_github_client, get_repository, From f763aff81d6a978bcb9b479c22607a9a6715e244 Mon Sep 17 00:00:00 2001 From: abuzarmahmood Date: Wed, 23 Jul 2025 00:18:20 +0000 Subject: [PATCH 3/4] feat: enhance blech_github_bot to handle 'catch_log' label and fetch logs Co-authored-by: aider (gpt-4o) --- src/git_utils.py | 13 +++++++++++++ src/response_agent.py | 5 +++++ src/triggers.py | 12 ++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/git_utils.py b/src/git_utils.py index 424c3e8..1f97b73 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -99,6 +99,19 @@ def add_signature_to_comment(comment_text: str, model: str) -> str: return comment_text +def parse_github_action_logs(logs: str) -> str: + """ + Parse GitHub Actions logs for errors or tracebacks. + + Args: + logs: The logs from a GitHub Actions workflow run. + + Returns: + A string containing the parsed error or traceback messages. + """ + error_lines = [line for line in logs.splitlines() if "error" in line.lower() or "traceback" in line.lower()] + return "\n".join(error_lines) if error_lines else "No errors or tracebacks found in logs." + def get_github_client() -> Github: """Initialize and return authenticated GitHub client""" load_dotenv() diff --git a/src/response_agent.py b/src/response_agent.py index b096a3a..1143ddf 100644 --- a/src/response_agent.py +++ b/src/response_agent.py @@ -143,6 +143,11 @@ def scrape_text_from_url(url: str) -> str: Returns: The scraped text content or a message if non-text content is detected. """ + if triggers.has_catch_log_label(issue_or_pr): + parsed_log = git_utils.fetch_and_parse_github_actions_log(issue_or_pr) + write_issue_response(issue_or_pr, f"Error log:\n```\n{parsed_log}\n```") + return True, None + try: response = requests.get(url, timeout=10) response.raise_for_status() # Raise an error for bad responses diff --git a/src/triggers.py b/src/triggers.py index b81a79f..614bd9e 100644 --- a/src/triggers.py +++ b/src/triggers.py @@ -34,6 +34,18 @@ def has_catch_log_label(issue: Issue) -> bool: return any(label.name == "catch_log" for label in issue.labels) +def has_catch_log_label(issue: Issue) -> bool: + """ + Check if the issue has the 'catch_log' label + + Args: + issue: The GitHub issue to check + + Returns: + True if the issue has the 'catch_log' label, False otherwise + """ + return any(label.name == "catch_log" for label in issue.labels) + def has_generate_edit_command_trigger(issue: Issue) -> bool: """ Check if the issue comments contain the trigger for generate_edit_command From f7a6160be46fb40dd6439c9bbe4fe5e1fbb7d26a Mon Sep 17 00:00:00 2001 From: abuzarmahmood Date: Wed, 23 Jul 2025 00:18:24 +0000 Subject: [PATCH 4/4] fix: correct search/replace block in src/git_utils.py for matching lines Co-authored-by: aider (gpt-4o) --- src/git_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/git_utils.py b/src/git_utils.py index 1f97b73..331c1e6 100644 --- a/src/git_utils.py +++ b/src/git_utils.py @@ -52,6 +52,7 @@ def fetch_and_parse_github_actions_log(issue: Issue) -> str: logs = response.text return parse_github_action_logs(logs) + return parse_github_action_logs(logs) # Determine base directory