1 代碼質(zhì)量測試
官方網(wǎng)站:http://www.sonarqube.org/
SonarQube 是一個用于代碼質(zhì)量管理的開放平臺,通過插件機制,SonarQube可以
集成不同的測試工具,代碼分析工具,以及持續(xù)集成工具,例如 Hudson/Jenkins 等
下載地址:https://www.sonarqube.org/downloads/
七個維度檢測代碼質(zhì)量:
復(fù)雜度分布:代碼復(fù)雜度過高將難以理解
重復(fù)代碼:程序中包含大量復(fù)制、粘貼的代碼而導(dǎo)致代碼臃腫,sonar 可以展示源碼中重復(fù)嚴重的地方
單元測試統(tǒng)計:統(tǒng)計并展示單元測試覆蓋率,開發(fā)或測試可以清楚測試代碼的覆蓋情況
代碼規(guī)則檢查:檢查代碼是否符合規(guī)范
注釋率:若代碼注釋過少,特別是人員變動后,其他人接手比較難接手;若過多,又不利于閱讀
潛在的 Bug:檢測潛在的 bug
結(jié)構(gòu)與設(shè)計:找出循環(huán),展示包與包、類與類之間的依賴、檢查程序之間耦合度
2 Sonarqube
2.1 Sonarqube架構(gòu)

Sonarqube代碼檢測功能由Sonarqube服務(wù)器端提供
SonarScanner需要在執(zhí)行代碼掃描的服務(wù)器安裝, 用于掃描代碼, 并且上傳到Sonarqube Server端
2.2 Sonarqube部署環(huán)境
10.0.0.139 Sonarqube Server 4G 2c v7.9.6
10.0.0.149 PGSQL 4G 2c
Jenkins master服務(wù)器負責(zé)代碼掃描, 需要安裝Sonar Scanner
2.3 Sonarqube Server安裝
2.3.1 包下載
https://www.sonarqube.org/downloads/
root@sonarserver:~# ls
sonarqube-7.9.6.zip
2.3.2 配置環(huán)境依賴
- 內(nèi)核參數(shù)要求
root@sonarserver:~# vim /etc/sysctl.conf
vm.max_map_count=262144
fs.file-max=65536
root@sonarserver:~# sysctl -p
vm.max_map_count = 262144
fs.file-max = 65536
- 文件描述符限制
root@sonarserver:~# vim /etc/security/limits.conf
sonarqube - nofile 65536
sonarqube - nproc 65536
2.3.3 創(chuàng)建sonarqube用戶
Sonarqube Server不能用root賬戶啟動
root@sonarserver:~# useradd -m -r -s /bin/bash sonarqube
2.3.4 安裝jdk-11
Sonarqube Server只支持jdk-11, 而SonarScanner支持jdk8和jdk11
root@sonarserver:~# apt -y install openjdk-11-jdk
root@sonarserver:~# reboot
2.3.5 安裝PGSQL
Sonarqube7.x開始支持PGSQL, 支持v10和v9.3-v9.6, 字符集必須是UTF-8
root@pgsql:~# apt-cache madison postgresql
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-security/main amd64 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-security/main i386 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-updates/main amd64 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-updates/main i386 Packages
postgresql | 10+190 | http://mirrors.aliyun.com/ubuntu bionic/main amd64 Packages
postgresql | 10+190 | http://mirrors.aliyun.com/ubuntu bionic/main i386 Packages
postgresql-common | 190 | http://mirrors.aliyun.com/ubuntu bionic/main Sources
postgresql-common | 190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-security/main Sources
postgresql-common | 190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-updates/main Sources
root@pgsql:~# apt install postgresql -y
切換到 postgres 操作,PostgresSQL 安裝后會自動創(chuàng)建 postgres 用戶且沒有密碼. 數(shù)據(jù)庫的創(chuàng)建必須使用postgres賬戶操作
root@pgsql:~# su - postgres
postgres@pgsql:~$ psql -U postgres
psql (10.17 (Ubuntu 10.17-0ubuntu0.18.04.1))
Type "help" for help.
postgres=# CREATE DATABASE sonar;
CREATE DATABASE
postgres=# CREATE USER sonar WITH ENCRYPTED PASSWORD '123456';
CREATE ROLE
postgres=# GRANT ALL PRIVILEGES ON DATABASE sonar TO sonar;
GRANT
postgres=# ALTER DATABASE sonar OWNER TO sonar;
ALTER DATABASE
修改監(jiān)聽地址, 使用root賬號配置
root@pgsql:~# vim /etc/postgresql/10/main/postgresql.conf
listen_addresses = '*' # 修改第59行
開啟遠程訪問
root@pgsql:~# vim /etc/postgresql/10/main/pg_hba.conf
host all all 10.0.0.0/24 md5 # 修改第92行, 允許某個網(wǎng)段或者某臺主機訪問
重啟服務(wù)
root@pgsql:~# systemctl restart postgresql
root@pgsql:~# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:5432 # 監(jiān)聽在0.0.0.0 0.0.0.0:*
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:5432 [::]:*
LISTEN 0 128 [::]:22 [::]:*
2.3.6 安裝Sonarqube Server
root@sonarserver:~# mkdir /apps
root@sonarserver:~# ls
sonarqube-7.9.6.zip
root@sonarserver:~# unzip sonarqube-7.9.6.zip -d /apps
root@sonarserver:~# cd /apps
root@sonarserver:/apps# ll
total 12
drwxr-xr-x 3 root root 4096 Jul 6 22:33 ./
drwxr-xr-x 25 root root 4096 Jul 6 22:32 ../
drwxr-xr-x 11 root root 4096 Mar 1 09:21 sonarqube-7.9.6/
root@sonarserver:/apps# ln -sv sonarqube-7.9.6/ sonarqube
'sonarqube' -> 'sonarqube-7.9.6/'
root@sonarserver:/apps# chown -R sonarqube.sonarqube /apps/sonarqube
root@sonarserver:/apps# chown -R sonarqube.sonarqube /apps/sonarqube/
root@sonarserver:/apps# ll /apps
total 12
drwxr-xr-x 3 root root 4096 Jul 6 22:34 ./
drwxr-xr-x 25 root root 4096 Jul 6 22:32 ../
lrwxrwxrwx 1 sonarqube sonarqube 16 Jul 6 22:34 sonarqube -> sonarqube-7.9.6//
drwxr-xr-x 11 sonarqube sonarqube 4096 Mar 1 09:21 sonarqube-7.9.6/
sonarqube@sonarserver:/apps/sonarqube$ vim conf/sonar.properties
sonarqube@sonarserver:/apps/sonarqube$ grep -E '^[a-zA-Z]' conf/sonar.properties
sonar.jdbc.username=sonar # 數(shù)據(jù)庫賬號
sonar.jdbc.password=123456 # 密碼
sonar.jdbc.url=jdbc:postgresql://10.0.0.149/sonar # 數(shù)據(jù)庫地址
2.3.7 啟動服務(wù)
使用sonarqube普通賬戶啟動, 如果用root賬戶啟動, 那么ES服務(wù)無法啟動, 間接造成Sonarqube無法啟動
sonarqube@sonarserver:/apps/sonarqube$ ./bin/linux-x86-64/sonar.sh start
Starting SonarQube...
Started SonarQube.
sonarqube@sonarserver:/apps/sonarqube$ tail logs/*.log
2021.07.06 22:41:32 INFO app[][o.s.a.SchedulerImpl] Process[ce] is up
2021.07.06 22:41:32 INFO app[][o.s.a.SchedulerImpl] SonarQube is up
2.3.8 訪問sonarqube
賬號:admin
密碼:admin

2.3.9 使用官方提供的Service文件啟動sonarqube
- 先停止服務(wù)
sonarqube@sonarserver:~$ /apps/sonarqube/bin/linux-x86-64/sonar.sh stop
Gracefully stopping SonarQube...
Stopped SonarQube.
- 使用root賬號, 創(chuàng)建Service文件
root@sonarserver:~# vim /etc/systemd/system/sonarqube.service
[Unit]
Description=SonarQube service
After=syslog.target network.target
[Service]
Type=simple
User=sonarqube
Group=sonarqube
PermissionsStartOnly=true
ExecStart=/usr/bin/nohup /usr/bin/java -Xms1024m -Xmx1024m -Djava.net.preferIPv4Stack=true -jar /apps/sonarqube/lib/sonar-application-7.9.6.jar
StandardOutput=syslog
LimitNOFILE=131072
LimitNPROC=8192
TimeoutStartSec=5
Restart=always
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
root@sonarserver:~# systemctl daemon-reload
root@sonarserver:~# systemctl restart sonarqube
root@sonarserver:~# systemctl enable --now sonarqube
Created symlink /etc/systemd/system/multi-user.target.wants/sonarqube.service → /etc/systemd/system/sonarqube.service.
root@sonarserver:/apps/sonarqube# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 25 *:9000 *:*
LISTEN 0 128 [::ffff:127.0.0.1]:9001 *:*
2.3.10 安裝中文插件

插件保存目錄
root@sonarserver:~# ll /apps/sonarqube/extensions/plugins/
total 87836
drwxr-xr-x 2 sonarqube sonarqube 4096 Mar 1 09:10 ./
drwxr-xr-x 5 sonarqube sonarqube 4096 Jul 6 22:41 ../
-rw-r--r-- 1 sonarqube sonarqube 224 Mar 1 09:10 README.txt
-rw-r--r-- 1 sonarqube sonarqube 287504 Mar 1 09:10 sonar-auth-github-plugin-1.5.0.870.jar
-rw-r--r-- 1 sonarqube sonarqube 3312399 Mar 1 09:10 sonar-auth-saml-plugin-1.2.0.682.jar
-rw-r--r-- 1 sonarqube sonarqube 4094975 Mar 1 09:10 sonar-csharp-plugin-7.15.0.8572.jar
-rw-r--r-- 1 sonarqube sonarqube 7015434 Mar 1 09:10 sonar-css-plugin-1.1.1.1010.jar
-rw-r--r-- 1 sonarqube sonarqube 1544789 Mar 1 09:10 sonar-flex-plugin-2.5.1.1831.jar
-rw-r--r-- 1 sonarqube sonarqube 3903342 Mar 1 09:10 sonar-go-plugin-1.1.1.2000.jar
-rw-r--r-- 1 sonarqube sonarqube 1727846 Mar 1 09:10 sonar-html-plugin-3.1.0.1615.jar
-rw-r--r-- 1 sonarqube sonarqube 15098 Mar 1 09:10 sonar-jacoco-plugin-1.0.2.475.jar
-rw-r--r-- 1 sonarqube sonarqube 8302745 Mar 1 09:10 sonar-java-plugin-5.13.1.18282.jar
-rw-r--r-- 1 sonarqube sonarqube 6866969 Mar 1 09:10 sonar-javascript-plugin-5.2.1.7778.jar
-rw-r--r-- 1 sonarqube sonarqube 7595999 Mar 1 09:10 sonar-kotlin-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonarqube sonarqube 300503 Mar 1 09:10 sonar-ldap-plugin-2.2.0.608.jar
-rw-r--r-- 1 sonarqube sonarqube 5105268 Mar 1 09:10 sonar-php-plugin-3.2.0.4868.jar
-rw-r--r-- 1 sonarqube sonarqube 2752167 Mar 1 09:10 sonar-python-plugin-1.14.1.3143.jar
-rw-r--r-- 1 sonarqube sonarqube 10036210 Mar 1 09:10 sonar-ruby-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonarqube sonarqube 9202024 Mar 1 09:10 sonar-scala-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonarqube sonarqube 2538373 Mar 1 09:10 sonar-scm-git-plugin-1.12.1.2064.jar
-rw-r--r-- 1 sonarqube sonarqube 7229293 Mar 1 09:10 sonar-scm-svn-plugin-1.9.0.1295.jar
-rw-r--r-- 1 sonarqube sonarqube 2239156 Mar 1 09:10 sonar-typescript-plugin-1.9.0.3766.jar
-rw-r--r-- 1 sonarqube sonarqube 3580236 Mar 1 09:10 sonar-vbnet-plugin-7.15.0.8572.jar
-rw-r--r-- 1 sonarqube sonarqube 2242738 Mar 1 09:10 sonar-xml-plugin-2.0.1.2020.jar
看到install pending后, 要點擊重啟服務(wù)器, 以便開始安裝



2.4 Sonar-Scanner安裝
Sonar-Scanner可以部署在單獨的服務(wù)器, 也可以部署在Jenkins服務(wù)器, Jenkins把代碼拉取到本地后, 直接通過Sonar-Scanner掃描
下載地址:https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/
官方文檔:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/
root@jenkins:/opt# ls
sonar-scanner-cli-4.5.0.2216-linux.zip
root@jenkins:~# unzip sonar-scanner-cli-4.5.0.2216-linux.zip -d /apps/
root@jenkins:/apps# ln -sv sonar-scanner-4.5.0.2216-linux/ sonar-scanner
root@jenkins:/apps# cd sonar-scanner
root@jenkins:/apps/sonar-scanner# vim conf/sonar-scanner.properties
#----- Default SonarQube server
sonar.host.url=http://10.0.0.139:9000
#----- Default source code encoding
sonar.sourceEncoding=UTF-8
2.5 利用官方提供的bug代碼進行掃描測試
https://github.com/SonarSource/sonar-scanning-examples
將示例代碼傳到Jenkins服務(wù)器
root@jenkins:~# cd /opt
root@jenkins:/opt# ls
sonar-scanning-examples-master.zip
root@jenkins:/opt# unzip sonar-scanning-examples-master.zip
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner# cd src/ # 代碼示例存放位置
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src# ll
total 80
drwxr-xr-x 20 root root 4096 Jun 24 16:41 ./
drwxr-xr-x 5 root root 4096 Jun 24 16:41 ../
drwxr-xr-x 2 root root 4096 Jun 24 16:41 abap/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 cobol/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 directory/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 erlang/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 flex/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 html/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 javascript/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 kotlin/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 package/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 php/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 pli/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 python/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 rpg/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 samples/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 sql/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 swift/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 vb6/
drwxr-xr-x 2 root root 4096 Jun 24 16:41 xml/
掃描php代碼, 每個代碼目錄都要有一個sonar-project.properties文件, 來指定項目名稱, 掃描代碼后會在sonarqube顯示
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# vim ../../sonar-project.properties
sonar.projectKey=org.sonarqube:sonarqube-scanner
sonar.projectName=Example of SonarQube Scanner Usage
sonar.projectVersion=1.0
sonar.sources=src,copybooks
sonar.sourceEncoding=UTF-8
## Cobol Specific Properties
# comma-separated paths to directories with copybooks
sonar.cobol.copy.directories=copybooks
# comma-separated list of suffixes
sonar.cobol.file.suffixes=cbl,cpy
sonar.cobol.copy.suffixes=cpy
## Flex Specific Properties
# retrieve code coverage data from the Cobertura report
sonar.flex.cobertura.reportPath=coverage-report/coverage-cobertua-flex.xml
# PL/I Specific Properties
sonar.pli.marginLeft=2
sonar.pli.marginRight=0
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# ll
total 16
drwxr-xr-x 2 root root 4096 Jun 24 16:41 ./
drwxr-xr-x 20 root root 4096 Jun 24 16:41 ../
-rw-r--r-- 1 root root 5559 Jun 24 16:41 Math.php
將sonar-project.properties文件拷貝到php目錄下, 做修改
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner# cp sonar-project.properties src/php/
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner# cd src/php
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# vim sonar-project.properties
sonar.projectKey=sonarqube-sample-php-projectKey
sonar.projectName=sonarqube-sample-php-projectName
sonar.projectVersion=1.0
sonar.sources=src # src目錄相對于php目錄, 因此, 在php目錄下還要創(chuàng)建src目錄, 存放php代碼
sonar.language=php
sonar.sourceEncoding=UTF-8
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# mkdir src
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# mv Math.php src/
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# ll
total 16
drwxr-xr-x 3 root root 4096 Jul 6 23:47 ./
drwxr-xr-x 20 root root 4096 Jun 24 16:41 ../
-rw-r--r-- 1 root root 172 Jul 6 23:47 sonar-project.properties
drwxr-xr-x 2 root root 4096 Jul 6 23:47 src/
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# ll src/
total 16
drwxr-xr-x 2 root root 4096 Jul 6 23:47 ./
drwxr-xr-x 3 root root 4096 Jul 6 23:47 ../
-rw-r--r-- 1 root root 5559 Jun 24 16:41 Math.php
在php目錄下執(zhí)行掃描命令
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# /apps/sonar-scanner/bin/sonar-scanner
...
INFO: ANALYSIS SUCCESSFUL, you can browse http://10.0.0.139:9000/dashboard?id=sonarqube-sample-php-projectKey
...
NFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 8.974s
INFO: Final Memory: 6M/24M
INFO:
- 查看結(jié)果


3 Gitlab+Jenkins+Sonarqube結(jié)合使用
讓Jenkins到Gitlab拉取代碼到本地, 之后使用SonarScanner進行代碼掃描, 然后傳到Sonarqube
3.1 通過Jenkins插件執(zhí)行代碼掃描
3.1.1 創(chuàng)建一個測試項目, 測試web-02項目克隆




3.1.2 Jenkins安裝插件

root@jenkins:/tmp# systemctl restart jenkins
3.1.3 在Jenkins上, 配置Sonarqube Server地址


3.1.4 在Jenkins上, 配置Sonarscanner的路徑


- 如果Jenkins服務(wù)器可以聯(lián)網(wǎng), 也可使用自動安裝, 這樣Jenkins會自動下載Scanner到本地, 如果不能上網(wǎng), 就要通過離線安裝包的方式
3.1.5 在Jenkins上, 配置項目構(gòu)建
選擇項目 --> 配置 --> 構(gòu)建 --> Execute SonarQube Scanner --> 將Analysis properties里的內(nèi)容填寫為代碼掃描的properties文件里的內(nèi)容

jenkins@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php$ vim sonar-project.properties
sonar.projectKey=sonarqube-sample-php-projectKey
sonar.projectName=sonarqube-sample-php-projectName
sonar.projectVersion=1.0
sonar.sources=src
sonar.language=php
sonar.sourceEncoding=UTF-8
本案例內(nèi)容
sonar.projectKey=project-web-02
sonar.projectName=project-web-02
sonar.projectVersion=1.0
sonar.sources=./ # 這里寫./表示當前目錄, 也就是相對于/var/lib/jenkins/workspace/test-scanner目錄, Scanner會掃描該目錄下的所有文件. 如果代碼放到了$WORKSPACE/src目錄, 那么這里就寫src
sonar.languagehtml # web-02里只有一個html文件
sonar.sourceEncoding=UTF-8
- 執(zhí)行構(gòu)建

- Sonarqube Server查看結(jié)果

3.2 通過腳本自定義代碼掃描
配置項目構(gòu)建時, 無需指定git倉庫, 也無需使用Scanner插件, 而是統(tǒng)一把流程定義在構(gòu)建的Shell腳本中.
先在Jenkins服務(wù)器上, 用Jenkins用戶運行腳本測試, 如果沒問題, 再把腳本保存的構(gòu)建的Shell腳本中
先用root用戶創(chuàng)建/data/jenkins/qq目錄, 然后授權(quán)給jenkins用戶
root@jenkins:~# mkdir -pv /data/jenkins/qq
root@jenkins:~# chown -R jenkins.jenkins /data/jenkins/
切換到j(luò)enkins用戶下, 創(chuàng)建腳本
jenkins@jenkins:/opt$ vim sonar.sh
#!/bin/bash
cd /data/jenkins/qq # 進到項目目錄
rm -rf * && git clone git@10.0.0.239:qq/web-02.git # 刪除舊的項目內(nèi)容, clone新的內(nèi)容
cd web-02 # 進到項目里面
cat >> sonar-project.properties <<EOF # 創(chuàng)建properties文件
sonar.projectKey=project-web-02-script
sonar.projectName=project-web-02-script
sonar.projectVersion=1.0
sonar.sources=./
sonar.languagehtml
sonar.sourceEncoding=UTF-8
EOF
/apps/sonar-scanner/bin/sonar-scanner # 開啟scanner, 會掃描當前目錄下所有的文件
INFO: Analysis total time: 3.226 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 3.916s
INFO: Final Memory: 12M/44M
INFO: ------------------------------------------------------------------------
測試沒問題, 保存到Jenkins配置

