iOS代码扫描(sonarQube)

2,697 阅读6分钟

所需环境配置和软件安装

下面是在mac机器上安装的工具

  • homebrew(mac命令管理软件工具)
  • Java JDK
  • xcode
  • sonarqube(代码扫描平台)
  • sonar-scanner(收集report.json、swiftlint.txt、lizard-report.xml上报到SonarQube)
  • scanner-swift(扫描OC\swift的插件)
  • xcpretty(处理xcodebuild.log,输出compile_commands.json)
  • swiftlint(处理swift文件,输出swiftlint.txt)
  • Tailor (Swift编程语言编写的源代码的静态分析和lint工具)
  • lizard(处理ObjC文件,输出lizard-report.xml)
  • oclint(一些代码规则问题)
  • salther(生成测试覆盖率报告)
1.安装SonarQube

使用的是官方长期支持和维护的版本SonarQube 8.9.7,下载后,放到你想要的目录,我这里放到了/usr/local (注意点:因为sonarqube-object-c插件需要付费,需要使用免费的scanner-swift,而scanner-swift不支持新版本。)

  • 修改sonar.properties文件配置
  • 进入sonarqube-8.9.7/conf目录下编辑sonar.properties,配置改为如下:
#----- 登录账号密码
sonar.login=admin
sonar.password=12345
#----- 数据库相关
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonarqube
sonar.jdbc.url=jdbc:postgresql://localhost/sonar
2.安装Java 11

下载Java 11, 前往官网下载Java SE Development Kit 11.0.16,下载java11是因为使用最新的版本或者java1.8都无法打开 http://localhost:9000

3.安装Sonar-scanner
  • 使用Homebrew安装
$ brew install sonar-scanner
  • 查看是否安装成功还有版本
$ sonar-scanner --version
INFO: Scanner configuration file: /usr/local/Cellar/sonar-scanner/4.7.0.2747/libexec/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarScanner 4.7.0.2747
INFO: Java 11.0.16.1 Homebrew (64-bit)
INFO: Mac OS X 11.5.2 x86_64
  • 注意:如果homebrew因为多次安装报错建议使用如下命令进行重装
$ /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
  • Sonar-Scanner配置参数 在SonarScanner的安装目录中找到/conf/sonar-scanner.properties,通过编辑更新全局设置:
#----- Default SonarQube server
#sonar.host.url=http://localhost:9000

#----- Default source code encoding
#sonar.sourceEncoding=UTF-8

#----- 登录账号密码
sonar.login=admin
sonar.password=xxxx
#----- 数据库
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonarqube
sonar.jdbc.url=jdbc:postgresql://localhost/sonar
4.安装PostgreSQL数据库
  • 使用Homebrew安装
$ brew install postgresql
  • 安装完成后初始化数据库
$ initdb /usr/local/var/postgres
  • 启动服务
$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
  • 创建账户
$ createuser username -P

username 是用户名,回车输入 2 次用户密码后即用户创建完成。更多用户创建信息可以 createuser --help 查看

  • 创建数据库
$ createdb sonarqube -O username -E UTF8 -e

上面创建了一个名为 sonarqube 的数据库,并指定 username 为改数据库的拥有者

5.安装xcpretty

使用sudo gem install -n /usr/local/bin xcpretty ,这样会有安装风险。 使用sonar-swift官方推荐安装

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.3.0.gem
6.安装SwiftLint

安装:brew install swiftlint 

7.安装Tailor

安装:brew install tailor 

8.安装slather

直接执行命令gem install slather 会报错,需要升级brew到最新版本

ERROR:  Error installing slather:
    ERROR: Failed to build gem native extension.

...省略一大堆信息...

extconf failed, exit code 1

Gem files will remain installed in /Library/Ruby/Gems/2.6.0/gems/racc-1.5.2 for inspection.
Results logged to /Library/Ruby/Gems/2.6.0/extensions/universal-darwin-19/2.6.0/racc-1.5.2/gem_make.out

更新ruby版本:

brew install ruby

执行完成后按照提示添加环境变量,并立即生效;

export PATH="/usr/local/opt/ruby/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/ruby/lib" 
export CPPFLAGS="-I/usr/local/opt/ruby/include"

继续执行gem install slather 安装完成,但是依然会找不到命令,建议执行以下命令重新安装即可;

sudo gem install -n /usr/local/bin slather
9.安装lizard

直接官方命令sudo pip install lizard 会报错,改用sudo pip3 install lizard

注意!:安装过程中如果出现依赖包下载失败情况,可单独先安装好依赖包,然后再次执行安装 

10.安装OCLint
  • 使用homebrew安装,但是有可能OCLint的版本不匹配你的Xcode版本导致检查出错
brew tap oclint/formulae  
brew install oclint
  • (建议直接下载)如果报错的话,前往 OCLint Releases 下载支持你当前Xcode版本的OCLint版本,放到任意目录下。可以和SonarQube同级。
    查看安装结果
% oclint --version
  OCLint (https://oclint.org):
  OCLint version 21.10.
  Built Oct 25 2021 (21:41:25).
11.SonarQube-swift插件包安装

建议下载完整master完整压缩包需要用到:sonar-project.properties文件和sonar-swift-plugin/src/main/shell/路径下的run-sonar-swift.sh文件

12.环境变量配置
  • 统一配置下环境变量:(java、sonarqube、sonar-scanner等的环境变量配置)
    打开配置文件
$ vim ~/.bash_profile
  • 根据自身安装路径进行如下配置:
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-11.0.16.1.jdk/Contents/Home

export PATH=$JAVA_HOME/bin:$PATH:.

export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.

OCLINT_HOME=/Users/xuejunting/bin/OCLint/oclint-21.10

export PATH=$OCLINT_HOME/bin:$PATH

export SONAR_RUNNER_HOME=/usr/local/sonarqube-8.9.7.52159

export PATH=$SONAR_RUNNER_HOME/bin:$PATH

export SONAR_SCANNER_HOME=/usr/local/sonar-scanner

export PATH=$SONAR_SCANNER_HOME/bin:$PATH

export PATH="/usr/local/opt/ruby/bin:$PATH"

export LDFLAGS="-L/usr/local/opt/ruby/lib"

export CPPFLAGS="-I/usr/local/opt/ruby/include"

export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles #ckbrew

eval $(/usr/local/Homebrew/bin/brew shellenv) #ckbrew

  • 退出并保存后运行
$ source ~/.bash_profile
13.扫描
  • 启动sonarqube
    终端cd到/usr/local/sonarqube-8.9.7.52159/bin/macosx-universal-64目录下运行
$ sh sonar.sh start
  • 启动数据库
$ pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
  • 在终端通过SonarQube推荐的指令集进行扫描
sonar-scanner \           
  -Dsonar.projectKey=TestPod \
  -Dsonar.sources=. \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.login=生成的口令,你创建扫描工程的时候会自动生成此条命令

打开http://localhost:9000找到项目查看结果
这时你会发现使用sonar-scanner分析项目后刷新SonarQube后台,得到了一份完美的报告,一个问题都没有,这时需要我们结合前面下载的诸多工具如:OCLint进行分析;

  • 需要在SnoarQube的设置
    在项目设置完成如下更改:

WechatIMG10506.png

WechatIMG10514.png 在SonarQube后台,我们进入项目配置-设置,可以在左侧看到前面添加的插件Swift (Backelite),点击后可以右侧看到一些路径配置,OCLint的报告的相对路径(Path to OCLint pmd formatted report)sonar-reports/*oclint.xml,我们在可以将OCLint分析报告放置在此路径中,SonarQube即可显示出分析结果。

WechatIMG10499.jpeg 常见报错:#oclint: error: compilation contains multiple jobs:
在需要扫描的项目中需要做如下更改:
第一步:podfile文件中添加

post_install do |pi|
    pi.pods_project.targets.each do |t|
        t.build_configurations.each do |config|
            config.build_settings['COMPILER_INDEX_STORE_ENABLE'] = "NO"
        end
    end
end

第二步:将project和target的COMPILER_INDEX_STORE_ENABLE,都设置为NO

截屏2022-10-17 下午3.37.11.png

  • 新建测试项目和配置sonar-project.properties文件

  • 新建一个sonar-project.properties在代码扫描的根目录(或者直接把下载好的添加到目录下),与 .xcodeproj同级,然后编辑sonar-project.properties文件,按实际名称进行填写;

#

# Swift SonarQube Plugin - Enables analysis of Swift and Objective-C projects into SonarQube.

# Copyright © 2015 Backelite (${email})

#

# This program is free software: you can redistribute it and/or modify

# it under the terms of the GNU Lesser General Public License as published by

# the Free Software Foundation, either version 3 of the License, or

# (at your option) any later version.

#

# This program is distributed in the hope that it will be useful,

# but WITHOUT ANY WARRANTY; without even the implied warranty of

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

# GNU Lesser General Public License for more details.

#

# You should have received a copy of the GNU Lesser General Public License

# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#

sonar.projectKey=FatePlusIOS

sonar.projectName=FatePlusIOS

# Number version (can be found automatically in plist, just comment this line)

#sonar.projectVersion=1.0

# Comment if you have a project with mixed ObjC / Swift

sonar.language=ObjC

# Project description

sonar.projectDescription=prjDescription

# Path to source directories

sonar.sources=FatePlusIOS

# Path to test directories (comment if no test)

sonar.tests=FatePlusIOSTests

# Destination Simulator to run surefire

# As string expected in destination argument of xcodebuild command

# Example = sonar.swift.simulator=platform=iOS Simulator,name=iPhone 6,OS=9.2

#sonar.swift.simulator=platform=iOS Simulator,name=iPhone X,OS=latest

sonar.swift.simulator=platform=iOS Simulator,name=iPhone 13,OS=15.0

# Xcode project configuration (.xcodeproj)

# and use the later to specify which project(s) to include in the analysis (comma separated list)

# Specify either xcodeproj or xcodeproj + xcworkspace

sonar.swift.project=FatePlusIOS.xcodeproj

sonar.swift.workspace=FatePlusIOS.xcworkspace

# Scheme to build your application

sonar.swift.appScheme=FatePlusIOS

# Specify your appname when different from targeted scheme.

# Or when slather fails with 'No product binary found'

# You can also provide a list of framework names to analyse for coverage.

# This will be something like "myApp" or "myApp,myFramework"

# sonar.coverage.binaryNames=myApp,myFramework


# Configuration to use for your scheme. if you do not specify that the default will be Debug

#sonar.swift.appConfiguration=MyConfiguration


##########################

# Optional configuration #

##########################

# Encoding of the source code

sonar.sourceEncoding=UTF-8

# SCM

# sonar.scm.enabled=true

# sonar.scm.url=scm:git:http://xxx

# 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/

# Lizard report generated by run-sonar.sh is stored in sonar-reports/lizard-report.xml

# Change it only if you generate the file on your own

# sonar.swift.lizard.report=sonar-reports/lizard-report.xml

# Cobertura report generated by run-sonar.sh is stored in sonar-reports/coverage-swift.xml

# Change it only if you generate the file on your own

# sonar.swift.coverage.reportPattern=sonar-reports/coverage-swift*.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.swift.swiftlint.report=sonar-reports/*swiftlint.txt

# Change it only if you generate the file on your own

# sonar.swift.tailor.report=sonar-reports/*tailor.txt

  


# Paths to exclude from coverage report (surefire, 3rd party libraries etc.)

# sonar.swift.excludedPathsFromCoverage=pattern1,pattern2

sonar.swift.excludedPathsFromCoverage=.*Tests.*,.*Specs.*

# Ability to skip tests (such as UI Tests running long time)

# Example = sonar.swift.skipTests=UITests

##########################

# Tailor configuration #

##########################

# Tailor configuration

# -l,--max-line-length=<0-999>                  maximum Line length (in characters)

#    --list-files                               display Swift source files to be analyzed

#    --max-class-length=<0-999>                 maximum Class length (in lines)

#    --max-closure-length=<0-999>               maximum Closure length (in lines)

#    --max-file-length=<0-999>                  maximum File length (in lines)

#    --max-function-length=<0-999>              maximum Function length (in lines)

#    --max-name-length=<0-999>                  maximum Identifier name length (in characters)

#    --max-severity=<error|warning (default)>   maximum severity

#    --max-struct-length=<0-999>                maximum Struct length (in lines)

#    --min-name-length=<1-999>                  minimum Identifier name length (in characters)

sonar.swift.tailor.config=--no-color --max-line-length=100 --max-file-length=500 --max-name-length=40 --max-name-length=40 --min-name-length=4

将下载好的run-sonar-swift.sh放到项目根目录下 然后在工程目录中执行以下命令:

sh run-sonar-swift.sh

执行完毕后,再次刷新sonarqube的后台就能看到完整的扫描信息,报错点击可查看具体问题内容了!

参考

IOS 代码扫描从放弃到入门
iOS 用sonar-swift实现SonarQube代码质量扫描
iOS 静态代码分析(SonarQube + Objective-C、Swift)
sonarqube进行iOS静态代码分析
Mac 配置 PostgreSQL 常用操作
sonar-swift