經過前面章節對 Note API 方式的探討,我們了解到那種方法更適合作為 POC(概念驗證)階段使用。今天我們要深入探討團隊真正導入 production 環境的完整解決方案 —— 基於 Discussion API 的精確行級 Code Review 系統。
這個方案的核心優勢在於能夠將 AI 的審查建議精確地標註到程式碼的特定行數上,而不是僅僅在 Merge Request 中留下總體評論,大幅提升了 Code Review 的實用性和可操作性。
預計於 Day 23 篇章詳細說明多專案權限管理,這邊只需要知道把專案的 webhook 帶入到對應專案裡面。
帶入以下程式碼,
為了避免不必要的資源消耗和 API 調用,
我們需要精確控制什麼情況下才觸發 AI Code Review。
{{
(
$json.body.object_attributes.action === "open" ||
$json.body.object_attributes.action === "update"
) &&
$json.body.object_attributes.state === "opened"
}}
邏輯說明:
open
)或更新(update
)時才觸發opened
)的 MR 才需要審查不同專案需要使用各自的 GitLab Token 來確保權限隔離和安全性。
延續步驟 1,Day 23 會詳細說明為什麼要這樣寫。
// 專案 token 設定: 格式 key:id, value:token
var mapToken = new Map();
mapToken.set("4835", "token callduck") // callduck 專案
mapToken.set("5036", "token beacon") // beacon 專案
return $input.all().map(item => {
const projectId = item.json.body.project.id;
const iid = item.json.body.object_attributes.iid;
const token = mapToken.get(projectId.toString());
const sourceBranch = item.json.body.object_attributes.source_branch;
return {
json: {
projectId: projectId,
iid: iid,
token: token,
sourceBranch: sourceBranch
}
}
});
這個步驟展示了如何將前一步驟獲取的 Token 動態注入到 GitLab API 調用中
const changes = $json.changes || [];
const headSha = $json?.diff_refs?.head_sha || '';
const baseSha = $json?.diff_refs?.base_sha || '';
const startSha = $json?.diff_refs?.start_sha || baseSha;
const projectId = $json.project_id || 0;
const iid = $json.iid || 0;
// 解析每個 diff 的第一個異動行
function getFirstChangedLine(diff) {
const lines = diff.split('\n');
let oldLineNum = 0;
let newLineNum = 0;
let headerFound = false;
for (const line of lines) {
if (line.startsWith('@@')) {
// 解析 diff header,獲取行數資訊
const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
if (match) {
oldLineNum = parseInt(match[1]) - 1;
newLineNum = parseInt(match[2]) - 1;
headerFound = true;
}
} else if (headerFound && line.startsWith('+') && !line.startsWith('+++')) {
// 處理新增的行
newLineNum++;
return {
type: 'added',
old_line: null,
new_line: newLineNum,
content: line.substring(1),
original_line: line
};
} else if (headerFound && line.startsWith('-') && !line.startsWith('---')) {
// 處理刪除的行
oldLineNum++;
return {
type: 'removed',
old_line: oldLineNum,
new_line: null,
content: line.substring(1),
original_line: line
};
} else if (headerFound && line.startsWith(' ')) {
// 處理未改變的行
oldLineNum++;
newLineNum++;
}
}
return null;
}
// 為每個檔案生成第一個變更行資料
const changesWithFirstLine = changes.map(change => {
const firstChangedLine = getFirstChangedLine(change.diff);
if (!firstChangedLine) {
return null;
}
return {
diff: change.diff,
new_path: change.new_path,
old_path: change.old_path || change.new_path, // 確保 old_path 不為空
new_file: change.new_file,
deleted_file: change.deleted_file,
old_line: firstChangedLine.old_line,
new_line: firstChangedLine.new_line,
baseSha: baseSha,
headSha: headSha,
startSha: startSha
};
}).filter(item => item !== null); // 過濾掉無效項目
// 輸出符合 GitLab Discussion API 格式的資料
return [
{
json: {
project_id: projectId,
iid,
changes_with_first_line: changesWithFirstLine
}
}
];
Diff 解析邏輯:
@@
開頭的 diff header,解析出起始行號資料結構設計:
這個 Discussion API 代表了我們團隊在 Code Review 自動化的使用方案。相比於前面介紹的 Note API 方案,這個版本在實用性、精確性和用戶體驗方面都有顯著提升。
由於這個方案涉及較多的程式碼實作細節,分成上中下篇章