sonarqube进行iOS静态代码分析

原文地址后续会有更改,可能不会及时同步在这里


参考文章:

  • Mac安装PostgreSQL
  • Fastlane+OCLint+SonarQube
  • OS Sonar集成流程详解
  • SonarQube 的安装与使用
  • sona-objective-c

背景

随着代码量的日益增加,以及团队的扩大,代码的质量需要有一定的保证,再加上目前有些功能需要oem给客户使用,一些KA用户会要求提供一些代码分析报告,所以本文将总结一下如何搭建iOS静态代码分析系统


本文涉及的工具及平台:

  • xcodebuild
  • oclint
  • xcpretty
  • sonarqube
    • sonar-scanner
    • sonar-server
    • postgresql

大部分iOS平台静态分析基本是基于开源的oclint进行的,本文虽然使用sonarqube,但免费的分析方案核心仍然是oclint

sonarqube是一个开源的静态代码分析平台,提供免费的社区版,免费的社区版不支持oc,但github有提供开源的插件,可以支持OC代码分析,付费的社区版plus有支持oc的分析插件SonarCFamily for C

无论免费方案还是付费方案,首先都是基于xcodebuid过程中的日志来进行的,下面先总结下免费的开源方案配置流程(ps:付费版试用还没申请成功,成功后再总结一下与开源方案对比一下)

对于使用开源方案来说,本质流程如下


image

xcodebuild

iOS核心工具,安装好Xcode就会自带此工具,因为oclint分析的核心是xcodebuild在编译app过程中的log,所以需要xcodebuild(build失败也会对已经build的日志进行分析,但尽量保证可以build成功)

如果项目是在workspace中需要指定-workspace和对应的scheme,可以通过xcodebuild -list查看

$ xcodebuild -list

Information about project "HHTestOClint":
    Targets:
        HHTestOClint_Example
        HHTestOClint_Tests

    Build Configurations:
        Debug
        Release

    If no build configuration is specified and -scheme is not passed then "Release" is used.

    Schemes:
        HHTestOClint-Example
//执行
$ xcodebuild -workspace HHTestOClint.xcworkspace -scheme HHTestOClint-Example

error: Signing for "HHTestOClint_Example" requires a development team. Select a development team in the Signing & Capabilities editor. (in target 'HHTestOClint_Example' from project 'HHTestOClint')

我们并不需要打出的包可以安装到手机上,只是需要build过程中的日志而已,所以我们只需要打出模拟器包Debug便可

$ xcodebuild -showsdks

iOS SDKs:
    iOS 13.2                        -sdk iphoneos13.2

iOS Simulator SDKs:
    Simulator - iOS 13.2            -sdk iphonesimulator13.2

因为xcodebuild会有缓存,所以我们每次执行前需要clean

xcodebuild -workspace HHTestOClint.xcworkspace -scheme -configuration Debug HHTestOClint-Example -sdk iphonesimulator13.2 clean build 

能编译成功的话就可以进入下一步了

xcpretty

xcpretty is a fast and flexible formatter for xcodebuild. It does one thing, and it should do it well.

xcpretty是一个格式化xcodebuild输出的工具,安装

$ gem install xcpretty

[!] Usage: xcodebuild [options] | xcpretty
    -t, --test                       Use RSpec style output
    -s, --simple                     Use simple output (default)
    -k, --knock                      Use knock output
        --tap                        Use TAP output
    -f, --formatter PATH             Use formatter returned from evaluating the specified Ruby file
    -c, --[no-]color                 Use colorized output. Default is auto
        --[no-]utf                   Use unicode characters in output. Default is auto.
    -r, --report FORMAT or PATH      Run FORMAT or PATH reporter
                                       Choices: junit, html, json-compilation-database
    -o, --output PATH                Write report output to PATH
        --screenshots                Collect screenshots in the HTML report
    -h, --help                       Show this message
    -v, --version                    Show version

-r, --report 指定生成的报告格式可选为junit, html, json-compilation-database

-o, --output指定生成的文件名称
这里我们使用json-compilation-database格式,输出文件名为compile_commands.json
(注意输出名称不能更改,否则后面oclint会报错,因为oclint源码中内置了校验名称,此处便是写死的解析文件名称的代码)

$ xcodebuild -workspace HHTestOClint.xcworkspace -scheme HHTestOClint-Example -sdk iphonesimulator13.2 clean build | xcpretty -r json-compilation-database -o compile_commands.json

OClint

OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code

OClint是进行OC代码分析的核心工具,主要对上一步生成的compile_commands.json进行分析,生成报告

$ oclint --help

Generic Options:

  -help                         - Display available options (-help-hidden for more)
  -help-list                    - Display list of available options (-help-list-hidden for more)
  -version                      - Display the version of this program

OCLint options:
  -disable-rule=     - Disable rules
  -list-enabled-rules           - List enabled rules
  -max-priority-1=   - The max allowed number of priority 1 violations
  -max-priority-2=   - The max allowed number of priority 2 violations
  -max-priority-3=   - The max allowed number of priority 3 violations
  -o=                     输出文件路径
  -p=                   解析路径
  -rc==       指定校验规则取值
  -report-type=           生成报告类型

For more information, please visit http://oclint.org

其中我们主要使用oclint-json-compilation-database,Github源码
oclint-json-compilation-database支持指定校验文件夹和过滤指定文件夹,本质上最终执行oclint -p命令,可以通过附加-v查看,同时还支持使用--后面跟上oclint执行参数

// 此处--符号后的参数是传递给oclint的
oclint-json-compilation-database -v -e Pods -e xxxx -- -report-type html -o report.html

oclint-rc选项可以自定义校验的参数值,如

oclint-json-compilation-database -v -e Pods -e xxxx -- -rc LONG_METHOD=60 -rc LONG_LINE=100

当我们需要自定义多个oclint参数时,我们可以将配置写在.oclint文件中

disable-rules:                      // 不使用的规则
  - LongLine
rulePaths:                          // oclint校验规则所在的路径,Mac端默认在/usr/local/lib/oclint/rules,如果不需要自定义规则的话可以不配置此项
 - /etc/rules
rule-configurations:                // 自定义配置参数
 - key: CYCLOMATIC_COMPLEXITY
   value: 15
 - key: NPATH_COMPLEXITY
   value: 300
output: oclint.xml                  // 生成的报告
report-type: xml                    // 生成的报告格式支持html、xml、json等
max-priority-1: 20                  // 级别1的问题最大个数,如果检测出的问题超过这个个数就会自动终止
max-priority-2: 40                  // 级别2的问题最大个数
max-priority-3: 60                  // 级别3的问题最大个数
enable-clang-static-analyzer: false // 

以下是所有支持的Rule,可以通过 -list-enabled-rules xxxx查看

Enabled rules:
- TooManyMethods
- DestructorOfVirtualClass
- DeadCode
- EmptyForStatement
- AvoidDefaultArgumentsOnVirtualMethods
- ProblematicBaseClassDestructor
- MisplacedDefaultLabel
- EmptyFinallyStatement
- CallingProhibitedMethod
- RedundantIfStatement
- CollapsibleIfStatements
- UnnecessaryElseStatement
- ConstantConditionalOperator
- DeepNestedBlock
- AssignIvarOutsideAccessors
- UnnecessaryNullCheckForDealloc
- RedundantNilCheck
- RedundantLocalVariable
- EmptyDoWhileStatement
- UnusedMethodParameter
- BitwiseOperatorInConditional
- ReturnFromFinallyBlock
- MultipleUnaryOperator
- DoubleNegative
- MissingCallToBaseMethod
- EmptyWhileStatement
- ShortVariableName
- ParameterReassignment
- UselessParentheses
- ThrowExceptionFromFinallyBlock
- UnnecessaryDefaultStatement
- HighNcssMethod
- PreferEarlyExit
- MissingBreakInSwitchStatement
- TooManyParameters
- CallingProtectedMethod
- AvoidBranchingStatementAsLastInLoop
- MissingAbstractMethodImplementation
- MissingHashMethod
- MisplacedNullCheck
- MisplacedNilCheck
- UseContainerLiteral
- LongLine
- ForLoopShouldBeWhileLoop
- HighNPathComplexity
- LongMethod
- EmptySwitchStatement
- RedundantConditionalOperator
- EmptyTryStatement
- EmptyCatchStatement
- UseObjectSubscripting
- AvoidPrivateStaticMembers
- EmptyElseBlock
- InvertedLogic
- LongClass
- LongVariableName
- GotoStatement
- BrokenOddnessCheck
- UseNumberLiteral
- TooFewBranchesInSwitchStatement
- UseBoxedExpression
- JumbledIncrementer
- EmptyIfStatement
- MissingDefaultStatement
- HighCyclomaticComplexity
- NonCaseLabelInSwitchStatement
- ConstantIfExpression
- BrokenNullCheck
- BrokenNilCheck
- TooManyFields
- UnusedLocalVariable

我们将.oclint放在与compile_commands.json相同的路径下,并在该路径下执行

oclint-json-compilation-database -v -e Pods -e Example

最终会生成oclint.xml(可以自己生成html格式,查看效果)

sonarqube

sonarqube是一个提供代码静态分析的平台,提供了一套完整的静态分析方案,包括后端及前端页面,可以结合jenkins、gitlab等平台来进行代码分析。
因为其底层源码为java开发的,所以对java代码支持比较完善,但是免费的社区版并不支持OC,所以我们如果要借助此平台的话,有以下两种方式:

  1. 开源插件sonar-object-c
    • github上开源的插件,目前作者已经停止迭代,上面是找了好久找到的能兼容sonarqube7.9的版本 ,核心是使用oclint检查,目前只有70+规则,但是可以自定义规则
  2. 付费使用社区版plus,提供了SonarCFamily for C插件
    • 有官方提供技术支持,250+的rules可供选择,不可自定义规则
      image

前提准备

无论使用上面哪种方案,首先要将服务搭建好服务,搭建服务有两种方式

  1. docker安装

  2. 下载安装包

下面主要总结使用安装包的配置流程:
安装包下载完成后,执行sonarqube-7.9.1/bin/macosx-universal-64/sonar.sh start,此时http://localhost:9000/应该已经可以访问了,默认账号为admin密码为admin,如果启动失败可以去sonarqube-7.9.1/logs下查看日志,启动成功后我们在最下面会看到warning

image

此处建议我们自己配置数据库,下面我们就来配置数据库(mysql后续将不再支持):这里我们使用的是PostgreSQL,配置参考

$ brew install postgresql                 //安装
$ pg_ctl -D /usr/local/var/postgres start //启动
$ createdb                                //创建数据库
$ psql                                    //登录控制台

数据库安装好后,我们需要提供一个数据库和账号供sonarqube使用

CREATE USER sonarqube WITH PASSWORD 'sonarqube';//创建用户
CREATE DATABASE sonar OWNER sonarqube;//创建属于该用户的数据库

然后我们去sonarqube-7.9.1/conf目录下编辑sonar.properties,将数据库相应配置配置完成

sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonarqube
sonar.jdbc.url=jdbc:postgresql://localhost/sonar

编辑完成后执行sonarqube-7.9.1/bin/macosx-universal-64/sonar.sh restart,此时警告已经消除了

image

至此我们的sonarqube的前端服务已经配置完成了
以下是配置过程中可能遇到的问题:

  • java.security.AccessControlException: access denied

    • java版本问题不支持高版本13,(使用docker就没这个问题)
  • Sonarqube will not start due to elasticsearch being unable to write yml settings file

    • elasticsearch不支持root用户启动,ls -la检查报错文件夹是否归属为root,如果为root就使用修改所属用户
      image
  • mysql连接失败(换个数据库吧)

    • 7.9可能不支持mysql
    • 低版本不支持mysql8
      image

分析工具选择

  • 开源插件sonar-object-c
  1. 下载jar包到sonarqube-7.9.1/extensions/plugins,然后重启服务器
  2. 下载sonar-scanner for cli
    image
  3. sonascanner添加至环境变量export PATH=$PATH:/path/to/scanner/(建议将此命令放到配置环境里,保证每个终端都包含此环境变量)

上述配置安装完成后,我们在需要检测的项目跟路径下创建sonar-project.properties文件,下面是简单的内容

# Required metadata
sonar.projectKey=xxxx           // 项目key 随便定义
sonar.projectName=xxxx          // 项目名称一般与检测项目一致,显示在sonar的web页面上
sonar.projectVersion=xx         // 项目版本
# Comma-separated paths to directories with sources
sonar.sources=xxxxx             // 项目需要检测的源码路径
sonar.objc.file.suffixes=.h,.m  // oc 文件前缀
sonar.sourceEncoding=UTF-8      // 编码
sonar.objectivec.oclint.report=oclint.xml 

这里的核心便是在上面步骤中由OCLint生成的xml文件,另外注意这里有一个坑,oclint.xml必须放至sonar-reports文件下,无论sonar.objectivec.oclint.report配置是什么,貌似都不生效

image

创建完成后,在sonar-project.properties路径下执行sonar-scanner,执行成功后,便可在sonar的前端页面看到对应的检测效果了

image

点击对应结果,可以查看详细信息,如果我们想过滤某些规则,或者自定义一些规则的取值,可以使用上面介绍的.oclint文件进行自定义配置

image

总结

从上面可以看出,开源方案其实核心就是oclint,只是借助了sonarqube提供的前端服务而已,所以如果有自定义需求,可以考虑自己搭建服务。

oclint提供的rule只有70+,还有一些是不适用oc的,但可以支持自定义规则,可定制性很高,所以如果不打算使用付费版的话,可以考虑自行定制规则。

你可能感兴趣的:(sonarqube进行iOS静态代码分析)