Sonarqube8.9的新代码判断的坑,已填好

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

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

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

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

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

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

问题现象

image

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

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

image

从上面的图中可以看到:

  • 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扫描结果:

image

问题原因

经过分析sonarqube 8.9的源码,代码模块是sonar-scanner-engine,关键的类是:org.sonar.scanner.repository.ForkDateSupplierorg.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的流水线环境中,可以用如下的配置配置:

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行代码。
    image

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

上面的解决方式只是用 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.BASE64Decoderjavax.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编译文件解析不对的问题(Java.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命令。

如下:

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)的版本中修复该问题。

其他

在使用了一段时间9.3版本后,发现在另外的方面存在一些问题。主要表现是,项目首页显示新增代码有问题,但点击去看,又显示没有问题。
解决办法: 升级到最新版9.4(54424) 解决了这个问题。(但9.4也有另外的问题(影响不大),把问题标记为关闭不修复后,首页的新问题未同步减少,需要重新扫描代码才生效,之前在8.9版本没有这个问题),在9.5版本已经解决了9.4版本的问题 nice(2022年6月26日)

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IccBoY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值