Reviewbot 開源 | 為什麼我們要打造自己的程式碼審查服務?
Reviewbot 是七牛雲開源的一個專案,旨在提供一個自託管的程式碼審查服務, 方便做 code review/靜態檢查, 以及自定義工程規範的落地。
靜態檢查不是個新鮮事。
我記得早在幾年前,我們就調研並使用過 sonarqube 做靜態檢查,但當時並沒有大範圍的推廣。主要原因在於,一是發現的問題多數是風格問題,較少能發現缺陷; 二是 sonarqube 社群版的 worker 數有限制,滿足不了我們大規模程式碼掃描的需求。當然,也是因為前一個問題,感覺付費並不是很划算。
而由於七牛主要使用 golang 語言,所以在靜態檢查方面,我們基本使用 go vet/fmt/lint 等,再就是後來的 golangci-lint,好像也夠用了。
但隨著程式碼倉庫的增多,以及對工程規範的不斷強化,我們越來越發現當前的落地方式,已經開始無法滿足我們的需求。
Linter 工具的引入與更新問題
以 golangci-lint 為例,它是 go 語言 linters 聚合器,內建了 100+ linters,使用也很簡單, golangci-lint run
一條命令即可。但你知道嗎?如果沒有特殊配置,你這條命令其實僅僅執行其中的 6 個 linter,絕大部分 linters 都沒有執行!
另外,工具本身需要更新,且很多時候我們也會自己定製 linter 工具,這種時候該怎麼做呢?如果僅有少量倉庫,可能還好,但如果倉庫很多,那維護成本就上去了。
還有就是新業務,新倉庫,如何保證相關的檢查能夠及時配置,相關的規範能夠正確落地?
靠自覺一定是不行的。
Linter 問題的發現與修復情況
如何確保發現的問題能夠被及時修復?如何讓問題能更及時、更容易的被修復?
埋藏在大量 raw log 中的問題,一定是不容易被發現的,查詢起來很麻煩,體驗很差。
歷史程式碼倉庫的存量問題,誰來改?改動就需要時間,但實際上很多業務研發可能並沒有動力來跟進。同樣,變動總是有風險的,有些 lint 問題修復起來也並不簡單,如果因修復 lint 問題而引入風險,那就得不償失了。
如果想了解當前組織內 lint 問題的分佈及修復情況,又該怎麼辦呢?
如何解決,方向在哪裡?
不可否認,linter 問題也是問題,如果每行程式碼都能進行充分的 lint 檢查,那一定比不檢查要強。
另一方面,組織內製定好的工程規範,落地在日常的開發流程中,那一定是希望被遵守的,這類就是強需。
所以這個事情值得做,但做的方式是值得思考的,尤其是當我們有更高追求時。
參考 CodeCov
的服務方式,以及 golangci-lint
reviewdog
等工具的設計理念,我們認為:
- 如果能對於新增倉庫、歷史倉庫,不需要專人配置 job,就能自動生效,那一定是優雅的
- 如果能只針對 PR/MR 中的變動做分析和反饋,類似我們做 Code Review 那樣,那對於提 PR 的同學來講一定是優雅的,可接受的,隨手修復的可能性極大
- 而進一步,針對 PR/MR 中涉及的檔案中的歷史程式碼進行反饋,在合理推動下,支援夾帶修改,持續改進的可能性也會大大增強
- Lint 工具多種多樣,或者我們自己開發出新工具時,能夠較為輕鬆的讓所有倉庫都自動生效,那也一定是非常讚的,不然就可能陷入工具越多負擔越重的風險
基於上面的思考,我認為我們需要的是: 一箇中心化的 Code Review/靜態檢查服務,它能自動接受整個組織內 PR/MR 事件,然後執行各種預定義的檢查,並給與精確到變動程式碼行的有效反饋。它要能作為程式碼門禁,持續的保障入庫程式碼質量。
而 Reviewbot 就是這樣一個專案。
Reviewbot 在設計和實現上有哪些特點?
面向改進的反饋方式
這將是 Reviewbot 反饋問題的核心方式,它會盡可能充分利用各 Git 平臺的自身能力,精確到變動的程式碼行,提供最佳的反饋體驗。
Github Check Run (Annotations)
Github Pull Request Review (Comments)
支援多種 Runner
Reviewbot 是自託管的服務,推薦大家在企業內自行部署,這樣對私有程式碼更友好。
Reviewbot 自身更像個管理服務,不限制部署方式。而對於任務的執行,它支援多種 Runner,以滿足不同的需求。比如:
- 不同的倉庫和 linter 工具,可能需要不同的基礎環境,這時候你就可以將相關的環境做成 docker 映象,直接透過 docker 來執行
- 而當任務較多時,為了執行效率,也可以選擇透過 kubernetes 叢集來執行任務。
使用也很簡單,在配置檔案中的目標倉庫指定即可。類似:
dockerAsRunner:
image: "aslan-spock-register.qiniu.io/reviewbot/base:go1.22.3-gocilint.1.59.1"
kubernetesAsRunner:
image: "aslan-spock-register.qiniu.io/reviewbot/base:go1.23.2-gocilint.1.61.0"
namespace: "reviewbot"
零配置 + 定製化
本質上,Reviewbot 也是個 webhook 服務,所以我們只需要在 git provider 平臺配置好 Reviewbot 的回撥地址即可 (github 也可以是 Github App)。
絕大部分的 linter 的預設最佳執行姿勢都已經固定到程式碼中,如無特殊,不需要額外配置就能對所有倉庫生效。
而如果倉庫需要特殊對待,那就可以透過配置來調整。
類似:
org/repo:
linters:
golangci-lint:
enable: true
dockerAsRunner:
image: "aslan-spock-register.qiniu.io/reviewbot/base:go1.22.3-gocilint.1.59.1"
command:
- "/bin/sh"
- "-c"
- "--"
args:
- |
source env.sh
export GO111MODULE=auto
go mod tidy
golangci-lint run --timeout=10m0s --allow-parallel-runners=true --print-issued-lines=false --out-format=line-number >> $ARTIFACT/lint.log 2>&1
可觀察
Reviewbot 是在對工程規範強管理的背景下產生的,那作為工程規範的推動方,我們自然有需求想了解組織內當前規範的執行情況。比如, 都有哪些問題被檢出?哪些倉庫的問題最多?哪些倉庫需要特殊配置?
目前 Reviewbot 支援透過企業微信來接收通知,比如:
- 檢出有效問題
- 遇到錯誤
當然,未來可能也會支援更多方式。
其他更多的功能和姿勢,請參考倉庫: https://github.com/qiniu/reviewbot
Reviewbot 的未來規劃
作為開源專案,Reviewbot 還需要解決很多可用性和易用性問題,以提升使用者體驗,比如最典型的,接入更多的 git provider(gitlab/gitee 等),支援 CLI 模式執行。
但我個人認為,作為 code review 服務,提供更多的檢測能力,才是重中之重。因為這不光是行業需求,也是我們自身需要。
所以後面我們除了會引入七牛內部推薦的規範,也會調研和探索更多的行業工具,同時會考慮引入 AI,探索 AI 在 code review 中的應用等等。
Anyway,Reviewbot 還很年輕,我們在持續的改進中,非常歡迎大家試用並提出寶貴意見。當然,更歡迎大家一起參與到專案建設中來。
感謝大家。
相關文章
- 為什麼我要寫自己的框架?框架
- 我們為什麼要閱讀webpack原始碼Web原始碼
- 程式碼審查“查”什麼?
- 為什麼我要編寫自己的UIKitUI
- 為什麼我們需要服務網格Service mesh?
- 程式碼審查“查”什麼?(1)
- 為什麼我要垂直對齊程式碼
- 我們為什麼需要模擬服務機器人?機器人
- 我們自己開發的程式碼託管服務,用於內部替代 Github,免費開源給大家使用Github
- GitHub的革命:為什麼我們現在都在開源Github
- 簡談為什麼遊戲公司要打造自己旗下的IP遊戲
- 我們程式設計師為什麼要關注 JavaScript ?程式設計師JavaScript
- 程式碼審查“查”什麼(3):效能
- 我們為什麼要技術寫作
- 為什麼我要豎向對齊程式程式碼
- 為什麼我們要關注醫療衛生服務面臨的網路安全威脅
- 程式碼審查“查”什麼(2):測試
- [譯]我們為什麼要寫 super(props)?
- 我們為什麼要從 HTTPRunner 轉向 MeterSphereHTTP
- #AWS:為什麼我們要持續投資Rust?Rust
- 我們為什麼要學Java?Java好在哪?Java
- 為什麼要貢獻開源
- 為什麼要做程式碼審計?
- 為什麼我們要選用 Elasticsearch 而不用 SolrElasticsearchSolr
- 為什麼我們要學習Microsoft Graph for Office 365ROS
- 我從 1000 份程式碼審查中學到了什麼
- 為什麼我們程式設計師寫不出好程式碼?程式設計師
- 為什麼我要垂直對齊程式碼(你也要如此!)
- 我能為開源做些什麼?
- 為什麼要搭建自己的部落格
- 程式碼審查“查”什麼?(5):SOLID原則Solid
- 為什麼我要公開程式碼和想法
- 為什麼我們需要資料庫事務資料庫
- 為什麼我們要學習DMAIC?—舉例說明AI
- 我們為什麼要嘗試前後端分離後端
- 為什麼我們要從 NodeJS 遷移到 Ruby on RailsNodeJSAI
- 聊聊分割槽Partition——我們為什麼要分割槽(下)
- 聊聊分割槽Partition——我們為什麼要分割槽(中)