SonarQube & SonarQube Scanner

CentOS MySQL SonarQube SonarQube Scanner

SonarQube 简介

  • SonarQube 能够提供对代码的一整套检查扫描和分析功能,拥有一套服务器端程序,然后再通过客户端或者别的软件的插件的形式完成对各开发环境和软件的支持。

  • 对编程语言的支持非常广泛,包括 C、C++、Java、Objective C、Python、JavaScript、PHP、C#、Swift、Erlang、Groovy 等众多语言
    提供了对 HTML、CSS、JSON、XML、CSV、SQL、JSP/JSF 等类型的文档的支持

  • 提供了以 FindBugs、PMD、CheckStyle 方式执行代码分析和测试检查的功能

  • 登录认证方式支持 LDAP、Bitbucket、Azure Active Directory(AAD)、Crowd 等方式

  • 提供了优美的 3D 视图方式下查看代码分析和测试结果报告

SonarQube 能带来什么???

➢ 糟糕的复杂度分布:文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员难以理解它们,且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试

➢ 重复:显然程序中包含大量复制粘贴的代码是质量低下的,sonar 可以展示源码中重复严重的地方

➢ 缺乏单元测试:sonar 可以很方便地统计并展示单元测试覆盖率

➢ 没有代码标准:sonar 可以通过 PMD、CheckStyle、Findbugs 等等代码规则检测工具规范代码编写

➢ 没有足够的或者过多的注释:没有注释将使代码可读性变差,特别是当不可避免地出现人员变动时,程序的可读性将大幅下降。而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷

➢ 潜在的 bug:sonar 可以通过 PMD、CheckStyle、Findbugs 等等代码规则检测工具检测出潜在的 bug

SonarQube 环境搭建

Tip:我这里安装的 SonarQube 6.3.1,需要 JDK 1.8 以上的版本,MySQL 版本建议 5.6 以上,若 MySQL 版本高于 5.6 可以直接进行第四步

  • 第一步:升级数据库
    重要的事情说三遍:先备份旧数据库,先备份旧数据库,先备份旧数据库,然后再删除,再安装新的
    安装包下载之后,按照以下步骤操作
验证MD5:md5sum mysql57-community-release-el6-9.noarch.rpm    
        验证包的MD5,务必要和官方给出的保持一致,确认无误才行

接着执行:rpm -ivh mysql57-community-release-el6-9.noarch.rpm
        -i 是安装指令install的简写,-v是详尽模式verbose的简写,-h是打印要安装的包的Hash码(与-v组合使用)

        开始安装MySQL的发布包,这个过程会瞬间完成。输出类似于下面这样的信息:
        Preparing...                ########################################### [100%]
           1:mysql57-community-relea########################################### [100%]
  • 第二步:执行yum install -y mysql-community-client mysql-community-server(这个过程会需要一些时间)

  • 第三步:安装完成之后,打开/etc/my.cnf文件,在[mysqld]节点下增加如下两行👇,然后重新启动mysqld服务

character_set_server=utf8  
init_connect='SET NAMES utf8'
FAQ:
1.如果启动' mysqld '服务时卡在Installing validate password plugin:这个步骤过不去,可以先中止这个过程,解决方案如下:
    ➯ vim /etc/my.cnf
    ➯ 在[mysqld]这个节下面添加一行内容`validate_password=off`
      这是临时禁止密码验证插件,可以在以后需要的时候再配置即可。
      此时的数据库已经正常工作了,但是我们还不能使用
    ➯ vim /var/log/mysqld.log,找到类似于下面的内容:
      A temporary password is generated for root@localhost: -?i;XHTuh5eH
      这里的' -?i;XHTuh5eH '就是临时密码,
    ➯ 重新启动mysqld服务之后,输入:mysql -u root -p,回车,之后输入临时密码
    ➯ 成功登录到MySQL,此时再使用命令:alter user 'root'@'localhost' identified by '123';
      更新root用户的默认密码,5.6以后的版本安全机制增强了,临时密码只允许登录,不允许操作数据库,所以必须更改。
2.忘记登录密码,解决方案如下:
    ➯ vim /etc/my.cnf
    ➯ 在文件中`[mysqld]`下添加skip-grant-tables,如图所示:
    ➯ 登录mysql:mysql -uroot -p (直接点击回车,密码为空)
    ➯ 设置用户密码:update mysql.user set authentication_string=PASSWORD('123456') where user='root';
    ➯ 更新privilige:flush privileges;
    ➯ 退出:exit
    ➯ 删除在my.cnf文件中`skip-grant-tables`
    ➯ 重启:service mysqld restart
    -------------------------------------------------------------------------------------------------------------------------------------------
    | 第2个问题按照上面设置之后如果在登陆之后操作之后的时候,遇见如下错误👇
    | `ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.` 
    | 解决方法:alter user 'root'@'localhost' IDENTIFIED with mysql_native_password AS '*0D3CED9BEC10A777AEC23CCC353A8C08A633045E';
    | 当之后重新设置密码时,遇见如下错误👇
    | `[ERROR 1819 (HY000): Your password does not satisfy the current policy requirements]`
    | 解决方法:输入 set global validate_password_policy=0;
    | 之后在设置密码就OK了,命令见`FAQ 2`设置用户密码,然后更新privilige
    | (正如上文所说,MySQL 5.6之后安全机制增强了,所以导致5.6之后的设置密码方式与之前不一样)
  • 第四步:创建sonar数据库及sonar用户及设置用户权限
➯ 创建数据库:
    CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;
➯ 创建SonarQube Server访问数据库的用户:
    CREATE USER 'sonar' IDENTIFIED BY 'sonar';
➯ 配置SonarQube Server访问数据库用户的权限
    GRANT ALL ON sonar.* TO 'sonar'@'%' IDENTIFIED BY 'sonar';
    GRANT ALL ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY 'sonar';
➯ 更新权限:flush privileges;
 -------------------------
 Tip:
      flush privileges 命令本质上的作用是将当前user和privilige表中的用户信息/权限设
置从mysql库(MySQL数据库的内置库)中提取到内存里。MySQL用户数据和权限有修改后,希望在
"不重启MySQL服务"的情况下直接生效,那么就需要执行这个命令。通常是在修改ROOT帐号的设置
后,怕重启后无法再登录进来,那么直接flush之后就可以看权限设置是否生效,而不必冒太大风险
  • 第五步:更改SonarQube配置文件,打开SonarQube下的conf/sonar.properties,如下图👇

sonar.properties

取消注释,并按照如下图👇所示,填写内容,其中sonar.jdbc.url这一行只要取消注释就可以
sonar.properties

  • 第六步:进入SonarQube目录下的/bin/linux-x86-64运行:nohup bash sonar.sh start &注:高版本中不能用 root 用户启动 SonarQube,需用非 root 用户启动)
    Tip:nohup command &表示将进程放置后台运行,而对于linux-x86-64这个文件夹是根据你当前安装SonarQube的系统决定的,是哪个系统就进那个文件夹
  • 第七步:访问http://127.0.0.1:9000,如果不是本机就输入http://IP:9000接着你会看到如下图所示👇

SonarQube

接着点击Log in,默认账号:admin,密码:admin

Log in

登录之后,按如下操作安装中文插件

install Chinese Pack
Restart
大功告成

SonarQube Scanner 配置

  • 准备工作

  • 第一步:下载之后解压zip包,之后进入该目录的conf文件夹下,打开文件sonar-scanner.properties,如下图所示👇

sonar-scanner.properties

在文件中,将下面一行取消注释即可

# 如果是远程的话,请将localhost修改为远程机器的IP地址
sonar.host.url=http://localhost:9000
sonar-scanner.properties
  • 第二步:到工程根目录下新建文件sonar-project.properties,文件内容如下👇,文件中的参数配置,参考Sonar Analysis Parameters这篇文章
# 指定SonarQube instance必须是唯一的
sonar.projectKey=Jacoco
# 设置SonarQube UI显示的名称 
# PS:有人会问这里的名称是否可以是中文名称,我在网上搜索了好多资料都说是不可以的(至少我看到的资料都是)
#     后来自己尝试了一下,答案是可以写成中文的,但是要换一种方式,比如你想把项目名称命名为“测试”,
#     那么在这里就要写成“\u6d4b\u8bd5”,那么下面这个参数就应该这样写“sonar.projectName= \u6d4b\u8bd5”,
#     说白了就是将中文转成Unicode
sonar.projectName= Jacoco
sonar.projectVersion=1.0
sonar.language=java
# 指定src和classes文件夹位置,当然也可以是全路径,如果是当前工程根目录下用“.”表示也可以,比如“sonar.sources=.”
sonar.sources=src
sonar.java.binaries=target
# 下面的这两个参数作用是相同的,因为有时我们需要指定某个文件夹或者忽略某个文件夹
# sonar.inclusions=src1/**,src3/**
# sonar.exclusions=src2/**,src4/**
# 源码编码,默认是系统编码
sonar.sourceEncoding=UTF-8
# Set jacoco Configuration
# 指定代码覆盖率工具
sonar.core.codeCoveragePlugin=jacoco
# 指定exec二进制文件存放路径
sonar.jacoco.reportPaths=[yourPath/]jacoco.exec
# 以下属性可选择性加,当然也可以不加
sonar.dynamicAnalysis=reuseReports
sonar.jacoco.reportMissing.force.zero=false

Tip:可以将这里的知识结合Jacoco Code Coverage结合这篇的中的Demo工程实践一下,当然如果同时想要分析代码覆盖率的话你就要在下载Demo工程之后,运行mvn test生成exec二进制文件,并将exec文件的路径补全,当然如果找不到这个文件也不会报错,只是在SonarQube平台上看不到代码覆盖率

  • 第三步:第一和第二步完成之后,进入sonar-scanner-xxxconf目录下,你会发现两个文件sonar-scanner&sonar-scanner-debug,配置一下环境变量,如下所示👇
export SONAR_SCANNER_HOME=[yourSonarScannerPath/]
export PATH=$PATH:$SONAR_SCANNER_HOME/bin:PATH

Tip:配置好环境变量之后,source一下使之生效
然后从终端进入工程根目录,运行sonar-scanner你会看到如下日志👇

INFO: Scanner configuration file: /Users/zc/Downloads/sonarqube-6.3.1/extensions/plugins/sonar-scanner-3.0.1.733-macosx/conf/sonar-scanner.properties
INFO: Project root configuration file: /Users/zc/Desktop/jacoco/sonar-project.properties
INFO: SonarQube Scanner 3.0.1.733
INFO: Java 1.8.0_121 Oracle Corporation (64-bit)
INFO: Mac OS X 10.12.4 x86_64
INFO: User cache: /Users/zc/.sonar/cache
INFO: Load global settings
INFO: Load global settings (done) | time=54ms
INFO: User cache: /Users/zc/.sonar/cache
INFO: Load plugins index
INFO: Load plugins index (done) | time=4ms
INFO: Plugin [l10nzh] defines 'l10nen' as base plugin. This metadata can be removed from manifest of l10n plugins since version 5.2.
INFO: SonarQube server 6.3.1
INFO: Default locale: "zh_CN", source code encoding: "UTF-8"
INFO: Process project properties
INFO: Load project repositories
INFO: Load project repositories (done) | time=51ms
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=12ms
INFO: Load active rules
INFO: Load active rules (done) | time=254ms
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=45ms
WARN: SCM provider autodetection failed. No SCM provider claims to support this project. Please use sonar.scm.provider to define SCM of your project.
INFO: Publish mode
INFO: Project key: com.jacoco
INFO: -------------  Scan JacocoTest
INFO: Load server rules
INFO: Load server rules (done) | time=49ms
INFO: Language is forced to java
INFO: Initializer GenericCoverageSensor
INFO: Initializer GenericCoverageSensor (done) | time=0ms
INFO: Base dir: /Users/zc/Desktop/jacoco
INFO: Working dir: /Users/zc/Desktop/jacoco/.scannerwork
INFO: Source paths: src
INFO: Source encoding: UTF-8, default locale: zh_CN
INFO: Index files
INFO: 2 files indexed
INFO: Quality profile for java: Sonar way
INFO: Sensor JavaSquidSensor [aemrules]
INFO: Configured Java source version (sonar.java.source): none
INFO: JavaClasspath initialization
WARN: Bytecode of dependencies was not provided for analysis of source files, you might end up with less precise results. Bytecode can be provided using sonar.java.libraries property
INFO: JavaClasspath initialization (done) | time=8ms
INFO: JavaTestClasspath initialization
INFO: JavaTestClasspath initialization (done) | time=0ms
INFO: Java Main Files AST scan
INFO: 2 source files to be analyzed
INFO: Java Main Files AST scan (done) | time=367ms
INFO: Java Test Files AST scan
INFO: 2/2 source files have been analyzed
INFO: 0 source files to be analyzed
INFO: Java Test Files AST scan (done) | time=0ms
INFO: Sensor JavaSquidSensor [aemrules] (done) | time=780ms
INFO: 0/0 source files have been analyzed
INFO: Sensor SurefireSensor [aemrules]
INFO: parsing /Users/zc/Desktop/jacoco/target/surefire-reports
INFO: Sensor SurefireSensor [aemrules] (done) | time=49ms
INFO: Sensor JaCoCoSensor [aemrules]
WARN: Property 'sonar.jacoco.reportMissing.force.zero' is deprecated and its value will be ignored.
INFO: Analysing /Users/zc/Desktop/jacoco/target/coverage-reports/jacoco-unit.exec
INFO: No information about coverage per test.
INFO: Sensor JaCoCoSensor [aemrules] (done) | time=58ms
INFO: Sensor SonarJavaXmlFileSensor [aemrules]
INFO: Sensor SonarJavaXmlFileSensor [aemrules] (done) | time=0ms
INFO: Sensor Analyzer for "php.ini" files [php]
INFO: Sensor Analyzer for "php.ini" files [php] (done) | time=2ms
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=11ms
INFO: Sensor Code Colorizer Sensor
INFO: Sensor Code Colorizer Sensor (done) | time=0ms
INFO: Sensor CPD Block Indexer
INFO: org.sonar.scanner.cpd.deprecated.JavaCpdBlockIndexer@6cf047cf is used for java
INFO: Sensor CPD Block Indexer (done) | time=17ms
INFO: No SCM system was detected. You can use the 'sonar.scm.provider' property to explicitly specify it.
INFO: Calculating CPD for 2 files
INFO: CPD calculation finished
INFO: Analysis report generated in 66ms, dir size=30 KB
INFO: Analysis reports compressed in 8ms, zip size=11 KB
INFO: Analysis report uploaded in 19ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/com.jacoco
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://localhost:9000/api/ce/task?id=AVwlSI7NKkvX7ZORxf9W
INFO: Task total time: 2.584 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 13.546s
INFO: Final Memory: 50M/306M
INFO: ------------------------------------------------------------------------

接下来我们回到之前搭建好的SonarQube平台,看一下检测的结果,效果展示如下图👇

说明一下:
   上文运用的Sonar Sanner只是实现代码检测方式的其中之一而已,当然还有其它做法,比如直接在
pom.xml文件中引用sonar插件,但是我这里考虑的是与Jenkins做成持续集成,如果我选择在项目中添
加sonar-project.properties文件,这样能更方面与Jenkins结合

到这里基本上就结束了,下面就是将Jenkins与SonarQube集成,详见:Jenkins + SonarQube & SonarQube Scanner

如在阅读或者实践过程中遇到问题,欢迎下方留言

推荐阅读更多精彩内容