代码审核(Code Review)是软件研发质量保障机制中非常重要的一环,但在实际项目执行过程中,却因为种种原因被Delay甚至是忽略。在实践中,给大家推荐一款免费、开放源代码的代码审查软件Gerrit。
1、Why Code Review
Code Review是什么
Code Review最直观的解释即看代码。常规的做法为自己看,有时代码逻辑问题可能自己看不出来,需要找同事一起看,在大家知识体系相对平均的情况下可能需要花钱专门的公司帮助查看。
Code Review需要看哪些?对于刚入职场或者刚接触到Coding的新人来说,代码风格是比较重要的一块。除此之外,编码规范及代码结构写法,框架和工具的选型,具体项目的业务逻辑,安全隐患,性能问题等都可以通过review的方式发现。Code Review从前往后大致分为结对编程,提交代码后,测试之前,发版之前,发版之后等几个阶段,越往后,Code Review的效果越差,修复的成本也越来越高。
为什么一定要做入库前Code Review
首先,代码审查的最大的功用是纯社会性的。如果你在编程,而且知道将会有同事检查你的代码,你编程态度就完全不一样了。你写出的代码将更加整洁,有更好的注释和程序结构。
其次,偷懒是人的天性,从节约成本的角度考虑,大家一般会选择在测试之前无限制的Delay Code Review。入库前做Code Review便是成本和效果之间最佳平衡点,它能及时发现问题,进行修改后确保代码质量。
最后,代码审查能传播知识。在很多开发团队里,经常每个人负责一个核心模块,每个人都只关注自己的模块。除非是同事的模块影响了自己的程序,他们从不相互交流。这种情况的后果是,每个模块只有一个人熟悉里面的代码。如果这个人休假或辞职了,其他人则束手无策。通过代码审查,至少会有两个人熟悉这些程序——作者,以及审查者。审查者并不能像程序的作者一样对程序十分了解,但至少他会熟悉程序的设计和架构,这是极其重要的。
2、Gerrit(盖瑞特)简介
Gerrit,是一种开放源代码的基于web平台的代码评审工具,基于 Git 版本控制系统。它在传统的源码管理协作流程中强制性引入代码审核机制,通过人工代码审核和自动化代码验证过程,将不符合要求的代码屏蔽在代码库之外,确保核心代码多人校验、多人互备和自动化构建核验。
l 作者是 Google 公司的 Shawn Pearce ,最初是为了管理 Android 项目而产生的。
l 它最初是由 Python 编写,在第二版后改用 Java 与 SQL。
l 名字来源于一名荷兰设计师及建筑师 Gerrit Thomas Rietveld(赫里特·托马斯·里特费尔德)的名字。
Gerrit工作流
git
Gerrit
或:
使用过git的同学,都知道,当我们git add —> git commit —> git push 之后,你的代码会被直接提交到repo,也就是代码仓库中,就是图中橘红色箭头指示的那样。
那么gerrit就是上图中的那只鸟,普通成员的代码是被先push到gerrit服务器上,然后由代码审核人员,就是左上角的integrator在web页面进行代码的审核(review),可以单人审核,也可以邀请其他成员一同审核,当代码审核通过(approve)之后,这次代码才会被提交(submit)到代码仓库(repo)中去。
无论有新的代码提交待审核,代码审核通过或被拒绝,代码提交者(Contributor)和所有的相关代码审核人员(Integrator)都会收到邮件提醒。
gerrit还有自动测试的功能,和主线有冲突或者测试不通过的代码,是会被直接拒绝掉的,这个功能似乎就是右下角那个老头(Jenkins)的任务。
整个流程就是这样。 在使用过程中,有两点需要特别注意下:
当进行commit时,必须要生成一个Change-Id,否则,push到gerrit服务器时,会收到一个错误提醒。
提交者不能直接把代码推到远程的master主线(或者其他远程分支)上去。这样就相当于越过了gerrit了。 gerrit必须依赖于一个refs/for/*的分支。
假如我们远程只有一个master主线,那么只有当你的代码被提交到refs/for/master分支时,gerrit才会知道,我收到了一个需要审核的代码推送,需要通知审核员来审核代码了。
当审核通过之后,gerrit会自动将这条分支合并到master主线上,然后邮件通知相关成员,master分支有更新,需要的成员再去pull就好了。而且这条refs/for/master分支,是透明的,也就是说普通成员其实是不需要知道这条线的,如果你正确配置了sourceTree,你也应该是看不到这条线的。
Gerrit适用性
几乎任何需要正式发布的项目都应当使用Gerrit来进行代码审查,如果Team中有新人,必须使用Gerrit确保代码质量。
Gerrit效果
整体上来说,个推使用的标准配置为Gerrit+Jenkins+Sonar,整个系统搭建完成后得到的效果为:100% Code Style问题避免入库,80% 设计问题避免入库,40% 逻辑错误避免入库,20% 安全隐患避免入库,100% 人员互备。
3、Gerrit入门实战
Gerrit部署和运行
JDK环境配置
java -jar gerrit-2.12.war init -d review_site
Gerrit用户角色和权限
Gerrit用户角色全新可以由管理者进行配置。
Gerrit用户角色:
admin: 拥有最高权限
verify: 确认+1权限,入库权限
reviewer: 代码评审权限,包含+1/-1,+2/-2的权限
developer: push权限
<br />第一个登录gerrit的web页的用户为admin管理员用户,创建dev帐号、review帐号和verify帐号,创建dev、review和verify用户组并添加相应用户。
Gerrit使用流程:
Gerrit相关配置
profile
注意设置Username,代码同步时需要用到。
初次登录时,Full Name 和 Email Address 字段都是空的,要设置一下,没有设置之前,右上角显示的用户名称也是admin
Preferences
Preferences页面用于配置gerrit的web页面,我一般把时间格式改成习惯的24小时制,同时确保Email Nofification
处于开启状态,这个默认就是开启的;然后在Show Change Number In Changes Tables
打上勾,这样能清楚地看到每个审核的编号,邮件里面显示的也是这个编号。
Watched Projects
这里有必要先说一下gerrit的两个默认项目:
我们点击左上方的菜单栏 Projects –> List,就能看到两个默认的项目All-Projects
和 All-Users
,这两个工程是两个基础的工程,我们新建的工程默认都是继承自All-Projects
的权限。关于权限部分我们在后面的章节详细介绍。
所以在Watched Projects
菜单中,就是当前用户要监听的项目,当这些项目发生变化时,你会收到邮件提醒,如果你选择了All-Projects
,那么就意味着你要监听所有的工程,因为所有工程都会默认继承自All-Projects
。
注意,后面的那些选项,勾选了某一项,就表示仅仅给当前项发送邮件提醒,保险期间,我们就全部勾上就好了。
Contact Information
这里是当前账号的配置,你可以在这里把full-name填写完全,这样右上角也会同步更新你刚设置好的名称。
注意这里的Preferred Email有两种设置方法:
- 如果你的邮件服务器配置完成了,可以点击Register New Email,你就会收到一封确认邮件,确认之后就能设置好了。
- 通过SSH在命令行中进行配置,通过命令行进行配置是最方便快捷,也是最优先推荐的方法。
不过因为SSH命令行的方式需要配置SSH公钥,所以我们这里先留空,一会通过命令行来配置。
SSH Public Keys
Groups
最后来看一下gerrit的分组。图片里面是gerrit默认的几个分组,我们需要知道的是Administrator
就是管理员分组,Anonymous Users
指的是所有添加到gerrit数据库中的成员都默认加入的一个组。之后我们还可以建立新的分组,加入新的成员等等。
示例:
接下来我们来做一个演示,看看一个新的成员是如何被添加到gerrit服务器中,然后他们又是如何协同工作的。
这里一共涉及到两个角色,一个是管理员,一个是普通成员。
管理员设置SSH
在之前的文章中我们提到过,gerrit自带的H2数据库就完全够用了,对成员的管理,邮件添加等操作,均可以通过SSH来完成。那第一步我们就来看一下管理员如何才能远程SSH到gerrit服务器。
首先确保在之前,已经成功把你的公钥添加到了web页面账户中。
接下来,需要修改之前~/.ssh/
文件夹下面的config文件,我们拿我的config文件做为示例,做个讲解。
我们还是先进入到~/.ssh/
文件夹中
然后查看一下config
文件: vim config
我们看到这里面有两个Host部分,我们重点来看第2个Host部分,这个是我们新建的,用于连接到gerrit服务器的配置。
照猫画虎,对于我们之前建立在192.168.1.100
的gerrit服务器来说,你的Host
配置可能如下:
12345 | Host gerritHostName “192.168.1.100”User “admin”IndentityFile “~/.ssh/id_rsa”port 29418 |
---|---|
User要和我们在gerrit服务器上注册的名称保持一致( 不是 full-name),认证文件注意要和公钥对应的私钥文件,端口要填写gerrit服务的端口号,这里是默认的29418
。
配置完config文件,我们就可以SSH到gerrit了,我们来尝试一下吧:
我们在管理员的机器上,输入ssh gerrit -l admin
命令,就可以得到gerrit服务器的响应,只不过因为我们禁用了shell,所以连接很快断开了,没有关系,这样证明做为管理员,已经可以通过命令行对gerrit服务器进行一系列的操作了。
添加普通成员
在管理员添加新的组员之前,我们需要先在普通成员的机器上生成ssh的公私钥,这里方便描述,我们把这个普通成员命名为test3。
在test3的电脑命令行中,生成利用ssh-keygen
命令,生成公私钥。
我们就使用默认的id_rsa命名好了。
接下来,test3成员需要把id_rsa.pub
公钥发送给管理员,这样管理员才能正常把test3添加到gerrit用户组中。
我们假设管理员将test3的pub公钥放到了~/home
目录下,也就是说,在管理员的电脑上,test3的公钥存放在~/home/id_rsa.pub
文件,当然我们也可以重新把它命名为test3.pub
,方便演示我这里就不做更名处理了,
接下来,管理员在命令行中输入如下的命令来完成添加普通成员的操作。注意: 这个命令很强大很方便,可以一步到位地把成员的的名称,全名,邮箱以及ssh公钥认证全部设置好。
1 | $ cat ~/home/id_rsa.pub | ssh gerrit gerrit create-account —full-name test3 —email test3@microwu.com —ssh-key - test3 |
---|---|
接下来我们来详细看一下这个命令:
|
符号把这个命令分成了两部分,第一部分的cat ~/home/id_rsa.pub
表示把test3的公钥内容读入到输入流中- ssh gerrit是我们之前在
~/.ssh/config
中配置好的gerrit服务器地址 - 又接着一个gerrit表示通过ssh中输入gerrit命令来进行相关操作
- create-account 表示要新建用户。注意,新建的用户名写在最后面,中间是其他参数
- full-name 就如同页面中的全名,我们这里命名为test3
- email表示该用户的email地址,我们填入 test3@microwu.com
- ssh-key - 注意,最后的
-
表示从输入流中读取ssh的公钥内容,也就是|
符号之前我们读入的test3用户公钥内容 - 最后面加上我们要create的用户名称
这个命令执行完之后,管理员就把test3用户加入到了gerrit用户组中,并且设置了他的全称,邮件以及公钥文件,是不是一步到位,非常方便??
这里我们回过头来,在管理员首次登陆web页面进行修改配置的时候,我们说过,管理员的邮箱可以通过命令行来设置,是的,同样通过ssh命令行:
1 | $ ssh gerrit gerrit set-account —add-email admin@microwu.com admin |
---|---|
这个命令就表示为我们的admin
用户添加emailadmin@microwu.com
。执行完这个命令,再回到web界面上的用户设置界面,看看是不是管理员的email已经被设置好了??
修改用户所在组
接下来我们看一下怎样修改test3用户所在的组吧。我们知道他已经出在Anonymous Users
组中了,那我们想要新建一个组,就叫test_user
吧,我们来看一下
我们在gerrit页面的顶部,点击People –> list, 看一下默认的两个分组,Administrator
和Non-interactive Users
,这两个分组我们都能从字面上理解是什么意思。我们注意到Anonymous Users
这个分组并没有显示在页面,因为它是匿名的嘛,所有的用户自动添加到这个分组中了。
选择Create New Group
,输入我们要添加的新的分组 test_user
新的分组中,我们看到管理员的账号被自动添加了进来
我们在Add
搜索栏中输入test,就会自动显示出来管理员之前在命令行中创建的test3用户,看到full-name和email了吧,都已经添加完成了!
test3用户已经添加到了test_user分组中了。
创建第一个项目,配置权限管理
添加project,选择 Inherit From All-Projects,当然也可以自定义Parent Project。
添加Verified标签支持,这里修改All-Project 项目的project.config,所有继承自All-Project的项目自动添加Verified 标签,也可针对项目自定义是否verify。
创建用户组
添加相关用户权限
将代码库同步到本地(SSH/Http)
HTTP 方式:
HTTP Password 密码在 账户 - ->> Settings —>> HTTP Password 处获取。
SSH方式:
添加SSH Public Key。
Clone代码到本地
git clone 后面的scp 是hook钩子,对git push提交进行监听,监听到后进行拦截操作,拦截后进行后续审核。
commit-msg ,提供自动写入change-Id 至git log内功能
提交第一个change
Gerrit上进行代码审查,确认入库
Verify:
工程里面接入了jenkins自动verify,结果可在上图红框内展示verify结果。
review代码,提交入库。
本地代码库更新,获取最新入库代码
代码submit后通过git pull - - rebase 更新代码。
Gerrit入门实战-初级修补
如果所有代码提交均被打回,可以进行暴力回滚:git reset
Gerrit入门实战-高级修补
如果单个提交打回,则可交互式回滚:git rebase -i
Rebase前
Rebase 后
rebase 在同一个点上修改,不会产生审核点,多个commit点同时存在是尤其有用。
Gerrit经验谈
第一,Git别名绑定,添加别名字段,通过git review master这样简单语法提交到master源端分支,可以省去很多工作。修改系统目录或者项目目下的.gitconfig 文件,添加
也可通过git config —global alias.review 命令修改
第二,工具只是一部分,更重要的是人与人当面的沟通交流,大家讨论一个好的解决方案,才能更好的解决问题。没有交流,工具也就失去了意义。
最后,关于review积压问题,要避免提交积压,代码审核过程要及时完成,避免 Code Review流于形式。
从个推实际使用效果看,Gerrit在核心代码质量控制、知识传承、团队培养等方面都具备很高的实用价值,推荐给广大开发团队用。