-
Notifications
You must be signed in to change notification settings - Fork 0
143 lines (123 loc) · 4.89 KB
/
ai-code-review.yml
File metadata and controls
143 lines (123 loc) · 4.89 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
name: AI Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
permissions:
pull-requests: write
contents: read
jobs:
code-review:
runs-on: ubuntu-latest
steps:
- name: Checkout PR code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get PR diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD > pr.diff
MAX_SIZE=50000
if [ $(wc -c < pr.diff) -gt $MAX_SIZE ]; then
head -c $MAX_SIZE pr.diff > pr_truncated.diff
mv pr_truncated.diff pr.diff
echo "warning=Diff truncated to ${MAX_SIZE} bytes" >> $GITHUB_OUTPUT
fi
FILES_CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | wc -l)
echo "files_changed=$FILES_CHANGED" >> $GITHUB_OUTPUT
- name: Code Review
id: review
env:
API_KEY: ${{ secrets.AI_PROVIDER_API_KEY }}
API_ENDPOINT: ${{ secrets.AI_PROVIDER_API_ENDPOINT }}
MODEL: ${{ secrets.AI_PROVIDER_MODEL }}
run: |
set +x # Disable verbose mode to prevent secret leakage in logs
DIFF=$(cat pr.diff | jq -Rs .)
# Retry logic with exponential backoff
MAX_RETRIES=3
RETRY_COUNT=0
HTTP_CODE=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
HTTP_CODE=$(curl -s -o response.json -w "%{http_code}" $API_ENDPOINT \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept-Language: en-US,en" \
-d "{
\"model\": \"$MODEL\",
\"messages\": [
{
\"role\": \"system\",
\"content\": \"You are an expert code reviewer. Analyze the PR diff and provide:\\n\\n1. **Summary**: Brief overview\\n2. **Issues**: Bugs or problems (if any)\\n3. **Security**: Security concerns (if any)\\n4. **Performance**: Performance considerations (if any)\\n5. **Best Practices**: Swift 6, concurrency, architecture (if any)\\n6. **Suggestions**: Optional improvements\\n\\nBe concise but thorough. Use markdown formatting.\"
},
{
\"role\": \"user\",
\"content\": ${DIFF}
}
],
\"temperature\": 0.3,
\"max_tokens\": 4096
}")
if [ "$HTTP_CODE" -eq 200 ]; then
break
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
WAIT_TIME=$((2 ** RETRY_COUNT))
echo "API returned $HTTP_CODE. Retrying in ${WAIT_TIME}s... (Attempt $RETRY_COUNT/$MAX_RETRIES)"
sleep $WAIT_TIME
fi
done
if [ "$HTTP_CODE" -ne 200 ]; then
echo "Error: API returned $HTTP_CODE after $MAX_RETRIES attempts"
cat response.json
exit 1
fi
RESPONSE=$(cat response.json)
REVIEW=$(echo "$RESPONSE" | jq -r '.choices[0].message.content')
# Check if review was extracted successfully
if [ -z "$REVIEW" ] || [ "$REVIEW" == "null" ]; then
echo "Error: Failed to extract review content from API response"
echo "Response: $RESPONSE"
exit 1
fi
echo "$REVIEW" > review.md
cat > review_with_header.md << EOF
### 🧠 AI Code Review
$REVIEW
EOF
if [ -n "${{ steps.diff.outputs.warning }}" ]; then
echo "" >> review_with_header.md
echo "⚠️ **Note**: ${{ steps.diff.outputs.warning }}" >> review_with_header.md
fi
- name: Post review as PR comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const review = fs.readFileSync('review_with_header.md', 'utf8');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('AI Code Review')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: review
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: review
});
}