From 393ed23ba09e3ff3e16b8437b149c4de061f418f Mon Sep 17 00:00:00 2001 From: Wes1ey Date: Fri, 11 Jul 2025 22:06:20 +0800 Subject: [PATCH 1/4] (feated) GitHub Issue auto debug script and guidelines for use --- prometheus/script/GitHub_Issue_Debug_Guide.md | 303 +++++++++++++ prometheus/script/github_issue_debug.py | 406 ++++++++++++++++++ 2 files changed, 709 insertions(+) create mode 100644 prometheus/script/GitHub_Issue_Debug_Guide.md create mode 100644 prometheus/script/github_issue_debug.py diff --git a/prometheus/script/GitHub_Issue_Debug_Guide.md b/prometheus/script/GitHub_Issue_Debug_Guide.md new file mode 100644 index 00000000..14d6cfd5 --- /dev/null +++ b/prometheus/script/GitHub_Issue_Debug_Guide.md @@ -0,0 +1,303 @@ +# GitHub Issue Auto Debug Script Usage Guide + +## Overview + +`github_issue_debug.py` is an automated script for: +1. Retrieving detailed information (title, body, comments, etc.) of a specified issue from the GitHub API. +2. Automatically uploading the GitHub repository to Prometheus. +3. Using Prometheus's AI analysis capabilities to debug the issue. +4. Returning analysis results, fix patches, etc. + +## Prerequisites + +### 1. Start Prometheus Service +Ensure the Prometheus service is running: +```bash +# Start using docker-compose +docker-compose -f docker-compose.win_mac.yml up -d + +# Check service status +docker-compose -f docker-compose.win_mac.yml ps +``` + +### 2. Obtain GitHub Personal Access Token +1. Visit https://github.com/settings/tokens +2. Click "Generate new token (classic)" +3. Select the appropriate permission scope: + - `repo` (access private repositories) + - `public_repo` (access public repositories) +4. Generate and save the token. + +### 3. Install Python Dependencies +```bash +pip install requests +``` + +## Basic Usage + +### Simple Example +```bash +python github_issue_debug.py \ + --github-token "your_token_here" \ + --repo "owner/repository" \ + --issue-number 42 +``` + +### Full Parameter Example +```bash +python github_issue_debug.py \ + --github-token "ghp_xxxxxxxxxxxxxxxxxxxx" \ + --repo "microsoft/vscode" \ + --issue-number 123 \ + --prometheus-url "http://localhost:8000" \ + --output-file "debug_result.json" \ + --run-build \ + --run-test \ + --push-to-remote \ + --image-name "python:3.11-slim" \ + --workdir "/app" \ + --build-commands "pip install -r requirements.txt" "python setup.py build" \ + --test-commands "pytest tests/" \ + --candidate-patches 3 +``` + +## Parameter Details + +### Required Parameters +- `--github-token`: GitHub Personal Access Token +- `--repo`: GitHub repository name in the format `owner/repo` +- `--issue-number`: Issue number to process + +### Optional Parameters +- `--prometheus-url`: Prometheus service address (default: http://localhost:8000) +- `--output-file`: Path to the result output file (if not specified, output to console) + +### Validation Options +- `--run-build`: Run build validation for the generated patch +- `--run-test`: Run test validation for the generated patch +- `--push-to-remote`: Push the fix to a remote Git branch + +### Docker Environment Configuration +- `--dockerfile-content`: Specify Dockerfile content directly +- `--image-name`: Use a predefined Docker image +- `--workdir`: Working directory inside the container (default: /app) +- `--build-commands`: List of build commands +- `--test-commands`: List of test commands + +### Other Options +- `--candidate-patches`: Number of candidate patches (default: 4) + +## Usage Scenarios + +### Scenario 1: Simple Bug Report Analysis +```bash +# Analyze a simple bug report without running any validation +python github_issue_debug.py \ + --github-token "your_token" \ + --repo "pytorch/pytorch" \ + --issue-number 89123 +``` + +### Scenario 2: Python Project with Test Validation +```bash +# Perform a complete debug for a Python project, including build and test validation +python github_issue_debug.py \ + --github-token "your_token" \ + --repo "requests/requests" \ + --issue-number 5678 \ + --run-build \ + --run-test \ + --image-name "python:3.11-slim" \ + --build-commands "pip install -e ." \ + --test-commands "pytest tests/test_requests.py" +``` + +### Scenario 3: Node.js Project with Auto Push +```bash +# Process an issue for a Node.js project and automatically push the fix to a remote branch +python github_issue_debug.py \ + --github-token "your_token" \ + --repo "facebook/react" \ + --issue-number 9876 \ + --run-build \ + --run-test \ + --push-to-remote \ + --image-name "node:18-slim" \ + --build-commands "npm ci" "npm run build" \ + --test-commands "npm test" +``` + +### Scenario 4: Custom Docker Environment +```bash +# Use a custom Dockerfile for debugging +python github_issue_debug.py \ + --github-token "your_token" \ + --repo "tensorflow/tensorflow" \ + --issue-number 4321 \ + --run-build \ + --dockerfile-content "FROM tensorflow/tensorflow:latest-gpu +WORKDIR /app +COPY . /app +RUN pip install -r requirements.txt" \ + --workdir "/app" \ + --build-commands "python setup.py build_ext --inplace" \ + --test-commands "python -m pytest tests/unit/" +``` + +## Output Result Explanation + +After execution, the script outputs results in JSON format, including the following fields: + +```json +{ + "success": true, + "issue_info": { + "repo": "owner/repo", + "number": 123, + "title": "Issue Title", + "url": "https://github.com/owner/repo/issues/123", + "state": "open" + }, + "prometheus_result": { + "patch": "Generated code patch", + "passed_reproducing_test": true, + "passed_build": true, + "passed_existing_test": false, + "issue_response": "AI-generated issue response", + "remote_branch_name": "prometheus-fix-issue-123" + } +} +``` + +### Result Field Description +- `success`: Whether the process was successful +- `issue_info`: Basic information about the GitHub issue +- `prometheus_result.patch`: Code fix patch generated by Prometheus +- `prometheus_result.passed_*`: Status of various validations +- `prometheus_result.issue_response`: AI-generated issue analysis and response +- `prometheus_result.remote_branch_name`: Name of the remote branch pushed (if enabled) + +## Common Issues and Solutions + +### 1. GitHub API Limitations +**Problem**: Encountering API limit errors +**Solution**: +- Ensure a valid Personal Access Token is used +- Check the token's permission scope +- Be mindful of GitHub API rate limits + +### 2. Prometheus Service Connection Failure +**Problem**: Unable to connect to the Prometheus service +**Solution**: +```bash +# Check service status +docker-compose -f docker-compose.win_mac.yml ps + +# Restart the service +docker-compose -f docker-compose.win_mac.yml restart + +# Check logs +docker-compose -f docker-compose.win_mac.yml logs prometheus +``` + +### 3. Repository Upload Failure +**Problem**: Unable to access private repositories +**Solution**: +- Ensure the GitHub token has `repo` permissions +- Check if the repository URL format is correct +- For private repositories, ensure the token owner has access permissions + +### 4. Build/Test Failure +**Problem**: Build or test failure in the Docker environment +**Solution**: +- Check if the specified Docker image is correct +- Validate the build and test commands +- Ensure the working directory is set correctly +- Check Prometheus logs for detailed error information + +## Advanced Usage Tips + +### 1. Batch Processing Multiple Issues +Create a batch script: +```bash +#!/bin/bash +GITHUB_TOKEN="your_token" +REPO="owner/repo" + +for issue in 123 124 125; do + echo "Processing issue #$issue" + python github_issue_debug.py \ + --github-token "$GITHUB_TOKEN" \ + --repo "$REPO" \ + --issue-number $issue \ + --output-file "results/issue_${issue}_result.json" +done +``` + +### 2. Integration into CI/CD +Use in GitHub Actions: +```yaml +- name: Debug Issue with Prometheus + run: | + python github_issue_debug.py \ + --github-token "${{ secrets.GITHUB_TOKEN }}" \ + --repo "${{ github.repository }}" \ + --issue-number "${{ github.event.issue.number }}" \ + --output-file "debug_result.json" +``` + +### 3. Post-Processing Results +Process results using Python: +```python +import json + +with open('debug_result.json', 'r') as f: + result = json.load(f) + +if result['success']: + patch = result['prometheus_result']['patch'] + # Further process the patch... +``` + +## Notes + +1. **Security**: + - Do not hardcode the GitHub token in the code + - Use environment variables or configuration files to store sensitive information + +2. **Performance**: + - Processing large repositories may take a long time + - It is recommended to test on smaller repositories first + +3. **Resource Usage**: + - Ensure sufficient disk space for cloning repositories + - Monitor Docker container resource usage + +4. **Network**: + - Ensure a stable network connection + - Some network environments may require proxy configuration + +## Troubleshooting + +### Enable Detailed Logs +Set environment variables to enable detailed output: +```bash +export PYTHONUNBUFFERED=1 +python github_issue_debug.py --your-args +``` + +### Check Prometheus Status +```bash +# Check API health status +curl http://localhost:8000/docs + +# Check knowledge graph status +curl http://localhost:8000/repository/exists/ +``` + +### Reset Prometheus State +If you need to start over: +```bash +# Delete existing knowledge graph +curl -X GET http://localhost:8000/repository/delete/ +``` diff --git a/prometheus/script/github_issue_debug.py b/prometheus/script/github_issue_debug.py new file mode 100644 index 00000000..ac432ac5 --- /dev/null +++ b/prometheus/script/github_issue_debug.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python3 +""" +GitHub Issue Auto Debug Script + +This script automatically retrieves issue information from GitHub, uploads the repository to Prometheus, and sends the issue for debug analysis. + +Usage: + python github_issue_debug.py --github-token YOUR_TOKEN --repo owner/repo --issue-number 42 + +Parameter Description: + --github-token: GitHub Personal Access Token (required) + --repo: GitHub repository (format: owner/repo) (required) + --issue-number: Issue number (required) + --prometheus-url: Prometheus service address (default: http://localhost:8000) + --output-file: Result output file (optional, default outputs to console) + --run-build: Whether to run build validation (default: False) + --run-test: Whether to run test validation (default: False) + --push-to-remote: Whether to push the fix to a remote branch (default: False) +""" + +import argparse +import json +import sys +from typing import Dict, List, Optional +import requests +from urllib.parse import urljoin + + +class GitHubIssueDebugger: + def __init__(self, github_token: str, prometheus_url: str = "http://localhost:8000"): + """ + Initialize GitHub Issue Debugger + + Args: + github_token: GitHub Personal Access Token + prometheus_url: Prometheus service URL + """ + self.github_token = github_token + self.prometheus_url = prometheus_url.rstrip('/') + self.github_headers = { + "Authorization": f"token {github_token}", + "Accept": "application/vnd.github.v3+json" + } + self.prometheus_headers = { + "Content-Type": "application/json" + } + + def get_github_issue(self, repo: str, issue_number: int) -> Dict: + """ + Retrieve issue information from GitHub + + Args: + repo: Repository name (format: owner/repo) + issue_number: Issue number + + Returns: + A dictionary containing issue information + """ + print(f"Retrieving GitHub issue: {repo}#{issue_number}") + + # Retrieve basic issue information + issue_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}" + response = requests.get(issue_url, headers=self.github_headers) + + if response.status_code != 200: + raise Exception(f"Failed to retrieve issue: {response.status_code} - {response.text}") + + issue_data = response.json() + + # Retrieve issue comments + comments_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}/comments" + comments_response = requests.get(comments_url, headers=self.github_headers) + + comments = [] + if comments_response.status_code == 200: + comments_data = comments_response.json() + comments = [ + { + "username": comment["user"]["login"], + "comment": comment["body"] + } + for comment in comments_data + ] + + return { + "number": issue_data["number"], + "title": issue_data["title"], + "body": issue_data["body"] or "", + "comments": comments, + "state": issue_data["state"], + "html_url": issue_data["html_url"] + } + + def upload_repository_to_prometheus(self, repo: str) -> bool: + """ + Upload GitHub repository to Prometheus + + Args: + repo: Repository name (format: owner/repo) + + Returns: + Whether the upload was successful + """ + print(f"Uploading repository to Prometheus: {repo}") + + # Construct GitHub HTTPS URL + github_url = f"https://github.com/{repo}.git" + + # Call Prometheus API to upload repository + upload_url = urljoin(self.prometheus_url, "/repository/github/") + params = {"https_url": github_url} + + response = requests.get(upload_url, params=params, headers=self.prometheus_headers) + + if response.status_code == 200: + print("Repository uploaded successfully") + return True + else: + print(f"Failed to upload repository: {response.status_code} - {response.text}") + return False + + def check_repository_exists(self) -> bool: + """ + Check if the knowledge graph already exists in Prometheus + + Returns: + Whether the knowledge graph exists + """ + exists_url = urljoin(self.prometheus_url, "/repository/exists/") + response = requests.get(exists_url, headers=self.prometheus_headers) + + if response.status_code == 200: + return response.json() + return False + + def send_issue_to_prometheus(self, issue_data: Dict, config: Dict) -> Dict: + """ + Send issue to Prometheus for debugging + + Args: + issue_data: GitHub issue data + config: Configuration parameters + + Returns: + Response from Prometheus + """ + print(f"Sending issue to Prometheus for debug analysis...") + + # Construct Prometheus API request data + request_data = { + "issue_number": issue_data["number"], + "issue_title": issue_data["title"], + "issue_body": issue_data["body"], + "issue_comments": issue_data["comments"], + "issue_type": "bug", + "run_build": config.get("run_build", False), + "run_existing_test": config.get("run_test", False), + "number_of_candidate_patch": config.get("candidate_patches", 4), + "push_to_remote": config.get("push_to_remote", False) + } + + # Add Docker configuration if present + if config.get("dockerfile_content"): + request_data["dockerfile_content"] = config["dockerfile_content"] + request_data["workdir"] = config.get("workdir", "/app") + elif config.get("image_name"): + request_data["image_name"] = config["image_name"] + request_data["workdir"] = config.get("workdir", "/app") + + if config.get("build_commands"): + request_data["build_commands"] = config["build_commands"] + + if config.get("test_commands"): + request_data["test_commands"] = config["test_commands"] + + # Send request to Prometheus + answer_url = urljoin(self.prometheus_url, "/issue/answer/") + response = requests.post(answer_url, json=request_data, headers=self.prometheus_headers) + + if response.status_code == 200: + return response.json() + else: + raise Exception(f"Prometheus processing failed: {response.status_code} - {response.text}") + + def process_issue(self, repo: str, issue_number: int, config: Dict) -> Dict: + """ + Complete issue processing workflow + + Args: + repo: Repository name + issue_number: Issue number + config: Configuration parameters + + Returns: + Processing result + """ + try: + # 1. Retrieve GitHub issue + issue_data = self.get_github_issue(repo, issue_number) + + # 2. Check if repository is already uploaded, if not, upload it + if not self.check_repository_exists(): + if not self.upload_repository_to_prometheus(repo): + raise Exception("Repository upload failed") + else: + print("Knowledge graph already exists in Prometheus, skipping repository upload") + + # 3. Send issue to Prometheus for debugging + result = self.send_issue_to_prometheus(issue_data, config) + + # 4. Integrate results + return { + "success": True, + "issue_info": { + "repo": repo, + "number": issue_data["number"], + "title": issue_data["title"], + "url": issue_data["html_url"], + "state": issue_data["state"] + }, + "prometheus_result": result + } + + except Exception as e: + return { + "success": False, + "error": str(e), + "issue_info": { + "repo": repo, + "number": issue_number + } + } + + +def main(): + parser = argparse.ArgumentParser( + description="GitHub Issue Auto Debug Script", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__ + ) + + parser.add_argument( + "--github-token", + required=True, + help="GitHub Personal Access Token" + ) + + parser.add_argument( + "--repo", + required=True, + help="GitHub repository (format: owner/repo)" + ) + + parser.add_argument( + "--issue-number", + type=int, + required=True, + help="Issue number" + ) + + parser.add_argument( + "--prometheus-url", + default="http://localhost:9002", + help="Prometheus service address (default: http://localhost:9002)" + ) + + parser.add_argument( + "--output-file", + help="Path to the result output file (optional, default outputs to console)" + ) + + parser.add_argument( + "--run-build", + action="store_true", + help="Run build validation" + ) + + parser.add_argument( + "--run-test", + action="store_true", + help="Run test validation" + ) + + parser.add_argument( + "--push-to-remote", + action="store_true", + help="Push fix to remote branch" + ) + + parser.add_argument( + "--dockerfile-content", + help="Dockerfile content (for specifying container environment)" + ) + + parser.add_argument( + "--image-name", + help="Docker image name (for specifying container environment)" + ) + + parser.add_argument( + "--workdir", + default="/app", + help="Working directory (required when using container environment)" + ) + + parser.add_argument( + "--build-commands", + nargs="+", + help="List of build commands" + ) + + parser.add_argument( + "--test-commands", + nargs="+", + help="List of test commands" + ) + + parser.add_argument( + "--candidate-patches", + type=int, + default=4, + help="Number of candidate patches (default: 4)" + ) + + args = parser.parse_args() + + # Validate repo format + if "/" not in args.repo: + print("Error: Invalid repo format, should be 'owner/repo'") + sys.exit(1) + + # Build configuration + config = { + "run_build": args.run_build, + "run_test": args.run_test, + "push_to_remote": args.push_to_remote, + "candidate_patches": args.candidate_patches, + "workdir": args.workdir + } + + if args.dockerfile_content: + config["dockerfile_content"] = args.dockerfile_content + + if args.image_name: + config["image_name"] = args.image_name + + if args.build_commands: + config["build_commands"] = args.build_commands + + if args.test_commands: + config["test_commands"] = args.test_commands + + # Create debugger and process issue + debugger = GitHubIssueDebugger(args.github_token, args.prometheus_url) + result = debugger.process_issue(args.repo, args.issue_number, config) + + # Output results + if args.output_file: + with open(args.output_file, 'w', encoding='utf-8') as f: + json.dump(result, f, indent=2, ensure_ascii=False) + print(f"Results saved to: {args.output_file}") + else: + print("\n" + "="*60) + print("Processing Results:") + print("="*60) + print(json.dumps(result, indent=2, ensure_ascii=False)) + + # Simplified summary output + print("\n" + "="*60) + print("Execution Summary:") + print("="*60) + + if result["success"]: + issue_info = result["issue_info"] + prometheus_result = result["prometheus_result"] + + print(f"✅ Successfully processed GitHub Issue") + print(f" Repository: {issue_info['repo']}") + print(f" Issue: #{issue_info['number']} - {issue_info['title']}") + print(f" URL: {issue_info['url']}") + print(f" State: {issue_info['state']}") + + if prometheus_result.get("patch"): + print(f"✅ Generated fix patch") + + if prometheus_result.get("passed_build") is not None: + status = "✅ Passed" if prometheus_result["passed_build"] else "❌ Failed" + print(f" Build Validation: {status}") + + if prometheus_result.get("passed_existing_test") is not None: + status = "✅ Passed" if prometheus_result["passed_existing_test"] else "❌ Failed" + print(f" Test Validation: {status}") + + if prometheus_result.get("remote_branch_name"): + print(f"✅ Pushed to remote branch: {prometheus_result['remote_branch_name']}") + + if prometheus_result.get("issue_response"): + print(f"📝 Prometheus analysis result generated") + + else: + print(f"❌ Processing failed: {result['error']}") + sys.exit(1) + + +if __name__ == "__main__": + main() From 6e6ada8aeb069b01e486e8507a92860ea91b6ea1 Mon Sep 17 00:00:00 2001 From: Yue Pan <79363355+dcloud347@users.noreply.github.com> Date: Sat, 12 Jul 2025 00:51:43 +0800 Subject: [PATCH 2/4] Refactor GitHub issue debug script for improved readability and consistency --- .../GitHub-Issue-Debug-Guide.md | 0 prometheus/script/github_issue_debug.py | 251 ++++++++---------- 2 files changed, 104 insertions(+), 147 deletions(-) rename prometheus/script/GitHub_Issue_Debug_Guide.md => docs/GitHub-Issue-Debug-Guide.md (100%) diff --git a/prometheus/script/GitHub_Issue_Debug_Guide.md b/docs/GitHub-Issue-Debug-Guide.md similarity index 100% rename from prometheus/script/GitHub_Issue_Debug_Guide.md rename to docs/GitHub-Issue-Debug-Guide.md diff --git a/prometheus/script/github_issue_debug.py b/prometheus/script/github_issue_debug.py index ac432ac5..9e3cd921 100644 --- a/prometheus/script/github_issue_debug.py +++ b/prometheus/script/github_issue_debug.py @@ -21,97 +21,93 @@ import argparse import json import sys -from typing import Dict, List, Optional -import requests +from typing import Dict from urllib.parse import urljoin +import requests + class GitHubIssueDebugger: def __init__(self, github_token: str, prometheus_url: str = "http://localhost:8000"): """ Initialize GitHub Issue Debugger - + Args: github_token: GitHub Personal Access Token prometheus_url: Prometheus service URL """ self.github_token = github_token - self.prometheus_url = prometheus_url.rstrip('/') + self.prometheus_url = prometheus_url.rstrip("/") self.github_headers = { "Authorization": f"token {github_token}", - "Accept": "application/vnd.github.v3+json" - } - self.prometheus_headers = { - "Content-Type": "application/json" + "Accept": "application/vnd.github.v3+json", } + self.prometheus_headers = {"Content-Type": "application/json"} def get_github_issue(self, repo: str, issue_number: int) -> Dict: """ Retrieve issue information from GitHub - + Args: repo: Repository name (format: owner/repo) issue_number: Issue number - + Returns: A dictionary containing issue information """ print(f"Retrieving GitHub issue: {repo}#{issue_number}") - + # Retrieve basic issue information issue_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}" response = requests.get(issue_url, headers=self.github_headers) - + if response.status_code != 200: raise Exception(f"Failed to retrieve issue: {response.status_code} - {response.text}") - + issue_data = response.json() - + # Retrieve issue comments comments_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}/comments" comments_response = requests.get(comments_url, headers=self.github_headers) - + comments = [] if comments_response.status_code == 200: comments_data = comments_response.json() comments = [ - { - "username": comment["user"]["login"], - "comment": comment["body"] - } + {"username": comment["user"]["login"], "comment": comment["body"]} for comment in comments_data ] - + return { "number": issue_data["number"], "title": issue_data["title"], "body": issue_data["body"] or "", "comments": comments, "state": issue_data["state"], - "html_url": issue_data["html_url"] + "html_url": issue_data["html_url"], } def upload_repository_to_prometheus(self, repo: str) -> bool: """ Upload GitHub repository to Prometheus - + Args: repo: Repository name (format: owner/repo) - + Returns: Whether the upload was successful """ print(f"Uploading repository to Prometheus: {repo}") - + # Construct GitHub HTTPS URL github_url = f"https://github.com/{repo}.git" - + # Call Prometheus API to upload repository upload_url = urljoin(self.prometheus_url, "/repository/github/") params = {"https_url": github_url} - + response = requests.get(upload_url, params=params, headers=self.prometheus_headers) - + if response.status_code == 200: print("Repository uploaded successfully") return True @@ -122,13 +118,13 @@ def upload_repository_to_prometheus(self, repo: str) -> bool: def check_repository_exists(self) -> bool: """ Check if the knowledge graph already exists in Prometheus - + Returns: Whether the knowledge graph exists """ exists_url = urljoin(self.prometheus_url, "/repository/exists/") response = requests.get(exists_url, headers=self.prometheus_headers) - + if response.status_code == 200: return response.json() return False @@ -136,29 +132,29 @@ def check_repository_exists(self) -> bool: def send_issue_to_prometheus(self, issue_data: Dict, config: Dict) -> Dict: """ Send issue to Prometheus for debugging - + Args: issue_data: GitHub issue data config: Configuration parameters - + Returns: Response from Prometheus """ - print(f"Sending issue to Prometheus for debug analysis...") - + print("Sending issue to Prometheus for debug analysis...") + # Construct Prometheus API request data request_data = { "issue_number": issue_data["number"], "issue_title": issue_data["title"], "issue_body": issue_data["body"], "issue_comments": issue_data["comments"], - "issue_type": "bug", + "issue_type": "bug", "run_build": config.get("run_build", False), "run_existing_test": config.get("run_test", False), "number_of_candidate_patch": config.get("candidate_patches", 4), - "push_to_remote": config.get("push_to_remote", False) + "push_to_remote": config.get("push_to_remote", False), } - + # Add Docker configuration if present if config.get("dockerfile_content"): request_data["dockerfile_content"] = config["dockerfile_content"] @@ -166,48 +162,50 @@ def send_issue_to_prometheus(self, issue_data: Dict, config: Dict) -> Dict: elif config.get("image_name"): request_data["image_name"] = config["image_name"] request_data["workdir"] = config.get("workdir", "/app") - + if config.get("build_commands"): request_data["build_commands"] = config["build_commands"] - + if config.get("test_commands"): request_data["test_commands"] = config["test_commands"] - + # Send request to Prometheus answer_url = urljoin(self.prometheus_url, "/issue/answer/") response = requests.post(answer_url, json=request_data, headers=self.prometheus_headers) - + if response.status_code == 200: return response.json() else: - raise Exception(f"Prometheus processing failed: {response.status_code} - {response.text}") + raise Exception( + f"Prometheus processing failed: {response.status_code} - {response.text}" + ) def process_issue(self, repo: str, issue_number: int, config: Dict) -> Dict: """ Complete issue processing workflow - + Args: repo: Repository name issue_number: Issue number config: Configuration parameters - + Returns: Processing result """ try: # 1. Retrieve GitHub issue issue_data = self.get_github_issue(repo, issue_number) - + # 2. Check if repository is already uploaded, if not, upload it if not self.check_repository_exists(): if not self.upload_repository_to_prometheus(repo): raise Exception("Repository upload failed") else: print("Knowledge graph already exists in Prometheus, skipping repository upload") - + # 3. Send issue to Prometheus for debugging result = self.send_issue_to_prometheus(issue_data, config) - + # 4. Integrate results return { "success": True, @@ -216,19 +214,16 @@ def process_issue(self, repo: str, issue_number: int, config: Dict) -> Dict: "number": issue_data["number"], "title": issue_data["title"], "url": issue_data["html_url"], - "state": issue_data["state"] + "state": issue_data["state"], }, - "prometheus_result": result + "prometheus_result": result, } - + except Exception as e: return { "success": False, "error": str(e), - "issue_info": { - "repo": repo, - "number": issue_number - } + "issue_info": {"repo": repo, "number": issue_number}, } @@ -236,167 +231,129 @@ def main(): parser = argparse.ArgumentParser( description="GitHub Issue Auto Debug Script", formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=__doc__ - ) - - parser.add_argument( - "--github-token", - required=True, - help="GitHub Personal Access Token" - ) - - parser.add_argument( - "--repo", - required=True, - help="GitHub repository (format: owner/repo)" - ) - - parser.add_argument( - "--issue-number", - type=int, - required=True, - help="Issue number" + epilog=__doc__, ) - + + parser.add_argument("--github-token", required=True, help="GitHub Personal Access Token") + + parser.add_argument("--repo", required=True, help="GitHub repository (format: owner/repo)") + + parser.add_argument("--issue-number", type=int, required=True, help="Issue number") + parser.add_argument( "--prometheus-url", default="http://localhost:9002", - help="Prometheus service address (default: http://localhost:9002)" + help="Prometheus service address (default: http://localhost:9002)", ) - + parser.add_argument( "--output-file", - help="Path to the result output file (optional, default outputs to console)" - ) - - parser.add_argument( - "--run-build", - action="store_true", - help="Run build validation" - ) - - parser.add_argument( - "--run-test", - action="store_true", - help="Run test validation" - ) - - parser.add_argument( - "--push-to-remote", - action="store_true", - help="Push fix to remote branch" + help="Path to the result output file (optional, default outputs to console)", ) - + + parser.add_argument("--run-build", action="store_true", help="Run build validation") + + parser.add_argument("--run-test", action="store_true", help="Run test validation") + + parser.add_argument("--push-to-remote", action="store_true", help="Push fix to remote branch") + parser.add_argument( - "--dockerfile-content", - help="Dockerfile content (for specifying container environment)" + "--dockerfile-content", help="Dockerfile content (for specifying container environment)" ) - + parser.add_argument( - "--image-name", - help="Docker image name (for specifying container environment)" + "--image-name", help="Docker image name (for specifying container environment)" ) - + parser.add_argument( "--workdir", default="/app", - help="Working directory (required when using container environment)" - ) - - parser.add_argument( - "--build-commands", - nargs="+", - help="List of build commands" - ) - - parser.add_argument( - "--test-commands", - nargs="+", - help="List of test commands" + help="Working directory (required when using container environment)", ) - + + parser.add_argument("--build-commands", nargs="+", help="List of build commands") + + parser.add_argument("--test-commands", nargs="+", help="List of test commands") + parser.add_argument( - "--candidate-patches", - type=int, - default=4, - help="Number of candidate patches (default: 4)" + "--candidate-patches", type=int, default=4, help="Number of candidate patches (default: 4)" ) - + args = parser.parse_args() - + # Validate repo format if "/" not in args.repo: print("Error: Invalid repo format, should be 'owner/repo'") sys.exit(1) - + # Build configuration config = { "run_build": args.run_build, "run_test": args.run_test, "push_to_remote": args.push_to_remote, "candidate_patches": args.candidate_patches, - "workdir": args.workdir + "workdir": args.workdir, } - + if args.dockerfile_content: config["dockerfile_content"] = args.dockerfile_content - + if args.image_name: config["image_name"] = args.image_name - + if args.build_commands: config["build_commands"] = args.build_commands - + if args.test_commands: config["test_commands"] = args.test_commands - + # Create debugger and process issue debugger = GitHubIssueDebugger(args.github_token, args.prometheus_url) result = debugger.process_issue(args.repo, args.issue_number, config) - + # Output results if args.output_file: - with open(args.output_file, 'w', encoding='utf-8') as f: + with open(args.output_file, "w", encoding="utf-8") as f: json.dump(result, f, indent=2, ensure_ascii=False) print(f"Results saved to: {args.output_file}") else: - print("\n" + "="*60) + print("\n" + "=" * 60) print("Processing Results:") - print("="*60) + print("=" * 60) print(json.dumps(result, indent=2, ensure_ascii=False)) - + # Simplified summary output - print("\n" + "="*60) + print("\n" + "=" * 60) print("Execution Summary:") - print("="*60) - + print("=" * 60) + if result["success"]: issue_info = result["issue_info"] prometheus_result = result["prometheus_result"] - - print(f"✅ Successfully processed GitHub Issue") + + print("✅ Successfully processed GitHub Issue") print(f" Repository: {issue_info['repo']}") print(f" Issue: #{issue_info['number']} - {issue_info['title']}") print(f" URL: {issue_info['url']}") print(f" State: {issue_info['state']}") - + if prometheus_result.get("patch"): - print(f"✅ Generated fix patch") - + print("✅ Generated fix patch") + if prometheus_result.get("passed_build") is not None: status = "✅ Passed" if prometheus_result["passed_build"] else "❌ Failed" print(f" Build Validation: {status}") - + if prometheus_result.get("passed_existing_test") is not None: status = "✅ Passed" if prometheus_result["passed_existing_test"] else "❌ Failed" print(f" Test Validation: {status}") - + if prometheus_result.get("remote_branch_name"): print(f"✅ Pushed to remote branch: {prometheus_result['remote_branch_name']}") - + if prometheus_result.get("issue_response"): - print(f"📝 Prometheus analysis result generated") - + print("📝 Prometheus analysis result generated") + else: print(f"❌ Processing failed: {result['error']}") sys.exit(1) From 1df9d1798ed08ed2b62e6b30dc97dc0a3cba2930 Mon Sep 17 00:00:00 2001 From: Yue Pan <79363355+dcloud347@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:37:12 +0800 Subject: [PATCH 3/4] feat: Enhance GitHub issue debugging script with new testing options and improved repository upload process --- docs/GitHub-Issue-Debug-Guide.md | 154 ++--------------- prometheus/script/github_issue_debug.py | 214 ++++++++++++++---------- prometheus/utils/github_utils.py | 51 ++++++ 3 files changed, 194 insertions(+), 225 deletions(-) create mode 100644 prometheus/utils/github_utils.py diff --git a/docs/GitHub-Issue-Debug-Guide.md b/docs/GitHub-Issue-Debug-Guide.md index 14d6cfd5..d91bf00d 100644 --- a/docs/GitHub-Issue-Debug-Guide.md +++ b/docs/GitHub-Issue-Debug-Guide.md @@ -2,7 +2,7 @@ ## Overview -`github_issue_debug.py` is an automated script for: +`prometheus/script/github_issue_debug.py` is an automated script for: 1. Retrieving detailed information (title, body, comments, etc.) of a specified issue from the GitHub API. 2. Automatically uploading the GitHub repository to Prometheus. 3. Using Prometheus's AI analysis capabilities to debug the issue. @@ -14,10 +14,7 @@ Ensure the Prometheus service is running: ```bash # Start using docker-compose -docker-compose -f docker-compose.win_mac.yml up -d - -# Check service status -docker-compose -f docker-compose.win_mac.yml ps +docker-compose up --build ``` ### 2. Obtain GitHub Personal Access Token @@ -49,10 +46,12 @@ python github_issue_debug.py \ --github-token "ghp_xxxxxxxxxxxxxxxxxxxx" \ --repo "microsoft/vscode" \ --issue-number 123 \ - --prometheus-url "http://localhost:8000" \ + --prometheus-url "http://localhost:9002/v1.2" \ --output-file "debug_result.json" \ --run-build \ --run-test \ + --run-reproduction-test \ + --run-regression-test \ --push-to-remote \ --image-name "python:3.11-slim" \ --workdir "/app" \ @@ -75,6 +74,8 @@ python github_issue_debug.py \ ### Validation Options - `--run-build`: Run build validation for the generated patch - `--run-test`: Run test validation for the generated patch +- `--run-reproduction-test`: Run reproduction test to verify if the issue can be reproduced +- `--run-regression-test`: Run regression test to ensure existing functionality is not broken - `--push-to-remote`: Push the fix to a remote Git branch ### Docker Environment Configuration @@ -85,7 +86,7 @@ python github_issue_debug.py \ - `--test-commands`: List of test commands ### Other Options -- `--candidate-patches`: Number of candidate patches (default: 4) +- `--candidate-patches`: Number of candidate patches (default: 6) ## Usage Scenarios @@ -107,6 +108,8 @@ python github_issue_debug.py \ --issue-number 5678 \ --run-build \ --run-test \ + --run-reproduction-test \ + --run-regression-test \ --image-name "python:3.11-slim" \ --build-commands "pip install -e ." \ --test-commands "pytest tests/test_requests.py" @@ -121,6 +124,8 @@ python github_issue_debug.py \ --issue-number 9876 \ --run-build \ --run-test \ + --run-reproduction-test \ + --run-regression-test \ --push-to-remote \ --image-name "node:18-slim" \ --build-commands "npm ci" "npm run build" \ @@ -163,9 +168,12 @@ After execution, the script outputs results in JSON format, including the follow "passed_reproducing_test": true, "passed_build": true, "passed_existing_test": false, - "issue_response": "AI-generated issue response", - "remote_branch_name": "prometheus-fix-issue-123" - } + "passed_regression_test": true, + "passed_reproduction_test": true, + "issue_response": "AI-generated issue response" + }, + "created_branch_and_pushed": true, + "branch_name": "fix-issue-123" } ``` @@ -175,129 +183,3 @@ After execution, the script outputs results in JSON format, including the follow - `prometheus_result.patch`: Code fix patch generated by Prometheus - `prometheus_result.passed_*`: Status of various validations - `prometheus_result.issue_response`: AI-generated issue analysis and response -- `prometheus_result.remote_branch_name`: Name of the remote branch pushed (if enabled) - -## Common Issues and Solutions - -### 1. GitHub API Limitations -**Problem**: Encountering API limit errors -**Solution**: -- Ensure a valid Personal Access Token is used -- Check the token's permission scope -- Be mindful of GitHub API rate limits - -### 2. Prometheus Service Connection Failure -**Problem**: Unable to connect to the Prometheus service -**Solution**: -```bash -# Check service status -docker-compose -f docker-compose.win_mac.yml ps - -# Restart the service -docker-compose -f docker-compose.win_mac.yml restart - -# Check logs -docker-compose -f docker-compose.win_mac.yml logs prometheus -``` - -### 3. Repository Upload Failure -**Problem**: Unable to access private repositories -**Solution**: -- Ensure the GitHub token has `repo` permissions -- Check if the repository URL format is correct -- For private repositories, ensure the token owner has access permissions - -### 4. Build/Test Failure -**Problem**: Build or test failure in the Docker environment -**Solution**: -- Check if the specified Docker image is correct -- Validate the build and test commands -- Ensure the working directory is set correctly -- Check Prometheus logs for detailed error information - -## Advanced Usage Tips - -### 1. Batch Processing Multiple Issues -Create a batch script: -```bash -#!/bin/bash -GITHUB_TOKEN="your_token" -REPO="owner/repo" - -for issue in 123 124 125; do - echo "Processing issue #$issue" - python github_issue_debug.py \ - --github-token "$GITHUB_TOKEN" \ - --repo "$REPO" \ - --issue-number $issue \ - --output-file "results/issue_${issue}_result.json" -done -``` - -### 2. Integration into CI/CD -Use in GitHub Actions: -```yaml -- name: Debug Issue with Prometheus - run: | - python github_issue_debug.py \ - --github-token "${{ secrets.GITHUB_TOKEN }}" \ - --repo "${{ github.repository }}" \ - --issue-number "${{ github.event.issue.number }}" \ - --output-file "debug_result.json" -``` - -### 3. Post-Processing Results -Process results using Python: -```python -import json - -with open('debug_result.json', 'r') as f: - result = json.load(f) - -if result['success']: - patch = result['prometheus_result']['patch'] - # Further process the patch... -``` - -## Notes - -1. **Security**: - - Do not hardcode the GitHub token in the code - - Use environment variables or configuration files to store sensitive information - -2. **Performance**: - - Processing large repositories may take a long time - - It is recommended to test on smaller repositories first - -3. **Resource Usage**: - - Ensure sufficient disk space for cloning repositories - - Monitor Docker container resource usage - -4. **Network**: - - Ensure a stable network connection - - Some network environments may require proxy configuration - -## Troubleshooting - -### Enable Detailed Logs -Set environment variables to enable detailed output: -```bash -export PYTHONUNBUFFERED=1 -python github_issue_debug.py --your-args -``` - -### Check Prometheus Status -```bash -# Check API health status -curl http://localhost:8000/docs - -# Check knowledge graph status -curl http://localhost:8000/repository/exists/ -``` - -### Reset Prometheus State -If you need to start over: -```bash -# Delete existing knowledge graph -curl -X GET http://localhost:8000/repository/delete/ -``` diff --git a/prometheus/script/github_issue_debug.py b/prometheus/script/github_issue_debug.py index 9e3cd921..ef652961 100644 --- a/prometheus/script/github_issue_debug.py +++ b/prometheus/script/github_issue_debug.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """ GitHub Issue Auto Debug Script @@ -11,10 +10,12 @@ --github-token: GitHub Personal Access Token (required) --repo: GitHub repository (format: owner/repo) (required) --issue-number: Issue number (required) - --prometheus-url: Prometheus service address (default: http://localhost:8000) + --prometheus-url: Prometheus service address (default: http://localhost:9002/v1.2) --output-file: Result output file (optional, default outputs to console) --run-build: Whether to run build validation (default: False) --run-test: Whether to run test validation (default: False) + --run-reproduction-test: Whether to run reproduction test (default: False) + --run-regression-test: Whether to run regression test (default: False) --push-to-remote: Whether to push the fix to a remote branch (default: False) """ @@ -22,13 +23,18 @@ import json import sys from typing import Dict -from urllib.parse import urljoin import requests +from prometheus.utils.github_utils import get_github_issue + +REPOSITORY_UPLOAD_ENDPOINT = "/repository/upload/" +ISSUE_ANSWER_ENDPOINT = "/issue/answer/" +CREATE_BRANCH_AND_PUSH_ENDPOINT = "/repository/create-branch-and-push/" + class GitHubIssueDebugger: - def __init__(self, github_token: str, prometheus_url: str = "http://localhost:8000"): + def __init__(self, github_token: str, prometheus_url: str = "http://localhost:9002/v1.2"): """ Initialize GitHub Issue Debugger @@ -58,36 +64,9 @@ def get_github_issue(self, repo: str, issue_number: int) -> Dict: print(f"Retrieving GitHub issue: {repo}#{issue_number}") # Retrieve basic issue information - issue_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}" - response = requests.get(issue_url, headers=self.github_headers) - - if response.status_code != 200: - raise Exception(f"Failed to retrieve issue: {response.status_code} - {response.text}") - - issue_data = response.json() + return get_github_issue(repo, issue_number, self.github_token) - # Retrieve issue comments - comments_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}/comments" - comments_response = requests.get(comments_url, headers=self.github_headers) - - comments = [] - if comments_response.status_code == 200: - comments_data = comments_response.json() - comments = [ - {"username": comment["user"]["login"], "comment": comment["body"]} - for comment in comments_data - ] - - return { - "number": issue_data["number"], - "title": issue_data["title"], - "body": issue_data["body"] or "", - "comments": comments, - "state": issue_data["state"], - "html_url": issue_data["html_url"], - } - - def upload_repository_to_prometheus(self, repo: str) -> bool: + def upload_repository_to_prometheus(self, repo: str) -> int: """ Upload GitHub repository to Prometheus @@ -95,7 +74,7 @@ def upload_repository_to_prometheus(self, repo: str) -> bool: repo: Repository name (format: owner/repo) Returns: - Whether the upload was successful + repository_id: ID of the uploaded repository in Prometheus """ print(f"Uploading repository to Prometheus: {repo}") @@ -103,37 +82,25 @@ def upload_repository_to_prometheus(self, repo: str) -> bool: github_url = f"https://github.com/{repo}.git" # Call Prometheus API to upload repository - upload_url = urljoin(self.prometheus_url, "/repository/github/") - params = {"https_url": github_url} + upload_url = self.prometheus_url + REPOSITORY_UPLOAD_ENDPOINT + params = {"https_url": github_url, "commit_id": None, "github_token": self.github_token} - response = requests.get(upload_url, params=params, headers=self.prometheus_headers) + response = requests.post(upload_url, json=params, headers=self.prometheus_headers) if response.status_code == 200: print("Repository uploaded successfully") - return True + return response.json()["data"]["repository_id"] else: - print(f"Failed to upload repository: {response.status_code} - {response.text}") - return False - - def check_repository_exists(self) -> bool: - """ - Check if the knowledge graph already exists in Prometheus - - Returns: - Whether the knowledge graph exists - """ - exists_url = urljoin(self.prometheus_url, "/repository/exists/") - response = requests.get(exists_url, headers=self.prometheus_headers) - - if response.status_code == 200: - return response.json() - return False + raise Exception( + f"Failed to upload repository: {response.status_code} - {response.text}" + ) - def send_issue_to_prometheus(self, issue_data: Dict, config: Dict) -> Dict: + def send_issue_to_prometheus(self, repository_id: int, issue_data: Dict, config: Dict) -> Dict: """ Send issue to Prometheus for debugging Args: + repository_id: GitHub repository id issue_data: GitHub issue data config: Configuration parameters @@ -144,33 +111,34 @@ def send_issue_to_prometheus(self, issue_data: Dict, config: Dict) -> Dict: # Construct Prometheus API request data request_data = { - "issue_number": issue_data["number"], + "repository_id": repository_id, "issue_title": issue_data["title"], "issue_body": issue_data["body"], "issue_comments": issue_data["comments"], "issue_type": "bug", "run_build": config.get("run_build", False), "run_existing_test": config.get("run_test", False), - "number_of_candidate_patch": config.get("candidate_patches", 4), - "push_to_remote": config.get("push_to_remote", False), + "run_regression_test": config.get("run_regression_test", True), + "run_reproduce_test": config.get("run_reproduce_test", True), + "number_of_candidate_patch": config.get("candidate_patches", 6), } # Add Docker configuration if present - if config.get("dockerfile_content"): + if "dockerfile_content" in config: request_data["dockerfile_content"] = config["dockerfile_content"] request_data["workdir"] = config.get("workdir", "/app") - elif config.get("image_name"): + elif "image_name" in config: request_data["image_name"] = config["image_name"] request_data["workdir"] = config.get("workdir", "/app") - if config.get("build_commands"): + if "build_commands" in config: request_data["build_commands"] = config["build_commands"] - if config.get("test_commands"): + if "test_commands" in config: request_data["test_commands"] = config["test_commands"] # Send request to Prometheus - answer_url = urljoin(self.prometheus_url, "/issue/answer/") + answer_url = self.prometheus_url + ISSUE_ANSWER_ENDPOINT response = requests.post(answer_url, json=request_data, headers=self.prometheus_headers) if response.status_code == 200: @@ -180,6 +148,38 @@ def send_issue_to_prometheus(self, issue_data: Dict, config: Dict) -> Dict: f"Prometheus processing failed: {response.status_code} - {response.text}" ) + def create_branch_and_push( + self, repo_id: int, branch_name: str, commit_message: str, patch: str + ): + """ + Create a new branch and push the patch to remote repository + + Args: + repo_id: Repository ID in Prometheus + branch_name: Name of the new branch + commit_message: Commit message + patch: Patch content to be applied + + Returns: + Response from Prometheus + """ + print(f"Pushing fix to remote branch: {branch_name}") + + push_url = self.prometheus_url + CREATE_BRANCH_AND_PUSH_ENDPOINT + push_data = { + "repository_id": repo_id, + "branch_name": branch_name, + "commit_message": commit_message, + "patch": patch, + } + + response = requests.post(push_url, json=push_data, headers=self.prometheus_headers) + + if response.status_code == 200: + print("Patch pushed successfully") + else: + raise Exception(f"Failed to push patch: {response.status_code} - {response.text}") + def process_issue(self, repo: str, issue_number: int, config: Dict) -> Dict: """ Complete issue processing workflow @@ -196,29 +196,11 @@ def process_issue(self, repo: str, issue_number: int, config: Dict) -> Dict: # 1. Retrieve GitHub issue issue_data = self.get_github_issue(repo, issue_number) - # 2. Check if repository is already uploaded, if not, upload it - if not self.check_repository_exists(): - if not self.upload_repository_to_prometheus(repo): - raise Exception("Repository upload failed") - else: - print("Knowledge graph already exists in Prometheus, skipping repository upload") + # 2. Upload repository to Prometheus + repository_id = self.upload_repository_to_prometheus(repo) # 3. Send issue to Prometheus for debugging - result = self.send_issue_to_prometheus(issue_data, config) - - # 4. Integrate results - return { - "success": True, - "issue_info": { - "repo": repo, - "number": issue_data["number"], - "title": issue_data["title"], - "url": issue_data["html_url"], - "state": issue_data["state"], - }, - "prometheus_result": result, - } - + result = self.send_issue_to_prometheus(repository_id, issue_data, config) except Exception as e: return { "success": False, @@ -226,6 +208,33 @@ def process_issue(self, repo: str, issue_number: int, config: Dict) -> Dict: "issue_info": {"repo": repo, "number": issue_number}, } + # 4. Upload it to GitHub if needed + created_branch_and_pushed = False + branch_name = f"fix-issue-{issue_number}" + if config.get("push_to_remote", False) and result["data"].get("patch"): + patch = result["data"]["patch"] + commit_message = f"Fix issue #{issue_number}: {issue_data['title']}" + + try: + self.create_branch_and_push(repository_id, branch_name, commit_message, patch) + except Exception: + created_branch_and_pushed = False + + # 5. Integrate results + return { + "success": True, + "issue_info": { + "repo": repo, + "number": issue_data["number"], + "title": issue_data["title"], + "url": issue_data["html_url"], + "state": issue_data["state"], + }, + "prometheus_result": result, + "created_branch_and_pushed": created_branch_and_pushed, + "branch_name": branch_name if created_branch_and_pushed else None, + } + def main(): parser = argparse.ArgumentParser( @@ -242,8 +251,8 @@ def main(): parser.add_argument( "--prometheus-url", - default="http://localhost:9002", - help="Prometheus service address (default: http://localhost:9002)", + default="http://localhost:9002/v1.2", + help="Prometheus service address (default: http://localhost:9002/v1.2)", ) parser.add_argument( @@ -255,6 +264,18 @@ def main(): parser.add_argument("--run-test", action="store_true", help="Run test validation") + parser.add_argument( + "--run-reproduction-test", + action="store_true", + help="Run reproduction test", + ) + + parser.add_argument( + "--run-regression-test", + action="store_true", + help="Run regression test", + ) + parser.add_argument("--push-to-remote", action="store_true", help="Push fix to remote branch") parser.add_argument( @@ -276,7 +297,7 @@ def main(): parser.add_argument("--test-commands", nargs="+", help="List of test commands") parser.add_argument( - "--candidate-patches", type=int, default=4, help="Number of candidate patches (default: 4)" + "--candidate-patches", type=int, default=6, help="Number of candidate patches (default: 6)" ) args = parser.parse_args() @@ -290,6 +311,8 @@ def main(): config = { "run_build": args.run_build, "run_test": args.run_test, + "run_reproduce_test": args.run_reproduction_test, + "run_regression_test": args.run_regression_test, "push_to_remote": args.push_to_remote, "candidate_patches": args.candidate_patches, "workdir": args.workdir, @@ -348,8 +371,21 @@ def main(): status = "✅ Passed" if prometheus_result["passed_existing_test"] else "❌ Failed" print(f" Test Validation: {status}") - if prometheus_result.get("remote_branch_name"): - print(f"✅ Pushed to remote branch: {prometheus_result['remote_branch_name']}") + if prometheus_result.get("passed_reproducing_test") is not None: + status = "✅ Passed" if prometheus_result["passed_reproducing_test"] else "❌ Failed" + print(f" Reproducing Test: {status}") + + if prometheus_result.get("passed_regression_test") is not None: + status = "✅ Passed" if prometheus_result["passed_regression_test"] else "❌ Failed" + print(f" Regression Test: {status}") + + if result.get("created_branch_and_pushed"): + print("✅ Fix patch pushed to remote repository") + else: + if args.push_to_remote: + print("⚠️ Failed to push fix patch to remote repository") + else: + print("ℹ️ Fix patch not pushed to remote repository (push_to_remote=False)") if prometheus_result.get("issue_response"): print("📝 Prometheus analysis result generated") diff --git a/prometheus/utils/github_utils.py b/prometheus/utils/github_utils.py new file mode 100644 index 00000000..34bfbe50 --- /dev/null +++ b/prometheus/utils/github_utils.py @@ -0,0 +1,51 @@ +from typing import Dict + +import requests + + +def get_github_issue(repo: str, issue_number: int, github_token: str) -> Dict: + """ + Retrieve issue information from GitHub + + Args: + repo: Repository name (format: owner/repo) + issue_number: Issue number + github_token: GitHub token + + Returns: + A dictionary containing issue information + """ + github_headers = { + "Authorization": f"token {github_token}", + "Accept": "application/vnd.github.v3+json", + } + + # Retrieve basic issue information + issue_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}" + response = requests.get(issue_url, headers=github_headers) + + if response.status_code != 200: + raise Exception(f"Failed to retrieve issue: {response.status_code} - {response.text}") + + issue_data = response.json() + + # Retrieve issue comments + comments_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}/comments" + comments_response = requests.get(comments_url, headers=github_headers) + + comments = [] + if comments_response.status_code == 200: + comments_data = comments_response.json() + comments = [ + {"username": comment["user"]["login"], "comment": comment["body"]} + for comment in comments_data + ] + + return { + "number": issue_data["number"], + "title": issue_data["title"], + "body": issue_data["body"] or "", + "comments": comments, + "state": issue_data["state"], + "html_url": issue_data["html_url"], + } From 3090df864f1733929eea3b66f2bbca12de6e61e2 Mon Sep 17 00:00:00 2001 From: Yue Pan <79363355+dcloud347@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:52:10 +0800 Subject: [PATCH 4/4] feat: Add new scripts section to README with usage instructions for JWT token generation, GitHub issue debugging, superuser creation, and LLM service testing --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index a2658ffb..d0a23831 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,26 @@ Verify Neo4J at: [http://localhost:7474](http://localhost:7474) --- +## 🛠️ Scripts +- **Generate JWT Token**: + ```bash + python -m prometheus.script.generate_jwt_token + ``` +- **GitHub Issue Debug Guide**: + A script to help debug GitHub issues using Prometheus. + See the full guide in [docs/GitHub-Issue-Debug-Guide.md](docs/GitHub-Issue-Debug-Guide.md). + +- **Create Superuser**: + ```bash + python -m prometheus.script.create_superuser --username --email --password --github_token + ``` +- **Test LLM Service**: +- ```bash + python -m prometheus.script.test_llm_service + ``` + +--- + ## 📄 License This project is dual-licensed: