前言

SonarQube是一个开源的代码质量管理系统,它支持包括ObjectiveC、Java、C/C++、C#、PHP在内的超过25种编程语言。它能够提供包括重复代码、编码标准、单元测试、代码覆盖率、代码复杂度、潜在Bug、注释的报告。它还可以与持续集成工具配合使用实现完全自动化的分析。

之前在网上搜索学习SonarQube在Mac上的集成和使用教程,发现教程都比较老,使用的都是较老版本的SonarQube,在集成最新的8.1版本时踩了不少坑。本文就是对在Mac系统上安装和使用新版SonarQube的总结。后续会继续更新使用SonarQube静态分析Swift代码及结合Jenkins进行自动化分析。

注意:SonarQube需要Java 11及以上的运行环境,在终端输入java --version即可查看系统的Java版本,如果不满足,请先自行下载和安装。

SonarQube平台架构

SonarQube平台主要由四大要件构成:

  • 数据库:存放配置数据和检测数据(7.9及以后的版本不再支持MySQL,本文使用的是PostgreSQL)
  • Web服务:在本地网页上查看配置数据和代码质量检测结果
  • 分析器:对项目代码进行分析(OCLint)
  • 插件:支持各种语言的插件

安装配置PostgreSQL数据库

SonarQube运行和储存数据需要数据库,而网上大多数教程使用的MySQL数据库已经不被7.9以后版本的SonarQube支持了,所以我选择了同样开源的关系数据库PostgreSQL。这个数据库和MySQL语法略有不同,但使用上基本大同小异。

我们先来安装和配置PostgreSQL数据库。

安装数据库

安装PostgreSQL数据库有两种方式,一种是Homebrew,一种是直接上官网下载安装程序安装,后一种有可视化界面使用上比较简单。

使用Homebrew安装

安装Homebrew(电脑上已经安装了的可以跳过这步)。

1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装数据库

1
brew install postgresql 

软件方式安装

进入官网按照提示进行下载和安装,安装完之后直接双击运行即可。

使用软件方式安装会自动创建两个用户,一个是postgres,一个是与电脑当前登录用户同名的用户,并且分别为两个用户创建了默认的数据库。后面我们添加用户和数据库时可以登录postgres这个用户进行创建。(注:PostgreSQL数据库可以使用pgAdmin在本地网页图形化界面上进行管理,具体安装和使用请自行搜索)

软件方式安装需要配置一下环境路径,这样我们就可以在命令行直接使用psql命令。

在 ~/.bash_profile中添加以下内容(具体路径可以查看从图形界面进入psql命令行时显示的路径)

1
export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/12/bin

保存之后退出,在终端输入source ~/.bash_profile使设置生效。然后就可以直接在终端中键入psql,显示如下则表示设置成功。

1
2
psql (12.1)
Type "help" for help.

默认情况下本地用户登录都是受信任的,不需要输入密码,如果想要使用密码登录,可以修改/Users/本地用户名/Library/Application Support/Postgres/var-12/pg_hba.conf文件,将以下内容里的trust替换为md5即可

1
2
3
4
5
6
7
8
9
10
11
12
13
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all trust
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust

替换后

1
2
3
4
5
6
7
8
9
10
11
12
13
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local all all md5
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all md5
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5

重启PostgreSQL之后使用psql -U 用户名登录就需要输入密码了。

注:PostgreSQL常用指令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
psql -U [user] -d [database] -h [host] -p [post] //登录
\password:设置当前登录用户的密码
\h:查看SQL命令的解释,比如\h select。
\?:查看psql命令列表。
\l:列出所有数据库。
\c [database_name]:连接其他数据库。
\d:列出当前数据库的所有表格。
\d [table_name]:列出某一张表格的结构。
\du:列出所有用户。
\e:打开文本编辑器。
\conninfo:列出当前数据库和连接的信息。
\password [user]: 修改用户密码
\q:退出

配置数据库

首先使用postgres用户登录数据库

1
psql postgres

然后创建用户sonar并设置密码,这里的密码你可以填写自己的密码

1
CREATE USER sonar WITH PASSWORD 'sonar';

创建属于用户sonar的数据库sonar

1
CREATE DATABASE sonar OWNER sonar;

sonar用户加上添加数据库的权限

1
ALTER ROLE sonar CREATEDB;

这样,数据库配置就完成了,接下来正式安装SonarQube

安装和配置SonarQube

安装SonarQube主要分为三步:

  • 安装配置SonarQube本地服务器
  • 安装配置sonar-scanner
  • 安装配置xcprettyOCLintslather等工具和插件

安装配置本地服务器

SonarQube的服务可以运行在本地服务器或者远程服务器上,本文主要讲解本地服务器的配置方式。

首先上SonarQube官网上下载SonarQube源文件并解压。

然后配置conf/sonar.properties文件

设置数据库版本

1
sonar.jdbc.url=jdbc:postgresql://localhost/sonar

设置数据库账号密码

1
2
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar

进入bin/macosx-universal-64文件夹,给sonar.sh设置权限

1
chmod 777 sonar.sh

使用./sonar.sh console来启动服务器,在浏览器输入http://localhost:9000来测试服务器是否启动成功。页面正常显示就表示启动成功。

如果启动失败,可以根据SonarQube项目目录的logs文件夹中的日志查找原因。大部分启动不成功的情况都是数据库原因,这个在web.log文件中有记录。

注:SonarQube常用命令如下:

1
2
3
4
./sonar.sh console #Debug信息
./sonar.sh start #启动服务
./sonar.sh stop #停止服务
./sonar.sh restart #重启服务

安装和配置sonar-scanner

直接使用HomeBrew安装sonar-scanner

1
brew install sonar-scanner

安装完成后输入sonar-scanner -v或者sonar-scanner --version可以看到如下配置文件地址和版本信息

1
2
3
4
5
INFO: Scanner configuration file: /usr/local/Cellar/sonar-scanner/4.2.0.1873/libexec/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarQube Scanner 4.2.0.1873
INFO: Java 11.0.5 Oracle Corporation (64-bit)
INFO: Mac OS X 10.15.2 x86_64

根据上面显示的配置文件地址打开配置文件,即/usr/local/Cellar/sonar-runner/2.5/libexec/conf/sonar-runner.properties,修改或添加以下内容

1
2
3
4
sonar.host.url=http://localhost:9000
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar
sonar.jdbc.url=jdbc:postgresql://localhost/sonar

修改完后保存,sonar-scanner这部分就完成了。

安装其他工具和插件

首先安装环境工具。

安装xcpretty

1
2
3
4
5
git clone https://github.com/Backelite/xcpretty.git
cd xcpretty
git checkout fix/duration_of_failed_tests_workaround
gem build xcpretty.gemspec
sudo gem install --both xcpretty-0.2.2.gem

安装oclint

1
brew cask install oclint

安装slather

1
gem install slather

安装lizard

1
sudo pip install lizard

然后是安装静态分析插件,由于官方插件SonarCFamily比较贵,使用开源的就好。

这里可以看到插件版本和与之对应的SonarQube版本,到Release里面下载相应版本的jar文件即可(也可以下载源文件自行编译,这个比较费时间,不推荐)。将下载好的jar文件放到SonarQube安装目录下的extensions/plugins文件夹中,插件安装就完成了。

使用SonarQube静态扫描代码

终端路径切换到待扫描项目的根目录下,输入touch run-sonar.sh命令生成run-sonar.sh,然后输入vi run-sonar.sh编辑文件,在里面添加以下内容(注意把里面的xxx更改为你的项目名称的Scheme名称):

1
2
3
4
5
6
7
8
9
10
11
12
13
xcodebuild -workspace xxx.xcworkspace -scheme xxx clean build | tee xcodebuild.log | xcpretty --report json-compilation-database

mv build/reports/compilation_db.json compile_commands.json

oclint-json-compilation-database -exclude Pods -- -report-type pmd -o oclint.xml -max-priority-1 99999 -max-priority-2 99999 -max-priority-3 99999 -rc LONG_LINE=140 -rc LONG_METHOD=80 -rc NCSS_METHOD=50 -rc SHORT_VARIABLE_NAME=1 -rc CYCLOMATIC_COMPLEXITY=13 -rc MINIMUM_CASES_IN_SWITCH=2 -rc NPATH_COMPLEXITY=1500

rm -rf sonar-reports

mkdir sonar-reports

cat oclint.xml | sed "s#Switch Statements Should Have Default Rule#switch statements should have default#g" | sed "s#missing hash method#must override hash with isEqual#g" | sed "s#prefer early exits and continue#use early exits and continue#g" | sed "s#use boxed expression#replace with boxed expression#g" | sed "s#use container literal#replace with container literal#g" | sed "s#use number literal#replace with number literal#g" | sed "s#use object subscripting#replace with object subscripting#g" | sed "s#missing default in switch statements#switch statements should have default#g" | sed "s#unnecessary default statement in covered switch statement#switch statements don't need default when fully covered#g" | sed "s#covered switch statements dont need default#switch statements don't need default when fully covered#g" > sonar-reports/oclint.xml

/bin/sh sonar-scanner -X

以同样的方式新建sonar-project.properties文件,使用vi命令添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
##########################
# Required configuration #
##########################

sonar.projectKey=你的项目Key
sonar.projectName=项目名
sonar.projectVersion=版本号
sonar.language=objc

# Project description
sonar.projectDescription=Text sonarquebe

# Path to source directories
sonar.sources=项目源码文件夹名称
# Path to test directories (comment if no test)
# sonar.tests=testSrcDir


# Xcode project configuration (.xcodeproj or .xcworkspace)
# -> If you have a project: configure only sonar.objectivec.project
# -> If you have a workspace: configure sonar.objectivec.workspace and sonar.objectivec.project
# and use the later to specify which project(s) to include in the analysis (comma separated list)
sonar.objectivec.project=项目名.xcodeproj
# sonar.objectivec.workspace=myApplication.xcworkspace

# Scheme to build your application
sonar.objectivec.appScheme=需要编译的Scheme名
# Scheme to build and run your tests (comment following line of you don't have any tests)
# sonar.objectivec.testScheme=myApplicationTests

##########################
# Optional configuration #
##########################

# Encoding of the source code
sonar.sourceEncoding=UTF-8

# JUnit report generated by run-sonar.sh is stored in sonar-reports/TEST-report.xml
# Change it only if you generate the file on your own
# The XML files have to be prefixed by TEST- otherwise they are not processed
# sonar.junit.reportsPath=sonar-reports/

# Cobertura report generated by run-sonar.sh is stored in sonar-reports/coverage.xml
# Change it only if you generate the file on your own
sonar.objectivec.coverage.reportPattern=sonar-reports/coverage*.xml

# OCLint report generated by run-sonar.sh is stored in sonar-reports/oclint.xml
# Change it only if you generate the file on your own
sonar.objectivec.oclint.report=oclint.xml
sonar.objectivec.oclint.reportPath=sonar-reports/oclint.xml

# Paths to exclude from coverage report (tests, 3rd party libraries etc.)
# sonar.objectivec.excludedPathsFromCoverage=pattern1,pattern2
sonar.objectivec.excludedPathsFromCoverage=.*Tests.*

# Project SCM settings
# sonar.scm.enabled=true
# sonar.scm.url=scm:git:https://...

输入wq命令保存并退出。

为避免编译的时候出现oclint: error: one compiler command contains multiple jobs:的报错,需要使用XCode打开工程文件并且在Build Settings中将COMPILER_INDEX_STORE_ENABLE设置为NO。

进入到SonarQube项目文件夹,进入到bin/macosx-universal-64,使用命令./sonar.sh restart来重启服务器。

上面的步骤全部完成后,就可以在工程目录下使用./run-sonar.shsh run-sonar.sh命令来执行脚本。

命令执行行完毕并且没有报错,就可以在浏览器中输入http://localhost:9000查看检测结果。