|
import gradio as gr |
|
from datetime import datetime, timedelta |
|
import google.generativeai as genai |
|
from github import Github, GithubException |
|
import gitlab |
|
import docx |
|
import tempfile |
|
import requests |
|
|
|
def generate_release_notes(git_provider, repo_url, personal_access_token, gemini_api_key, start_date, end_date): |
|
try: |
|
start_date = datetime.strptime(start_date, "%Y-%m-%d") |
|
end_date = datetime.strptime(end_date, "%Y-%m-%d") |
|
|
|
if git_provider == "GitHub": |
|
g = Github(personal_access_token) |
|
repo = g.get_repo(repo_url) |
|
commits = list(repo.get_commits(since=start_date, until=end_date)) |
|
commit_messages = [commit.commit.message for commit in commits] |
|
elif git_provider == "GitLab": |
|
gl = gitlab.Gitlab(url='https://gitlab.com', private_token=personal_access_token) |
|
project = gl.projects.get(repo_url) |
|
commits = project.commits.list(since=start_date.isoformat(), until=end_date.isoformat()) |
|
commit_messages = [commit.message for commit in commits] |
|
elif git_provider == "Gitea": |
|
base_url = "https://gitea.com/api/v1" |
|
headers = {"Authorization": f"token {personal_access_token}"} |
|
response = requests.get(f"{base_url}/repos/{repo_url}/commits", headers=headers, params={ |
|
"since": start_date.isoformat(), |
|
"until": end_date.isoformat() |
|
}) |
|
response.raise_for_status() |
|
commits = response.json() |
|
commit_messages = [commit['commit']['message'] for commit in commits] |
|
else: |
|
return "Unsupported Git provider", None, None |
|
|
|
commit_text = "\n".join(commit_messages) |
|
|
|
if not commit_text: |
|
return "No commits found in the specified date range.", None, None |
|
|
|
genai.configure(api_key=gemini_api_key) |
|
model = genai.GenerativeModel('gemini-2.0-flash-lite') |
|
|
|
prompt = f"""Based on the following commit messages, generate comprehensive release notes: |
|
|
|
{commit_text} |
|
|
|
Please organize the release notes into sections such as: |
|
1. New Features |
|
2. Bug Fixes |
|
3. Improvements |
|
4. Breaking Changes (if any) |
|
|
|
Provide a concise summary for each item. Do not include any links, but keep issue numbers if present. |
|
|
|
Important formatting instructions: |
|
- The output should be plain text without any markdown or "-" for post processing |
|
- Use section titles followed by a colon (e.g., "New Features:") |
|
- Start each item on a new line |
|
- Be sure to briefly explain the why and benefits of the change for average users that are non-technical |
|
""" |
|
|
|
response = model.generate_content(prompt) |
|
release_notes = response.text |
|
|
|
|
|
doc = docx.Document() |
|
doc.add_heading('Release Notes', 0) |
|
|
|
current_section = None |
|
for line in release_notes.split('\n'): |
|
line = line.strip() |
|
if line.endswith(':'): |
|
doc.add_heading(line, level=1) |
|
current_section = None |
|
elif line: |
|
if current_section is None: |
|
current_section = doc.add_paragraph().style |
|
current_section.name = 'List Bullet' |
|
doc.add_paragraph(line, style=current_section) |
|
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix='.docx') as temp_docx: |
|
doc.save(temp_docx.name) |
|
docx_path = temp_docx.name |
|
|
|
|
|
markdown_content = "# Release Notes\n\n" |
|
for line in release_notes.split('\n'): |
|
line = line.strip() |
|
if line.endswith(':'): |
|
markdown_content += f"\n## {line}\n\n" |
|
elif line: |
|
markdown_content += f"- {line}\n" |
|
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix='.md', mode='w', encoding='utf-8') as temp_md: |
|
temp_md.write(markdown_content) |
|
md_path = temp_md.name |
|
|
|
return release_notes, docx_path, md_path |
|
|
|
except Exception as e: |
|
return f"An error occurred: {str(e)}", None, None |
|
|
|
default_end_date = datetime.now() |
|
default_start_date = default_end_date - timedelta(days=30) |
|
|
|
iface = gr.Interface( |
|
fn=generate_release_notes, |
|
inputs=[ |
|
gr.Dropdown( |
|
choices=["GitHub", "GitLab", "Gitea"], |
|
label="Git Provider" |
|
), |
|
gr.Textbox(label="Repository URL", placeholder="owner/repo"), |
|
gr.Textbox(label="Personal Access Token", type="password"), |
|
gr.Textbox(label="Gemini API Key", type="password"), |
|
gr.Textbox( |
|
label="Start Date", |
|
placeholder="YYYY-MM-DD", |
|
value=default_start_date.strftime("%Y-%m-%d"), |
|
), |
|
gr.Textbox( |
|
label="End Date", |
|
placeholder="YYYY-MM-DD", |
|
value=default_end_date.strftime("%Y-%m-%d"), |
|
) |
|
], |
|
outputs=[ |
|
gr.Textbox(label="Generated Release Notes"), |
|
gr.File(label="Download Release Notes (DOCX)"), |
|
gr.File(label="Download Release Notes (Markdown)") |
|
], |
|
title="Automated Release Notes Generator", |
|
description="Generate release notes based on Git commits using Gemini AI. Select a Git provider, enter repository details, and specify the date range for commits.", |
|
allow_flagging="never", |
|
theme="default", |
|
analytics_enabled=False, |
|
) |
|
|
|
iface.launch() |