| name | compile-community-pulse-report-json |
| description | How to compile PR and issue statistics into a report.json file for a GitHub repository community pulse report, using jq to build the final JSON structure. |
Compiling a Community Pulse report.json
Overall Workflow
- Fetch PR data with precise repo and date scoping
- Fetch issue data excluding PRs
- Compute all metrics
- Assemble into a single JSON file
Step-by-Step Script
#!/bin/bash
set -e
REPO="cli/cli"
START="2024-12-01"
END="2024-12-31"
gh pr list --repo "$REPO" --search "created:${START}..${END}" --state all --limit 300 \
--json number,author,state,createdAt,mergedAt > /tmp/prs.json
PR_TOTAL=$(jq length /tmp/prs.json)
PR_MERGED=$(jq '[.[] | select(.mergedAt != null and .mergedAt != "")] | length' /tmp/prs.json)
PR_CLOSED=$(jq '[.[] | select(
(.state == "closed" or .state == "CLOSED") and
(.mergedAt == null or .mergedAt == "")
)] | length' /tmp/prs.json)
AVG_MERGE=$(jq '
[.[] | select(.mergedAt != null and .mergedAt != "") |
(((.mergedAt | fromdateiso8601) - (.createdAt | fromdateiso8601)) / 86400)
] | if length > 0 then (add / length * 10 | round / 10) else 0 end
' /tmp/prs.json)
TOP_CONTRIBUTOR=$(jq -r '
[.[] | .author.login] | group_by(.) |
map({login: .[0], count: length}) |
sort_by(-.count) | .[0].login
' /tmp/prs.json)
gh issue list --repo "$REPO" --search "created:${START}..${END}" --state all --limit 300 \
--json number,labels,state,createdAt,closedAt > /tmp/issues.json
ISSUE_TOTAL=$(jq length /tmp/issues.json)
BUG_COUNT=$(jq '[.[] | select(.labels | map(.name) | any(test("bug";"i")))] | length' /tmp/issues.json)
RESOLVED_BUGS=$(jq '[.[] | select(
(.state == "closed" or .state == "CLOSED") and
(.labels | map(.name) | any(test("bug";"i")))
)] | length' /tmp/issues.json)
jq -n \
--argjson pr_total "$PR_TOTAL" \
--argjson pr_merged "$PR_MERGED" \
--argjson pr_closed "$PR_CLOSED" \
--argjson avg_merge "$AVG_MERGE" \
--arg top "$TOP_CONTRIBUTOR" \
--argjson issue_total "$ISSUE_TOTAL" \
--argjson bug "$BUG_COUNT" \
--argjson resolved "$RESOLVED_BUGS" \
'{
pr: {
total: $pr_total,
merged: $pr_merged,
closed: $pr_closed,
avg_merge_days: $avg_merge,
top_contributor: $top
},
issue: {
total: $issue_total,
bug: $bug,
resolved_bugs: $resolved
}
}' > /app/report.json
cat /app/report.json
Key Points
closed in PR section = closed WITHOUT merge (not all closed PRs)
gh issue list inherently excludes PRs, unlike gh search issues
gh pr list is repo-scoped and won't include fork PRs
- Bug detection uses case-insensitive substring match on label names for "bug"
avg_merge_days is rounded to 1 decimal place
top_contributor is the author login who opened the most PRs in the period
Debugging Tips
If counts seem off:
- Check that
createdAt dates are within range: jq '[.[] | .createdAt] | sort' /tmp/prs.json
- Check for PR contamination in issues:
jq '[.[] | .url // .number]' /tmp/issues.json
- Verify merged detection:
jq '[.[] | {number, state, mergedAt}]' /tmp/prs.json
- Cross-reference totals with GitHub web UI search:
repo:cli/cli is:pr created:2024-12-01..2024-12-31