sonrqube版本6.7.7
關於jenkins和sonarqube的安裝不在本博客中詳細講解,可參考我的其他博客:
https://www.cnblogs.com/zndxall/p/9336879.html (jenkins集成soanrqube)
https://www.cnblogs.com/zndxall/p/12095769.html (linux上sonar的安裝和總結)
soanrqube插件很多在應用市場是下載不了的,同樣給出了下載插件的博客:https://www.cnblogs.com/zndxall/p/13534244.html
這是我使用到的插件以及版本(sonarqube-6.7.7/extensions/plugins下):
另外,如果啟動sonarqube的時候報錯jdbc鏈接失敗,你可以會用到下面這個jar:mysql-connector-java-5.1.42.jar 放 在sonarqube-6.7.7/lib/jdbc/mysql路徑下
由於公司代碼倉比較多,涉及到java,js,go,c++,objectivec,不想一個工程一個工程的配置soanrqube,所以打算寫個腳本,根據傳入參數來掃描涉及到的這些語言:
第二個掃C++的,第三個掃objectivec的,第一個和最后一個掃java,go,js的,如下sonar_Ios的工程如下:
設置了掃描倉庫和分支,以及是要執行掃描(run),還是要獲取掃描結果(result),其他工程的配置是一樣的,區別只是倉庫名。
shell腳本調用如下:
參數1: 是run執行掃描,result是獲取掃描結果 ; 參數2是倉庫名,參數3是掃描語言,參數4是掃描分支
如果不知道掃描語言具體怎么寫,可以使用sonarqube-api查詢喲,命令是:
curl http://服務器ip地址:9000/api/languages/list 比如我的返回如下:
表明我的sonarqube支持掃描的語言有這些,其中的‘key’值就是語言的”字符串“
具體的sonarqube api可以查詢http://服務器ip地址:9000/web_api,或者直接從sonarqube界面最下面點擊跳轉:
下面詳細介紹各語言的掃描,除了sonarqube的界面配置,其他以下語言掃描描述都寫入了sonar_scan.sh腳本,這樣可以提交入庫,查看修改記錄,不然哪天改了掃不出來都不知道為啥,原來是啥也不記得。
關於sonar-project.properties的內容,我是根據不同工程的配置在shell中使用echo寫入的,不需要一個工程一個sonar-project.properties存起來,麻煩。
1.掃描java語言:
效果圖:
這是最好配置的了,很簡單,只需要設置下掃描語言就可以了,sonar-project.properties如下設置:
sonar.projectKey=sonar_test_java sonar.projectName=sonar_test_java sonar.projectVersion=1.0.0 sonar.sourceEncoding=UTF-8 sonar.language=java #掃描語言 sonar.java.binaries=./ sonar.sources=./ #掃描所有代碼,如果你需要指定目錄的話 換成目錄即可,比如test1
然后在sonar-project.properties的同級目錄下執行sonar-runner即可,稍后就能在sonarqube服務器上看到掃描結果。
2.掃描js語言
效果圖:
sonar.projectKey=sonar_test_js sonar.projectName=sonar_test_js sonar.projectVersion=1.0.0 sonar.sourceEncoding=UTF-8 sonar.language=js sonar.java.binaries=./ sonar.sources=./
很明顯,區別只是把語言換成了js
然后在sonar-project.properties的同級目錄下執行sonar-runner即可,稍后就能在sonarqube服務器上看到掃描結果。
3.掃描go
和上面的java和js是一樣的,把語言換成go就可以了
效果圖:
4.掃描C/C++
效果圖:
這個花費了我很久的時間,首先是插件問題,最新的1.3.2插件不要用,不然默認規則數是0,掃不出來,因為我看插件網站上https://github.com/SonarOpenCommunity/sonar-cxx/releases
的解釋是這個版本的插件激活的規則太多了,所以默認規則是關閉的,
需要你自己復制一個版本,然后按照自己的規則,激活你想要的已有的資源庫的規則。如下:
點擊“Ensure that a rule is enabled”
我使用的是1.3.0版本的。
還有一點,我以為我掃描出來的bug和漏洞都是0是因為我插件不兼容導致的,因為我看到了上面的兼容性表,發現只有0.9.5和0.9.1和sonarqube 6.7.*系列兼容,但是使用這兩個版本,
我連sonarqube都起不來了,web.log報錯就是報加載c++插件失敗,詳細的報錯是一個類找不到,我呵呵了,不用這兩個版本,那沒版本了呀,要不我再裝一個7.9TLS的版本的,結果啟動的
時候,告訴我不在支持mysql,O!M!G! 果斷放棄了7.9系列的。接下來就解密下我為什么c++一直掃出來的bug和漏洞都是0吧?可是我單獨執行cppcheck分明bug不為0啊!
是因為我沒有實現執行cppcheck
下面的這一段話提醒了我:
sonar-project.properties 配置如下: sonar.projectKey=sonar_test_c sonar.projectName=sonar_test_c sonar.projectVersion=1.0.0 sonar.sourceEncoding=UTF-8 sonar.language=c++ sonar.sources=dir1,dir2,dir3 #多個目錄用逗號隔開,比如dir1,dir2,dir3,所有使用./ sonar.cxx.cppcheck.reportPath=cppcheck-result.xml sonar.cxx.suffixes.sources=cpp
然后在
sonar-project.properties相同目錄下執行如下幾條腳本:
if [ "$scan_lan" == "c++" ];then #掃描C++語言,需要先執行cppcheck 生成報告,然后執行sonar-runner將結果上傳到sonarqube上
scan_dir="`cat sonar-project.properties | grep sonar.sources |awk -F "=" '{print $2}' | sed 's/,/ /g'`"
echo scan_dir=$scan_dir
[ "x$scan_dir" == "x" ] && echo not find sonar.sources && exit 1
[ -f cppcheck-result.xml ] && echo rm cppcheck-result.xml && rm -f cppcheck-result.xml
echo cppcheck -q -j 8 --enable=warning --inconclusive --xml --xml-version=2 \"$scan_dir\" #默認是enable=error的,添加其他是追加
cppcheck -q -j 8 --enable=warning --inconclusive --xml --xml-version=2 \"$scan_dir\" 2> cppcheck-result.xml #重點是這條,cppchek掃描sonar- project.properties中配置的sonar.sources指定的目錄
error_msg="cppcheck: error: could not find or open any of the paths given"
error_flag=`grep "$error_msg" cppcheck-result.xml`
[ "x$error_msg" == "x" ] && echo $error_msg && echo cppcheck failed && exit 1
fi
相同目錄下執行sonar-runner將掃描結果cppcheck-result.xm上傳到sonarqube上。
另外sonarqube上關於掃描報告需要配置下:
然后就可以在sonarqube上看到bug不是0的掃描結果了。
5.掃描ios的objectivec
這個就有點復雜了,不單純是sonar-runner,還要執行編譯,和生成oclint報告
效果圖:
先看看sonar-project.properties的配置:
sonar.projectKey=sonar_test_objectivec sonar.projectName=sonar_test_objectivec sonar.projectVersion=1.0.0 sonar.sourceEncoding=UTF-8 sonar.language=objectivec sonar.objectivec.project=HPtest.xcodeproj sonar.objectivec.appScheme=HPOff sonar.sources=./ sonar.objectivec.oclint.report=oclint.xml
然后在相同目錄下執行:
(1)當是workspace的時候
xcodebuild clean -workspace "$bscheme".xcworkspace -scheme "$bscheme" -configuration Release
xcodebuild archive -workspace "$bscheme".xcworkspace -scheme "$bscheme" -archivePath arch/"$bscheme".xcarchive -configuration Release | tee xcodebuild.log | xcpretty -r json-compilation-database --output compile_commands.json
(2)但是project的時候
xcodebuild clean -project "$bscheme".xcodeproj -scheme "$bscheme" -configuration Release
xcodebuild build -project "$bscheme".xcodeproj -scheme "$bscheme" -configuration Release | tee xcodebuild.log | xcpretty -r json-compilation-database --output compile_commands.json
以上(1)(2)是兩種不一樣的代碼倉庫結構配置,根據自己的代碼選擇一直即可。$bscheme是你的工程名或者scheme的名字,因為我的都是一樣的,所以我引用了相同的變量。
命令執行結束以后會在當前目錄下生成一個compile_commands.json。
然后相同目錄下執行:
oclint-json-compilation-database -- -max-priority-1 10000 -max-priority-2 10000 -max-priority-3 10000 -extra-arg=-Wno-everything -rc LONG_LINE=150 -report-type pmd -o oclint.xml
要等一段時間,會輸出類似下面的東東:
然后最后會生成一個oclint.xml 的掃描報告文件,如果你想生成html的, 把上面的oclint-json-compilation-database命令后面換成-report-type html就可以了。
再在同一目錄下執行sonar-runner把這個oclint.xml的掃描報告上傳到sonarqube服務器上,此外sonarqube服務器液壓配置objective-c下這個掃描報告的名字,如下:
這樣,就可以掃描objectivec了。
另外,由於我的jenkins采用的是分布式的方式,也就是說用master-slaver的方式,master是centos的,負責執行一部分linux任何和下發任務到各個slave機器上,比如這樣的:
master jenkins 控制了各個slave,可以根據不同的編譯環境下發不同的編譯任務,關於如何配置這種master-slave的jenkins,如果有需要的話,請參考我的另外的博客:https://www.cnblogs.com/zndxall/p/8297356.html
很明顯,這里我們需要處理的是ios、mac的代碼,那么我們執行上面的xcodebuild命令肯定是在上面截圖的“Ios-mac”的mac機器上執行,這就涉及到環境變量的問題了,我們用到的xcpretty,sonar-runner,oclint-json-compilation-database ,要加到環境變量中,然后jenkins調用腳本時要先source下,比如我把他們的環境變量加到了我的~/.bashrc文件中,如下:
olcint-json-compilation-database在bin中,xcpretty在截圖的ruby那個路徑下,還加了sonar-runner到環境變量中,如果你不知道他們在哪,執行which 后解命令,比如which xcpretty 就可以找到他們在哪,一般環境變量只需要到bin層就夠了。
加號以后,在shell腳本中要source下才能生效,即source ~/.bashrc,這段如下:
這里要說一下為什么掃描出來的bug總是0,只有壞味道,原因如下:
這里的一個bug的規則描述看一下:
掃描出的bug一直是0的原因:代碼規則中只有一個bug的規則,其他都是壞味道,這一個bug還是關於單元測試的,就是說如果你的單元測試沒過,才算觸發了這條規則,如果你都沒有單元測試,那你的掃描結果中bug為0,其他都是壞味道,就說的通了。你可以嘗試激活更多規則來看看會不會有更多關於bug的規則,目前我沒有嘗試。
報錯處理:
1.ERROR: Caused by: The rule 'OCLint:compiler warning' does not exist.
解決:加“-extra-arg=-Wno-everything”,如下:
oclint-json-compilation-database -- -max-priority-1 10000-max-priority-2 10000 -max-priority-3 10000 -extra-arg=-Wno-everything -rc LONG_LINE=150 -report-type pmd -o oclint.xml
2.ERROR: Caused by: The rule 'OCLint:compiler error' does not exist
解決:看描述是這條規則不存在,但是查資料沒查到如何禁用這條規則,也沒查到如何加這條規則,詳細的規則是類似如下這樣的:
rule="compiler error" ruleset="clang",但是他掃描到oclint.xml文件中了,沒辦法,只能刪掉他了,但是看上面的截圖可以,應該把整個<file></file>節點刪掉,而不是只刪除匹配的這一行,因為他關聯了好幾行,如果只刪這一條,依然后sonar-runner失敗,所以我寫了一個函數來專門刪除這個規則,放在oclint-json-comilation-database后,即下面截圖的del_clang
del_clang函數的詳細腳本如下:
function del_clang() { grep -rn "rule=\"compiler error\"" oclint.xml | awk -F ":" '{print $2}' > clang_lines lnsum=`cat clang_lines |wc -l` for ((i=1;i<=$lnsum;i++)) #循環次數 do cls=`grep -rn "rule=\"compiler error\"" oclint.xml | awk -F ":" '{print $2}' |sed -n 1p` #因為刪除過程中行號會變化,所以要動態獲取 cl1=`expr $cls - 1` #獲取匹配上的上一行行號 cl2=`expr $cls + 3` #獲取匹配上的下三行行號 sed -i "" $cl1,"$cl2"d oclint.xml #刪除匹配行的從上一行到下三行的內容,比如匹配了第3行,那么就使用就刪除第2行到第6行 done clang_flag=`grep "rule=\"compiler error\"" oclint.xml` [ "x$clang_flag" != "x" ] && echo also have clang compiler error, this rule not exist && exit 1 #刪除后還要匹配行,表示刪除失敗 #sed -i "" 3'b\'"<pmd version=\"oclint-0.13\">" oclint.xml #在第三行前插入這個 因為前面的刪除會把這行刪掉(這里在mac上執行一直失敗,所以用下面色sed -n 那幾行代替) sed -n 1p oclint.xml > oclint_bak.xml #顯示第一行重定向到新文件 echo "<pmd version=\"oclint-0.13\">" >> oclint_bak.xml #寫入pmd版本這一行到新文件(如果不加這一行,不僅bug漏洞為0,壞味道也會為0) sed -n '3,$p' oclint.xml >> oclint_bak.xml #顯示第三行以及后面全部到新文件中 rm -f oclint.xml mv oclint_bak.xml oclint.xml #重命名新文件 sed -i "" '/^\s*$/d' oclint.xml #刪除文件中的空行 }
其中,上面紅色的加粗這行很重要,執行del_clang函數之前,打開oclint.xml你就明白了,
因為第一個匹配的file行包含了<pmd version="oclint-0.13">,執行首次執行sed -i "" $cl1,"$cl2"d oclint.xml 會把行刪掉,所以后面要追加進去,否則bug,漏洞,壞味道都全部為0.
3.log日志報錯:Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (4522715 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.
解決:https://www.cnblogs.com/zndxall/p/13531151.html
4. The size of BLOB/TEXT data inserted in one transaction is greater than 10% of redo log size. Increase the redo log size using innodb_log_file_size
解決:在/etc/my.cnf中加上(大小根據自己的時間情況調整),添加以后記得重啟數據庫( systemctl restart mysqld),然后記得還要重啟sonarqube(記得不能使用root用戶啟動喲,切換到普通用戶才能啟動成功)
max_allowed_packet = 64M
innodb_log_file_size=640M
5.oclint: error: Cannot change dictionary into "/Users/xxxx/Classes/Files\(文件\)/Libs/Core/WebSocket.m", please make sure the directory exists and you have permission to access!
解決:這個報錯是因為路徑中含有中文,把路徑中的中文改成英文就可以了。(因為我換了掃描一個英文文件夾就正常了,使用-i 指定)
(oclint-json-compilation-database -i Classes/AppsModule -- -max-priority-1 10000 -max-priority-2 10000 -max-priority-3 10000 -extra-arg=-Wno-everything -rc LONG_LINE=150 -report-type pmd -o oclint.xml -i 指定要掃描的目錄)
參考:
http://www.uml.org.cn/jchgj/201808103.asp?artid=21046?weiid=2390