本文系列将介绍Sonar在实际工程项目中落地的场景,例如: 1)多语言项目的扫描,如JAVA/JS/C /C#/PLSQL 2)多分支扫描 3)覆盖率如何统计 等等。 不在讨论范围内的问题 1)自定义扫描规则? 2)扫出来的问题,怎么让开发及时修复? 本文作为开篇,将介绍 1)Sonar Scanner的工作机制, 2)Java项目中利用 Maven的Sonar Scanner 插件进行扫描的配置和步骤 3)使用Token,多Module项目扫描和忽略等一些实际问题。
与Jenkins不同的工作机制
与Jenkins类似,SonarQube也是一个C/S架构的服务。根据其官网所述,是以下的一个架构。 包括了:
- SonarQube服务端:
主要包括以下三部分
- Web服务器
- 搜索引擎-Elasticsearch to back searches from the UI
- 后台计算服务-连接数据库
- 后台数据库:
- SonarQube实例的配置信息,如安全、插件等
- 项目、视图的质量快照数据
- SonarQube Plugin 安装在服务端的插件,例如语言包、SCM、认证、治理等等
- SonarScanner 在构建和持续集成服务器上执行并分析项目
image.png
这其中Sonar Scanner是本文所要介绍的主角。通过上述架构图中的数据流转方向,我们可以了解到Sonar和Jenkins的一个很大的不同。也就是Sonar中的客户端(Scanner)只负责数据的上报,它可以自行触发扫描,并不接受来自服务端的指令,不像Jenkins的Agent受到服务端的任务触发后才会执行。笔者在设计测试用例管理系统时,也参考了类似这样的架构,让测试用例执行的起点由客户端自行控制,只要将最终结果汇报上来即可。
解决方案一览
在公司的产品线中,既有核心的实时类C/C 程序,也有传统的C#前台 SP后台的遗留系统。目前也正在实现微服务转型,JAVA和前端JS类项目也日益多了起来。因此,我们的SonarQube质量检测服务,需要支持上述所有的类型。而根据Sonar官方提供的方案,需要用到如下的Scanner 在实践中也发现,Sonar Scanner以同一次扫描结果作为一个SonarQube Project的范围。即使指定了相同的Project Key,不同扫描器的扫描结果只会互相覆盖。因此,由于扫描器的不同,一个包含了C#、C 和PLSQL的项目,很不幸需要被三个扫描器各自扫描一次,同时生成三个SonarQube project来呈现扫描结果。 本文将分别介绍上述语言的项目中,如何利用Scanner来进行扫描。
image.png
JAVA类的项目
假设项目中使用的是Maven作为构建工具。配套的,我们通过SonarQube官方提供的SonarQube Scanner for Maven这个插件来进行代码的扫描,如果还要得到单元测试和代码覆盖率报告,那么还需要使用Maven Surefire插件以及Jacoco这样的覆盖率统计工具。 接下来逐一介绍下。
1、指定SonarQube服务器地址和口令
整个方案的基础是,让Maven中的Sonar Scanner插件能知道SonarQube服务器和登录口令。修改maven配置文件MAVEN_HOME/conf/settings.xml或者 ~/.m2/settings.xml。文件的访问顺序是:~/.m2/settings.xml优先,若无此文件,maven自动去读MAVEN_HOME/conf/settings.xml
代码语言:javascript复制 <profiles>
<profile>
<id>sonar</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonar.host.url>http://IP:PORT </sonar.host.url>
<sonar.login>TOKEN </sonar.login>
</properties>
</profile>
</profiles>
另外,配置了sonar.login使用TOKEN后,不要再配置sonar.password了,不然sonar scanner会将token作为用户名去登录,导致用户名密码不匹配登陆失败。Token产生,可以参见SonarQube使用说明。需要注意的是,这个token的生成是被设计为“阅后即焚”的。在SonarQube页面上生成并关闭后,再也无法看到了,需要注意保存,否则只能再次生成了。
2、引入指定Sonar Scanner for Maven的Maven插件
方法一(推荐):修改工程的pom.xml。
代码语言:javascript复制 <build>
<pluginManagement>
<plugins>
......
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
</plugin>
</plugins>
</pluginManagement>
</build>
方法二:修改maven配置文件MAVEN_HOME/conf/settings.xml 或者 ~/.m2/settings.xml。(~/.m2/settings.xml优先,若无此文件,maven自动去读MAVEN_HOME/conf/settings.xml )
代码语言:javascript复制 <pluginGroups>
<pluginGroup>org.sonarsource.scanner.maven</pluginGroup>
</pluginGroups>
3、配置单元测试执行报告的路径
配置单元测试执行报告的路径,修改最外层pom.xml 场景一:单个module工程
代码语言:javascript复制 <properties>
.......
<sonar.jacoco.reportPaths>
${project.basedir}/target/jacoco.exec
</sonar.jacoco.reportPaths>
</properties>
场景二:多个modules工程
代码语言:javascript复制 <properties>
.......
<sonar.jacoco.reportPaths>
${project.basedir}/../target/jacoco.exec
</sonar.jacoco.reportPaths>
</properties>
4、配置单元测试覆盖率统计插件jacoco
这个配置在网上很容易找到,为了内容的完整性还是放一下。功能就是把jacoco 挂载到maven 的各个phase/goal上去,如在单元测试和集成测试时,实现jacoco的插桩。
代码语言:javascript复制 <profiles>
<profile>
<id>sonar-coverage</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration> <destFile>${sonar.jacoco.reportPaths}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent-for-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>agent-for-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
如果需要实现集成测试/系统测试的代码覆盖率的话,则需要通过tcp等方式去dump覆盖率结果。这块不是本文的范围,就不展开了。
5、实施扫描
如果启用了分支,就需要分两次执行扫描。如果未使用的话,则一次扫描即可。 第一次扫描,先初始化执行master分支扫描 构建步骤增加 ”mvn sonar:sonar 不指定分支名字,默认是将扫描结果归属到master分支。 第二次扫描,指定分支名称 ”mvn sonar:sonar -Dsonnar.branch.name=${branchName}“** 如果挂载到了maven某个生命周期的某个阶段上,则执行 mvn clean install也可实现上述目的。
6、杂项
- 若只想做静态代码扫描,不执行测试用例和覆盖率,则在 mvn clean compile后执行sonar即可。
2)为了确保工程有单元测试执行结果,以便于让Sonar统计测试结果,需要忽略失败的测试结果,强制让Maven surefire插件生成测试报告 mvn clean test -Dmaven.test.failure.ignore=true 注意一定要加****-Dmaven.test.failure.ignore=true* **参数哦。
- 如何忽略用例, a) 忽略某个modules工程,在该module下配置 <sonar.skip>true</sonar.skip> 即可 b) 忽略如测试用例或其它某些package或.java文件,则配置<sonar.exclusions>[...]</sonar.exclusions>。
【未完待续】 1)如果一个项目中包含C /C#/PLSQL多种语言,如何实施SonarQube扫描?需要扫几次,是几个项目? 2)社区版本的SonarQube没有扫描C /PLSQL等语言的能力,怎么办? 3)如果代码库有多个分支,如何为每个分支产生扫描结果?社区版好像没有这个功能哎,怎么办? 4)为什么C 项目扫出来缺陷、安全漏洞都是0?覆盖率也是0%?