Leon’s Blog

Dreams don't work unless you do.

本地自动化Code Review集成

在项目开工之前,为了保证代码质量,通常我们会和团队中的成员讨论并制定一份代码规范文档,虽然文档已经形成了,但是在实际开发的过程中为了赶项目亦或者某个成员习惯于自己以前的代码风格忽略了规范文档中的细节要求,导致了部分代码风格不统一,这时候再通过审视写过的代码来排查是一件枯燥又乏味的过程,相信大多数紧张进行中的团队也没有足够的时间来做这样一件事情,如果我们能够像xcode编译工程代码一样Command + B就能提示哪里没有符合代码规范就省去了我们大量的Code Review时间,既然本篇文章讲的是自动化Code Review,接下来我们实现这一自动化过程。

OCLint


OCLint 是一个开源的,基于 Clang 用 C++ 编写而成的,可以用于 C、C++ 和 Objective-C 的静态代码分析器。它可以在扫描的过程中动态加载规则文件(Rules),因此可以实现非常灵活的,高度可自定义的代码分析方案。它几乎可以和大多数系统无缝集成,例如 Cmake、Bear、xcodebuild、xctool、Xcode、xcpretty、Jenkins CI、Travis CI 等。

最新版的OCLint已经自带了71条Rules,这些都是先人宝贵的经验,我们可以选择性的去选择规则,也可以去开发自己的Rules。

OCLint 提供了 ClangAST (Abstract Syntax Tree) 的一层封装,使我们不必对抽象语法树进行解析,只需要专注规则相关的逻辑开发即可。在开发好相关的规则后,打包成 dylib,就可以在分析的时候加载我们自己的 Rule 了

安装OCLint

1.使用Homebrew安装,首先需要设置brew的第三方仓库oclint/formulae。

1
brew tap oclint/formulae

2.安装OCLint

1
brew install oclint

3.对oclint升级的方法

1
brew updatebrew upgrade oclint

4.brew清理旧版本的数据

1
brew cleanup

分析自动化Code Review过程

  1. Command + B之后xcode开始编译 + 运行脚本
  2. 生成compile_commands.json文件
  3. OCLint读取Rules,逐个扫描compile_commands.json文件中的.m文件
  4. OCLint将生成的报告展示在xcode上。

从上面的过程可以看出首先我们要有一个compile_commands.json的文件,它是 Clang 定义的一个规范,里面存放了一组工作目录、目标文件、需要被执行的命令,帮助相关工具可以独立于编译系统来将源代码文件转换为 AST 并做对应的事。

了解compile_commands.json的地位后我们就生一个出来玩玩!

首先,进入到项目所在目录利用xcodebuild 生成 xcodebuild.log 文件。

1
xcodebuild | tee xcodebuild.log

然后使用 oclint-xcodebuild 生成 compile_commands.json

1
oclint-xcodebuild

最后在当前目录发现compile_commands.json生成了(是个闺女[偷笑]),但是终端控制器中却显示了这样一段话

1
2
This binary is no longer under maintenance by OCLint team.
Please consider using xcpretty (https://github.com/supermarin/xcpretty) instead!

原来OCLint团队将不再维护oclint-xcodebuild,并告诉我们使用xcpretty来替代,好吧,动手再生一个!

xcpretty


xcpretty是用来格式化xcodebuild输出的工具,使用ruby开发。

安装

1
gem install xcpretty

安装后可以通过gem list 来查看列表中有无xcpretty,或者xcpretty –version 来查看版本,如果有xcpretty的相关信息的话恭喜你安装成功了!

使用xcpretty生成compile_commands.json

1
xcodebuild |xcpretty -r json-compilation-database

在build/reports中得到文件compilation_db.json,我们发现新生成的compilation_db.json名字和compile_commands.json是有区别的,当我们使用oclint-json-compilation-database对其分析的时候发现找不到文件,报如下错误:

1
2
» oclint-json-compilation-database -- -o=report.html
Error: compile_commands.json not found at current location.

这时候要么我们把build/reports中的compilation_db.json文件复制一份到当前目录并重命名为compile_commands.json,或者我们在使用xcpretty生成.json文件的时候在后面加上导出路径并命名.json文件: –output ./compile_commands.json

1
xcodebuild | xcpretty -r json-compilation-database --output ./compile_commands.json

然后再运行

1
oclint-json-compilation-database -- -o=report.html

生成最终的报告report.html,打开报告就可以看到哪些代码是不符合规范的了。

我们项目中经常会用到cocopods来管理第三方库,第三方库的代码我们是不需要检查的,可以使用-e来忽略不需要分析的目录

1
oclint-json-compilation-database -e Pods -- -o=report.html

如果想改变规则的默认值,使用-rc来修改,比如:变量名的最长字节限制为200

1
oclint-json-compilation-database -- -rc=LONG_VARIABLE_NAME=200 -o=report.html

如果想禁止某一个规则的使用可以使用命令-disable-rule

1
oclint-json-compilation-database -disable-rule=LongLine

具体都有哪些规则可以查看Rules index,还有OCLint的更多命令说明

最后我们把下面的脚本集成到xcode工程,实现xcode中command + B 编译提示不符合规范的代码警告

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
#! /bin/sh
if which oclint 2>/dev/null; then
echo 'oclint exist'
else
brew tap oclint/formulae
brew install oclint
fi
if which xcpretty 2>/dev/null; then
echo 'xcpretty exist'
else
gem install xcpretty
fi
source ~/.bash_profile
cd ${SRCROOT}
xcodebuild clean
xcodebuild | xcpretty -r json-compilation-database
cp build/reports/compilation_db.json compile_commands.json
oclint-json-compilation-database \
-e Pods \
-- \
-disable-rule=IvarAssignmentOutsideAccessorsOrInit \
-disable-rule=HighCyclomaticComplexity \
-disable-rule=UnusedMethodParameter \
-disable-rule=AssignIvarOutsideAccessors \
-max-priority-1=100000 \
-max-priority-2=100000 \
-max-priority-3=100000 \
-report-type xcode

悲剧~结果报错了!错误如下所示:

发现压根没有生成reports文件夹,所以导致compilation_db.json找不到,也就无法copy到当前目录了,查阅了各种资料,而然并没有找到相关问题,终端命令是可以生成compile_commands.json文件的,脚本在xcode中跑就无法生成了- -,哪位朋友如果知道原因的话还请告知一下。

这样不行,我们又想在xcode中查看结果报告,在无法跨越前面的坎儿的情况下只能另辟蹊径了。既然是找不到compile_commands.json文件就报错的,那么我们就先用终端命令在当前目录生成compile_commands.json文件,然后再编译一下,激动人心的时刻——成功了!

如果你的代码不符合规范的话就会报诸如这样的警告⚠️:

从警告可以看出是不符合Size规则中的LongLine规范,我们可以打开Rules查看具体不符合哪一条规则:

Issues


可能一路操作过来并不是很顺利,会遇到各种各样的问题,比如下面这样的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Running OCLint....20 errors generated.
21 errors generated.
1 error generated.
1 error generated.
24 errors generated.
1 error generated.
1 error generated.
1 error generated.
3 errors generated.
1 error generated.
2 errors generated.
1 error generated.
32 errors generated.
1 error generated.
1 error generated.
20 errors generated.
21 errors generated.
1 error generated.
1 error generated.
24 errors generated.
1 error generated.
...

我也遇到过上面的报错,不过我是升级了一下oclint就解决了的,如果解决不了的话可以参考一下这里,里面有很多issues以及解决办法,希望可以帮助到你^ ^

既然有本地Code Review那么肯定也会有远端Code Review了,二者的区别在于本地Review主要是给开发者一个及时的代码质量反馈,远端Review主要是生成报表给各位管理者看的。由于目前还未用到远端Code Review,所以还没有开展这方面的实践,后续还是会把这块空缺补上滴。