OPPO自研代码审查系统火眼Code Review实践

1. 背景

随着OPPO互联网业务快速增加,团队规模的不断扩大,对代码质量的要求也在不断地提升,而现有的代码审查工具GitLab和Gerrit已经没法知足咱们的评审需求,主要凸显如下几个问题:git

  • 没法高效的审查代码中的bug或潜在的质量问题
  • 团队内部的代码规范难以践行
  • 新人从代码中获得成长有限
  • 代码评审的便利性有待提升

咱们迫切须要一款高效、简洁的代码审查工具来辅助咱们作代码评审。算法

2. 自研仍是改造

若是只作一个评审工具,缺乏代码管理功能,须要频繁在代码评审工具和代码托管工具之间切换,用户体验不友好。数据库

代码审核和代码管理最好在一个系统中,但要开发一个二者兼备的工具系统存在两个问题:服务器

第1、要实现具有代码管理功能的代码评审系统,须要开发一套较为完善的代码管理系统,而已有的代码托管平台自己已比较成熟,再另外开发其难度和工做量都比较大。架构

第2、项目风险高,开发出来的系统稳定性和可靠性存在必定的挑战。工具

是否能够存在一种方法:既不用开发代码管理系统但又能实现Code Review的简单解决方案。在进行深度调研以后,咱们发如今GitLab之上开发Code Review具备可行性,通过几月的研发,咱们的Code Review系统火眼就这么诞生了。post

火眼是OPPO互联网自研的代码审查工具,它融合了Gerrit的评审功能和GitLab代码管理功能,其主要功能包括:spa

  • 强制/非强制代码审查
  • Merge Request
  • 代码仓库管理

火眼相较于其余代码评审工具,主要有如下特色:命令行

  • 评审代码冲突预检测
  • 灵活的评审人以及规则(普通和必要评审人,并设置经过的阀值)
  • 灵活的分支评审规则(自定义须要评审的分支)
  • 支持多种协同开发模式(包括强制评审、Merge Request两种模式)
  • 无缝对接内部通信即时聊天工具和邮件系统

3. 火眼的原理

为了方便你们理解后文,这里对火眼原理作一个简单的介绍。火眼主要利用了Git的refs命名空间的特性,下图是某一个Git仓库在服务器存储的目录结构:代理

这个结构主要包含如下几个部分:

  • hook目录存放项目的服务端钩子脚本,代码提交仓库以前会触发pre-receive脚本,提交后会触发post-receive脚本,咱们主要就用到了这两个脚本;
  • objects目录存储着Git数据库的全部内容;
  • refs 目录存储着全部分支指向各自提交对象的指针,每一个指针指向对应分支或者tag最新的CommitId。默认的分支都会在refs/heads这个子文件夹下,例如咱们常用的master分支指向的就是refs/heads/master。

火眼在实现Code Review利用的就是将对分支refs/heads/{Branch}的提交,改成指向到refs/changes/{ChangeId}/{Branch},其中ChangeId是指的某个特性,Branch是相应的开发分支,经过这个特性来存储待评审的Commit内容,当评审经过时,将refs/changes/{ChangeId}/{Branch}合并到原先正常的分支中。以开发dev分支为例,提交的模型以下:


对于每一个特性(ChangeId),都独立的产生评审,当评审完成以后再合并到其对应的分支。当初咱们的隔离维度是分支维度,相同分支产生的评审存储在一块儿。当咱们发现这些评审存储在一块儿后,评审的代码会相互干扰,影响评审的独立性,因此才产生了现有的以特性为隔离维度的评审模式。

4. 火眼技术架构

下图展现了火眼系统目前的架构:

4.1 火眼RPC

火眼RPC是一个Dubbo实现的代理服务,其主要完成如下Git操做:

  • 代码合并
  • 标签操做
  • 分支操做
  • 对比操做
  • 提交历史操做

火眼Web调用火眼RPC来完成对Git仓库的操做。火眼RPC的核心处理Git底层数据是采用JGit(一款开源的Java操做Git的工具)实现,火眼RPC在JGit基础上实现了全部的Git查看操做,可是JGit并无提供基于裸库(服务端存储Git文件的形式)的合并方法。咱们就基于JGit提供的底层的原子方法,通过封装、改造获得了咱们想要的基于裸库的合并算法。

4.2 火眼Web

火眼Web是一个 Web工程,其主要处理如下内容:

  • 评审、评论以及其状态扭转
  • 设置(评审人/审核规则/通知/仓库设置)
  • 仓库的基本管理
  • GitLab权限同步

评审

在用户提交了评审以后,评审人会收到评审邀请连接,点击后便可进行评审。对于评论咱们设置了一个标记为解决的状态,方便评审人或评审发起者跟踪问题。

为了使评审功能更加完善,咱们将GitLab的Merge Request模式移植了过来,并作了一些改进。其中一个特别的改进点是:锁定提交。 当用户在选择锁定提交的时候,合入分支的后续提交将在本次Merge Request不会被合入。咱们认为这点在多人开发的时候很重要,保证了须要被合并的代码就只包含发起Merge Request时的代码。

冲突预检测

以往其余团队在使用Gerrit作评审的时候的一个比较大的痛点是:在评审流程走完以后合并代码的时候发现被评审的代码与已经合入到仓库里面的代码有冲突,这个时候又不得再也不次合并代码,从新发起评审流程。火眼特别解决了这个问题,在用户作评审时,将被评审的代码和将要合入分支在内存中合并一次,若是发生了冲突就在评审界面醒目的提示发生冲突,并告知解决冲突方案。

仓库的基本管理

像主流的代码托管工具同样咱们在界面上提供了可视化操做Git基本数据的功能。经过火眼RPC目前实现了如下功能:分支管理、文件管理、标签管理、提交历史查看、对比等。

GitLab权限同步

咱们并未在火眼系统中单独开发一套权限系统,整个系统是复用的GitLab权限,每隔一段时间或GitLab权限发生改变时,火眼会拉取一遍GitLab的权限数据,主要包括:项目,组,项目与人的关系,组与人的关系。

4.3 火眼Git钩子

火眼Git钩子是火眼系统实现的两个Git服务端两个钩子:提交前钩子(pre-receive)和提交后钩子(post-receive)。提交前钩子用于提交代码用户选择普通提交并开启强制评审时,系统拒绝本次提交。提交后钩子用于当评审代码已成功提交,调用火眼平台,生成评审任务。下图展现了两个钩子在提交代码过程当中各自的功能:

4.4 火眼命令行

火眼命令行是火眼用于提交评审的客户端命令行。由于若是须要提交评审任务,须要执行git push HEAD:refs/changes/{ ChangeId } /{Branch}命令,该命令太长,使用者体验不友好,上手难度高,因此咱们决定使用客户端命令行的方式来简化提交过程,并下降使用成本。

为了让各个平台(Linux/Windows/Mac)都能使用火眼命令行,火眼命令行用Go语言编写,并编译成各个平台的二进制文件。

5. 火眼使用步骤

准备工做:安装火眼命令行,下列为具体使用步骤:

  1. 编写代码:和往常编写的代码步骤同样,写完后git addgit commit代码。
  2. 提交评审:使用火眼命令行提交代码,系统会反馈代码评审地址,并用内部通信工具通知相关评审人。下图展现了使用火眼命令行提交评审、生成任务的过程:

  1. 评审代码:在火眼平台对代码进行审查,审查经过后代码会自动合入(可配置手动合入)。

在开发流程上和平常开发差别不大,只是用火眼的提交命令替代了Git的提交命令。

6. 将来的规划

6.1 自动扫描

Code Review能解决业务人工评审问题,但部分代码bug或smell(代码臭味)能够经过代码扫描工具提早发现,所以后续咱们将引入自研的自动化扫描工具,并在评审流程中嵌入此过程,以辅助评审。

6.2 自由评审

自由评审模式相较提交后即自动发起评审模式,区别在于其可以评审任意提交,该模式适用于代码开发完毕回顾或审查代码,但不涉及到合并代码的场景,如代码评审会议。

7 总结

火眼系统是基于GitLab提交代码的过程作拦截,现有GitLab用户能够在很低的使用成本上使用火眼。火眼系统灵活的评审模式、多样化的评审规则以及灵活的评审分支选择能够很好的辅助团队作好代码评审工做,达到了该系统开发的预期效果。

相关文章
相关标签/搜索