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