昨天我們成功使用了SonarQube進行第一次的掃描。今天我們就讓SonarQube跟Jenkins整合到一起,使得每次的程式碼開發都會觸發一次掃描。這個做法可以使得程式碼中的問題盡快反映到SonarQube中,開發者就可以於技術債務還不算多的時候就光速進行處理。
昨天我們利用了一個NodeJS的範例程式進行了掃描,所以這次我們依舊使用同一個範例程式去做教學。
由於SonarQube在掃描的過程中需要運行NodeJS才可以成功進行,所以我們第一步要先讓Jenkins有能力運行NodeJS。為此我們必須先安裝一個Jenkins的插件。
首先,在左方的選單中按下Manage Jenkins
,進入設定的主畫面。
然後選擇Manage Plugins
。
選擇Available
的分頁。
然後在搜尋欄中輸入NodeJS
,然後勾選NodeJS的插件後按Install without restart
。當然你也可以重啟Jenkins。
安裝完成後,回到設定的主畫面。然後按下Global Tool Configuration
。
找到NodeJS的部份,然後按下Add NodeJS
。
在Name
中輸入NodeJS
,這個名字一會我們會用到。然後選擇你所需要的NodeJS版本。此次我們使用最新的NodeJS版本去運行我們的範例。輸入後以後,在最底的部份按下Save
儲存。
這樣我們就設定好了NodeJS的插件了!
這個設定的目的是讓我們的Jenkins Runner有能力運行如npm install
或是node
等指令。如果你使用多於一個Jenkins Runner的話,可以在有需要的Runner中安裝此插件。如果你使用的是Java,亦需要作類此的設定,本次系列不詳細說明了。
當準備好NodeJS的設定後,我們可以使用同樣的方法去安裝SonarQube的插件,使Jenkins有掃瞄程式碼的能力。
再次進入到Manage Plugins
的頁面中,然後在Available
的分頁入輸入SonarQube Scanner
,勾選插件然後按下Install without restart
。
然後我們需要設定SonarQube的服務器位址,以取得不同語言的掃描規則,以及上載掃描後的報告。
進入Jenkins的設定頁面,然後按下Configure System
。
找到SonarQube servers的部份,然後按下Add SonarQube
。
由於我使用本機架設的SonarQube,所以我在名稱中輸入Local
。然後輸入本機SonarQube的位址。如果不知道本機Docker架起的SonarQube的IP,可以用以下指令取得IP。
docker inspect {SonarQube Container Name} | grep "IPAddress"
{SonarQube Container Name}
: 換成你的SonarQube容器的名稱然後我們需要加入Jenkins連接到SonarQube時所使用的認證。在Server authentication token
的下拉選單下方,找到Add
的按鈕,然後按下Jenkins
。
在彈出的畫面中,Kind
的下拉選單中找到Secret text
,代表使用Token進行認證。在Secret
的欄位中,輸入我們昨天使用過的Token。然後在ID欄位中輸入LocalSonarQube
。然後按Add
。
回到上一個畫面後,在下拉選單中選擇新加的LocalSonarQube
,然後按Save
儲存。
設定了服務器後,我們需要為Jenkins設定掃描器。進入Jenkins的設定頁面,然後按下Global Tools Configuration
。然後找到SonarQube Scanner
的部份,按下Add SonarQube Scanner
。
在Name
的欄位中輸入CliScanner
,以後會用到。
由於我們使用NodeJS,所以我們不能直接使用Maven提供的Scanner。所以我們要使用CLI版本的Sonar Scanner。按下Add Installer
去新增一個新的Scanner。然後選擇Extract *.zip/*.tar.gz
,在URL一欄中,輸入SonarQube提供的CLI版Sonar Scanner下載連結(https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.7.0.2747-linux.zip)。
然後按下Save
儲存。
成功設定好SonarQube Scanner!
打開我們在Day 6的第一條Pipeline,然後我們開始設置意義上的第一個自動化流程。
打開我們在Day 6設置好的Jenkinsfile,把Hello
的Stage移除。然後在Stages中加入Code Scanning的 Stage。
pipeline {
agent any
stages {
stage('Code Scanning') {
}
}
}
由於我們使用CLI的Sonar Scanner,我們需要引用到Sonar Scanner的解壓縮工作位置。在Stage中加入以下的Environment(環境變數)。
pipeline {
agent any
stages {
stage('Code Scanning') {
environment {
scannerHome = tool 'CliScanner'
}
}
}
}
這裡其實是一個變數,讓scannerHome這個變數取得CliScanner
在Jenkins的工作位置。而CliScanner
就是上一個部份我們設定的Scanner插件時所填入的名稱。
然後再加入SonarQube Scanning的Step。
pipeline {
agent any
stages {
stage('Code Scanning') {
environment {
scannerHome = tool 'CliScanner'
}
steps {
withSonarQubeEnv('Local'){
}
}
}
}
}
這裡withSonarQubeEnv
是一個由SonarQube插件提供的block,後面的Local
是最初我們設定的服務器名稱。如果填入不同的名稱,可以讓我們選擇使用不同的SonarQube服務器。
然後中間的部份,我們先輸出Start Scanning…
,代表我們成功進入了這個block開始進行檢測的步驟。然後用sh
去執行SonarQube的Scanning。
pipeline {
agent any
stages {
stage('Code Scanning') {
environment {
scannerHome = tool 'CliScanner'
}
steps {
withSonarQubeEnv('Local'){
echo "Start Scanning..."
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
}
}
這裡可以看到sh
所執行的指令,就是引用scannerHome
這個變數的位置,然後取得當中的bin/sonar-scanner
並執行。
完成後我們把源碼commit到專案並上傳到remote的Git專案中,然後先執行一次Pipeline。我們先回到Jenkins中,按下Build Now
。
成功了!我們回到SonarQube看一下結果。
噫!跟想像中不太一樣。我們測試專案中應該有一些Bug存在的,但為甚麼這次檢測不到呢?
讓我們回到Jenkins中查看一下檢測過程。
在左方的Build History
中找到最後的Pipeline執行結果。
然後在左方按下Console Output
。
仔細查看後,發現原來SonarQube執行檢測的過程中,由於缺少了NodeJS的功能,因此未能成功掃描專案。這個問題很容易解決,還記得最初我們已經設定了NodeJS的執行環境嗎?是時候派上用場了!
讓我們回到Jenkinsfile中,然後在withSonarQubeEnv
的block中加入NodeJS的block。
pipeline {
agent any
stages {
stage('Code Scanning') {
environment {
scannerHome = tool 'CliScanner'
}
steps {
withSonarQubeEnv('Local'){
nodejs(nodeJSInstallationName: 'NodeJS') {
echo "Start Scanning..."
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
}
}
}
nodeJSInstallationName
: 最初設定的NodeJS環境的名稱然後再commit、上傳、執行。
跑完Pipeline後回到SonarQube。
耶!錯誤都回來了!(明明有Bug不知道是在興奮甚麼…)
就是這樣,我們成功使用了第一個靜態測試軟體,並且整合到了我們的Pipeline中。其實這裡我們可以再加入Quality Gates的概念到Pipeline中,使得當我們掃描結果不理想的時候中斷後續的步驟。但由於篇幅的關係,這裡就留待大家自己按需要去發掘Jenkins的更多功能了。
其他軟體的整合方式其實都是大同小異,當加入更多的Stage在Pipeline以後,每次自動化就會報行更多的自動化的操作。接下來就讓我們一起為這條Pipeline加入更多的功能吧!
SonarQube真的挺好的一套軟體,免費版本除了支援不少語言外,近來還加入了CloudFormation跟Terraform的掃描。基本上我之前參與的項目中,每一條Pipeline都一定有這個軟體的存在,所以這幾天多講了一點相關的內容。希望這幾天的介紹對大家有所幫助啦!