解决研发痛点SnoarQube代码检查实战

DevOpSec
• 阅读 311

来源: DevOpSec公众号 作者: DevOpSec

做CI的兄弟基本上都会用到代码质量检查,下面从五个部分给大家讲一下我的sonarqube代码质量检测实战经验,欢迎指正交流

一、需求
二、sonarqube介绍
三、部署
四、SonarQube使用
五、使用中遇到的问题

一、需求

  1. 代码质量检查,想知道团队成员代码质量情况,团队人多后每个人的代码风格和代码水平不一通过sonar检测能做到代码基准的一个把控。

  2. master代码质量是基准,可以理解master分支的sonar检测是通过的,分支代码质量检查和master代码进行比对,我们是master上线。

  3. sonar检测后把结果发送通知给对应的开发和其TL,开发能及时知道自己开发代码是否有问题

二、sonarqube 介绍

SonarQube 使所有开发人员能够编写更干净、更安全的代码。

SonarQube 是一种自动代码审查工具,用于检测代码中的错误、漏洞和代码异味。它可以与您现有的工作流程集成,以实现跨项目分支和拉取请求的持续代码检查。

SonarQube 是一个用于代码质量管理的开源平台,用于管理源代码的质量。 通过插件形式,可以支持包括 java, C#, C/C++, PL/SQL, Cobol, JavaScrip, Groovy 等等二十几种编程语言的代码质量管理与检测。

sonarqube 版本介绍

个人觉得社区版加上插件就够用了。

sonarqube分为社区版,开发者,企业版和数据中心版4种

版本功能比较统计:

社区版:在CI / CD中采用代码质量的起点

开发者版:最大应用程序安全性跨分支机构和PR的最大值

企业版:管理您的应用程序组合,在企业级别启用代码质量和安全性。

数据中心版:高可用性,适用于全球部署

版本列表,官网资料:https://www.sonarqube.org/downloads/

解决研发痛点SnoarQube代码检查实战

架构

sonarQube: web界面管理平台。

​ 1)展示所有的项目代码的质量数据。

​ 2)配置质量规则、管理项目、配置通知、配置SCM等。

sonarScanner: 代码扫描工具。

​ 专门用来扫描和分析项目代码。支持20+语言。

​ 代码扫描和分析完成之后,会将扫描结果存储到数据库当中,在sonarQube平台可以看到扫描数据。

工作流程

解决研发痛点SnoarQube代码检查实战

工作流程介绍

1.开发人员在IDE中开发和合并代码,并将代码签入到DevOps平台。

2.持续集成工具(如jenkins)检查、构建和运行单元测试,集成SonarQube扫描仪分析结果。

3.扫描程序将结果发布到SonarQube服务器,该服务器通过SonarQube界面、电子邮件、IDE内通知(通过SonarLint)和拉入或合并请求的装饰(使用Developer Edition及更高版本时)向开发人员提供反馈。

SonarQube主要作用

编写整洁代码

把出现在代码里的新问题都解决掉,就可以创建并维护一个干净的代码基础。即使是遗留项目,保持新代码的整洁,也能最终获得一个值得骄傲的代码基础。

修复代码缺陷

缺陷图例和默认质量阈都是基于新代码周期的 - 当前周期就是处理问题的时间。主要的关注点是上一个版本,通常会选择30天作为一个周期。

加强质量阈

项目的质量阈是在发布到生产环境之前所需要达到的一系列的条件标准。质量阈可以确保下一个版本的代码质量总能高于上一个版本。

Sonar的优点

(1)支持所有语言的检测。一个工具,搞定所有。

(2)灵活扩展,插拔式使用。自定义的代码检测规则,可自定义插件,独立打成JAR包放到SONARQUBE插件目录下,重启即生效,开发使用非常方便。而且自带UT验证框架,开发效率高。

(3)规则支持多租户隔离。租户可定制自己的规则集。

(4)生态强大,业界有诸多插件,与jenkins友好集成。

(5)部署使用便捷。

(6)架构松耦合,通过与maven/jenkins等集成,将代码扫描的计算消耗迁移到业务或者构建方的资源上,极大的提升了自身的吞吐能力。

衡量代码质量的几个指标

1.Bugs Bug是出现了明显错误或是高度近似期望之外行为的代码。

2.漏洞 漏洞是指代码中可能出现被黑客利用的潜在风险点。

3.安全热点 安全敏感代码需要手工审核,以便判断是否存在安全漏洞。

4.异味 代码异味会困扰代码的维护者并降低他们的开发效率。主要的衡量标准是修复它们所需的时间。

5.重复率 新代码中的重复行密度 (%),重复行数,重复代码块

6.行数 程序中代码的行数

可以根据需要创建自己的质量阈,比如如果公司单测覆盖率低或者基本没有单元测试可以把单元测试覆盖率检查规则去了。下图是自定义的代码检测规则:

解决研发痛点SnoarQube代码检查实战

三、部署

部署

部署之前先说两个插件,一是汉化国人毕竟中文看着舒服,二是多分支扫描支持

  1. 汉化插件

增加 sonar-l10n-zh-plugin-version.jar 到 /opt/sonarqube/extensions/plugins/ 重启启动sonarqube 即可

  1. 多分支检查插件(注意sonarqube的版本要和插件版本兼容)

2.1、下载对应版本的Community Branch Plugin插件,我们使用的sonarqube:9.6.1-community,因此下载对应的1.12.0 版本的插件。

SonarQube Version Plugin Version
9.8+ 1.14.0
9.7 1.13.0
9.1-9.6 1.12.0
9.0 1.9.0
8.9 1.8.1
8.7 - 8.8 1.7.0
8.5 - 8.6 1.6.0
8.2 - 8.4 1.5.0
8.1 1.4.0
7.8 - 8.0 1.3.2
7.4 - 7.7 1.0.2

2.2、将下载的jar包放到拷贝到/opt/sonarqube/extensions/plugins目录。
2.3、添加sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.12.0.jar=websonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.12.0.jar=ce/opt/sonarqube/conf/sonar.properties
2.4、重启SonarQube,接受关于使用第三方插件的警告。
2.5、检查安装情况,查看插件配置,进入Administration—>General Settings—>Housekeeping。基本上不用设置,保持默认即可。 解决研发痛点SnoarQube代码检查实战

  1. 容器化部署 Dockerfile
    FROM docker.io/library/sonarqube:9.6.1-community

    ADD ./sonarqube-community-branch-plugin-1.12.0.jar /opt/sonarqube/extensions/plugins/
    ADD ./sonar-l10n-zh-plugin-9.6.jar /opt/sonarqube/extensions/plugins/
    ADD ./sonar-findbugs-plugin-4.2.2.jar /opt/sonarqube/extensions/plugins/

build 镜像,基于官方镜像把汉化和多分支扫描插件都打进去

    docker build -t harbor.xxx.com/docker-admin/sonarqube:9.6.1-community-zh .
    docker push harbor.xxx.com/docker-admin/sonarqube:9.6.1-community-zh

有镜像后通过docker方式或者k8s pod部署都可以的,推荐通过k8s的方式部署。

四、SonarQube使用

多分支扫描

分支代码的质量是和master分支代码质量对比 首先需要扫描master代码的质量,然后再扫描分支的代码质量

master分支ci 触发代码扫描sonarscanner 配置。

    cat /opt/sonar-scanner/conf/sonar-scanner.properties

    sonar.host.url=http://sonarqube.sonarqube:9000
    sonar.login=xxxxxxxx
    sonar.projectKey=webapp-tomcat
    sonar.projectName=webapp-tomcat
    sonar.projectVersion=master_fsfwe135
    sonar.sourceEncoding=UTF-8
    sonar.ws.timeout=60
    sonar.exclusions=**/target/**/*.tar.gz,**/target/**/*.war, *.py, *.tar.gz, *.war, *.sh
    sonar.java.source=1.8
    sonar.java.binaries=**/*
    sonar.sources=.

其他分支ci 触发代码扫描sonarscanner 配置,这里的分支名是:create_session

    cat /opt/sonar-scanner/conf/sonar-scanner.properties

    sonar.host.url=http://sonarqube.sonarqube:9000
    sonar.login=xxxxxxxx
    sonar.projectKey=webapp-tomcat
    sonar.projectName=webapp-tomcat
    sonar.projectVersion=master_fsfwe135
    sonar.sourceEncoding=UTF-8
    sonar.ws.timeout=60
    sonar.exclusions=**/target/**/*.tar.gz,**/target/**/*.war, *.py, *.tar.gz, *.war, *.sh
    sonar.java.source=1.8
    sonar.java.binaries=**/*
    sonar.sources=.
    sonar.pullrequest.base=master
    sonar.pullrequest.branch=create_session
    sonar.pullrequest.key=create_session

运行之后的效果图,出现错误,说明create_session分支如果要merge到master分支会带来bug,建议研发修复

解决研发痛点SnoarQube代码检查实战

注意: a. 上面的配置文件没有跟着项目走,是全局的配置 b. 每个项目在跑sonar-scanner之前都会通过CI提前生成sonar-scanner.properties文件,然后在容器运行的sonar-scanner进行代码质量检查

质量检查不通过发送告警

master和其他分支代码检查不通过发送告警给开发者和开发者TL 这里使用sonarqube的API结合python实现

首先需要生成token

解决研发痛点SnoarQube代码检查实战

其次知道API怎么用,API帮助文档入口

解决研发痛点SnoarQube代码检查实战

第三拿到获取project sonar scan之后的 project_status

解决研发痛点SnoarQube代码检查实战

直接上伪代码

#/usr/bin/env python
# coding: utf-8
import requests
import sys
import json
import time
from requests.auth import HTTPBasicAuth

token = 'xxxxxxx'

# projectKey 最好是模块名,见名知意
project_key=sys.argv[1]
pull_request=sys.argv[2]
build_user=sys.argv[3]

#接口api
url = f'https://sonarqube.xxxx.com/api/qualitygates/project_status?projectKey={project_key}'

#展示页面,发送消息提醒,后在im里可以直接点击该链接进入sonarqube server web端
durl = f'https://sonarqube.xxxxx.com/dashboard?id={project_key}'

#默认url和durl对应的结果是master分支,如果不是master分支,加上pullRequest也即与master分支对别之后的结果。
if pull_request != "master":
    url = url + f'&pullRequest={pull_request}'
    durl = durl + f'&pullRequest={pull_request}'

#获取开发的leader,这个根据自己家公司api实现即可
def get_user_leader(build_user):
    return leader

def check_scanner_result():
    is_ok="OK"
    try:
        # sleep 5s ,scan后会有个入库时间有延迟,所以sleep 5s 
        time.sleep(5)
        #获取scanner结果是否通过代码质量检查
        r = requests.get(url % (), auth=HTTPBasicAuth(token, "")).json()
        is_ok = r['projectStatus']['status']
    except:
        # master 分支没有构建
        sys.exit(0)

    userlist=""

    #发送IM文案
    msg=f"OK: 分支:{pull_request} sonar 代码质量检查通过\n具体请见URL:{durl} \n构建者:{build_user}"
    if is_ok !="OK":
        msg=f"ERROR: 分支:{pull_request} sonar 代码质量检查不通过\n具体请见URL:{durl} \n构建者:{build_user}"
        leader=get_user_leader(build_user)
        userlist=build_user+","+leader

    #发送消息,这块也是根据自己家公司api实现即可
    content = str(msg)
    sendmsg(content, userlist)

#运行
check_scanner_result()

代码质量不通过阻断CI流程

不要上线后就阻断CI流程,是否阻断建议先和开发团队达成共识,然后在做决定

使用中遇到的问题

排除某些规则

和研发达成共识,某些策略可以忽略 比如: 解决研发痛点SnoarQube代码检查实战

调整如下: 解决研发痛点SnoarQube代码检查实战

排除某些文件不扫描

项目中包含Criteria.java 结尾的文件不扫码

解决研发痛点SnoarQube代码检查实战

某些项目编译出错,错误如下

ERROR: Error during SonarScanner execution
java.lang.IllegalStateException: Can not execute Findbugs
        at org.sonar.plugins.findbugs.FindbugsExecutor.execute(FindbugsExecutor.java:188)
        at org.sonar.plugins.findbugs.FindbugsSensor.execute(FindbugsSensor.java:130)
        at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:64)
        at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:88)
        at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:61)
        at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:79)
        at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:61)
        at org.sonar.scanner.scan.SpringModuleScanContainer.doAfterStart(SpringModuleScanContainer.java:81)
        at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:188)
        at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:167)
        at org.sonar.scanner.scan.SpringProjectScanContainer.scan(SpringProjectScanContainer.java:396)
        at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:392)
        at org.sonar.scanner.scan.SpringProjectScanContainer.doAfterStart(SpringProjectScanContainer.java:361)
        at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:188)
        at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:167)
        at org.sonar.scanner.bootstrap.SpringGlobalContainer.doAfterStart(SpringGlobalContainer.java:135)
        at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:188)
        at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:167)
        at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:72)
        at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:66)
        at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.base/java.lang.reflect.Method.invoke(Unknown Source)
        at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
        at com.sun.proxy.$Proxy0.execute(Unknown Source)
        at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:189)
        at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138)
        at org.sonarsource.scanner.cli.Main.execute(Main.java:112)
        at org.sonarsource.scanner.cli.Main.execute(Main.java:75)
        at org.sonarsource.scanner.cli.Main.main(Main.java:61)
Caused by: java.lang.IllegalStateException: One (sub)project contains Java source files that are not compiled (/data/data/jenkins-node/workspace/weapp-tomcat_master).
sonar.java.binaries was set to **/*
Sonar JavaResourceLocator.classFilesToAnalyze was empty
        at org.sonar.plugins.findbugs.FindbugsConfiguration.buildMissingCompiledCodeException(FindbugsConfiguration.java:153)
        at org.sonar.plugins.findbugs.FindbugsConfiguration.initializeFindbugsProject(FindbugsConfiguration.java:123)
        at org.sonar.plugins.findbugs.FindbugsExecutor.execute(FindbugsExecutor.java:117)
        ... 31 more
ERROR:
ERROR: Re-run SonarScanner using the -X switch to enable full debug logging.

错误原因:当安装Findbugs插件后,JSP的默认profiles被设置为FindBugs Security JSP。

解决研发痛点SnoarQube代码检查实战

Findbugs分析的不是java源代码,而是编译后的class文件。通过下图进行配置忽略未编译的jsp文件。

下面是全局配置,对所有项目都生效:

解决研发痛点SnoarQube代码检查实战

针对某些项目生效: 在CI时针对该模块配置文件sonar-scanner.properties单独写上 sonar.findbugs.allowuncompiledcode=true

点赞
收藏
评论区
推荐文章
保卫大萝卜 保卫大萝卜
2年前
低代码,虽然有点毒瘤,但管用就好
最近看到不少低门槛开发软件应用的新闻:“30分钟搭一款核酸检测登记应用”、“2小时紧急上线抗疫求助应用”、“00后低代码开发者毕业月薪过万”等等。近期,广西防城港市出现疫情,全市展开一轮大规模核酸检测。柳钢工人彭期文在钉钉上仅用30分钟就通过低代码搭起一款“核酸检测登记”应用,原本需要大规模的排队登记,如今手机一扫,3小时就能完成7000余人
低代码开发平台 | 低代码的衍生历程、优势及未来趋势
通过简单的拖拉拽操作,而不用编写复杂的代码,实现少写代码或者不写代码,就能快速高效完成业务目标。低代码平台演进1.低代码概念低代码是无需编码(0代码)或通过少量代码就可以快速生成应用程序的开发平台。通过可视化进行应用程序开发的方法,具有不同经验水平的开发人员可以通过图形化的用户界面,使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程序。2.低代码衍生历
万木春 万木春
1年前
高效易用的C++单元测试框架:轻松构建高质量代码
单元测试是构建稳定、高质量的程序、服务或系统的必不可少的一环。通过单元测试,我们可以在开发过程中及时发现和修复代码中的问题,提高代码的质量和可维护性。同时,单元测试也可以帮助我们更好地理解代码的功能和实现细节,从而更好地进行代码重构和优化。
云原生引擎单元测试实践
快速迭代的开发工作中如何提高代码质量一直是团队痛点,特别是没有测试支持的开发团队。合理的使用单元测试,并关注单元测试通过率、代码覆盖率可以有效提高代码质量。今天就来讲讲云原生引擎单元测试实践。
Stella981 Stella981
2年前
Jenkins Pipeline集成Sonar进行代码质量检测
JenkinsPipeline集成Sonar进行代码质量检测简介jenkinspipelineJenkinsPipeline(或简称为"Pipeline")是一套jenkins插件,将持续交付的实现和实施集成到Jenkins中。Jenk
Stella981 Stella981
2年前
Git 使用教程—以 GitLab 上的 Django 项目为例
一、代码提交流程1\.clone代码到本地有两个命令,第一个是clonemaster主分支代码,第二个是clone某个branch分支代码。团队项目开发中,我一般是clone别人分支代码进行整合,master主分支代码很少动。gitclonehttp://www.xxx.xxx.git
Stella981 Stella981
2年前
RubyCritic:一款不错的检测代码质量工具
关注代码质量是高效开发必须要做的一件事,那么在Ruby开发的过程中,是否有什么好的代码质量检测工具呢?下面由Ruby工程师路英瑞介绍一下RubyCritic——一款还不错的代码质量检测工具。最近在开发CloudInsightAPI(https://www.oschina.net/action/GoToLink?urlhttp
Stella981 Stella981
2年前
Code Review最佳实践
  我一直认为CodeReview(代码审查)是软件开发中的最佳实践之一,可以有效提高整体代码质量,及时发现代码中可能存在的问题。包括像Google、微软这些公司,CodeReview都是基本要求,代码合并之前必须要有人审查通过才行。  然而对于我观察到的大部分软件开发团队来说,认真做CodeReview的很少,有的流于形式,有的可能根本就没有Co
想要做好代码质量,如何破局?
作者:苗现方想要做好代码质量,我们不得不提什么是代码质量?本文中讨论的代码质量一般是指代码的风格、重复率和复杂度等,代码是技术团队的价值产物,是宝贵的财富,同样代码质量的好坏可以直接体现出团队的重视程度和技术管理水平。代码质量的下降是内
kenx kenx
11个月前
程序员的十级孤独,你体会过几级
都说天才程序员是和疯子就差一步之遥。有极致孤独与追求,有自己的精神世界,我就是有代码洁癖的,追求极致代码要求。如何看到别人写代码不按照自己的,来我就会很抓马就会不通过他的代码质量检查,以致于我现在有点极致的病态要求了尤其作为项目中的leader我感受更加深