快捷搜索:  汽车  科技

sonarjenkins优缺点(Sonarqube8.9的新代码判断的坑)

sonarjenkins优缺点(Sonarqube8.9的新代码判断的坑)fea/jira-2前面两次提交后,新代码显示70行,也没问题。合并master后,新代码却显示0行,然后提交代码3后,新代码显示60行。问题就出在这里!按道理来说新代码显示应该是130行,但却因为合并导致新代码计算错误。每次提交代码后,触发分支的流水线进行扫描sonar质量,fea/jira-1每次都没有问题,新代码统计正确,第一次提交后,新代码显示50行,第二次提交后,新代码显示150行。每个特性分支开始都是从master分支新建过来的。每次sonar扫描后,都会与master进行比较。但此时问题就出现了。现象如下:从上面的图中可以看到:

Sonarqube8.9社区版(已安装插件Community Branch Plugin 1.8.1)的新代码检查策略有3种,分别是:

  • 上个版本(新代码周期会从上个版本的分析开始计算)
  • 天数(使用指定天数作为新代码周期的浮动窗口)
  • 引用分支(为新代码选择引用分支)

采用不同的代码分支管理策略,可以选择不同的新代码策略。

  1. 如果是单分支串行开发,则可以选择 上个版本作为新代码的策略;
  2. 如果是多特性分支开发,master作为发布分支,则可以选择引用分支作为新代码的策略;

上个版本 需要注意的是 项目的版本号不能随意地修改,因为如果修改了版本号,sonarqube就会认为是一个新的开始,新代码就会从你修改那一刻开始计算。

引用分支一般是:特性分支配置为引用分支(选择基准分支为发布分支,如:master),然后master的新代码策略则选择为:上个版本。

问题现象

sonarjenkins优缺点(Sonarqube8.9的新代码判断的坑)(1)

每个特性分支开始都是从master分支新建过来的。每次sonar扫描后,都会与master进行比较。

但此时问题就出现了。现象如下:

sonarjenkins优缺点(Sonarqube8.9的新代码判断的坑)(2)

从上面的图中可以看到:

  • fea/jira-1从创建分支到上线,一共提交了2次,新代码一共150行;
  • fea/jira-2从创建分支到上线,一共提交了3次,新代码一共130行,期间中途合并了一次master代码。

每次提交代码后,触发分支的流水线进行扫描sonar质量,fea/jira-1每次都没有问题,新代码统计正确,第一次提交后,新代码显示50行,第二次提交后,新代码显示150行。

fea/jira-2前面两次提交后,新代码显示70行,也没问题。合并master后,新代码却显示0行,然后提交代码3后,新代码显示60行。问题就出在这里!按道理来说新代码显示应该是130行,但却因为合并导致新代码计算错误。

下图是合并master代码后的sonar扫描结果:

sonarjenkins优缺点(Sonarqube8.9的新代码判断的坑)(3)

问题原因

经过分析sonarqube 8.9的源码,代码模块是sonar-scanner-engine 关键的类是:org.sonar.scanner.repository.forkDateSupplier 和org.sonar.scm.git.GitScmProvider。

8.9版本的新代码是通过ForkDateSupplier进行计算。

ForkDateSupplier.Java

@CheckForNull public Instant get() { // branches will be empty in CE if (branchConfiguration.isPullRequest() || branches.isEmpty()) { return null; } Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG_WS); String branchName = branchConfiguration.branchName() != null ? branchConfiguration.branchName() : branches.defaultBranchName(); NewCodePeriods.ShowWSResponse newCode = newCodePeriodLoader.load(project.key() branchName); profiler.stopInfo(); if (newCode.getType() != NewCodePeriods.NewCodePeriodType.REFERENCE_BRANCH) { return null; } String referenceBranchName = newCode.getValue(); if (branchName.equals(referenceBranchName)) { LOG.warn("New Code reference branch is set to the branch being analyzed. Skipping the computation of New Code"); return null; } LOG.info("Computing New Code since fork with '{}'" referenceBranchName); if (scmConfiguration.isDisabled() || scmConfiguration.provider() == null) { LOG.warn("SCM provider is disabled. No New Code will be computed."); analysisWarnings.addUnique("The scanner failed to compute New Code because no SCM provider was found. Please check your scanner logs."); return null; } Instant forkdate = scmConfiguration.provider().forkDate(referenceBranchName project.getBaseDir()); if (forkdate != null) { LOG.debug("Fork detected at '{}'" referenceBranchName forkdate); } else { analysisWarnings.addUnique("The scanner failed to compute New Code. Please check your scanner logs."); LOG.warn("Failed to detect fork date. No New Code will be computed." referenceBranchName); } return forkdate; }

上面的Instant forkdate = scmConfiguration.provider().forkDate(referenceBranchName project.getBaseDir()) 就是在计算当前分支(fea/jira-2)和目标分支(master)的最近一次merge的时间点。

所以就能理解为什么fea/jira-2的新项目,为什么在merge master代码后,新代码的数据就从新开始算了。

解决办法

在不修改源码的情况下,怎么解决呢?提供两种方法:一是通过 pull request的方式来解决(但此种方式,sonar扫描后只能看到新代码相关的指标,不能看到全量代码的指标数据),二是通过升级sonarqube版本来解决(测试了9.3的版本,是没问题的,)

方法一

正常情况下:执行mvn sonar:sonar会默认当成分支处理模式,为了能让其变为 pull request的模式,可以在执行命令时增加3个属性,如下:

- mvn sonar:sonar -Dsonar.pullrequest.branch=fea/jira-2 -Dsonar.pullrequest.base=master -Dsonar.pullrequest.key=fea/jira-2 `` 如果是在gitlab-ci的流水线环境中,可以用如下的配置配置: ```yml Commit-CodeAnalysis: stage: Commit-CodeAnalysis variables: branch_name: $CI_COMMIT_REF_NAME script: - unset CI_COMMIT_REF_NAME CI_COMMIT_REF_SLUG - mvn sonar:sonar -Dsonar.pullrequest.branch=$branch_name -Dsonar.pullrequest.base=$CI_DEFAULT_BRANCH -Dsonar.pullrequest.key=$branch_name

$CI_COMMIT_REF_NAME 表示的当前分支

$CI_DEFAULT_BRANCH 表示的主分支(这个项目配置的是master)

注意在实现sonar:sonar命令前,移除了两个属性unset CI_COMMIT_REF_NAME CI_COMMIT_REF_SLUG,目的主要是让sonar判断为这是pull request模式,而不是分支模式。

扫描后的结果截图如下:

下图中:

  • 第一个红框 对应的是:sonar.pullrequest.key
  • 第二个红框 对应的是:sonar.pullrequest.branch
  • 第三个红框 对应的是:sonar.pullrequest.base
  • 第四个红框 这表示的是 当前分支fea/jira-2和master比较 新增了130行代码。

但从上图中 看不到 全部代码的选项卡。

上面的解决方式只是用 pull rquest的方式(模拟发起合并代码请求)的方式来解决,效果达到了,但解决方法并不优雅。

方法二

升级sonarqube到最新版,目前最新版是9.3 (build 51899)。升级方法:见官方文档(Upgrade Guide)。(在写这篇文章时,官方已经推送了9.4版本的更新)

  • 遇到的问题 如果我们的项目是Java项目,会遇到JDK版本不兼容的问题。

sonarqube从9.X开始,不再支持jdk8 需要用jdk11 才能运行。

如果我们项目项目用的是jdk1.8,同时还使用了1.8里面的一些后续版本不再兼容的包类,如:rt.jar里面的sun.misc.BASE64Decoder 、javax.xml.bind.Marshaller等。用jdk11来运行就会报错。

mvn clean test sonar:sonar ... [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project iccboy-sonar-test: Compilation failure [ERROR] /opt/code/iccboy-sonar-test/iccboy-sonar/iccboy-sonar-common/src/main/java/com/iccboy/sonar/test/common/utils/FileUtil.java:[8 16] 找不到符号 [ERROR] 符号: 类 BASE64Decoder [ERROR] 位置: 程序包 sun.misc ...

如果我们用jdk8来执行,则优化报sonar的class编译文件解析不对的问题(ava.lang.UnsupportedClassVersionError)。

mvn clean test sonar:sonar ... [ERROR] Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.0.2155:sonar (default-cli) on project iccboy-sonar-test: Execution default-cli of goal org.sonarsou rce.scanner.maven:sonar-maven-plugin:3.9.0.2155:sonar failed: An API incompatibility was encountered while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.0.2155:sonar: java.lang.UnsupportedClassVersionError: org/sonar/batch/bootstrapper/EnvironmentInformation has been compiled by a more recent version of the Java Runtime (class file version 55.0) th is version of the Java Runtime only recognizes class file versions up to 52.0 [ERROR] ----------------------------------------------------- [ERROR] realm = plugin>org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.0.2155 [ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy [ERROR] urls[0] = file:/opt/repository/org/sonarsource/scanner/maven/sonar-maven-plugin/3.9.0.2155/sonar-maven-plugin-3.9.0.2155.jar [ERROR] urls[1] = file:/opt/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.4/plexus-sec-dispatcher-1.4.jar [ERROR] urls[2] = file:/opt/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar [ERROR] urls[3] = file:/opt/repository/org/codehaus/plexus/plexus-utils/3.2.1/plexus-utils-3.2.1.jar [ERROR] urls[4] = file:/opt/repository/org/sonarsource/scanner/api/sonar-scanner-api/2.16.1.361/sonar-scanner-api-2.16.1.361.jar [ERROR] urls[5] = file:/opt/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar [ERROR] Number of foreign imports: 1 [ERROR] import: Entry[import from realm ClassRealm[maven.api parent: null]] ... 为了解决上面的问题,则将命令分步骤执行。 第一步先用jdk8执行项目的编译和测试。 第二部在用jdk11执行sonar命令。 如下: ```sh export JAVA_HOME=/usr/local/jdk8/jdk1.8.0_211 mvn clean test export JAVA_HOME=/usr/local/jdk11/jdk-11.0.14 mvn sonar:sonar

如果是windows环境,则将export改为set

从sonarqube的github提交记录来看,在2022-1-11号开始进行了问题的修复。目前在9.3 版本已经修复了这个问题。

SONAR-14929 New Code using a 'reference branch' doesn't detect changed code with git merge workflow 3ec97d1a Duarte Meneses <duarte.meneses@sonarsource.com> on 2022/1/11 at 0:09 committed by sonartech <sonartech@sonarsource.com> on 2022/1/22 at 4:03

这次提交中做了很多的更改,上文中的ForkDateSupplier也改为了ReferenceBranchSupplier。

最后希望官方能在sonarqube8.9(LST)的版本中也修复该问题。

猜您喜欢: