[Tool Note] - 讓 SonarQube 成為你的糞 Code 守門員

Introduction & 前言

SonarQube 糞 Code 守門員

『奇怪怎麼程式碼越寫越大包?』『同事的 PR 一次常常都幾百幾千行,到底怎麼看?』『專案的技術債越來越重啊…』

你是不是曾經有過這樣的時候呢?當專案越來越多人的時候,發現技術債越來越龐大時,似乎已經來不及了,有沒有什麼好方法呢?

這篇文章將會帶你簡單入門 SonarQube,讓你在代碼審視上更加輕鬆。

這次世足大家都看 買好買滿(看好看滿) 了嗎? SonarQube 將會像是克羅埃西雅強大的守門員一樣,幫你守住重重困難,直到勝利到手。


Summary & 摘要

這篇文章預設讀者已經有基本的 docker 能力。

本篇文章預設學習前的基本條件需求:

  • 會基本的英文
  • 會使用 Terminal
  • 會基本的 Docker 指令(選配)
  • 會使用 Docker Compose(選配)
  • 有一顆熱忱且耐心的心

本篇文章將會學到:

  1. 基礎認識 - 何謂 SonarQube
  2. 事前準備 - 安裝環境準備
  3. 開始安裝 - 環境安裝及設定
  4. 多分支設定 - 套件安裝

備註:如果不會 Docker 也無妨,SonarQube 官方也有提供下載檔案方式安裝,但是透過 Docker 會更省事,有興趣也可以參考筆者的另一篇文章 [CI/CD Note] — 透過 Docker 快速建立及部署環境


為何要寫這篇

在開始前要先說一下為什麼要寫這篇文章,最近在幾個朋友間的談論,無意間討論到有個工程師常常需要幫同事 Code Review,雖然這個滿正常的,但他說每次的 PR 都是幾千行起跳,他都快跪下來了。

先撇除公司的制裁,該工程師詢問有無其它的方法可以解決這個問題,就在這時候有個朋友就跳出來說,試試看 SonarQube 啊!

基於好康道相報的原因,筆者將此物分享給公司同事,剛好就獲得一個技術分享的機會,順道將過程記錄下來,方便日後複習,也方便有更多有興趣的人一起研究。


基礎認識

SonarQube Logo v9.7

這邊就廢話不多說,直接介紹本日主角 SonarQube,這是一款開源的程式碼檢測平台,雖然目前有很多的檢測工具軟體,但滿多都還是需要花費價格,對於一些資金吃緊的團隊來說,這往往只是可替代性的東西,雖然方便,但我們先共體時艱辛苦一下用肉眼檢測就可以解決了對吧?

SonarQube 是基於 Java 開發的程式碼檢測與品質管理系統,因為 Java 的關係,是可以跨平台使用的。

先說一下要使用這套工具最後還會搭配一個叫做 SonarScanner 的分析工具,整體流程大概會像是下圖一樣,我們會有一台伺服器專門拿來放置 SonarQube,然後會在想要檢測程式碼的那一個專案的伺服器環境內安裝 SonarScanner

大致概念圖

基於這樣的設定,我們可以在不同專案內建置 SonarScanner,只要最後將掃描後的結果傳遞至放置 SonarQube 的伺服器內產出報告即可。


事前準備

關於 Docker

這次我們會將 SonarQube 透過 Docker 的方式安裝在本地,如果你有一台 VM 可以放置 SonarQube 的話當然更好。

如果你不會或者沒有使用 Docker 的話,官方也提供另一種直接安裝的方式,只是這種方式需要注意一下環境的部分,詳細可參考官方文件 Installing a local instance of SonarQube

先透過 Docker 官網下載安裝 Docker Desktop,如果你是 Win10 之前的版本,可以參考這篇文章 How To Install Docker on Windows 7/8/10 Home and Pro

*備註:如果是 Win10 安裝 Docker Desktop 也要記得注意一下 WSL2 的問題,可參考 在 WSL 2 上開始使用 Docker 遠端容器*。

另外我們會使用到 Docker Compose,這邊就不詳述安裝方式,可參考 Runoob.com 的 Docker Compose 介紹簡介,內有各種環境安裝介紹。

關於 SonarQube

官網 SonarQube 各版本介紹頁面

SonarQube 有幾個版本(詳細可查看 Download SonarQube Document),基本上分為免費的開源版本及付費的商業版本,這邊我們使用免費的開源版本,不過不用點擊下載,因為我們要透過 Docker 來安裝。

注意事項

這邊對於 M1/M2 晶片請用不同安裝方式,由於官方提供的安裝方式會直接安裝到 AMD64 的版本,速度會很慢,所以請改透過使用 mwizner/sonarqube 這個 Docker Image 來安裝。

ARM64 的 Docker Image

我們先不操作,如果透過官網查看 Docker 的安裝的方式會發現非常簡單。

Install SonarQube with Docker

只要裝好 Docker Desktop 後,執行下列代碼後打開網頁輸入 http://localhost:9000 訪問即可使用:

1
$ docker run -d --name sonarqube -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true -p 9000:9000 sonarqube:latest

但是呢,透過上面的安裝方式非 M1/M2 Mac 的朋友應該會用的滿痛苦的,就如上方提到,官網提供的 Docker Image - sonarqube 對於使用 ARM 晶片的果粉們會速度慢得很痛苦,所以清改用接下來下面的方式。


開始安裝

步驟一

  • M1/M2 Mac 請使用:
1
2
3
$ docker pull mwizner/sonarqube:latest

$ docker run -d -p 9000:9000 --name sonarqube -it mwizner/sonarqube:latest

備註:版本可自行設定,或者帶入 latest 取得最新版

  • Window 系統或非 M1/M2 Mac 請再隨意的地方創建一支 sonarqube-composer.yml 檔案,然後內容請輸入:
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
version: "3"

services:
sonarqube:
image: sonarqube:lts-community
depends_on:
- db
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
networks:
- sonarQubeNet
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_conf:/opt/sonarqube/conf
expose:
- 9000
ports:
- 9000:9000
db:
image: postgres
ports:
- 5432:5432
networks:
- sonarQubeNet
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
volumes:
- postgresql:/var/lib/postgresql
- postgresql_data:/var/lib/postgresql/data
adminer:
image: adminer
restart: always
ports:
- 8085:8080

networks:
sonarQubeNet:
driver: bridge

volumes:
sonarqube_conf:
sonarqube_data:
sonarqube_extensions:
sonarqube_bundled-plugins:
postgresql:
postgresql_data:

備註:adminer 的部分可有可無,只是方便使用圖形化介面查看,此外因為 sonarQube 8.0 版本以上不支持 MySQL,所以大部分的教學都會改為使用 PostgreSQL 資料庫

儲存後,開啟終端機輸入 docker-compose -f sonarqube-composer.yml up,如果想要讓 sonarQube 跑在背景程式裡,參數可以多加一個 -d,改為輸入 docker-compose -f sonarqube-composer.yml up -d 即可。

跑起來

之後等待一小段時間,讓 sonarQube 服務運行起來,再去瀏覽器輸入 http://localhost:9000,就會看到畫面了,如果出現找不到畫面,可能是服務還沒起起來,可以再稍等一下在刷新頁面。

登入畫面

第一次登入帳號密碼都是 admin,登入後系統會要求你改密碼。

更改密碼

最後可以點開 Docker Desktop 查看服務是否都成功啟動了。

Docker Desktop

備註:如果進入 http://localhost:9000 發現有正在更新的圖示,表示架構需要更新,直接到 http://localhost:9000/setup 就會顯示可以更新的內容了

更新系統

備註2:如果服務啟動後掛了,可以參考一下 Terminal 是否有顯示 memory areas vm.max_map_count [65530] is too low, increase to at least [262144] 這種錯誤訊息,是的話代表記憶體不足,詳細解決方式可參考 Sonarqube crashed still with latest image #282,其實只要提高 Docker 映像檔記憶體上線即可,輸入 sysctl -w vm.max_map_count=262144,之後重啟 Container

步驟二

創建專案

在接著繼續下去之前我們先在 sonarQube 上創建專案,一般免費版是不支援多分支掃描,所以有的教學文章會請你一個分支創建一個 Project,不過等等後面我們會透過安裝插件的方式解決。

登入後應該正常都是空的,點擊 Add a project 按鈕。

接下來我們選擇 Manually,筆者沒記錯的話,在 Community 版本中,專案類型只支援手動(Manually) 的方式。

Manually

這邊需要再輸入專案的 Key,可以使用 英文、數字、連字線(-)、底線(_)、句點(.)或 冒號(:)

Project Key

接著會需要設定一個 Token 名稱,然後按下 Generate 按鈕,產生一個新的 Token

新建 Token

這時候會產生一組 Token,請自行保管好,不要外洩,這就相當於是專案的密碼。

產出 Token

產生完 Token 之後,點擊 Continue 會跳到 Run analysis on your project,這邊會簡單的詢問要跑 Scanner 的環境是什麼,也會請你查看 official documentation of the Scanner 頁面安裝 sonar-scanner,下面會簡單產出掃描的指令。

依要分析的專案當下環境去選擇

這時候就可以繼續下一步啦。

步驟三

Sonar Scanner

安裝完 sonarQube 之後,就要安裝主角之一的 sonar-scanner,安裝方式有兩種,一種直接將 sonar-scanner 下載到本地(如果之後是在 VM 上請安裝到 VM 的全域環境,還記得嗎?我們上面的圖有說明道,不同專案可以透過 sonar-scanner 將掃描報告輸出到 sonarQube 去),另一種則是透過 Docker

備註:*M1/M2 Mac 的人建議使用 Mac OS X 64-bit 的下載點直接安裝,不要透過 Docker,掃描速度會非常慢*

安裝方式一:Docker

第一種安裝方式比較簡單;我們先拿隨便一個專案來試試手,選好專案後取得該專案的路徑,然後在 Terminal 裡輸入以下內容:

1
2
3
4
5
6
7
8
docker run \
--rm \
--network=host \
-e SONAR_HOST_URL='http://127.0.0.1:9000' \
-e SONAR_SCANNER_OPTS="-Dsonar.projectKey=${站台創建的 Project 名稱} -Dsonar.inclusions=/src/*" \
-e SONAR_LOGIN="${站台創建 Token}" \
-v "${專案路徑}:/usr/src" \
sonarsource/sonar-scanner-cli
  • ${站台創建的 Project 名稱} 對應到剛剛步驟二的內容為 local:web-admin
  • ${{站台創建 Token} 對應到剛剛步驟二的內容為那一長串 Token
  • ${專案路徑} 對應到你要掃描的專案路徑

跑起來

SONAR_SCANNER_OPTS 後面可以加上一些設定,在這邊加上的 inclusions 是指定要掃描的範圍,不指定就會整個資料夾都跑過,詳細可參考 SonarQube Doc

設定的部分最常見可以設定這幾個

  1. exclusions - 需跳檔案設定
  2. inclusions - 涵蓋範圍設定
  3. tests - 測試檔案所在位子
  4. sources - 掃描目錄

安裝方式二:本機安裝

本機安裝按照官方的方式走,裝完之後把掃描命令加到全域去。

備註:如果 Token 遺忘了,可以透過 My Account 裡面的 Security 再去 Generate 一個 Token

產生新 Token

步驟四

在跑完分析後,我們就可以刷新 http://localhost:9000 頁面,這時候看一下剛剛新增的 Project,應該會長得不一樣,點擊該 Project 進去,可以查看更多訊息。

掃描結束

點擊進入後,我們可以看到更多的訊息,包含**技術債、Code Smells…**等等,其中這邊會有兩個頁籤,一個為 New Code 一個為 Overall Code

頁籤切換

下面會有線圖可以看,這個可以很清楚地看到技術債是否有被解決或者越來越嚴重,另外也可以看到目前測試的涵蓋率。

技術債及測試涵蓋率


多分支設定

當我們一個專案多人開發,不太可能會只有掃描 Develop 或者 Master,我們可能會想要在同事發 PR 時就先檢測一次,這時候請安裝 Community 版本分支套件。

下面將會有三個步驟來安裝這個套件,如果你覺得不好理解或者不知道怎麼操作,也可以參考官方的指南 **Manual Install**。

套件安裝步驟

步驟一

這邊需要先到套件 Sonarqube Community Branch Plugin - GitHub 去查看目前適用於你 SonarQube 版本的掃描分支套件,不同版本必須安裝不同版本的掃描套件版本。

查看適用的版本

因為我們剛剛安裝的 SonarQube Versionlts,所以查看版本的方式可以直接到 http://localhost:9000 頁面的底部看。

版本在此

對應 8.9.10 我們必須要安裝 Plugin Version1.8.2 的版本,請到 sonarqube-community-branch-plugin - Release 去下載 1.8.2jar 檔。

請找到對應版本的 Release,下載 .jar 檔

步驟二

安裝的壓縮要複製一份放到 SonarQubeDocker 映像檔中,輸入 docker cp ${檔案位置} sonarqube_sonarqube_1:/opt/sonarqube/extensions/plugins

將壓縮檔放到這裡面去

筆者這邊最後輸入為 docker cp /Users/rexHung/Downloads/sonarqube-community-branch-plugin-1.8.2.jar sonarqube_sonarqube_1:/opt/sonarqube/extensions/plugins

輸入結束後透過 Docker 終端機進到 SonarQube 映像檔去看是否有成功複製進去。

進入終端機

進入終端機輸入 cd /extensions/plugins/ 接著輸入 ls,如果有出現剛剛下載的 .jar 檔,就是成功了

查看套件資料夾

步驟三

然後輸入 cd ../../ 回到外層,再輸入 cd conf,接著輸入 vi sonar.properties,在滑到檔案最底部,貼上下面兩行:

1
2
sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.2.jar=web
sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.8.2.jar=ce

修改設定檔

結束後重啟這個映像檔,再次輸入 http://localhost:9000 進入到站台頁面,這時候應該會看到跳出警示,點擊 I understand the risk 按鈕。

我了解風險!!

之後點擊上面的 Administration 之後,點擊 Marketplace,點擊底下的 Installed,確認套件已安裝成功。

確認套件已經安裝成功了

步驟四

最後我們需要更改掃描的命令,還有切換到即將發 PR 的分支,然後在 Terminal 上輸入:

1
2
3
4
5
6
7
8
9
10
11
12
13
docker run \
--rm \
--network=host \
-e SONAR_HOST_URL='http://127.0.0.1:9000' \
-e SONAR_SCANNER_OPTS=" \
-Dsonar.projectKey=${站台創建的 Project 名稱} \
-Dsonar.inclusions=/src/* \
-Dsonar.pullrequest.key=${輸入隨意數字} \
-Dsonar.pullrequest.branch=${分支名稱} \
-Dsonar.pullrequest.base=master" \
-e SONAR_LOGIN="${站台創建 Token}" \
-v "${專案路徑}:/usr/src" \
sonarsource/sonar-scanner-cli

這邊一樣也可以使用 Local 指令的方式去掃描:

1
2
3
4
5
6
7
8
9
sonar-scanner \
-D"sonar.projectKey=${站台創建的 Project 名稱}" \
-D"sonar.sources=." \
-D"sonar.host.url=http://localhost:9000" \
-D"sonar.login=${站台創建 Token}" \
-D"sonar.inclusions=*/**/*_src.js" \
-D"sonar.pullrequest.key=${輸入隨意數字}" \
-D"sonar.pullrequest.branch=${分支名稱}" \
-D"sonar.pullrequest.base=master"

掃描結束後刷新 http://localhost:9000 頁面去看一下專案裡的分支,點擊下拉後就會發現一個新的分支出現了,也就是剛剛掃描的分之,就此,大功告成!

新分支出現了


總結

其實這次一聽到有工具可以檢測程式碼是否有 Code Smell 且可以整合到 CI/CD 內就非常吸引我,抓了時間就研究起來,這套工具不只是可以單純手動跑檢測,如果搭配 Git Pre-commit 的指令,或是 GitLab Pipeline,肯定都能發揮莫大用處。

筆者一直想要摸索 CI/CD 的領域,從 Docker 入門後突然地接觸到這套工具,讓我有了點方向,我想下次就可以來玩玩 **Docker + SonarQube + Bot 推播…**等等的 Side Project

依照官網的介紹,還能搭配 SonarLint 做一個全方位的檢測,從程式碼的書寫規則檢測一直到技術方面的檢測,其中能搭配 Jenkins 等等打出一套組合拳,真的是相當香啊!

Dev Cycle

備註:如果沒有要使用 SonarQube 的時候,請記得要把 Docker Container 關閉,不然這個工具其實很吃資源的,這大概是這工具唯一的缺點,畢竟他會把你整份代碼 Clone 下來去分析


Conclusion & 結論

這次只是在本地部署,下次會開始嘗試部署到服務器上去,到時候或許又會碰到不一樣的坑,不過寫程式的樂趣就在這邊,解決問題的同時或的成就感,同時筆記下來或許能幫助到下一個也正要啟程的勇者,希望本篇文章能幫助到你/妳。


參考網站