OPPO自研代碼審查系統火眼Code Review實踐
1. 背景
隨着OPPO互聯網業務快速增長,團隊規模的不斷擴大,對代碼質量的要求也在不斷地提高,而現有的代碼審查工具GitLab和Gerrit已經無法滿足我們的評審需求,主要凸顯以下幾個問題:
-
無法高效的審查代碼中的bug或潛在的質量問題
-
團隊內部的代碼規範難以踐行
-
新人從代碼中得到成長有限
-
代碼評審的便利性有待提高
我們迫切需要一款高效、簡潔的代碼審查工具來輔助我們做代碼評審。
2. 自研還是改造
如果只做一個評審工具,缺少代碼管理功能,需要頻繁在代碼評審工具和代碼託管工具之間切換,用戶體驗不友好。
代碼審覈和代碼管理最好在一個系統中,但要開發一個兩者兼備的工具系統存在兩個問題:
第一、要實現具備代碼管理功能的代碼評審系統,需要開發一套較爲完善的代碼管理系統,而已有的代碼託管平臺本身已比較成熟,再另外開發其難度和工作量都比較大。
第二、項目風險高,開發出來的系統穩定性和可靠性存在一定的挑戰。
是否可以存在一種方法:既不用開發代碼管理系統但又能實現Code Review的簡單解決方案。在進行深度調研之後,我們發現在GitLab之上開發Code Review具有可行性,經過幾月的研發,我們的Code Review系統火眼就這麼誕生了。
火眼是OPPO互聯網自研的代碼審查工具,它融合了Gerrit的評審功能和GitLab代碼管理功能,其主要功能包括:
-
強制/非強制代碼審查
-
Merge Request
-
代碼倉庫管理
火眼相較於其他代碼評審工具,主要有以下特點:
-
評審代碼衝突預檢測
-
靈活的評審人以及規則(普通和必要評審人,並設置通過的閥值)
-
靈活的分支評審規則(自定義需要評審的分支)
-
支持多種協同開發模式(包括強制評審、Merge Request兩種模式)
-
無縫對接內部通訊即時聊天工具和郵件系統
3. 火眼的原理
爲了方便大家理解後文,這裏對火眼原理做一個簡單的介紹。火眼主要利用了Git的refs命名空間的特性,下圖是某一個Git倉庫在服務器存儲的目錄結構:
這個結構主要包含以下幾個部分:
-
hook目錄存放項目的服務端鉤子腳本,代碼提交倉庫之前會觸發pre-receive腳本,提交後會觸發post-receive腳本,我們主要就用到了這兩個腳本;
-
objects目錄存儲着Git數據庫的所有內容;
-
refs目錄存儲着所有分支指向各自提交對象的指針,每個指針指向對應分支或者tag最新的CommitId。默認的分支都會在refs/heads這個子文件夾下,例如我們經常使用的master分支指向的就是refs/heads/master。
火眼在實現Code Review利用的就是將對分支refs/heads/{Branch}的提交,改爲指向到refs/changes/{ChangeId}/{Branch},其中ChangeId是指的某個特性,Branch是相應的開發分支,通過這個特性來存儲待評審的Commit內容,當評審通過時,將refs/changes/{ChangeId}/{Branch}合併到原先正常的分支中。以開發dev分支爲例,提交的模型如下:
對於每個特性(ChangeId),都獨立的產生評審,當評審完成之後再合併到其對應的分支。當初我們的隔離維度是分支維度,相同分支產生的評審存儲在一起。當我們發現這些評審存儲在一起後,評審的代碼會相互干擾,影響評審的獨立性,所以才產生了現有的以特性爲隔離維度的評審模式。
4. 火眼技術架構
下圖展示了火眼系統目前的架構:
4.1 火眼RPC
火眼RPC是一個Dubbo實現的代理服務,其主要完成以下Git操作:
-
代碼合併
-
標籤操作
-
分支操作
-
對比操作
-
提交歷史操作
火眼Web調用火眼RPC來完成對Git倉庫的操作。火眼RPC的核心處理Git底層數據是採用JGit(一款開源的Java操作Git的工具)實現,火眼RPC在JGit基礎上實現了所有的Git查看操作,但是JGit並沒有提供基於裸庫(服務端存儲Git文件的形式)的合併方法。我們就基於JGit提供的底層的原子方法,經過封裝、改造得到了我們想要的基於裸庫的合併算法。
4.2 火眼Web
火眼Web是一個 Web工程,其主要處理以下內容:
-
評審、評論以及其狀態扭轉
-
設置(評審人/審覈規則/通知/倉庫設置)
-
倉庫的基本管理
-
GitLab權限同步
評審
在用戶提交了評審之後,評審人會收到評審邀請鏈接,點擊後即可進行評審。對於評論我們設置了一個標記爲解決的狀態,方便評審人或評審發起者跟蹤問題。
爲了使評審功能更加完善,我們將GitLab的Merge Request模式移植了過來,並做了一些改進。其中一個特別的改進點是: 鎖定提交 。當用戶在選擇鎖定提交的時候,合入分支的後續提交將在本次Merge Request不會被合入。我們認爲這點在多人開發的時候很重要,保證了需要被合併的代碼就只包含發起Merge Request時的代碼。
火眼評審界面
衝突預檢測
以往其他團隊在使用Gerrit做評審的時候的一個比較大的痛點是:在評審流程走完之後合併代碼的時候發現被評審的代碼與已經合入到倉庫裏面的代碼有衝突,這個時候又不得不再次合併代碼,重新發起評審流程。火眼特別解決了這個問題,在用戶做評審時,將被評審的代碼和將要合入分支在內存中合併一次,如果發生了衝突就在評審界面醒目的提示發生衝突,並告知解決衝突方案。
倉庫的基本管理
像主流的代碼託管工具一樣我們在界面上提供了可視化操作Git基本數據的功能。通過火眼RPC目前實現了以下功能:分支管理、文件管理、標籤管理、提交歷史查看、對比等。
GitLab權限同步
我們並未在火眼系統中單獨開發一套權限系統,整個系統是複用的GitLab權限,每隔一段時間或GitLab權限發生改變時,火眼會拉取一遍GitLab的權限數據,主要包括:項目,組,項目與人的關係,組與人的關係。
4.3 火眼Git鉤子
火眼Git鉤子是火眼系統實現的兩個Git服務端兩個鉤子: 提交前鉤子 (pre-receive)和 提交後鉤子 (post-receive)。提交前鉤子用於提交代碼用戶選擇普通提交併開啓強制評審時,系統拒絕本次提交。提交後鉤子用於當評審代碼已成功提交,調用火眼平臺,生成評審任務。下圖展示了兩個鉤子在提交代碼過程中各自的功能:
4.4 火眼命令行
火眼命令行是火眼用於提交評審的客戶端命令行。因爲如果需要提交評審任務,需要執行 git push HEAD:refs/changes/{ ChangeId } /{Branch} 命令,該命令太長,使用者體驗不友好,上手難度高,所以我們決定使用客戶端命令行的方式來簡化提交過程,並降低使用成本。
爲了讓各個平臺(Linux/Windows/Mac)都能使用火眼命令行,火眼命令行用Go語言編寫,並編譯成各個平臺的二進制文件。
5. 火眼使用步驟
準備工作:安裝火眼命令行,下列爲具體使用步驟:
-
編寫代碼:和往常編寫的代碼步驟一樣,寫完後 git add , git commit 代碼。
-
提交評審:使用火眼命令行提交代碼,系統會反饋代碼評審地址,並用內部通訊工具通知相關評審人。下圖展示了使用火眼命令行提交評審、生成任務的過程:
-
評審代碼:在火眼平臺對代碼進行審查,審查通過後代碼會自動合入(可配置手動合入)。
在開發流程上和日常開發差異不大,只是用火眼的提交命令替代了Git的提交命令。
6. 未來的規劃
6.1 自動掃描
Code Review能解決業務人工評審問題,但部分代碼bug或smell(代碼臭味)可以通過代碼掃描工具提前發現,因此後續我們將引入自研的自動化掃描工具,並在評審流程中嵌入此過程,以輔助評審。
6.2 自由評審
自由評審模式相較提交後即自動發起評審模式,區別在於其能夠評審任意提交,該模式適用於代碼開發完畢回顧或審查代碼,但不涉及到合併代碼的場景,如代碼評審會議。
7 總結
火眼系統是基於GitLab提交代碼的過程做攔截,現有GitLab用戶可以在很低的使用成本上使用火眼。火眼系統靈活的評審模式、多樣化的評審規則以及靈活的評審分支選擇可以很好的輔助團隊做好代碼評審工作,達到了該系統開發的預期效果。
聲明:本文來自OPPO互聯網技術,版權歸作者所有。文章內容僅代表作者獨立觀點,不代表安全內參立場,轉載目的在於傳遞更多信息。如有侵權,請聯繫 [email protected]。