-
Notifications
You must be signed in to change notification settings - Fork 187
Add code review metrics to track reviewer participation and identify review gaps #1823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,292 @@ | ||||||||||||||||||
| --- | ||||||||||||||||||
| name: Code Review Metrics | ||||||||||||||||||
|
|
||||||||||||||||||
| on: | ||||||||||||||||||
| schedule: | ||||||||||||||||||
| - cron: '0 0 * * 1' # Weekly on Mondays at midnight UTC | ||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||
| inputs: | ||||||||||||||||||
| days: | ||||||||||||||||||
| description: 'Analysis period in days' | ||||||||||||||||||
| required: false | ||||||||||||||||||
| default: '30' | ||||||||||||||||||
| type: string | ||||||||||||||||||
|
|
||||||||||||||||||
| permissions: | ||||||||||||||||||
| contents: read | ||||||||||||||||||
| pull-requests: read | ||||||||||||||||||
| issues: read | ||||||||||||||||||
|
|
||||||||||||||||||
| jobs: | ||||||||||||||||||
| review-metrics: | ||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||
| name: Generate Code Review Metrics | ||||||||||||||||||
|
|
||||||||||||||||||
| steps: | ||||||||||||||||||
| - name: Checkout | ||||||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Calculate Date Range | ||||||||||||||||||
| id: date-range | ||||||||||||||||||
| run: | | ||||||||||||||||||
| days="${{ github.event.inputs.days || '30' }}" | ||||||||||||||||||
| start_date=$(date -d "$days days ago" +%Y-%m-%d) | ||||||||||||||||||
| echo "start_date=$start_date" >> $GITHUB_OUTPUT | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Collect Code Review Metrics | ||||||||||||||||||
| run: | | ||||||||||||||||||
| # Authenticate with GitHub CLI | ||||||||||||||||||
| echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | ||||||||||||||||||
|
|
||||||||||||||||||
| # Get PR data for the specified period | ||||||||||||||||||
| start_date="${{ steps.date-range.outputs.start_date }}" | ||||||||||||||||||
| days="${{ github.event.inputs.days || '30' }}" | ||||||||||||||||||
|
|
||||||||||||||||||
| echo "Collecting review data for PRs created since: $start_date" | ||||||||||||||||||
|
|
||||||||||||||||||
| # Create output files | ||||||||||||||||||
| mkdir -p review-data | ||||||||||||||||||
|
|
||||||||||||||||||
| # Get PRs and their reviews (filtering will be done in Python for better control) | ||||||||||||||||||
| gh pr list \ | ||||||||||||||||||
| --repo "${{ github.repository }}" \ | ||||||||||||||||||
| --state all \ | ||||||||||||||||||
| --limit 1000 \ | ||||||||||||||||||
| --json number,title,author,createdAt,mergedAt,reviews,reviewRequests \ | ||||||||||||||||||
| --jq ".[] | select(.createdAt >= \"$start_date\")" \ | ||||||||||||||||||
| > review-data/prs.json | ||||||||||||||||||
|
|
||||||||||||||||||
| # Process review data to generate metrics focused on who is reviewing and review counts | ||||||||||||||||||
| python3 << 'EOF' | ||||||||||||||||||
| import json | ||||||||||||||||||
| import sys | ||||||||||||||||||
| from collections import defaultdict | ||||||||||||||||||
|
|
||||||||||||||||||
| # Load PR data | ||||||||||||||||||
| with open('review-data/prs.json', 'r') as f: | ||||||||||||||||||
| prs = [json.loads(line) for line in f if line.strip()] | ||||||||||||||||||
|
||||||||||||||||||
| prs = [json.loads(line) for line in f if line.strip()] | |
| prs = [] | |
| for line_num, line in enumerate(f, 1): | |
| if line.strip(): | |
| try: | |
| prs.append(json.loads(line)) | |
| except json.JSONDecodeError as e: | |
| print(f"Warning: Skipping malformed JSON on line {line_num}: {e}", file=sys.stderr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit 70cc6f1. Added try-except error handling around json.loads() to gracefully skip malformed JSON lines with a warning message instead of failing the entire workflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot - looks like there are two steps both installing the gh cli. Please only use the github/gh-cli-action@v2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit a5b9c21. Removed the duplicate manual GH CLI installation step and consolidated to use only the github/gh-cli-action@v2.