持續檢查 Java 程式碼品質

SonarQube 是一套 程式碼品質檢查工具,可以幫我們檢查 code 的 bugs、 vulenrability、code smell 與 duplication,也屬於 持續整合 重要的一環。

SonarQube 已經內建 SonarJava,可以直接對 Java 進行檢查,本文將以 Java + Gradle 為例,並在 Eclipse 中使用 SonarLint 對 Java 專案進行檢查。

Version


macOS High Sierra 10.13.4
SonarQube 7.1
SonarQube Scanner 3.1.0.1141
Eclipse Oxygen.3a (4.7 3a)
Java SE 1.8.0_171

GitHub


java000

  1. 本文將 Java 專案放在 https://github.com/oomusou/javasonarqube

Gradle

安裝 Gradle

1
$ brew install gradle

Gradle 類似 JavaScript 世界的 Webpack,負責整個專案的編譯管理,使用 Homebrew 安裝。

專案初始化

1
~/MyProject $gradle init --type java-application

下載範例後,進入專案目錄,使用 Gradle 對專案初始化。

java001

建置專案

1
~/MyProject $ ./gradlew build

使用 Gradle 第一次 build 專案。

java002

Eclipse


安裝 Plugin

java003

Help -> Eclipse Marketplace…

java004

請安裝以下兩個套件:

  1. Buildship Gradle Integration 2.0:在 Eclipse 使用 Gradle 建置專案
  2. SonarLint 3.5:讓 Eclipse 能即時執行 SonarQube 檢查

匯入專案

java005

File -> Import

java006

  1. 選擇 Gradle -> Existing Gradle Project
  2. Next 繼續

java007

  1. 選擇專案目錄
  2. Next 繼續

java008

  1. Finish 結束

新增 SonarQube Plugin

build.gradle

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
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/4.7/userguide/tutorial_java_projects.html
*/


plugins {
// Apply the java plugin to add support for Java
id 'java'

// Gradle plugin to help analyzing projects with SonarQube
id 'org.sonarqube' version '2.6.2'

// Apply the application plugin to add support for building an application
id 'application'
}

// Define the main class for the application
mainClassName = 'App'

dependencies {
// This dependency is found on compile classpath of this component and consumers.
compile 'com.google.guava:guava:23.0'

// Use JUnit test framework
testCompile 'junit:junit:4.12'
}

// In this section you declare where to find the dependencies of your project
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}

13 行

1
2
// Gradle plugin to help analyzing projects with SonarQube
id 'org.sonarqube' version '2.6.2'

在 Gradle 新增 SonarQube plugin,將來可透過 Gradle 執行 SonarQube。

java009

  1. 開啟 build.gradle 檔案
  2. 新增 SonarQube plugin

建置專案

java010

  1. 右側 Gradle Tasks
  2. build 展開,執行 build
  3. 在 Console 出現 BUILD SUCCESSFUL 表示建置成功

目前為止,Gradle 在 Eclipse 已經正常執行,接下來要設定 SonarQube

SonarQube


安裝 SonarQube

1
$ brew install sonarqube

使用 Homebrew 安裝 SonarQube。

啟動 SonarQube

1
$ sonar console

使用 sonar console 自行啟動 SonarQube。

java011

測試 SonarQube

java012

  1. 輸入 localhost:9000,若看到 SonarQube 首頁,則表示安裝成功
  2. 右上角 Log in 可登入管理設定 SonarQube,預設為 admin/admin

SonarQube Scanner


SonarQube 雖然已經包含 SonarJava,但必須靠 SonarQube Scanner 才能執行,預設 SonarQube 並沒有包含 Scanner,必須自行安裝。

安裝 SonarQube Scanner

1
$ brew install sonar-scanner

設定 SonarQube Server

sonar-scanner.properties

1
2
3
4
5
6
7
8
#Configure here general information about the environment, such as SonarQube server connection details for example
#No information about specific project should appear here

#----- Default SonarQube server
sonar.host.url=http://localhost:9000

#----- Default source code encoding
#sonar.sourceEncoding=UTF-8

將第 5 行的 # 拿掉,設定 SonarQube server 的 URL 位址。

java013

  1. 將目錄移到 /usr/local/Cellar/sonar-scanner/3.1.0.1141/libexec/conf
  2. 開啟 sonar-scanner.properties
  3. 使用 vim 開啟 sonar-scanner.properties

java014

  1. 設定 SonarQube server

測試 SonarQube Scanner

1
~/MyProject $ gradle sonarqube

使用 Gradle 執行 SonarQube 檢查。

java015

SonarQube 顯示結果

java016

進入 SonarQube 網頁,就可看到 JavaSonarQube 專案已經出現 SonarQube。

目前為止,SonarQube 已經可以正常透過 Gradle 執行,實務上可以透過 Jenkins 執行 Gradle,就可透過 CI 自動執行 SonarQube,但這種方式較被動,若發現有任何 issue,還要開 ticket 要求修改,一來一回可能好幾天,若能在開發階段就即時 SonarQube 檢查,就能「及早發現,及早治療」。

SonarLint


java017

在 Code Smell 部分,SonarQube 已經檢查出:

  • Move this file to a named package
  • Remove this method and declare a constant for this variable
  • Replace this use of System.out or System.err by a logger

若能在 Eclipse 也能顯示這些警告訊息,那就太好了。

連接 SonarQube Server

java018

  1. 選擇專案按滑鼠右鍵
  2. 選擇 SonarLint
  3. 選擇 Bind to a SonarQube project…

java019

  1. Connect to a SonarQube server…

java020

  1. 選擇 sonarqube
  2. Next 繼續

java021

  1. 輸入 SonarQube server 網址
  2. Next 繼續

java022

  1. 選擇 Username + Password
  2. Next 繼續

java023

  1. 輸入 SonarQube 帳號與密碼
  2. Next 繼續

java024

  1. 輸入 connection 名稱
  2. Next 繼續

java025

  1. Finish 完成設定

java026

  1. 是否要 Eclipse 提供 Password hint,選 NoYes 都可以

java027

  1. Finish 完成連接 SonarQube server 動作

java028

  1. 顯示 SonarQube 連線正常

執行 SonarQube 檢查

java029

  1. 選擇專案按滑鼠右鍵
  2. 選擇 SonarLint
  3. 選擇 Analyze

java030

  1. 下方顯示了與 SonarQube 網頁完全相同的警告,因此 developer 在開發階段,就可以完全獲得 SonarQube 的支援

java031

  1. 在 editor 也會即時警告
  2. 將滑鼠放在警告之上,也會顯示與 SonarQube 相同的警告訊息

java032

  1. 點選 SonarLint Rule Description,會顯示該警告更詳細的解釋,甚至還有範例說明

Conclusion


  • 我對 Java 與 Gradle 完全不熟,本篇要感謝 Carl Su 的友情幫助,才能在 Eclipse 順利執行 SonarLint
  • 有了 SonarLint,developer 就能更即時的獲得 SonarQube 的建議,養成寫出 clean code 的好習慣

Sample Code


完整的範例可以在我的 GitHub 上找到

Appendix


JAVA_HOME
~/.bash_profile

1
export JAVA_HOME=$(/usr/libexec/java_home)

這裡在執行 Gradle 時遇到一個雷,由於 Gradle 與 Eclipse 都會依賴系統變數 $JAVA_HOME,必須在 bash_profile 設定 $JAVA_HOME 才會讓 Gradle 與 Eclipse 順利抓到,而不能只設定在 .zshrc ,所以不要覺得在 iTerm 2 能 echo $JAVA_HOME 就沒事,畢竟 Gradle 與 Eclipse 不是吃 .zshrc,而是吃 .bash_profile

2018-05-17