最近隨著團隊的人數變多
看MR的次數也跟著增加
改動的內容一多
MR就無法看得很仔細
剛好公司有提供AI 的API
所以就來實作AI Code Review

目標是在每次發MR時
AI針對diff的內容給出建議
並且自動留言到MR

步驟如下
1. 建立Job
在原本的.gitlab-ci.yml
加入review的Job
並且只有在Merge Request的時後才發動

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
stages:
- build

ai-code-review:
stage: build
image: python:3.11

rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: on_success
- when: never

before_script:
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

script:
- pip install requests
- python House-Demo/Scripts/ai_code_review.py

2. 在專案內新建ai_code_review.py

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
import os
import re
import subprocess
import requests
import sys

# =====================
# Environment Variables
# =====================
AI_API_KEY = os.getenv("AI_API_KEY")
API_URL = os.getenv("API_URL")

TARGET_BRANCH = os.getenv("CI_MERGE_REQUEST_TARGET_BRANCH_NAME")
GITLAB_API = os.getenv("CI_API_V4_URL")
PROJECT_ID = os.getenv("CI_PROJECT_ID")
MR_IID = os.getenv("CI_MERGE_REQUEST_IID")
GITLAB_TOKEN = os.getenv("AI_REVIEW_COMMENT_TOKEN")


# =====================
# Git Diff
# =====================
diff = subprocess.check_output(
["git", "diff", f"origin/{TARGET_BRANCH}..HEAD"]
).decode("utf-8", errors="ignore")

filtered = []
current = []
keep = False

for line in diff.splitlines():
if line.startswith("diff --git"):
if current and keep:
filtered.extend(current)

current = [line]
keep = bool(re.search(r'\.(cs|csproj|sln)$', line))
else:
current.append(line)

if current and keep:
filtered.extend(current)

filtered_diff = "\n".join(filtered)

# =====================
# Prompt (.NET only)
# =====================
prompt = f"""
你是一位資深 .NET / ASP.NET Core 架構師,請針對以下 Git diff 做 Code Review。

請只針對「實質問題」給建議,不要評論排版或命名風格。

請特別注意:
1. 潛在 Bug(null reference、async/await 誤用、thread safety)
2. ASP.NET Core 常見陷阱(DI lifetime、middleware、filter)
3. 安全性(SQL Injection、XSS、反序列化風險、過度信任輸入)
4. 效能(不必要的 allocation、LINQ 誤用、同步 IO)
5. 可維護性(過度耦合、責任不清)

請用條列方式輸出,最多 10 點,越嚴重的排越前面。

Git diff:
{filtered_diff}
"""

# =====================
# Call LLM
# =====================
resp = requests.post(
API_URL+AI_API_KEY,
headers={
"Content-Type": "application/json",
},
json={
"contents": [
{
"parts": [
{
"text": prompt
}
]
}
]
}
)
print(resp.json())

review = resp.json()["candidates"][0]["content"]["parts"][0]["text"]

print("===== AI Code Review (.NET) =====")
print(review)

# =====================
# Post to Merge Request
# =====================
note_url = (
f"{GITLAB_API}/projects/{PROJECT_ID}"
f"/merge_requests/{MR_IID}/notes"
)

r = requests.post(
note_url,
headers={
"PRIVATE-TOKEN": GITLAB_TOKEN
},
json={
"body": review
}
)

r.raise_for_status()

print("✅ AI review posted to Merge Request")

demo的專案是用Google AI Studio提供的API
實際上API的參數、回傳、Key值
都需要依實際狀況調整

3. 設定gitlab的CI/CD變數
因為要讓pipeline可以自動留note到MR
所以需要申請一個token
可以到Settings的Access tokens新增
scopes勾選api
Role至少要是developer以上
ai-code-review-1.png
ai-code-review-2.png

再來就可以到Settings的CI/CD
新增剛剛.py裡面所需要的環境變數
Flags記得不要勾選Protect variable
並且選 Expand variable reference
否則會讀取不到
ai-code-review-3.png

4. 建立PR
接著就是建立分支,並且發起MR
當pipeline跑完後
就可以看到AI的 review建議已經新增到MR上面
ai-code-review-4.png

這個review的建議
很大程度受到AI模型、專案規模、Prompt的精準度影響
所以絕對不是照單全收
實測上會給出很多over design的建議
還是得由工程師來把關
不過多了AI協助review
多少還是有幫助的