|
import gradio as gr |
|
from github import Github, GithubException |
|
import os |
|
import requests |
|
import re |
|
from collections import Counter |
|
|
|
|
|
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') |
|
g = Github(GITHUB_TOKEN) |
|
|
|
|
|
PROJECT_TEMPLATES = { |
|
"flask": { |
|
"files": { |
|
"app.py": """from flask import Flask |
|
app = Flask(__name__) |
|
|
|
@app.route('/') |
|
def hello(): |
|
return "Hello, Flask!" |
|
|
|
if __name__ == '__main__': |
|
app.run(debug=True)""", |
|
"requirements.txt": "Flask", |
|
".gitignore": "__pycache__/\n*.pyc\nvenv/\ninstance/" |
|
} |
|
}, |
|
"react": { |
|
"files": { |
|
"package.json": """{ |
|
"name": "react-app", |
|
"private": true, |
|
"version": "0.0.0", |
|
"type": "module", |
|
"scripts": { |
|
"dev": "vite", |
|
"build": "vite build", |
|
"preview": "vite preview" |
|
}, |
|
"dependencies": { |
|
"react": "^18.2.0", |
|
"react-dom": "^18.2.0" |
|
}, |
|
"devDependencies": { |
|
"@vitejs/plugin-react": "^4.2.1", |
|
"vite": "^5.0.8" |
|
}}""", |
|
"vite.config.js": """import { defineConfig } from 'vite' |
|
import react from '@vitejs/plugin-react' |
|
|
|
// https://vitejs.dev/config/ |
|
export default defineConfig({ |
|
plugins: [react()], |
|
})""", |
|
"index.html": """<!doctype html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8" /> |
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|
<title>Vite + React</title> |
|
</head> |
|
<body> |
|
<div id="root"></div> |
|
<script type="module" src="/src/main.jsx"></script> |
|
</body> |
|
</html>""", |
|
"src/main.jsx": """import React from 'react' |
|
import ReactDOM from 'react-dom/client' |
|
import App from './App.jsx' |
|
import './index.css' |
|
|
|
ReactDOM.createRoot(document.getElementById('root')).render( |
|
<React.StrictMode> |
|
<App /> |
|
</React.StrictMode>, |
|
)""", |
|
"src/App.jsx": """import React from 'react' |
|
import './App.css' |
|
|
|
function App() { |
|
return ( |
|
<> |
|
<h1>Hello from React!</h1> |
|
</> |
|
) |
|
} |
|
|
|
export default App""", |
|
"src/index.css": """body { |
|
margin: 0; |
|
font-family: sans-serif; |
|
-webkit-font-smoothing: antialiased; |
|
-moz-osx-font-smoothing: grayscale; |
|
} |
|
|
|
code { |
|
font-family: monospace; |
|
}""", |
|
".gitignore": "node_modules/\ndist/" |
|
} |
|
}} |
|
|
|
def get_file_content(owner, repo_name, path, branch="main"): |
|
url = f"https://raw.githubusercontent.com/{owner}/{repo_name}/{branch}/{path}" |
|
response = requests.get(url) |
|
if response.status_code == 200: |
|
return response.text |
|
else: |
|
return f"Błąd pobierania pliku: {response.status_code}" |
|
|
|
def extract_repo_info(url): |
|
"""Wyodrębnia nazwę użytkownika i repozytorium z linku GitHub.""" |
|
match = re.search(r"github\.com/([^/]+)/([^/]+)", url) |
|
if match: |
|
return match.group(1), match.group(2) |
|
else: |
|
return None, None |
|
|
|
def analyze_file_content(content, file_path): |
|
"""Analizuje zawartość pliku i zwraca statystyki.""" |
|
lines = content.splitlines() |
|
word_count = sum(len(line.split()) for line in lines) |
|
line_count = len(lines) |
|
file_extension = file_path.split('.')[-1].lower() if '.' in file_path else "unknown" |
|
return { |
|
"line_count": line_count, |
|
"word_count": word_count, |
|
"file_extension": file_extension, |
|
} |
|
|
|
def github_tool( |
|
action: str, |
|
repo_name: str = None, |
|
branch: str = "main", |
|
path: str = None, |
|
content: str = None, |
|
message: str = None, |
|
owner: str = None, |
|
vcs_url: str = None, |
|
title: str = None, |
|
body: str = None, |
|
base: str = None, |
|
head: str = None, |
|
issue_number: int = None, |
|
labels: str = None, |
|
tag: str = None, |
|
name: str = None, |
|
file_url: str = None, |
|
repo_url: str = None, |
|
template_name: str = None, |
|
): |
|
"""Narzędzie do zarządzania repozytoriami GitHub.""" |
|
user = g.get_user() |
|
try: |
|
if action == "import_repository": |
|
if not all([owner, repo_name, vcs_url]): |
|
raise ValueError( |
|
"Brakujące parametry: owner, repo_name, vcs_url") |
|
|
|
try: |
|
repo = user.get_repo(repo_name) |
|
return "Repozytorium o tej nazwie już istnieje." |
|
except GithubException: |
|
pass |
|
headers = { |
|
'Authorization': f'token {GITHUB_TOKEN}', |
|
'Accept': 'application/vnd.github.v3+json', |
|
} |
|
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import' |
|
payload = {'vcs_url': vcs_url, 'vcs': 'git'} |
|
response = requests.put(import_url, json=payload, headers=headers) |
|
if response.status_code == 201: |
|
return "Import repozytorium został rozpoczęty." |
|
else: |
|
return f"Błąd importu: {response.status_code}, {response.json()}" |
|
elif action == "create_repository": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = user.create_repo(name=repo_name) |
|
return f"Repozytorium **{repo_name}** utworzone! [Otwórz repozytorium]({repo.html_url})" |
|
elif action == "create_project_from_template": |
|
if not all([repo_name, template_name]): |
|
raise ValueError("Brakujące parametry: repo_name, template_name") |
|
if template_name not in PROJECT_TEMPLATES: |
|
raise ValueError(f"Nieznany szablon projektu: {template_name}. Dostępne szablony: {', '.join(PROJECT_TEMPLATES.keys())}") |
|
repo = user.create_repo(name=repo_name) |
|
template = PROJECT_TEMPLATES[template_name] |
|
for file_path, file_content in template["files"].items(): |
|
repo.create_file(file_path, f"Utworzenie {file_path} z szablonu {template_name}", file_content, branch="main") |
|
return f"Repozytorium **{repo_name}** utworzone z szablonu **{template_name}**! [Otwórz repozytorium]({repo.html_url})" |
|
elif action == "create_file": |
|
if not all([repo_name, path, content, message]): |
|
raise ValueError( |
|
"Brakujące parametry: repo_name, path, content, message") |
|
repo = user.get_repo(repo_name) |
|
repo.create_file(path, message, content, branch=branch) |
|
return f"Plik **`{path}`** utworzony w repozytorium **`{repo_name}`** na gałęzi **`{branch}`**." |
|
elif action == "get_file": |
|
if not all([repo_name, path]): |
|
raise ValueError("Brakujące parametry: repo_name, path") |
|
repo = user.get_repo(repo_name) |
|
file_content = repo.get_contents(path, ref=branch) |
|
return f"Zawartość pliku **`{path}`** z repozytorium **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`" |
|
elif action == "get_file_content_by_url": |
|
if not file_url: |
|
raise ValueError("Brakujący parametr: file_url") |
|
response = requests.get(file_url) |
|
response.raise_for_status() |
|
return f"Zawartość pliku z URL **`{file_url}`**:\n\n`\n{response.text}\n`" |
|
elif action == "delete_file": |
|
if not all([repo_name, path]): |
|
raise ValueError("Brakujące parametry: repo_name, path") |
|
repo = user.get_repo(repo_name) |
|
file_contents = repo.get_contents(path, ref=branch) |
|
repo.delete_file(path, "Usunięcie pliku", |
|
file_contents.sha, branch=branch) |
|
return f"Plik **`{path}`** usunięty z repozytorium **`{repo_name}`** na gałęzi **`{branch}`**." |
|
elif action == "update_file": |
|
if not all([repo_name, path, content, message]): |
|
raise ValueError( |
|
"Brakujące parametry: repo_name, path, content, message") |
|
repo = user.get_repo(repo_name) |
|
file_contents = repo.get_contents(path, ref=branch) |
|
repo.update_file(path, message, content, |
|
file_contents.sha, branch=branch) |
|
return f"Plik **`{path}`** zaktualizowany w repozytorium **`{repo_name}`** na gałęzi **`{branch}`**." |
|
elif action == "list_branches": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = user.get_repo(repo_name) |
|
branches = repo.get_branches() |
|
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches]) |
|
return f"Gałęzie w repozytorium **`{repo_name}`**:\n{branch_list}" |
|
elif action == "create_branch": |
|
if not all([repo_name, base, head]): |
|
raise ValueError("Brakujące parametry: repo_name, base, head") |
|
repo = user.get_repo(repo_name) |
|
source_branch = repo.get_branch(base) |
|
repo.create_git_ref(ref=f"refs/heads/{head}", |
|
sha=source_branch.commit.sha) |
|
return f"Gałąź **`{head}`** utworzona z **`{base}`** w repozytorium **`{repo_name}`**." |
|
elif action == "delete_branch": |
|
if not all([repo_name, branch]): |
|
raise ValueError("Brakujące parametry: repo_name, branch") |
|
repo = user.get_repo(repo_name) |
|
repo.get_git_ref(f"heads/{branch}").delete() |
|
return f"Gałąź **`{branch}`** usunięta z repozytorium **`{repo_name}`**." |
|
elif action == "create_pull_request": |
|
if not all([repo_name, title, body, base, head]): |
|
raise ValueError( |
|
"Brakujące parametry: repo_name, title, body, base, head") |
|
repo = user.get_repo(repo_name) |
|
pr = repo.create_pull(title=title, body=body, base=base, head=head) |
|
return f"Pull request utworzony! [Otwórz Pull Request]({pr.html_url})" |
|
elif action == "list_open_pull_requests": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = user.get_repo(repo_name) |
|
open_prs = repo.get_pulls(state='open') |
|
if not open_prs: |
|
return f"Brak otwartych pull requestów w repozytorium **`{repo_name}`**." |
|
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs]) |
|
return f"Otwarte pull requesty w repozytorium **`{repo_name}`**:\n{prs_list}" |
|
elif action == "create_issue": |
|
if not all([repo_name, title, body]): |
|
raise ValueError("Brakujące parametry: repo_name, title, body") |
|
repo = user.get_repo(repo_name) |
|
issue = repo.create_issue(title=title, body=body) |
|
return f"Issue utworzone! [Otwórz Issue]({issue.html_url})" |
|
elif action == "list_issues": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = user.get_repo(repo_name) |
|
issues = repo.get_issues(state='open') |
|
if not issues: |
|
return f"Brak otwartych issues w repozytorium **`{repo_name}`**." |
|
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues]) |
|
return f"Otwarte issues w repozytorium **`{repo_name}`**:\n{issues_list}" |
|
elif action == "add_label_to_issue": |
|
if not all([repo_name, issue_number, labels]): |
|
raise ValueError( |
|
"Brakujące parametry: repo_name, issue_number, labels") |
|
repo = user.get_repo(repo_name) |
|
issue = repo.get_issue(number=int(issue_number)) |
|
for label in labels.split(","): |
|
issue.add_to_labels(label.strip()) |
|
return f"Etykiety **`{labels}`** dodane do issue **#{issue_number}** w repozytorium **`{repo_name}`**." |
|
elif action == "close_issue": |
|
if not all([repo_name, issue_number]): |
|
raise ValueError("Brakujące parametry: repo_name, issue_number") |
|
repo = user.get_repo(repo_name) |
|
issue = repo.get_issue(number=int(issue_number)) |
|
issue.edit(state='closed') |
|
return f"Issue **#{issue_number}** zamknięte w repozytorium **`{repo_name}`**." |
|
elif action == "add_comment_to_issue": |
|
if not all([repo_name, issue_number, message]): |
|
raise ValueError( |
|
"Brakujące parametry: repo_name, issue_number, message") |
|
repo = user.get_repo(repo_name) |
|
issue = repo.get_issue(number=int(issue_number)) |
|
issue.create_comment(body=message) |
|
return f"Komentarz dodany do issue **#{issue_number}** w repozytorium **`{repo_name}`**." |
|
elif action == "create_release": |
|
if not all([repo_name, tag, name, message]): |
|
raise ValueError( |
|
"Brakujące parametry: repo_name, tag, name, message") |
|
repo = user.get_repo(repo_name) |
|
release = repo.create_git_release( |
|
tag=tag, name=name, message=message) |
|
return f"Release **`{name}`** utworzone w repozytorium **`{repo_name}`**! [Otwórz Release]({release.html_url})" |
|
elif action == "list_releases": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = user.get_repo(repo_name) |
|
releases = repo.get_releases() |
|
if not releases: |
|
return f"Brak release'ów w repozytorium **`{repo_name}`**." |
|
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases]) |
|
return f"Releases w repozytorium **`{repo_name}`**:\n{releases_list}" |
|
elif action == "fork_repository": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = g.get_repo(repo_name) |
|
fork = user.create_fork(repo) |
|
return f"Repozytorium **`{repo_name}`** zostało zforkowane! [Otwórz fork]({fork.html_url})" |
|
elif action == "list_forks": |
|
if not repo_name: |
|
raise ValueError("Brakujący parametr: repo_name") |
|
repo = g.get_repo(repo_name) |
|
forks = repo.get_forks() |
|
if not forks: |
|
return f"Brak forków repozytorium **`{repo_name}`**." |
|
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks]) |
|
return f"Linki do forków repozytorium **`{repo_name}`**:\n{forks_list}" |
|
elif action == "list_files": |
|
if not all([owner, repo_name]): |
|
raise ValueError("Brakujące parametry: owner, repo_name") |
|
repo = g.get_repo(f"{owner}/{repo_name}") |
|
|
|
if not path: |
|
contents = repo.get_contents("") |
|
else: |
|
contents = repo.get_contents(path) |
|
if not contents: |
|
return f"Brak plików w ścieżce **`{path}`** repozytorium **`{repo_name}`**." |
|
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents]) |
|
return f"Pliki w ścieżce **`{path}`** repozytorium **`{repo_name}`**:\n{files_list}" |
|
elif action == "get_repository_info": |
|
if not all([owner, repo_name]): |
|
raise ValueError("Brakujące parametry: owner, repo_name") |
|
repo = g.get_repo(f"{owner}/{repo_name}") |
|
info = { |
|
"Nazwa": repo.name, |
|
"Opis": repo.description, |
|
"URL": repo.html_url, |
|
"Właściciel": repo.owner.login, |
|
"Gałąź domyślna": repo.default_branch, |
|
"Język": repo.language, |
|
"Liczba gwiazdek": repo.stargazers_count, |
|
"Liczba forków": repo.forks_count, |
|
"Utworzone": str(repo.created_at), |
|
"Ostatnia aktualizacja": str(repo.updated_at) |
|
} |
|
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()]) |
|
return f"Informacje o repozytorium **`{repo_name}`**:\n{info_md}" |
|
elif action == "get_file_content": |
|
if not all([owner, repo_name, path]): |
|
raise ValueError("Brakujące parametry: owner, repo_name, path") |
|
content_text = get_file_content(owner, repo_name, path, branch) |
|
return f"Zawartość pliku **`{path}`** z repozytorium **`{repo_name}`**:\n\n`\n{content_text}\n`" |
|
elif action == "analyze_repository_by_url": |
|
if not repo_url: |
|
raise ValueError("Brakujący parametr: repo_url") |
|
owner, repo_name = extract_repo_info(repo_url) |
|
if not owner or not repo_name: |
|
raise ValueError("Nieprawidłowy link do repozytorium") |
|
try: |
|
repo = g.get_repo(f"{owner}/{repo_name}") |
|
|
|
contents = repo.get_contents("") |
|
|
|
file_analyses = [] |
|
for content in contents: |
|
if content.type == "file": |
|
file_content = content.decoded_content.decode() |
|
analysis = analyze_file_content(file_content, content.path) |
|
file_analyses.append({ |
|
"name": content.name, |
|
"path": content.path, |
|
"analysis": analysis, |
|
}) |
|
|
|
analysis_md = "Analiza plików repozytorium:\n" + "\n".join([ |
|
f"- **{f['path']}**:\n" |
|
f" - Liczba linii: {f['analysis']['line_count']}\n" |
|
f" - Liczba słów: {f['analysis']['word_count']}\n" |
|
f" - Rozszerzenie pliku: {f['analysis']['file_extension']}" |
|
for f in file_analyses |
|
]) |
|
return analysis_md |
|
except GithubException as e: |
|
return f"Błąd GitHub: {str(e)}" |
|
raise ValueError(f"Nieznana akcja: {action}") |
|
|
|
elif action == "analyze_repository_content": |
|
if not all([owner, repo_name]): |
|
raise ValueError("Brakujące parametry: owner, repo_name") |
|
try: |
|
repo = g.get_repo(f"{owner}/{repo_name}") |
|
|
|
contents = repo.get_contents("") |
|
file_analyses = [] |
|
|
|
for content in contents: |
|
if content.type == "file": |
|
file_content = get_file_content(owner, repo_name, content.path, branch) |
|
analysis = analyze_file_content(file_content, content.path) |
|
file_analyses.append({ |
|
"name": content.name, |
|
"path": content.path, |
|
"analysis": analysis, |
|
}) |
|
|
|
analysis_md = "Analiza zawartości plików repozytorium:\n" + "\n".join([ |
|
f"- **{f['path']}**:\n" |
|
f" - Liczba linii: {f['analysis']['line_count']}\n" |
|
f" - Liczba słów: {f['analysis']['word_count']}\n" |
|
f" - Rozszerzenie pliku: {f['analysis']['file_extension']}" |
|
for f in file_analyses |
|
]) |
|
return analysis_md |
|
raise ValueError(f"Nieznana akcja: {action}") |
|
|
|
except GithubException as e: |
|
return f"**Błąd GitHub:** {str(e)}" |
|
except ValueError as e: |
|
return f"**Błąd:** {str(e)}" |
|
except requests.exceptions.RequestException as e: |
|
return f"**Błąd połączenia:** {str(e)}" |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("# Narzędzie GitHub Plugingit (Uproszczony Interfejs)") |
|
with gr.Column(): |
|
action = gr.Dropdown( |
|
choices=[ |
|
"import_repository", |
|
"create_repository", |
|
"create_project_from_template", |
|
"create_file", |
|
"get_file", |
|
"get_file_content_by_url", |
|
"delete_file", |
|
"update_file", |
|
"list_branches", |
|
"create_branch", |
|
"delete_branch", |
|
"create_pull_request", |
|
"list_open_pull_requests", |
|
"create_issue", |
|
"list_issues", |
|
"add_label_to_issue", |
|
"close_issue", |
|
"add_comment_to_issue", |
|
"create_release", |
|
"list_releases", |
|
"fork_repository", |
|
"list_forks", |
|
"list_files", |
|
"get_repository_info", |
|
"get_file_content", |
|
"analyze_repository_by_url", |
|
"analyze_repository_content", |
|
], |
|
label="Wybierz akcję", |
|
) |
|
repo_name = gr.Textbox(label="Nazwa repozytorium") |
|
template_name = gr.Dropdown( |
|
choices=list(PROJECT_TEMPLATES.keys()), |
|
label="Szablon projektu", |
|
allow_none=True, |
|
) |
|
branch = gr.Textbox(label="Gałąź", value="main") |
|
path = gr.Textbox(label="Ścieżka do pliku") |
|
content = gr.Code(label="Zawartość pliku", lines=5, language='python') |
|
message = gr.Textbox(label="Wiadomość/Komentarz") |
|
owner = gr.Textbox(label="Właściciel") |
|
vcs_url = gr.Textbox(label="URL VCS") |
|
title = gr.Textbox(label="Tytuł") |
|
body = gr.Textbox(label="Treść") |
|
base = gr.Textbox(label="Gałąź bazowa") |
|
head = gr.Textbox(label="Gałąź docelowa/Nowa gałąź") |
|
issue_number = gr.Number(label="Numer issue", precision=0) |
|
labels = gr.Textbox(label="Etykiety (oddzielone przecinkami)") |
|
tag = gr.Textbox(label="Tag") |
|
release_name = gr.Textbox(label="Nazwa release") |
|
file_url = gr.Textbox(label="URL pliku") |
|
repo_url = gr.Textbox(label="Link do repozytorium") |
|
|
|
run_button = gr.Button("Wykonaj") |
|
output = gr.Markdown(label="Wynik") |
|
|
|
run_button.click( |
|
github_tool, |
|
inputs=[ |
|
action, |
|
repo_name, |
|
branch, |
|
path, |
|
content, |
|
message, |
|
owner, |
|
vcs_url, |
|
title, |
|
body, |
|
base, |
|
head, |
|
issue_number, |
|
labels, |
|
tag, |
|
release_name, |
|
file_url, |
|
repo_url, |
|
template_name, |
|
], |
|
outputs=output, |
|
api_name="github_tool" |
|
) |
|
|
|
demo.launch() |