Skip to content

Commit 987fe0a

Browse files
committed
push
1 parent e96544c commit 987fe0a

16 files changed

+5686
-0
lines changed

README.md

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
# Better Reviewers
2+
3+
A Go program that intelligently finds and assigns reviewers for GitHub pull requests based on code context and reviewer activity.
4+
5+
## Features
6+
7+
- **Context-based reviewer selection**: Finds reviewers who have previously worked on the lines being changed
8+
- **Activity-based reviewer selection**: Identifies reviewers who have been active on similar files
9+
- **Configurable time constraints**: Only processes PRs within specified age ranges
10+
- **Dry-run mode**: Test the logic without actually assigning reviewers
11+
- **Polling support**: Continuously monitor repositories for new PRs
12+
- **Comprehensive logging**: Detailed logs to understand reviewer selection decisions
13+
14+
## Installation
15+
16+
```bash
17+
go build -o better-reviewers
18+
```
19+
20+
## Prerequisites
21+
22+
- Go 1.21 or later
23+
- GitHub CLI (`gh`) installed and authenticated
24+
- GitHub token with appropriate permissions (repo access)
25+
26+
## Usage
27+
28+
### Single PR Analysis
29+
30+
```bash
31+
./better-reviewers -pr "https://github.com/owner/repo/pull/123"
32+
./better-reviewers -pr "owner/repo#123"
33+
```
34+
35+
### Project Monitoring
36+
37+
```bash
38+
./better-reviewers -project "owner/repo"
39+
```
40+
41+
### Organization Monitoring (Coming Soon)
42+
43+
```bash
44+
./better-reviewers -org "myorg"
45+
```
46+
47+
### Polling Mode
48+
49+
```bash
50+
./better-reviewers -project "owner/repo" -poll 1h
51+
```
52+
53+
### Dry Run Mode
54+
55+
```bash
56+
./better-reviewers -pr "owner/repo#123" -dry-run
57+
```
58+
59+
## Command Line Options
60+
61+
### Target Flags (Mutually Exclusive)
62+
63+
- `-pr`: Pull request URL or shorthand (e.g., `https://github.com/owner/repo/pull/123` or `owner/repo#123`)
64+
- `-project`: GitHub project to monitor (e.g., `owner/repo`)
65+
- `-org`: GitHub organization to monitor (not yet implemented)
66+
67+
### Behavior Flags
68+
69+
- `-poll`: Polling interval (e.g., `1h`, `30m`). If not set, runs once
70+
- `-dry-run`: Run in dry-run mode (no actual reviewer assignments)
71+
- `-min-age`: Minimum time since last commit or review for PR assignment (default: 1h)
72+
- `-max-age`: Maximum time since last commit or review for PR assignment (default: 180 days)
73+
74+
## How It Works
75+
76+
### Reviewer Selection Algorithm
77+
78+
The program finds exactly two reviewers for each PR: a **primary reviewer** (with author context) and a **secondary reviewer** (who actively reviews code).
79+
80+
#### Primary Reviewer (Author Context)
81+
82+
The primary reviewer is selected based on who knows the code best, in this priority order:
83+
84+
1. **Blame-based Authors**:
85+
- Examines GitHub blame history for changed files
86+
- Considers the top 5 PRs by overlap with edited lines
87+
- Selects authors of these PRs who still have write access
88+
- Verifies write access via author_association
89+
90+
2. **Directory Author** (fallback):
91+
- Most recent author of a merged PR in the same directory
92+
93+
3. **Project Author** (fallback):
94+
- Most recent author of a merged PR in the project
95+
96+
#### Secondary Reviewer (Active Reviewer)
97+
98+
The secondary reviewer is selected based on review activity, in this priority order:
99+
100+
1. **Blame-based Reviewers**:
101+
- Examines the same GitHub blame history
102+
- Considers the top 5 PRs by overlap with edited lines
103+
- Selects reviewers/approvers of these PRs
104+
105+
2. **Directory Reviewer** (fallback):
106+
- Most recent reviewer of a merged PR in the same directory
107+
108+
3. **Project Reviewer** (fallback):
109+
- Most recent reviewer of a merged PR in the project
110+
111+
### Assignment Rules
112+
113+
- Always attempts to assign exactly 2 reviewers: primary and secondary
114+
- The PR author cannot be a reviewer
115+
- Primary and secondary must be different people
116+
- Each reviewer selection logs the mechanism used (e.g., "primary-blame-author", "secondary-directory-reviewer")
117+
- **Draft PRs**: Skips reviewer assignment for draft PRs but logs who would have been assigned
118+
119+
### Error Handling
120+
121+
- If after exhausting all fallback mechanisms, the only candidate found is the PR author, the program will error with a clear message
122+
- This ensures that the PR author is never assigned as their own reviewer
123+
- The error message will indicate that all candidates have been exhausted
124+
125+
### GitHub API Usage
126+
127+
The program uses:
128+
- GitHub REST API v3 for PR data, file changes, and reviews
129+
- GitHub GraphQL API v4 for blame data and efficient directory/project searches
130+
- **No longer uses the slow Search API** - replaced with GraphQL queries
131+
- Caches blame data to avoid redundant API calls
132+
- 120-second timeout for API calls to handle slow responses
133+
- Retry logic with exponential backoff for GraphQL requests (up to 3 attempts)
134+
- Proper authentication using `gh auth token` for all API calls
135+
136+
## Architecture
137+
138+
The codebase is organized into several key files:
139+
140+
- `main.go`: Command-line interface and main program logic
141+
- `github.go`: GitHub API client implementation
142+
- `reviewer.go`: Core reviewer finding and assignment logic
143+
- `analysis.go`: Blame data analysis and PR relationship detection
144+
- `main_test.go`: Unit tests for core functionality
145+
146+
## Testing
147+
148+
Run the test suite:
149+
150+
```bash
151+
go test -v
152+
```
153+
154+
## Example Output
155+
156+
### Successful Primary/Secondary Selection
157+
```
158+
2024/01/15 10:30:45 Processing PR owner/repo#123: Add new feature
159+
2024/01/15 10:30:45 Analyzing 3 changed files for PR 123
160+
2024/01/15 10:30:46 === Finding PRIMARY reviewer (author context) ===
161+
2024/01/15 10:30:46 Checking blame-based authors for primary reviewer
162+
2024/01/15 10:30:46 Found author alice from PR 89 with 25 line overlap
163+
2024/01/15 10:30:46 Found author charlie from PR 76 with 15 line overlap
164+
2024/01/15 10:30:46 Selected blame-based author: alice (score: 25, association: MEMBER)
165+
2024/01/15 10:30:47 === Finding SECONDARY reviewer (active reviewer) ===
166+
2024/01/15 10:30:47 Checking blame-based reviewers for secondary reviewer
167+
2024/01/15 10:30:47 Found reviewer bob from PR 89 with 25 line overlap
168+
2024/01/15 10:30:47 Found reviewer dave from PR 76 with 15 line overlap
169+
2024/01/15 10:30:47 Selected blame-based reviewer: bob (score: 25)
170+
2024/01/15 10:30:47 PRIMARY reviewer selected: alice (method: primary-blame-author)
171+
2024/01/15 10:30:47 SECONDARY reviewer selected: bob (method: secondary-blame-reviewer)
172+
2024/01/15 10:30:47 Found 2 reviewer candidates for PR 123
173+
2024/01/15 10:30:47 Adding reviewers [alice bob] to PR owner/repo#123
174+
2024/01/15 10:30:48 Successfully added reviewers [alice bob] to PR 123
175+
```
176+
177+
### Fallback Mechanism in Action
178+
```
179+
2024/01/15 10:31:00 Processing PR owner/repo#124: Fix minor bug
180+
2024/01/15 10:31:00 Analyzing 3 changed files for PR 124
181+
2024/01/15 10:31:01 === Finding PRIMARY reviewer (author context) ===
182+
2024/01/15 10:31:01 Checking blame-based authors for primary reviewer
183+
2024/01/15 10:31:01 No blame-based authors found, checking directory authors
184+
2024/01/15 10:31:02 PRIMARY reviewer selected: charlie (method: primary-directory-author)
185+
2024/01/15 10:31:02 === Finding SECONDARY reviewer (active reviewer) ===
186+
2024/01/15 10:31:02 Checking blame-based reviewers for secondary reviewer
187+
2024/01/15 10:31:02 No blame-based reviewers found, checking directory reviewers
188+
2024/01/15 10:31:03 No directory reviewers found, checking project reviewers
189+
2024/01/15 10:31:03 SECONDARY reviewer selected: dave (method: secondary-project-reviewer)
190+
2024/01/15 10:31:03 Found 2 reviewer candidates for PR 124
191+
2024/01/15 10:31:03 Adding reviewers [charlie dave] to PR owner/repo#124
192+
2024/01/15 10:31:03 Successfully added reviewers [charlie dave] to PR 124
193+
```
194+
195+
### Error Case: Only PR Author Found
196+
```
197+
2024/01/15 10:32:00 Processing PR owner/repo#125: Initial commit
198+
2024/01/15 10:32:00 Top changed files for PR 125: [main.go, go.mod, README.md]
199+
2024/01/15 10:32:01 Finding context reviewers using blame data for 3 files
200+
2024/01/15 10:32:01 Finding activity reviewers for 3 files
201+
2024/01/15 10:32:01 Found only 0 candidates, trying fallback to line authors
202+
2024/01/15 10:32:01 Finding line authors with write access for fallback
203+
2024/01/15 10:32:01 Line author fallback candidate: john-doe (lines: 50, association: OWNER, method: fallback-line-author)
204+
2024/01/15 10:32:02 Found only 1 candidates, trying fallback to recent file authors
205+
2024/01/15 10:32:02 Found only 1 candidates, trying directory-based fallbacks
206+
2024/01/15 10:32:02 Found only 1 candidates, trying project-wide fallbacks
207+
2024/01/15 10:32:03 Project author fallback candidate: john-doe (method: fallback-project-author)
208+
2024/01/15 10:32:03 Failed to find reviewer candidates: exhausted all reviewer candidates: the only candidate found was the PR author (john-doe)
209+
```
210+
211+
### Draft PR Handling
212+
```
213+
2024/01/15 10:33:00 Processing PR owner/repo#126 [DRAFT]: WIP: New feature
214+
2024/01/15 10:33:00 Top changed files for PR 126: [feature.go, feature_test.go]
215+
2024/01/15 10:33:01 Finding context reviewers using blame data for 2 files
216+
2024/01/15 10:33:01 Context reviewer candidate: alice (score: 20, method: context-blame-approver)
217+
2024/01/15 10:33:01 Activity reviewer candidate: bob (PR size: 120, method: activity-recent-approver)
218+
2024/01/15 10:33:01 Found 2 reviewer candidates for PR 126
219+
2024/01/15 10:33:01 Selected reviewer: alice (method: context-blame-approver, context score: 20, activity score: 0)
220+
2024/01/15 10:33:01 Selected reviewer: bob (method: activity-recent-approver, context score: 0, activity score: 120)
221+
2024/01/15 10:33:01 PR 126 is a draft - skipping reviewer assignment
222+
2024/01/15 10:33:01 Would have assigned reviewers [alice bob] to PR 126 if it wasn't a draft
223+
```
224+
225+
## Contributing
226+
227+
1. Follow Go best practices and code review guidelines from go.dev
228+
2. Add tests for new functionality
229+
3. Ensure comprehensive logging for debugging
230+
4. Use minimal external dependencies
231+
232+
## License
233+
234+
This project is provided as-is for educational and productivity purposes.

0 commit comments

Comments
 (0)