前言
sonar文档:docs.sonarqube.org/latest/arch…
这篇文章主要讲的是iOS大工程接入SonarQube平台(主要是静态分析,依赖OCLint)及持续集成的大致流程和遇到的坑。sonar平台的搭建在此不再赘述,大家可以网上搜索下。(最新的版本,有jdk,mysql的前提下,下载直接运行脚本就可以把服务启动起来,很方便)
总览及准备工作
先放两张图,通过这两张图大家基本可以对SonarQube及iOS工程接入有个大概了解
准备工作
我们需要的:xcodebuild
,xcpretty
,oclint
,sonar-project.properties
,sonar-scanner
,oc的非官方插件
。
- xcpretty [增加xcodebuild输出的可读性]:github.com/xcpretty/xc… ,
gem install xcpretty
直接安装 - oclint [静态分析工具]:github.com/oclint/ocli… 直接下载可执行文件最方便
- sonar-project.properties:sonar-scanner扫描必要的配置文件。(下面提供示例)
- sonar-scanner:docs.sonarqube.org/latest/anal…
- 插件
github.com/Backelite/s… 使用mvn编译完生成jar,放到sonarQube对应的插件目录下。 这个项目还提供了一个
run-sonar.sh
的脚本,不需要打xcodebuild
,oclint
这些命令,都集成到这个脚本里,一键完成上传。这个项目的sonar-objc版本已不再维护。
以下提供几个示例或命令:
xcodebuild+xcpretty:
xcodebuild -workspace xxx -project xxx -scheme xxx -configure Debug | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json
oclint:
oclint-json-compilation-database -- -report-type pmd -o oclint.xml -e Pods -max-priority-1 100000 -max-priority-2 100000 -max-priority-3 100000
sonar-project.properties:
#sonarServer地址 (这两行sonarServer管理员会提供)
sonar.host.url=http://sonar.xxx.com:9000
sonar.login=adasdadadadadadad
# Sonar项目标识,在 SonarQube实例下必须唯一
sonar.projectKey=ObjcTest2
# 在 SonarQube UI 中显示的项目名称
sonar.projectName=ObjcDoc2
# 项目版本
sonar.projectVersion=1.0
# 项目代码与 sonar-project.properties 文件的相对路径
sonar.sources=SonarTestProject
# 代码文件的编码
sonar.sourceEncoding=UTF-8
# 排除不参与代码分析的文件或目录
sonar.exclusions=node_modules/**/*,.idea/**/*
sonar.language=objc
sonar.objectivec.workspace=SonarTestProject.xcworkspace
sonar.objectivec.project=SonarTestProject.xcodeproj
sonar.objectivec.appScheme=SonarTestProject
sonar.objectivec.simulator=platform=iOS Simulator,name=iPhone 8,OS=latest
#这里需要注意,特别是oc,cpp混编的工程,下面一章节会讲到
sonar.cxx.suffixes.headers=-
sonar.c.suffixes.headers=-
sonar.c.suffixes.sources=-
#这步针对sonar-scanner 4.2没啥作用,下一章会讲到
#sonar.objectivec.oclint.report=oclint.xml
sonar-scanner
在工程目录下,直接运行sonar-scanner
即可(记得增加环境变量)
一步步走下来,开始我们升级打怪阶段。
遇到的问题
** 1. sonarQube有对应的项目,但是显示 the main branch of this project is empty
**
这里需要安装插件,原本我以为插件是对sonarQube的扩展,装不装插件和功能丰富度有关,但是针对oc项目静态分析必须安装插件。官方有收费的插件,比较贵。所以我们用开源的插件。而且sonarQube社区版是不支持oc的静态分析的。
** 2.sonar-scanner执行成功,oclint.xml也包含对应的错误,sonarQube显示全是0或者数量有误**
2.1 sonar-scanner扫描的时候回去当前工程下的sonar-reports文档中扫描,需要创建文件夹并复制进去,错误信息才能被真正上传。(参考的文章中说道在sonar-project.properties中配置sonar.objectivec.oclint.report=oclint.xml,试了几次没效果。sonar-scanner 4.2;后面是了插件提供的run-sonar.sh
脚本成功)
2.2 oclint.xml中的错误不包含在oclint规则库中。默认规则库可以在sonarQube平台上看到或者在oclint规则文档中看。
** 3.sonar-scanner扫描的时候可能遇到 Language of file can’t be decided (default language patterns sonar.lang.patterns.c and sonar.lang.patterns.c++)
**
混编的工程中,可能有.c,.h后面谁的文件,在同一个工程中,无法被认定为两种以上类型的语言。所以在上一节的文章中提到的,sonar-project.properties
中c,c++的文件设置置为空。
sonar.cxx.suffixes.headers=-
sonar.c.suffixes.headers=-
sonar.c.suffixes.sources=-
参考:community.sonarsource.com/t/language-…
** 4. oclint argument list too long**
在大工程,文件特别多,产生的compiler_commands.json
文件也会特别大,导致oclint报错。解决方案:github.com/wuwen1030/o…
原理:compiler_commands.json
分片成compiler_commands01.json
,compiler_commands02.json
,compiler_commands03.json
... 分别进行oclint处理(这里有一步特别重要,需要将处理的compiler_commands%d.json重命名为compiler_commands,因为oclint只认compiler_commands,相当于这个参数oclint是写死的)生成oclint01.xml
,oclint02.xml
,oclint03.xml
...,最后把以上xml合并为最终的oclint.xml
** 5.分析时间过长**
我们的工程有4个G,产生的compile_commands会有70M,oclint分析的时间会达到一个小时左右。CI过程会非常频繁,接入集群的Mac机器非常少,资源有限,1个小时的处理时间肯定是不允许的。我们的主要处理方案是:对compile_commands.json
进行瘦身。
5.1. xcodebuild阶段:配置和-destination,不然会处理多个多个架构,导致compile_commands翻倍。
**5.2. 有针对性的静态分析:**既然sonar-scanner可以指定文件夹上传,是不是可以指定文件夹进行oclint,这样在集成到CI流程中也有个非常好的对应。既然compile_commands.json
是json
文件,那我们就对compile_commands.json
的数据进行删减,只匹配我们需要的文件。
[{
"directory":"",
"command":"/Application/xxxxx/clang -x objective-c -target ... ",可以看到主要是clang干了活
"file":""
},
...]
直接对file或者directory进行处理就好了,需要的进行保留。最后oclint的时间大大缩减,指定了某个模块的代码,时间从原来的一小时锐减到几分钟。
TODO
- 自定义规则,需要自己写oclint的规则。
- compiler error,这个规则没有在规则库中,认为这个在开发的过程中编译错误就应该被解决掉,所以没加到库中。个人觉得这个信息特别有用,特别是一些类型错误,这些不算编译错误,不一定会产生错误,但是隐患非常大。希望能在项目中体现。
- 增量分析,针对我们的大规模工程,增量分析减少分析时间是很有必要的。可以采用5.2的方式,但是这样不够完美。因为这样会覆盖之前的分析结果。考虑到的方案是,先全局静态分析拿到基准oclint.xml. 然后增量分析采用5.2方式,最后替换掉oclint.xml中对应文件的分析结果。