-
-
Notifications
You must be signed in to change notification settings - Fork 254
205 lines (174 loc) · 8.11 KB
/
droid-code-review.yml
File metadata and controls
205 lines (174 loc) · 8.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
name: Droid Code Review
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
concurrency:
group: droid-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
pull-requests: write
contents: read
issues: write
jobs:
code-review:
runs-on: ubuntu-latest
timeout-minutes: 15
# Skip automated code review for draft PRs
if: github.event.pull_request.draft == false
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Install Droid CLI
run: |
curl -fsSL https://app.factory.ai/cli | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
"$HOME/.local/bin/droid" --version
- name: Configure git identity
run: |
git config user.name "Droid Agent"
git config user.email "droidagent@factory.ai"
- name: Prepare review context
run: |
# Get the PR diff
git fetch origin ${{ github.event.pull_request.base.ref }}
git diff origin/${{ github.event.pull_request.base.ref }}...${{ github.event.pull_request.head.sha }} > diff.txt
# Get existing comments using GitHub API
curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
> existing_comments.json
# Get changed files with patches for positioning
curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" \
| jq '[.[] | {filename: .filename, patch: .patch}]' > files.json
- name: Perform automated code review
env:
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cat > prompt.txt << 'EOF'
You are an automated code review system. Review the PR diff and identify clear issues that need to be fixed.
Input files (already in current directory):
- diff.txt: the code changes to review
- files.json: file patches with line numbers for positioning comments
- existing_comments.json: skip issues already mentioned here
Task: Create a file called comments.json with this exact format:
[{ "path": "path/to/file.js", "position": 42, "body": "Your comment here" }]
Focus on these types of issues:
- Dead/unreachable code (if (false), while (false), code after return/throw/break)
- Broken control flow (missing break in switch, fallthrough bugs)
- Async/await mistakes (missing await, .then without return, unhandled promise rejections)
- Array/object mutations in React components or reducers
- UseEffect dependency array problems (missing deps, incorrect deps)
- Incorrect operator usage (== vs ===, && vs ||, = in conditions)
- Off-by-one errors in loops or array indexing
- Integer overflow/underflow in calculations
- Regex catastrophic backtracking vulnerabilities
- Missing base cases in recursive functions
- Incorrect type coercion that changes behavior
- Environment variable access without defaults or validation
- Null/undefined dereferences
- Resource leaks (unclosed files or connections)
- SQL/XSS injection vulnerabilities
- Concurrency/race conditions
- Missing error handling for critical operations
Comment format:
- Clearly describe the issue: "This code block is unreachable due to the if (false) condition"
- Provide a concrete fix: "Remove this entire if block as it will never execute"
- When possible, suggest the exact code change:
```suggestion
// Remove the unreachable code
```
- Be specific about why it's a problem: "This will cause a TypeError if input is null"
- No emojis, just clear technical language
Skip commenting on:
- Code style, formatting, or naming conventions
- Minor performance optimizations
- Architectural decisions or design patterns
- Features or functionality (unless broken)
- Test coverage (unless tests are clearly broken)
Position calculation:
- Use the "position" field from files.json patches
- This is the line number in the diff, not the file
- Comments must align with exact changed lines only
Output:
- Empty array [] if no issues found
- Otherwise array of comment objects with path, position, body
- Each comment should be actionable and clear about what needs to be fixed
- Maximum 10 comments total; prioritize the most critical issues
EOF
# Run droid exec with the prompt
echo "Running code review analysis..."
droid exec --auto high -f prompt.txt
# Check if comments.json was created
if [ ! -f comments.json ]; then
echo "❌ ERROR: droid exec did not create comments.json"
echo "This usually indicates the review run failed (e.g. missing FACTORY_API_KEY or runtime error)."
exit 1
fi
echo "=== Review Results ==="
cat comments.json
- name: Submit inline review comments
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const prNumber = context.payload.pull_request.number;
if (!fs.existsSync('comments.json')) {
core.info('comments.json missing; skipping review submission');
return;
}
const comments = JSON.parse(fs.readFileSync('comments.json', 'utf8'));
if (!Array.isArray(comments) || comments.length === 0) {
// Check if we already have a "no issues" comment
const existing = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
per_page: 100
});
const hasNoIssuesComment = existing.some(c =>
c.user.login.includes('[bot]') &&
/no issues found|lgtm|✅/i.test(c.body || '')
);
if (!hasNoIssuesComment) {
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
event: 'COMMENT',
body: '✅ No issues found in the current changes.'
});
}
return;
}
// Submit review with inline comments
const summary = `Found ${comments.length} potential issue${comments.length === 1 ? '' : 's'} that should be addressed.`;
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
event: 'COMMENT',
body: summary,
comments: comments
});
core.info(`Submitted review with ${comments.length} inline comments`);
- name: Upload debug artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@v4
with:
name: droid-review-debug-${{ github.run_id }}
path: |
diff.txt
files.json
existing_comments.json
prompt.txt
comments.json
${{ runner.home }}/.factory/logs/droid-log-single.log
${{ runner.home }}/.factory/logs/console.log
if-no-files-found: ignore
retention-days: 7