Skip to content

Instantly share code, notes, and snippets.

@llimllib
Last active August 9, 2025 13:47
Show Gist options
  • Save llimllib/921345e181dc8466dfa3cd7e6baa34e5 to your computer and use it in GitHub Desktop.
Save llimllib/921345e181dc8466dfa3cd7e6baa34e5 to your computer and use it in GitHub Desktop.
show all the PRs and issues you've filed on different repos
# 1. set GH_TOKEN to be a valid github API token. I used `GH_TOKEN=$(gh auth)` to set it
# 2. run `python count.py <username>`
#
# This script will print out each repository you've filed a PR on or submitted an issue to,
# and a link to no more than 5 of them
import sys
import os
import json
import urllib.request
import urllib.error
from datetime import datetime
from urllib.parse import quote
from collections import defaultdict
def get_repos_with_items(username, item_type, token=None, collect_urls=False):
"""Fetch all repositories a user has made pull requests or issues to.
Args:
username: GitHub username
item_type: 'pr' for pull requests or 'issue' for issues
token: GitHub API token (optional)
collect_urls: Whether to collect item URLs
Returns:
If collect_urls is False: Sorted list of repository names
If collect_urls is True: Dictionary mapping repo names to lists of item URLs
"""
base_url = f"https://api.github.com/search/issues?q=author:{quote(username)}+type:{item_type}"
headers = {"Accept": "application/vnd.github.v3+json"}
if token:
headers["Authorization"] = f"token {token}"
if collect_urls:
repo_items = defaultdict(list)
else:
repos = set()
page = 1
while True:
url = f"{base_url}&page={page}&per_page=100"
req = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(req) as response:
data = json.loads(response.read().decode("utf-8"))
items = data.get("items", [])
if not items:
break
for item in items:
repo_url = item.get("repository_url", "")
if repo_url:
repo_name = "/".join(repo_url.split("/")[-2:])
if collect_urls:
html_url = item.get("html_url")
if html_url:
repo_items[repo_name].append(html_url)
else:
repos.add(repo_name)
# Check if we've processed all pages
if len(items) < 100:
break
page += 1
except urllib.error.HTTPError as e:
if e.code == 403:
rate_limit = e.headers.get("X-RateLimit-Remaining", "0")
if rate_limit == "0":
reset_timestamp = int(e.headers.get("X-RateLimit-Reset", "0"))
reset_time = datetime.fromtimestamp(reset_timestamp).strftime(
"%Y-%m-%d %H:%M:%S"
)
print(
f"Error: GitHub API rate limit exceeded. Resets at: {reset_time}"
)
print("Consider using a GitHub token for higher rate limits.")
else:
print(f"HTTP Error: {e.code} - {e.reason}")
break
except urllib.error.URLError as e:
print(f"URL Error: {e.reason}")
break
except Exception as e:
print(f"Error: {e}")
break
if collect_urls:
return {k: v for k, v in sorted(repo_items.items())}
else:
return sorted(list(repos))
def get_repos_with_prs(username, token=None, collect_urls=False):
"""Fetch all repositories a user has made pull requests to."""
return get_repos_with_items(username, "pr", token, collect_urls)
def get_repos_with_issues(username, token=None, collect_urls=False):
"""Fetch all repositories a user has filed issues in."""
return get_repos_with_items(username, "issue", token, collect_urls)
def main():
if len(sys.argv) < 2:
print("Usage: python github_pr_repos.py <github_username> [github_token]")
sys.exit(1)
username = sys.argv[1]
# Check for token in args or environment
token = None
if len(sys.argv) > 2:
token = sys.argv[2]
elif "GITHUB_TOKEN" in os.environ:
token = os.environ["GITHUB_TOKEN"]
print(f"Fetching repositories where {username} has submitted pull requests...")
pr_repos_with_urls = get_repos_with_prs(username, token, collect_urls=True)
print(f"Fetching repositories where {username} has filed issues...")
issue_repos_with_urls = get_repos_with_issues(username, token, collect_urls=True)
if pr_repos_with_urls:
print(f"\nFound {len(pr_repos_with_urls)} repositories with pull requests:")
for i, (repo, pr_urls) in enumerate(pr_repos_with_urls.items(), 1):
print(f"{i}. {repo}")
# Display up to 5 PR links per repository
for j, url in enumerate(pr_urls[:5], 1):
print(f" PR {j}: {url}")
if len(pr_urls) > 5:
print(f" ... and {len(pr_urls) - 5} more PRs")
else:
print("No repositories with pull requests found.")
if issue_repos_with_urls:
print(f"\nFound {len(issue_repos_with_urls)} repositories with issues:")
for i, (repo, issue_urls) in enumerate(issue_repos_with_urls.items(), 1):
print(f"{i}. {repo}")
# Display up to 5 issue links per repository
for j, url in enumerate(issue_urls[:5], 1):
print(f" Issue {j}: {url}")
if len(issue_urls) > 5:
print(f" ... and {len(issue_urls) - 5} more issues")
else:
print("No repositories with issues found.")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment