Update app.py
Browse files
app.py
CHANGED
@@ -5,21 +5,21 @@ import requests
|
|
5 |
import re
|
6 |
from collections import Counter
|
7 |
|
8 |
-
#
|
9 |
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
|
|
|
|
10 |
g = Github(GITHUB_TOKEN)
|
11 |
|
12 |
-
#
|
13 |
PROJECT_TEMPLATES = {
|
14 |
"flask": {
|
15 |
"files": {
|
16 |
"app.py": """from flask import Flask
|
17 |
app = Flask(__name__)
|
18 |
-
|
19 |
@app.route('/')
|
20 |
def hello():
|
21 |
return "Hello, Flask!"
|
22 |
-
|
23 |
if __name__ == '__main__':
|
24 |
app.run(debug=True)""",
|
25 |
"requirements.txt": "Flask",
|
@@ -48,8 +48,7 @@ if __name__ == '__main__':
|
|
48 |
}}""",
|
49 |
"vite.config.js": """import { defineConfig } from 'vite'
|
50 |
import react from '@vitejs/plugin-react'
|
51 |
-
|
52 |
-
// https://vitejs.dev/config/
|
53 |
export default defineConfig({
|
54 |
plugins: [react()],
|
55 |
})""",
|
@@ -70,7 +69,6 @@ export default defineConfig({
|
|
70 |
import ReactDOM from 'react-dom/client'
|
71 |
import App from './App.jsx'
|
72 |
import './index.css'
|
73 |
-
|
74 |
ReactDOM.createRoot(document.getElementById('root')).render(
|
75 |
<React.StrictMode>
|
76 |
<App />
|
@@ -78,7 +76,6 @@ ReactDOM.createRoot(document.getElementById('root')).render(
|
|
78 |
)""",
|
79 |
"src/App.jsx": """import React from 'react'
|
80 |
import './App.css'
|
81 |
-
|
82 |
function App() {
|
83 |
return (
|
84 |
<>
|
@@ -86,7 +83,6 @@ function App() {
|
|
86 |
</>
|
87 |
)
|
88 |
}
|
89 |
-
|
90 |
export default App""",
|
91 |
"src/index.css": """body {
|
92 |
margin: 0;
|
@@ -94,7 +90,6 @@ export default App""",
|
|
94 |
-webkit-font-smoothing: antialiased;
|
95 |
-moz-osx-font-smoothing: grayscale;
|
96 |
}
|
97 |
-
|
98 |
code {
|
99 |
font-family: monospace;
|
100 |
}""",
|
@@ -102,24 +97,26 @@ code {
|
|
102 |
}
|
103 |
}}
|
104 |
|
|
|
105 |
def get_file_content(owner, repo_name, path, branch="main"):
|
|
|
106 |
url = f"https://raw.githubusercontent.com/{owner}/{repo_name}/{branch}/{path}"
|
107 |
-
|
108 |
-
|
|
|
109 |
return response.text
|
110 |
-
|
111 |
-
return f"
|
|
|
112 |
|
113 |
def extract_repo_info(url):
|
114 |
-
"""
|
115 |
match = re.search(r"github\.com/([^/]+)/([^/]+)", url)
|
116 |
-
if match
|
117 |
-
|
118 |
-
else:
|
119 |
-
return None, None
|
120 |
|
121 |
def analyze_file_content(content, file_path):
|
122 |
-
"""
|
123 |
lines = content.splitlines()
|
124 |
word_count = sum(len(line.split()) for line in lines)
|
125 |
line_count = len(lines)
|
@@ -130,10 +127,11 @@ def analyze_file_content(content, file_path):
|
|
130 |
"file_extension": file_extension,
|
131 |
}
|
132 |
|
|
|
133 |
def github_tool(
|
134 |
action: str,
|
135 |
repo_name: str = None,
|
136 |
-
branch: str = "main",
|
137 |
path: str = None,
|
138 |
content: str = None,
|
139 |
message: str = None,
|
@@ -144,304 +142,324 @@ def github_tool(
|
|
144 |
base: str = None,
|
145 |
head: str = None,
|
146 |
issue_number: int = None,
|
147 |
-
labels: str = None,
|
148 |
tag: str = None,
|
149 |
-
name: str = None,
|
150 |
-
file_url: str = None,
|
151 |
-
repo_url: str = None,
|
152 |
-
template_name: str = None,
|
153 |
):
|
154 |
-
"""
|
155 |
user = g.get_user()
|
156 |
-
|
|
|
157 |
if action == "import_repository":
|
158 |
if not all([owner, repo_name, vcs_url]):
|
159 |
-
raise ValueError(
|
160 |
-
"Brakuj膮ce parametry: owner, repo_name, vcs_url")
|
161 |
-
# Sprawd藕, czy repozytorium ju偶 istnieje
|
162 |
try:
|
163 |
-
|
164 |
-
return "
|
165 |
except GithubException:
|
166 |
-
pass
|
|
|
167 |
headers = {
|
168 |
'Authorization': f'token {GITHUB_TOKEN}',
|
169 |
'Accept': 'application/vnd.github.v3+json',
|
170 |
}
|
171 |
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
|
172 |
-
|
173 |
-
response
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
return f"B艂膮d importu: {response.status_code}, {response.json()}"
|
178 |
elif action == "create_repository":
|
179 |
if not repo_name:
|
180 |
-
raise ValueError("
|
181 |
repo = user.create_repo(name=repo_name)
|
182 |
-
return f"
|
|
|
183 |
elif action == "create_project_from_template":
|
184 |
if not all([repo_name, template_name]):
|
185 |
-
raise ValueError("
|
186 |
if template_name not in PROJECT_TEMPLATES:
|
187 |
-
raise ValueError(
|
|
|
|
|
188 |
repo = user.create_repo(name=repo_name)
|
189 |
template = PROJECT_TEMPLATES[template_name]
|
190 |
for file_path, file_content in template["files"].items():
|
191 |
-
repo.create_file(
|
192 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
elif action == "create_file":
|
194 |
if not all([repo_name, path, content, message]):
|
195 |
-
raise ValueError(
|
196 |
-
"Brakuj膮ce parametry: repo_name, path, content, message")
|
197 |
repo = user.get_repo(repo_name)
|
198 |
repo.create_file(path, message, content, branch=branch)
|
199 |
-
return f"
|
|
|
200 |
elif action == "get_file":
|
201 |
if not all([repo_name, path]):
|
202 |
-
raise ValueError("
|
203 |
repo = user.get_repo(repo_name)
|
204 |
file_content = repo.get_contents(path, ref=branch)
|
205 |
-
return
|
|
|
|
|
|
|
206 |
elif action == "get_file_content_by_url":
|
207 |
if not file_url:
|
208 |
-
raise ValueError("
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
elif action == "delete_file":
|
213 |
if not all([repo_name, path]):
|
214 |
-
raise ValueError("
|
215 |
repo = user.get_repo(repo_name)
|
216 |
file_contents = repo.get_contents(path, ref=branch)
|
217 |
-
repo.delete_file(path, "
|
218 |
-
|
219 |
-
|
220 |
elif action == "update_file":
|
221 |
if not all([repo_name, path, content, message]):
|
222 |
-
raise ValueError(
|
223 |
-
"Brakuj膮ce parametry: repo_name, path, content, message")
|
224 |
repo = user.get_repo(repo_name)
|
225 |
file_contents = repo.get_contents(path, ref=branch)
|
226 |
-
repo.update_file(path, message, content,
|
227 |
-
|
228 |
-
|
229 |
elif action == "list_branches":
|
230 |
if not repo_name:
|
231 |
-
raise ValueError("
|
232 |
repo = user.get_repo(repo_name)
|
233 |
branches = repo.get_branches()
|
234 |
-
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
|
235 |
-
return f"
|
|
|
236 |
elif action == "create_branch":
|
237 |
-
if not all([repo_name, base, head]):
|
238 |
-
raise ValueError("
|
239 |
repo = user.get_repo(repo_name)
|
240 |
source_branch = repo.get_branch(base)
|
241 |
-
repo.create_git_ref(ref=f"refs/heads/{head}",
|
242 |
-
|
243 |
-
|
244 |
elif action == "delete_branch":
|
245 |
if not all([repo_name, branch]):
|
246 |
-
raise ValueError("
|
247 |
repo = user.get_repo(repo_name)
|
248 |
repo.get_git_ref(f"heads/{branch}").delete()
|
249 |
-
return f"
|
|
|
250 |
elif action == "create_pull_request":
|
251 |
if not all([repo_name, title, body, base, head]):
|
252 |
-
raise ValueError(
|
253 |
-
"Brakuj膮ce parametry: repo_name, title, body, base, head")
|
254 |
repo = user.get_repo(repo_name)
|
255 |
pr = repo.create_pull(title=title, body=body, base=base, head=head)
|
256 |
-
return f"Pull request
|
|
|
257 |
elif action == "list_open_pull_requests":
|
258 |
if not repo_name:
|
259 |
-
raise ValueError("
|
260 |
repo = user.get_repo(repo_name)
|
261 |
open_prs = repo.get_pulls(state='open')
|
262 |
if not open_prs:
|
263 |
-
return f"
|
264 |
-
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
|
265 |
-
return f"
|
|
|
266 |
elif action == "create_issue":
|
267 |
if not all([repo_name, title, body]):
|
268 |
-
raise ValueError("
|
269 |
repo = user.get_repo(repo_name)
|
270 |
issue = repo.create_issue(title=title, body=body)
|
271 |
-
return f"Issue
|
|
|
272 |
elif action == "list_issues":
|
273 |
if not repo_name:
|
274 |
-
raise ValueError("
|
275 |
repo = user.get_repo(repo_name)
|
276 |
issues = repo.get_issues(state='open')
|
277 |
if not issues:
|
278 |
-
return f"
|
279 |
-
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
280 |
-
return f"
|
|
|
281 |
elif action == "add_label_to_issue":
|
282 |
if not all([repo_name, issue_number, labels]):
|
283 |
-
raise ValueError(
|
284 |
-
"Brakuj膮ce parametry: repo_name, issue_number, labels")
|
285 |
repo = user.get_repo(repo_name)
|
286 |
issue = repo.get_issue(number=int(issue_number))
|
287 |
for label in labels.split(","):
|
288 |
issue.add_to_labels(label.strip())
|
289 |
-
return
|
|
|
|
|
|
|
290 |
elif action == "close_issue":
|
291 |
if not all([repo_name, issue_number]):
|
292 |
-
raise ValueError("
|
293 |
repo = user.get_repo(repo_name)
|
294 |
issue = repo.get_issue(number=int(issue_number))
|
295 |
issue.edit(state='closed')
|
296 |
-
return f"Issue **#{issue_number}**
|
|
|
297 |
elif action == "add_comment_to_issue":
|
298 |
-
if not all([repo_name, issue_number, message]):
|
299 |
-
raise ValueError(
|
300 |
-
"Brakuj膮ce parametry: repo_name, issue_number, message")
|
301 |
repo = user.get_repo(repo_name)
|
302 |
issue = repo.get_issue(number=int(issue_number))
|
303 |
issue.create_comment(body=message)
|
304 |
-
return f"
|
|
|
305 |
elif action == "create_release":
|
306 |
if not all([repo_name, tag, name, message]):
|
307 |
-
raise ValueError(
|
308 |
-
"Brakuj膮ce parametry: repo_name, tag, name, message")
|
309 |
repo = user.get_repo(repo_name)
|
310 |
-
release = repo.create_git_release(
|
311 |
-
|
312 |
-
|
|
|
|
|
313 |
elif action == "list_releases":
|
314 |
if not repo_name:
|
315 |
-
raise ValueError("
|
316 |
repo = user.get_repo(repo_name)
|
317 |
releases = repo.get_releases()
|
318 |
if not releases:
|
319 |
-
return f"
|
320 |
-
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
|
321 |
-
return f"Releases
|
|
|
322 |
elif action == "fork_repository":
|
323 |
if not repo_name:
|
324 |
-
raise ValueError("
|
325 |
-
repo = g.get_repo(repo_name)
|
326 |
fork = user.create_fork(repo)
|
327 |
-
return f"
|
|
|
328 |
elif action == "list_forks":
|
329 |
if not repo_name:
|
330 |
-
raise ValueError("
|
331 |
-
repo = g.get_repo(repo_name)
|
332 |
forks = repo.get_forks()
|
333 |
if not forks:
|
334 |
-
return f"
|
335 |
-
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
|
336 |
-
return f"
|
|
|
337 |
elif action == "list_files":
|
338 |
if not all([owner, repo_name]):
|
339 |
-
raise ValueError("
|
340 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
341 |
-
#
|
342 |
-
if not path:
|
343 |
-
contents = repo.get_contents("") # Pobierz zawarto艣膰 g艂贸wnego katalogu
|
344 |
-
else:
|
345 |
-
contents = repo.get_contents(path)
|
346 |
if not contents:
|
347 |
-
return f"
|
348 |
-
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
|
349 |
-
return f"
|
|
|
350 |
elif action == "get_repository_info":
|
351 |
if not all([owner, repo_name]):
|
352 |
-
raise ValueError("
|
353 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
354 |
info = {
|
355 |
-
"
|
356 |
-
"
|
357 |
"URL": repo.html_url,
|
358 |
-
"
|
359 |
-
"
|
360 |
-
"
|
361 |
-
"
|
362 |
-
"
|
363 |
-
"
|
364 |
-
"
|
365 |
}
|
366 |
-
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
|
367 |
-
return f"
|
|
|
368 |
elif action == "get_file_content":
|
369 |
if not all([owner, repo_name, path]):
|
370 |
-
raise ValueError("
|
371 |
content_text = get_file_content(owner, repo_name, path, branch)
|
372 |
-
return
|
|
|
|
|
|
|
373 |
elif action == "analyze_repository_by_url":
|
374 |
if not repo_url:
|
375 |
-
raise ValueError("
|
376 |
owner, repo_name = extract_repo_info(repo_url)
|
377 |
if not owner or not repo_name:
|
378 |
-
raise ValueError("
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
for f in file_analyses
|
401 |
-
])
|
402 |
-
return analysis_md
|
403 |
-
except GithubException as e:
|
404 |
-
return f"B艂膮d GitHub: {str(e)}"
|
405 |
-
raise ValueError(f"Nieznana akcja: {action}") # Correctly placed for unknown action handling
|
406 |
|
407 |
elif action == "analyze_repository_content":
|
408 |
if not all([owner, repo_name]):
|
409 |
-
raise ValueError("
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
except GithubException as e:
|
437 |
-
return f"**
|
438 |
except ValueError as e:
|
439 |
-
return f"**
|
440 |
except requests.exceptions.RequestException as e:
|
441 |
-
return f"**
|
|
|
|
|
|
|
442 |
|
443 |
with gr.Blocks() as demo:
|
444 |
-
gr.Markdown("#
|
|
|
445 |
with gr.Column():
|
446 |
action = gr.Dropdown(
|
447 |
choices=[
|
@@ -473,33 +491,33 @@ with gr.Blocks() as demo:
|
|
473 |
"analyze_repository_by_url",
|
474 |
"analyze_repository_content",
|
475 |
],
|
476 |
-
label="
|
477 |
)
|
478 |
-
repo_name = gr.Textbox(label="
|
479 |
template_name = gr.Dropdown(
|
480 |
choices=list(PROJECT_TEMPLATES.keys()),
|
481 |
-
label="
|
482 |
-
allow_none=True,
|
483 |
)
|
484 |
-
branch = gr.Textbox(label="
|
485 |
-
path = gr.Textbox(label="
|
486 |
-
content = gr.Code(label="
|
487 |
-
message = gr.Textbox(label="
|
488 |
-
owner = gr.Textbox(label="
|
489 |
-
vcs_url = gr.Textbox(label="URL
|
490 |
-
title = gr.Textbox(label="
|
491 |
-
body = gr.Textbox(label="
|
492 |
-
base = gr.Textbox(label="
|
493 |
-
head = gr.Textbox(label="
|
494 |
-
issue_number = gr.Number(label="
|
495 |
-
labels = gr.Textbox(label="
|
496 |
tag = gr.Textbox(label="Tag")
|
497 |
-
release_name = gr.Textbox(label="
|
498 |
-
file_url = gr.Textbox(label="URL
|
499 |
-
repo_url = gr.Textbox(label="
|
500 |
|
501 |
-
run_button = gr.Button("
|
502 |
-
output = gr.Markdown(label="
|
503 |
|
504 |
run_button.click(
|
505 |
github_tool,
|
@@ -525,7 +543,7 @@ with gr.Blocks() as demo:
|
|
525 |
template_name,
|
526 |
],
|
527 |
outputs=output,
|
528 |
-
api_name="github_tool"
|
529 |
)
|
530 |
|
531 |
demo.launch()
|
|
|
5 |
import re
|
6 |
from collections import Counter
|
7 |
|
8 |
+
# Load token. Best practice is to use environment variables.
|
9 |
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
10 |
+
if not GITHUB_TOKEN: # Good practice to have this check.
|
11 |
+
raise ValueError("GITHUB_TOKEN environment variable not set!")
|
12 |
g = Github(GITHUB_TOKEN)
|
13 |
|
14 |
+
# Project templates (well-structured).
|
15 |
PROJECT_TEMPLATES = {
|
16 |
"flask": {
|
17 |
"files": {
|
18 |
"app.py": """from flask import Flask
|
19 |
app = Flask(__name__)
|
|
|
20 |
@app.route('/')
|
21 |
def hello():
|
22 |
return "Hello, Flask!"
|
|
|
23 |
if __name__ == '__main__':
|
24 |
app.run(debug=True)""",
|
25 |
"requirements.txt": "Flask",
|
|
|
48 |
}}""",
|
49 |
"vite.config.js": """import { defineConfig } from 'vite'
|
50 |
import react from '@vitejs/plugin-react'
|
51 |
+
# https://vitejs.dev/config/
|
|
|
52 |
export default defineConfig({
|
53 |
plugins: [react()],
|
54 |
})""",
|
|
|
69 |
import ReactDOM from 'react-dom/client'
|
70 |
import App from './App.jsx'
|
71 |
import './index.css'
|
|
|
72 |
ReactDOM.createRoot(document.getElementById('root')).render(
|
73 |
<React.StrictMode>
|
74 |
<App />
|
|
|
76 |
)""",
|
77 |
"src/App.jsx": """import React from 'react'
|
78 |
import './App.css'
|
|
|
79 |
function App() {
|
80 |
return (
|
81 |
<>
|
|
|
83 |
</>
|
84 |
)
|
85 |
}
|
|
|
86 |
export default App""",
|
87 |
"src/index.css": """body {
|
88 |
margin: 0;
|
|
|
90 |
-webkit-font-smoothing: antialiased;
|
91 |
-moz-osx-font-smoothing: grayscale;
|
92 |
}
|
|
|
93 |
code {
|
94 |
font-family: monospace;
|
95 |
}""",
|
|
|
97 |
}
|
98 |
}}
|
99 |
|
100 |
+
|
101 |
def get_file_content(owner, repo_name, path, branch="main"):
|
102 |
+
"""Fetches file content from a GitHub repository."""
|
103 |
url = f"https://raw.githubusercontent.com/{owner}/{repo_name}/{branch}/{path}"
|
104 |
+
try:
|
105 |
+
response = requests.get(url)
|
106 |
+
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
|
107 |
return response.text
|
108 |
+
except requests.exceptions.RequestException as e:
|
109 |
+
return f"Error fetching file: {e}"
|
110 |
+
|
111 |
|
112 |
def extract_repo_info(url):
|
113 |
+
"""Extracts owner and repo name from a GitHub URL."""
|
114 |
match = re.search(r"github\.com/([^/]+)/([^/]+)", url)
|
115 |
+
return match.group(1), match.group(2) if match else (None, None)
|
116 |
+
|
|
|
|
|
117 |
|
118 |
def analyze_file_content(content, file_path):
|
119 |
+
"""Analyzes file content and returns statistics."""
|
120 |
lines = content.splitlines()
|
121 |
word_count = sum(len(line.split()) for line in lines)
|
122 |
line_count = len(lines)
|
|
|
127 |
"file_extension": file_extension,
|
128 |
}
|
129 |
|
130 |
+
|
131 |
def github_tool(
|
132 |
action: str,
|
133 |
repo_name: str = None,
|
134 |
+
branch: str = "main",
|
135 |
path: str = None,
|
136 |
content: str = None,
|
137 |
message: str = None,
|
|
|
142 |
base: str = None,
|
143 |
head: str = None,
|
144 |
issue_number: int = None,
|
145 |
+
labels: str = None,
|
146 |
tag: str = None,
|
147 |
+
name: str = None,
|
148 |
+
file_url: str = None,
|
149 |
+
repo_url: str = None,
|
150 |
+
template_name: str = None,
|
151 |
):
|
152 |
+
"""Manages GitHub repositories."""
|
153 |
user = g.get_user()
|
154 |
+
|
155 |
+
try: # Single try block for ALL actions (Solution 1)
|
156 |
if action == "import_repository":
|
157 |
if not all([owner, repo_name, vcs_url]):
|
158 |
+
raise ValueError("Missing parameters: owner, repo_name, vcs_url")
|
|
|
|
|
159 |
try:
|
160 |
+
user.get_repo(repo_name) # Check if repo exists (simplified)
|
161 |
+
return "Repository already exists."
|
162 |
except GithubException:
|
163 |
+
pass # Repo doesn't exist, proceed with import
|
164 |
+
|
165 |
headers = {
|
166 |
'Authorization': f'token {GITHUB_TOKEN}',
|
167 |
'Accept': 'application/vnd.github.v3+json',
|
168 |
}
|
169 |
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
|
170 |
+
response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
|
171 |
+
response.raise_for_status() # Handle potential HTTP errors.
|
172 |
+
return "Repository import started."
|
173 |
+
|
174 |
+
|
|
|
175 |
elif action == "create_repository":
|
176 |
if not repo_name:
|
177 |
+
raise ValueError("Missing parameter: repo_name")
|
178 |
repo = user.create_repo(name=repo_name)
|
179 |
+
return f"Repository **{repo_name}** created! [Open repository]({repo.html_url})"
|
180 |
+
|
181 |
elif action == "create_project_from_template":
|
182 |
if not all([repo_name, template_name]):
|
183 |
+
raise ValueError("Missing parameters: repo_name, template_name")
|
184 |
if template_name not in PROJECT_TEMPLATES:
|
185 |
+
raise ValueError(
|
186 |
+
f"Unknown template: {template_name}. Available: {', '.join(PROJECT_TEMPLATES.keys())}"
|
187 |
+
)
|
188 |
repo = user.create_repo(name=repo_name)
|
189 |
template = PROJECT_TEMPLATES[template_name]
|
190 |
for file_path, file_content in template["files"].items():
|
191 |
+
repo.create_file(
|
192 |
+
file_path,
|
193 |
+
f"Create {file_path} from template {template_name}",
|
194 |
+
file_content,
|
195 |
+
branch="main",
|
196 |
+
)
|
197 |
+
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
|
198 |
+
|
199 |
elif action == "create_file":
|
200 |
if not all([repo_name, path, content, message]):
|
201 |
+
raise ValueError("Missing parameters: repo_name, path, content, message")
|
|
|
202 |
repo = user.get_repo(repo_name)
|
203 |
repo.create_file(path, message, content, branch=branch)
|
204 |
+
return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
|
205 |
+
|
206 |
elif action == "get_file":
|
207 |
if not all([repo_name, path]):
|
208 |
+
raise ValueError("Missing parameters: repo_name, path")
|
209 |
repo = user.get_repo(repo_name)
|
210 |
file_content = repo.get_contents(path, ref=branch)
|
211 |
+
return (
|
212 |
+
f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
|
213 |
+
)
|
214 |
+
|
215 |
elif action == "get_file_content_by_url":
|
216 |
if not file_url:
|
217 |
+
raise ValueError("Missing parameter: file_url")
|
218 |
+
file_content = get_file_content(None, None, None, None) # Dummy call to avoid UnboundLocalError. get_file_content changed!
|
219 |
+
return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
|
220 |
+
|
221 |
elif action == "delete_file":
|
222 |
if not all([repo_name, path]):
|
223 |
+
raise ValueError("Missing parameters: repo_name, path")
|
224 |
repo = user.get_repo(repo_name)
|
225 |
file_contents = repo.get_contents(path, ref=branch)
|
226 |
+
repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
|
227 |
+
return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
|
228 |
+
|
229 |
elif action == "update_file":
|
230 |
if not all([repo_name, path, content, message]):
|
231 |
+
raise ValueError("Missing parameters: repo_name, path, content, message")
|
|
|
232 |
repo = user.get_repo(repo_name)
|
233 |
file_contents = repo.get_contents(path, ref=branch)
|
234 |
+
repo.update_file(path, message, content, file_contents.sha, branch=branch)
|
235 |
+
return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
|
236 |
+
|
237 |
elif action == "list_branches":
|
238 |
if not repo_name:
|
239 |
+
raise ValueError("Missing parameter: repo_name")
|
240 |
repo = user.get_repo(repo_name)
|
241 |
branches = repo.get_branches()
|
242 |
+
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
|
243 |
+
return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
|
244 |
+
|
245 |
elif action == "create_branch":
|
246 |
+
if not all([repo_name, base, head]):
|
247 |
+
raise ValueError("Missing parameters: repo_name, base, head")
|
248 |
repo = user.get_repo(repo_name)
|
249 |
source_branch = repo.get_branch(base)
|
250 |
+
repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
|
251 |
+
return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
|
252 |
+
|
253 |
elif action == "delete_branch":
|
254 |
if not all([repo_name, branch]):
|
255 |
+
raise ValueError("Missing parameters: repo_name, branch")
|
256 |
repo = user.get_repo(repo_name)
|
257 |
repo.get_git_ref(f"heads/{branch}").delete()
|
258 |
+
return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
|
259 |
+
|
260 |
elif action == "create_pull_request":
|
261 |
if not all([repo_name, title, body, base, head]):
|
262 |
+
raise ValueError("Missing parameters: repo_name, title, body, base, head")
|
|
|
263 |
repo = user.get_repo(repo_name)
|
264 |
pr = repo.create_pull(title=title, body=body, base=base, head=head)
|
265 |
+
return f"Pull request created! [Open Pull Request]({pr.html_url})"
|
266 |
+
|
267 |
elif action == "list_open_pull_requests":
|
268 |
if not repo_name:
|
269 |
+
raise ValueError("Missing parameter: repo_name")
|
270 |
repo = user.get_repo(repo_name)
|
271 |
open_prs = repo.get_pulls(state='open')
|
272 |
if not open_prs:
|
273 |
+
return f"No open pull requests in repository **`{repo_name}`**."
|
274 |
+
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
|
275 |
+
return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
|
276 |
+
|
277 |
elif action == "create_issue":
|
278 |
if not all([repo_name, title, body]):
|
279 |
+
raise ValueError("Missing parameters: repo_name, title, body")
|
280 |
repo = user.get_repo(repo_name)
|
281 |
issue = repo.create_issue(title=title, body=body)
|
282 |
+
return f"Issue created! [Open Issue]({issue.html_url})"
|
283 |
+
|
284 |
elif action == "list_issues":
|
285 |
if not repo_name:
|
286 |
+
raise ValueError("Missing parameter: repo_name")
|
287 |
repo = user.get_repo(repo_name)
|
288 |
issues = repo.get_issues(state='open')
|
289 |
if not issues:
|
290 |
+
return f"No open issues in repository **`{repo_name}`**."
|
291 |
+
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
292 |
+
return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
|
293 |
+
|
294 |
elif action == "add_label_to_issue":
|
295 |
if not all([repo_name, issue_number, labels]):
|
296 |
+
raise ValueError("Missing parameters: repo_name, issue_number, labels")
|
|
|
297 |
repo = user.get_repo(repo_name)
|
298 |
issue = repo.get_issue(number=int(issue_number))
|
299 |
for label in labels.split(","):
|
300 |
issue.add_to_labels(label.strip())
|
301 |
+
return (
|
302 |
+
f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
303 |
+
)
|
304 |
+
|
305 |
elif action == "close_issue":
|
306 |
if not all([repo_name, issue_number]):
|
307 |
+
raise ValueError("Missing parameters: repo_name, issue_number")
|
308 |
repo = user.get_repo(repo_name)
|
309 |
issue = repo.get_issue(number=int(issue_number))
|
310 |
issue.edit(state='closed')
|
311 |
+
return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
|
312 |
+
|
313 |
elif action == "add_comment_to_issue":
|
314 |
+
if not all([repo_name, issue_number, message]):
|
315 |
+
raise ValueError("Missing parameters: repo_name, issue_number, message")
|
|
|
316 |
repo = user.get_repo(repo_name)
|
317 |
issue = repo.get_issue(number=int(issue_number))
|
318 |
issue.create_comment(body=message)
|
319 |
+
return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
320 |
+
|
321 |
elif action == "create_release":
|
322 |
if not all([repo_name, tag, name, message]):
|
323 |
+
raise ValueError("Missing parameters: repo_name, tag, name, message")
|
|
|
324 |
repo = user.get_repo(repo_name)
|
325 |
+
release = repo.create_git_release(tag=tag, name=name, message=message)
|
326 |
+
return (
|
327 |
+
f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
|
328 |
+
)
|
329 |
+
|
330 |
elif action == "list_releases":
|
331 |
if not repo_name:
|
332 |
+
raise ValueError("Missing parameter: repo_name")
|
333 |
repo = user.get_repo(repo_name)
|
334 |
releases = repo.get_releases()
|
335 |
if not releases:
|
336 |
+
return f"No releases in repository **`{repo_name}`**."
|
337 |
+
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
|
338 |
+
return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
|
339 |
+
|
340 |
elif action == "fork_repository":
|
341 |
if not repo_name:
|
342 |
+
raise ValueError("Missing parameter: repo_name")
|
343 |
+
repo = g.get_repo(repo_name)
|
344 |
fork = user.create_fork(repo)
|
345 |
+
return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
|
346 |
+
|
347 |
elif action == "list_forks":
|
348 |
if not repo_name:
|
349 |
+
raise ValueError("Missing parameter: repo_name")
|
350 |
+
repo = g.get_repo(repo_name)
|
351 |
forks = repo.get_forks()
|
352 |
if not forks:
|
353 |
+
return f"No forks of repository **`{repo_name}`**."
|
354 |
+
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
|
355 |
+
return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
|
356 |
+
|
357 |
elif action == "list_files":
|
358 |
if not all([owner, repo_name]):
|
359 |
+
raise ValueError("Missing parameters: owner, repo_name")
|
360 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
361 |
+
contents = repo.get_contents("" if not path else path) # Simplified path handling
|
|
|
|
|
|
|
|
|
362 |
if not contents:
|
363 |
+
return f"No files in path **`{path}`** of repository **`{repo_name}`**."
|
364 |
+
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
|
365 |
+
return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
|
366 |
+
|
367 |
elif action == "get_repository_info":
|
368 |
if not all([owner, repo_name]):
|
369 |
+
raise ValueError("Missing parameters: owner, repo_name")
|
370 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
371 |
info = {
|
372 |
+
"Name": repo.name,
|
373 |
+
"Description": repo.description,
|
374 |
"URL": repo.html_url,
|
375 |
+
"Owner": repo.owner.login,
|
376 |
+
"Default branch": repo.default_branch,
|
377 |
+
"Language": repo.language,
|
378 |
+
"Stars": repo.stargazers_count,
|
379 |
+
"Forks": repo.forks_count,
|
380 |
+
"Created at": str(repo.created_at),
|
381 |
+
"Last updated": str(repo.updated_at),
|
382 |
}
|
383 |
+
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
|
384 |
+
return f"Repository info for **`{repo_name}`**:\n{info_md}"
|
385 |
+
|
386 |
elif action == "get_file_content":
|
387 |
if not all([owner, repo_name, path]):
|
388 |
+
raise ValueError("Missing parameters: owner, repo_name, path")
|
389 |
content_text = get_file_content(owner, repo_name, path, branch)
|
390 |
+
return (
|
391 |
+
f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
|
392 |
+
)
|
393 |
+
|
394 |
elif action == "analyze_repository_by_url":
|
395 |
if not repo_url:
|
396 |
+
raise ValueError("Missing parameter: repo_url")
|
397 |
owner, repo_name = extract_repo_info(repo_url)
|
398 |
if not owner or not repo_name:
|
399 |
+
raise ValueError("Invalid repository URL")
|
400 |
+
|
401 |
+
repo = g.get_repo(f"{owner}/{repo_name}")
|
402 |
+
contents = repo.get_contents("")
|
403 |
+
file_analyses = []
|
404 |
+
for content in contents:
|
405 |
+
if content.type == "file":
|
406 |
+
file_content = content.decoded_content.decode()
|
407 |
+
analysis = analyze_file_content(file_content, content.path)
|
408 |
+
file_analyses.append({
|
409 |
+
"name": content.name,
|
410 |
+
"path": content.path,
|
411 |
+
"analysis": analysis,
|
412 |
+
})
|
413 |
+
analysis_md = "Repository file analysis:\n" + "\n".join([
|
414 |
+
f"- **{f['path']}**:\n"
|
415 |
+
f" - Lines: {f['analysis']['line_count']}\n"
|
416 |
+
f" - Words: {f['analysis']['word_count']}\n"
|
417 |
+
f" - Extension: {f['analysis']['file_extension']}"
|
418 |
+
for f in file_analyses
|
419 |
+
])
|
420 |
+
return analysis_md
|
|
|
|
|
|
|
|
|
|
|
|
|
421 |
|
422 |
elif action == "analyze_repository_content":
|
423 |
if not all([owner, repo_name]):
|
424 |
+
raise ValueError("Missing parameters: owner, repo_name")
|
425 |
+
repo = g.get_repo(f"{owner}/{repo_name}")
|
426 |
+
contents = repo.get_contents("")
|
427 |
+
file_analyses = []
|
428 |
+
for content in contents:
|
429 |
+
if content.type == "file":
|
430 |
+
file_content = get_file_content(owner, repo_name, content.path, branch) # Use helper
|
431 |
+
analysis = analyze_file_content(file_content, content.path)
|
432 |
+
file_analyses.append({
|
433 |
+
"name": content.name,
|
434 |
+
"path": content.path,
|
435 |
+
"analysis": analysis,
|
436 |
+
})
|
437 |
+
analysis_md = "Repository content analysis:\n" + "\n".join([
|
438 |
+
f"- **{f['path']}**:\n"
|
439 |
+
f" - Lines: {f['analysis']['line_count']}\n"
|
440 |
+
f" - Words: {f['analysis']['word_count']}\n"
|
441 |
+
f" - Extension: {f['analysis']['file_extension']}"
|
442 |
+
for f in file_analyses
|
443 |
+
])
|
444 |
+
return analysis_md
|
445 |
+
|
446 |
+
else: # Correct else for handling unknown actions
|
447 |
+
raise ValueError(f"Unknown action: {action}")
|
448 |
+
|
449 |
+
|
|
|
450 |
except GithubException as e:
|
451 |
+
return f"**GitHub Error:** {e}"
|
452 |
except ValueError as e:
|
453 |
+
return f"**Error:** {e}" # This is line 434 (now corrected)
|
454 |
except requests.exceptions.RequestException as e:
|
455 |
+
return f"**Connection Error:** {e}"
|
456 |
+
except Exception as e:
|
457 |
+
return f"**Unexpected Error:** {e}" # Catch all.
|
458 |
+
|
459 |
|
460 |
with gr.Blocks() as demo:
|
461 |
+
gr.Markdown("# GitHub Tool Plugingit (Simplified Interface)") # More descriptive title
|
462 |
+
|
463 |
with gr.Column():
|
464 |
action = gr.Dropdown(
|
465 |
choices=[
|
|
|
491 |
"analyze_repository_by_url",
|
492 |
"analyze_repository_content",
|
493 |
],
|
494 |
+
label="Select Action",
|
495 |
)
|
496 |
+
repo_name = gr.Textbox(label="Repository Name")
|
497 |
template_name = gr.Dropdown(
|
498 |
choices=list(PROJECT_TEMPLATES.keys()),
|
499 |
+
label="Project Template",
|
500 |
+
allow_none=True, # Allow no template to be selected
|
501 |
)
|
502 |
+
branch = gr.Textbox(label="Branch", value="main")
|
503 |
+
path = gr.Textbox(label="File Path")
|
504 |
+
content = gr.Code(label="File Content", lines=5, language='python') # Larger code box
|
505 |
+
message = gr.Textbox(label="Message/Comment")
|
506 |
+
owner = gr.Textbox(label="Owner")
|
507 |
+
vcs_url = gr.Textbox(label="VCS URL")
|
508 |
+
title = gr.Textbox(label="Title")
|
509 |
+
body = gr.Textbox(label="Body")
|
510 |
+
base = gr.Textbox(label="Base Branch")
|
511 |
+
head = gr.Textbox(label="Head Branch/New Branch")
|
512 |
+
issue_number = gr.Number(label="Issue Number", precision=0)
|
513 |
+
labels = gr.Textbox(label="Labels (comma-separated)")
|
514 |
tag = gr.Textbox(label="Tag")
|
515 |
+
release_name = gr.Textbox(label="Release Name")
|
516 |
+
file_url = gr.Textbox(label="File URL")
|
517 |
+
repo_url = gr.Textbox(label="Repository URL")
|
518 |
|
519 |
+
run_button = gr.Button("Execute")
|
520 |
+
output = gr.Markdown(label="Result") # Use Markdown for richer output
|
521 |
|
522 |
run_button.click(
|
523 |
github_tool,
|
|
|
543 |
template_name,
|
544 |
],
|
545 |
outputs=output,
|
546 |
+
api_name="github_tool"
|
547 |
)
|
548 |
|
549 |
demo.launch()
|