Skip to content

Commit afd604d

Browse files
akoclaude
andcommitted
Add automated AI PR review workflow using GitHub Models API
Uses GPT-4.1 via models.github.ai with the built-in GITHUB_TOKEN — no API keys or secrets needed. Reviews every PR for bugs, security, scope, and proposal alignment, then posts findings as a comment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8908d4d commit afd604d

1 file changed

Lines changed: 122 additions & 0 deletions

File tree

.github/workflows/ai-review.yml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: AI PR Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
models: read
11+
12+
jobs:
13+
review:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v5
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Get PR diff
21+
id: diff
22+
env:
23+
GH_TOKEN: ${{ github.token }}
24+
run: |
25+
gh pr diff ${{ github.event.pull_request.number }} > /tmp/pr.diff
26+
# Truncate to ~100k chars to fit model context
27+
head -c 100000 /tmp/pr.diff > /tmp/pr-truncated.diff
28+
echo "diff_size=$(wc -c < /tmp/pr.diff)" >> "$GITHUB_OUTPUT"
29+
echo "truncated=$([ $(wc -c < /tmp/pr.diff) -gt 100000 ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
30+
31+
- name: Get PR info
32+
id: pr
33+
env:
34+
GH_TOKEN: ${{ github.token }}
35+
run: |
36+
gh pr view ${{ github.event.pull_request.number }} --json title,body > /tmp/pr-info.json
37+
38+
- name: Check for relevant proposals
39+
id: proposals
40+
run: |
41+
# Extract key terms from PR title for proposal matching
42+
PROPOSALS=""
43+
if [ -d "docs/03-development/proposals" ]; then
44+
PROPOSALS=$(ls docs/03-development/proposals/ 2>/dev/null | head -20)
45+
fi
46+
echo "list<<EOF" >> "$GITHUB_OUTPUT"
47+
echo "$PROPOSALS" >> "$GITHUB_OUTPUT"
48+
echo "EOF" >> "$GITHUB_OUTPUT"
49+
50+
- name: Read project context
51+
id: context
52+
run: |
53+
# Read CLAUDE.md summary (first 100 lines for context)
54+
if [ -f "CLAUDE.md" ]; then
55+
head -100 CLAUDE.md > /tmp/project-context.txt
56+
else
57+
echo "No CLAUDE.md found" > /tmp/project-context.txt
58+
fi
59+
60+
- name: AI Review
61+
id: review
62+
env:
63+
GITHUB_TOKEN: ${{ github.token }}
64+
run: |
65+
# Build the review prompt
66+
DIFF=$(cat /tmp/pr-truncated.diff)
67+
PR_INFO=$(cat /tmp/pr-info.json)
68+
PROJECT_CONTEXT=$(cat /tmp/project-context.txt)
69+
PROPOSALS="${{ steps.proposals.outputs.list }}"
70+
TRUNCATED="${{ steps.diff.outputs.truncated }}"
71+
72+
TRUNCATION_NOTE=""
73+
if [ "$TRUNCATED" = "true" ]; then
74+
TRUNCATION_NOTE="NOTE: The diff was truncated to 100k characters. Total size: ${{ steps.diff.outputs.diff_size }} bytes. Focus on what's visible."
75+
fi
76+
77+
# Call GitHub Models API
78+
RESPONSE=$(curl -s -X POST \
79+
-H "Authorization: Bearer $GITHUB_TOKEN" \
80+
-H "Content-Type: application/json" \
81+
https://models.github.ai/inference/chat/completions \
82+
-d "$(jq -n \
83+
--arg diff "$DIFF" \
84+
--arg pr_info "$PR_INFO" \
85+
--arg context "$PROJECT_CONTEXT" \
86+
--arg proposals "$PROPOSALS" \
87+
--arg truncation "$TRUNCATION_NOTE" \
88+
'{
89+
model: "openai/gpt-4.1",
90+
messages: [
91+
{
92+
role: "system",
93+
content: "You are a code reviewer for a Go CLI project (mxcli) that reads/modifies Mendix application projects. Key patterns: ANTLR4 grammar → AST → visitor → executor → BSON writer. Generated ANTLR parser files (mdl/grammar/parser/) are noise — note but skip. Review thoroughly but concisely."
94+
},
95+
{
96+
role: "user",
97+
content: ("Review this PR.\n\nPR Info:\n" + $pr_info + "\n\nProject context:\n" + $context + "\n\nProposals in repo:\n" + $proposals + "\n\n" + $truncation + "\n\nFocus on:\n1. Bugs, logic errors, race conditions, resource leaks\n2. Error handling gaps\n3. Security concerns (command injection, temp files, predictable paths)\n4. Scope — flag if PR bundles unrelated changes\n5. If proposals exist that match the PR topic, check alignment\n6. Check if PR claims to fix already-fixed issues\n\nStructure: Critical Issues, Moderate Issues, Minor Issues, What Looks Good, Recommendation (approve/request changes).\n\nDiff:\n```\n" + $diff + "\n```")
98+
}
99+
],
100+
max_tokens: 4000
101+
}'
102+
)")
103+
104+
# Extract the review text
105+
REVIEW=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // empty')
106+
107+
if [ -z "$REVIEW" ]; then
108+
echo "::warning::AI review failed. Response: $(echo "$RESPONSE" | head -c 500)"
109+
exit 0
110+
fi
111+
112+
# Post as PR comment
113+
gh pr comment ${{ github.event.pull_request.number }} --body "$(cat <<EOF
114+
## AI Code Review
115+
116+
$REVIEW
117+
118+
---
119+
*Automated review by GitHub Models API (GPT-4.1) — [workflow source](${{ github.server_url }}/${{ github.repository }}/blob/main/.github/workflows/ai-review.yml)*
120+
EOF
121+
)"
122+

0 commit comments

Comments
 (0)