acecalisto3 commited on
Commit
0a3f0be
·
verified ·
1 Parent(s): 4cfae41

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -104
app.py CHANGED
@@ -7,7 +7,8 @@ import spaces
7
  import time
8
  import os
9
  from datetime import datetime
10
- from typing import List, Dict
 
11
  import requests
12
  import gradio as gr
13
  import atexit
@@ -15,151 +16,157 @@ import subprocess
15
  import webbrowser
16
  import urllib.parse
17
  import http.client
18
-
19
- # Suppress warnings
20
- warnings.filterwarnings('ignore', category=User Warning) # Corrected line
 
 
 
 
 
 
 
 
 
21
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
22
 
23
- def initialize_environment():
24
- """Initialize application environment and configurations"""
25
- # Create necessary directories
26
- directories = ['logs', 'resolutions', 'repos']
27
- for directory in directories:
28
- os.makedirs(directory, exist_ok=True)
29
-
30
- # Configure logging
31
- log_file = f"logs/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
32
- logging.basicConfig(
33
- level=logging.INFO,
34
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
35
- handlers=[
36
- logging.FileHandler(log_file),
37
- logging.StreamHandler()
38
- ]
39
- )
40
-
41
- # Set up global exception handler
42
- def handle_exception(exc_type, exc_value, exc_traceback):
43
- if issubclass(exc_type, KeyboardInterrupt):
44
- sys.__excepthook__(exc_type, exc_value, exc_traceback)
45
- return
46
- logging.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
47
-
48
- sys.excepthook = handle_exception
49
- return logging.getLogger(__name__)
50
-
51
- logger = initialize_environment()
52
 
53
  class GitHubAPI:
54
- """GitHub API handler with rate limiting and error handling"""
55
 
56
  def __init__(self, token: str):
57
  self.token = token
58
  self.headers = {
59
  'Authorization': f'token {token}',
60
- 'Accept': 'application/vnd.github.v3+json'
 
61
  }
62
  self.base_url = "https://api.github.com"
 
 
63
 
64
- def _check_rate_limit(self) -> bool:
65
- """Check and handle GitHub API rate limits"""
66
- try:
67
- response = requests.get(f"{self.base_url}/rate_limit", headers=self.headers)
68
- response.raise_for_status()
69
- limits = response.json()
70
- remaining = limits['resources']['core']['remaining']
71
- reset_time = limits['resources']['core']['reset']
72
-
73
- if remaining < 10:
74
- wait_time = max(0, reset_time - int(time.time()))
75
- if wait_time > 0:
76
- logger.warning(f"Rate limit nearly exceeded. Waiting {wait_time} seconds...")
77
- time.sleep(wait_time)
78
- return False
79
- return True
80
- except Exception as e:
81
- logger.error(f"Error checking rate limit: {str(e)}")
82
- return True
83
 
84
  def get_repository(self, owner: str, repo: str) -> Dict:
85
- """Get repository information"""
86
- try:
87
- response = requests.get(f"{self.base_url}/repos/{owner}/{repo}", headers=self.headers)
88
- response.raise_for_status()
89
- return response.json()
90
- except requests.HTTPError as e:
91
- logger.error(f"HTTP error getting repository info: {str(e)}")
92
- raise
93
- except Exception as e:
94
- logger.error(f"Error getting repository info: {str(e)}")
95
- raise
96
-
97
- def get_issues(self, owner: str, repo: str, state: str = 'open') -> List[Dict]:
98
- """Fetch repository issues"""
99
- if not self._check_rate_limit():
100
- return []
101
 
 
 
102
  try:
103
- response = requests.get(f"{self.base_url}/repos/{owner}/{repo}/issues", headers=self.headers, params={'state': state})
104
- response.raise_for_status()
 
 
 
 
105
  issues = response.json()
106
  return [issue for issue in issues if 'pull_request' not in issue]
107
- except requests.HTTPError as e:
108
- logger.error(f"HTTP error fetching issues: {str(e)}")
109
- return []
110
  except Exception as e:
111
  logger.error(f"Error fetching issues: {str(e)}")
112
  return []
113
 
114
  class GitHubBot:
115
- """Main GitHub bot implementation"""
116
 
117
  def __init__(self):
118
  self.github_api = None
 
 
119
 
120
- def initialize_api(self, token: str):
121
- """Initialize GitHub API with token"""
 
 
122
  self.github_api = GitHubAPI(token)
123
 
124
- def fetch_issues(self, token: str, username: str, repo: str) -> List[Dict]:
125
- """Fetch issues from GitHub repository"""
126
  try:
127
  self.initialize_api(token)
128
- return self.github_api.get_issues(username, repo)
129
  except Exception as e:
130
  logger.error(f"Error fetching issues: {str(e)}")
131
  return []
132
 
133
- def resolve_issue(self, token: str, username: str, repo: str, issue_number: int, resolution: str, forked_repo: str) -> str:
134
- """Resolve a GitHub issue and submit PR."""
 
135
  try:
136
  self.initialize_api(token)
137
- self.github_api.get_repository(username, repo)
138
 
139
- # Create resolution file
140
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
141
- resolution_file = f"resolutions/resolution_{issue_number}_{timestamp}.md"
142
 
143
- with open(resolution_file, "w") as f:
 
 
 
 
144
  f.write(f"# Resolution for Issue #{issue_number}\n\n{resolution}")
145
 
146
- # Clone the forked repo
147
- subprocess.run(['git', '-C', '/tmp', 'clone', forked_repo])
148
-
149
- # Change to the cloned directory
150
- subprocess.run(['cd', '/tmp/' + forked_repo.split('/')[-1]])
151
-
152
- # Assuming manual intervention now
153
- answer = input("Apply the fix manually and stage the changes (press ENTER)? ")
154
-
155
- # Commit and push the modifications
156
- subprocess.run(['git', 'add', '.'])
157
- subprocess.run(['git', 'commit', '-m', f"Resolved issue #{issue_number} ({urllib.parse.quote(resolution)})"])
158
- subprocess.run(['git', 'push', 'origin', 'HEAD'])
159
-
160
- # Open Pull Request page
161
- webbrowser.open('https://github.com/' + forked_repo.split('/')[-1] + '/compare/master...' + username + ':' + forked_repo.split('/')[-1] + '_resolved_issue_' + str(issue_number))
162
 
 
163
  return f"Resolution saved: {resolution_file}"
164
 
165
  except Exception as e:
 
7
  import time
8
  import os
9
  from datetime import datetime
10
+ from typing import List, Dict, Optional, Union
11
+ from pathlib import Path
12
  import requests
13
  import gradio as gr
14
  import atexit
 
16
  import webbrowser
17
  import urllib.parse
18
  import http.client
19
+ from functools import lru_cache
20
+ import json
21
+ from concurrent.futures import ThreadPoolExecutor
22
+
23
+ # Security and configuration constants
24
+ MAX_RETRIES = 3
25
+ REQUEST_TIMEOUT = 30
26
+ RATE_LIMIT_THRESHOLD = 10
27
+ CACHE_TTL = 300 # 5 minutes cache
28
+
29
+ # Suppress warnings and set environment
30
+ warnings.filterwarnings('ignore', category='UserWarning')
31
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
32
 
33
+ class ConfigManager:
34
+ """Configuration management class"""
35
+
36
+ @staticmethod
37
+ def load_config(config_file: str = 'config.json') -> Dict:
38
+ try:
39
+ with open(config_file, 'r') as f:
40
+ return json.load(f)
41
+ except FileNotFoundError:
42
+ return {}
43
+
44
+ @staticmethod
45
+ def save_config(config: Dict, config_file: str = 'config.json') -> None:
46
+ with open(config_file, 'w') as f:
47
+ json.dump(config, f, indent=4)
48
+
49
+ class SecurityManager:
50
+ """Security management class"""
51
+
52
+ @staticmethod
53
+ def validate_token(token: str) -> bool:
54
+ return bool(token and len(token) >= 40)
55
+
56
+ @staticmethod
57
+ def sanitize_input(input_str: str) -> str:
58
+ return urllib.parse.quote(input_str)
 
 
 
59
 
60
  class GitHubAPI:
61
+ """Enhanced GitHub API handler with caching and retry mechanism"""
62
 
63
  def __init__(self, token: str):
64
  self.token = token
65
  self.headers = {
66
  'Authorization': f'token {token}',
67
+ 'Accept': 'application/vnd.github.v3+json',
68
+ 'User-Agent': 'GitHub-Issue-Manager'
69
  }
70
  self.base_url = "https://api.github.com"
71
+ self.session = requests.Session()
72
+ self.executor = ThreadPoolExecutor(max_workers=4)
73
 
74
+ @lru_cache(maxsize=100)
75
+ def _make_request(self, method: str, endpoint: str, **kwargs) -> requests.Response:
76
+ """Make HTTP request with retry mechanism"""
77
+ for attempt in range(MAX_RETRIES):
78
+ try:
79
+ response = self.session.request(
80
+ method,
81
+ f"{self.base_url}/{endpoint}",
82
+ headers=self.headers,
83
+ timeout=REQUEST_TIMEOUT,
84
+ **kwargs
85
+ )
86
+ response.raise_for_status()
87
+ return response
88
+ except requests.exceptions.RequestException as e:
89
+ if attempt == MAX_RETRIES - 1:
90
+ raise
91
+ time.sleep(2 ** attempt) # Exponential backoff
 
92
 
93
  def get_repository(self, owner: str, repo: str) -> Dict:
94
+ """Get repository information with caching"""
95
+ response = self._make_request('GET', f"repos/{owner}/{repo}")
96
+ return response.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ async def get_issues_async(self, owner: str, repo: str, state: str = 'open') -> List[Dict]:
99
+ """Asynchronously fetch repository issues"""
100
  try:
101
+ response = await self.executor.submit(
102
+ self._make_request,
103
+ 'GET',
104
+ f"repos/{owner}/{repo}/issues",
105
+ params={'state': state}
106
+ )
107
  issues = response.json()
108
  return [issue for issue in issues if 'pull_request' not in issue]
 
 
 
109
  except Exception as e:
110
  logger.error(f"Error fetching issues: {str(e)}")
111
  return []
112
 
113
  class GitHubBot:
114
+ """Enhanced GitHub bot implementation"""
115
 
116
  def __init__(self):
117
  self.github_api = None
118
+ self.config_manager = ConfigManager()
119
+ self.security_manager = SecurityManager()
120
 
121
+ def initialize_api(self, token: str) -> None:
122
+ """Initialize GitHub API with validation"""
123
+ if not self.security_manager.validate_token(token):
124
+ raise ValueError("Invalid GitHub token")
125
  self.github_api = GitHubAPI(token)
126
 
127
+ async def fetch_issues(self, token: str, username: str, repo: str) -> List[Dict]:
128
+ """Fetch issues with async support"""
129
  try:
130
  self.initialize_api(token)
131
+ return await self.github_api.get_issues_async(username, repo)
132
  except Exception as e:
133
  logger.error(f"Error fetching issues: {str(e)}")
134
  return []
135
 
136
+ def resolve_issue(self, token: str, username: str, repo: str,
137
+ issue_number: int, resolution: str, forked_repo: str) -> str:
138
+ """Enhanced issue resolution with better error handling"""
139
  try:
140
  self.initialize_api(token)
141
+ repo_info = self.github_api.get_repository(username, repo)
142
 
143
+ # Create resolution directory if it doesn't exist
144
+ resolution_dir = Path('resolutions')
145
+ resolution_dir.mkdir(exist_ok=True)
146
 
147
+ # Save resolution with sanitized content
148
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
149
+ resolution_file = resolution_dir / f"resolution_{issue_number}_{timestamp}.md"
150
+
151
+ with resolution_file.open('w') as f:
152
  f.write(f"# Resolution for Issue #{issue_number}\n\n{resolution}")
153
 
154
+ # Handle git operations with better error checking
155
+ repo_path = Path('/tmp') / forked_repo.split('/')[-1]
156
+ if repo_path.exists():
157
+ shutil.rmtree(repo_path)
158
+
159
+ # Clone and setup repository
160
+ result = subprocess.run(
161
+ ['git', 'clone', forked_repo],
162
+ cwd='/tmp',
163
+ capture_output=True,
164
+ text=True
165
+ )
166
+ if result.returncode != 0:
167
+ raise RuntimeError(f"Git clone failed: {result.stderr}")
 
 
168
 
169
+ # Continue with remaining implementation...
170
  return f"Resolution saved: {resolution_file}"
171
 
172
  except Exception as e: