Gh pr analysis
How to fetch and analyze pull request data from a GitHub repository for a given time period: counts, merge rates, average time-to-merge, and top contributors. Use this skill whenever the user wants PR metrics, pull request summaries, contributor leaderboards, or community pulse reports.From its SKILL.md
npx -y skills add cxcscmu/SkillLearnBench --skill gh-pr-analysisAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
3.0 KB, 707 tokens by cl100k_base, as published. Nobody here has run it
PR Analysis via GitHub REST API
Fetching PRs created in a date window
Use the /repos/{owner}/{repo}/pulls endpoint with state=all and since:
BASE = "https://api.github.com/repos/cli/cli"
def get_prs(start_iso, end_iso, token=None):
"""Fetch all PRs created between start_iso and end_iso (ISO 8601 strings)."""
headers = {"Accept": "application/vnd.github+json"}
if token:
headers["Authorization"] = f"token {token}"
start_dt = datetime.fromisoformat(start_iso.replace("Z", "+00:00"))
end_dt = datetime.fromisoformat(end_iso.replace("Z", "+00:00"))
results, page = [], 1
while True:
r = requests.get(f"{BASE}/pulls",
headers=headers,
params={"state": "all", "sort": "created",
"direction": "desc", "per_page": 100,
"page": page})
data = r.json()
if not data:
break
# Trim pages that are entirely before our window (sorted desc)
page_items = []
stop = False
for pr in data:
created = datetime.fromisoformat(pr["created_at"].replace("Z", "+00:00"))
if created > end_dt:
continue # too recent
if created < start_dt:
stop = True # gone past our window, no need to paginate further
break
page_items.append(pr)
results.extend(page_items)
if stop or len(data) < 100:
break
page += 1
return results
Key calculations
Merged vs closed-not-merged
merged = [p for p in prs if p.get("merged_at")]
# "closed" means closed without merge (GitHub convention in this report)
closed_not_merged = [p for p in prs if p["state"] == "closed" and not p.get("merged_at")]
Average time-to-merge (days, 1 decimal)
def ttm(pr):
c = datetime.fromisoformat(pr["created_at"].replace("Z", "+00:00"))
m = datetime.fromisoformat(pr["merged_at"].replace("Z", "+00:00"))
return (m - c).total_seconds() / 86400
avg_merge_days = round(sum(ttm(p) for p in merged) / len(merged), 1) if merged else 0.0
Top contributor
from collections import Counter
top_contributor = Counter(p["user"]["login"] for p in prs).most_common(1)[0][0]
Gotchas
merged_atis only present on the/pullsendpoint response, NOT on the/issuesendpoint. Always use/pulls?state=allfor PR data.- GitHub sorts by
createddesc by default; bail out oncecreated_at < startto avoid reading thousands of old PRs. - Bots (e.g.
dependabot[bot],github-actions[bot]) appear as contributors; decide whether to include/exclude them based on context.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.