Created
April 12, 2025 13:48
-
-
Save incognitojam/ec163cdaaa932bcc436c2e5e5cd88bb2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /// script | |
# dependencies = [ | |
# "requests", | |
# ] | |
# /// | |
import requests | |
import re | |
import sys | |
from datetime import datetime | |
def parse_github_issue_url(url: str) -> tuple[str, str, str]: | |
"""Extract owner, repo, and issue number from a GitHub issue URL.""" | |
match = re.match(r'https://github\.com/([^/]+)/([^/]+)/issues/(\d+)', url) | |
if not match: | |
raise ValueError("Invalid GitHub issue URL.") | |
return match.group(1), match.group(2), match.group(3) | |
def get_issue_data(owner: str, repo: str, issue_number: str) -> tuple[dict, list[dict]]: | |
"""Fetch issue data and comments from GitHub API.""" | |
base_url = f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}" | |
headers = {"Accept": "application/vnd.github+json"} | |
issue_response = requests.get(base_url, headers=headers) | |
comments_response = requests.get(base_url + "/comments", headers=headers) | |
if issue_response.status_code != 200: | |
raise Exception(f"Failed to fetch issue: {issue_response.status_code}") | |
if comments_response.status_code != 200: | |
raise Exception(f"Failed to fetch comments: {comments_response.status_code}") | |
return issue_response.json(), comments_response.json() | |
def format_markdown(issue: dict, comments: list[dict]) -> str: | |
"""Generate a Markdown string from issue data.""" | |
title = issue["title"] | |
number = issue["number"] | |
user = issue["user"]["login"] | |
created_at = datetime.strptime(issue["created_at"], "%Y-%m-%dT%H:%M:%SZ").strftime("%Y-%m-%d") | |
body = issue["body"] or "*No description provided.*" | |
labels = ", ".join(label["name"] for label in issue.get("labels", [])) or "*No labels*" | |
md = f"# {title} (#{number})\n\n" | |
md += f"**opened by {user} on {created_at}**\n\n" | |
md += f"{body}\n\n" | |
md += f"**Labels:** {labels}\n\n" | |
md += "## Comments\n\n" | |
for comment in comments: | |
comment_user = comment["user"]["login"] | |
comment_date = datetime.strptime(comment["created_at"], "%Y-%m-%dT%H:%M:%SZ").strftime("%Y-%m-%d") | |
comment_body = comment["body"] | |
md += f"**{comment_user} on {comment_date}:**\n{comment_body}\n\n" | |
return md | |
def save_markdown(content: str, filename: str) -> None: | |
with open(filename, "w", encoding="utf-8") as f: | |
f.write(content) | |
def main() -> None: | |
if len(sys.argv) < 2: | |
print("Usage: uv run issue2md.py <github_issue_url>") | |
sys.exit(1) | |
url = sys.argv[1] | |
try: | |
owner, repo, issue_number = parse_github_issue_url(url) | |
issue, comments = get_issue_data(owner, repo, issue_number) | |
markdown = format_markdown(issue, comments) | |
filename = f"{repo}_issue_{issue_number}.md" | |
save_markdown(markdown, filename) | |
print(f"Issue saved to {filename}") | |
except Exception as e: | |
print(f"Error: {e}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment