CodeDiff实现方案简述
作者|黄莹
CodeDiff-从字面上理解就是代码差异的比较,其实我们的测试工作从某种程度上可以理解为针对代码逻辑的测试。因此CodeDiff可以作为一种补充测试的手段,辅助我们在测试过程中通过代码内容更好地判断测试范围,以及加深对技术实现的理解,使得我们能够从内到外更好地把控项目的风险与质量。
在日常工作中大家进行CodeDiff所用的工具和方式多样化,但其目的都是通过两个版本的比对拿到差异内容,通过差异内容进行流程性或者模块化的梳理从而得出此次提测的改动点,然后再对其进行需求/业务相关性评估。CodeDiff需要测试人员熟悉原有业务流程与新需求所涉及的范围,对所涉及模块之间上下游的调用关系、数据流向、状态变化等有一定程度的了解,通过了解开发设计方案、接口改动等等方面来综合评估影响面以及测试/回归范围。
1、CodeDiff工具方式多样化,希望提供一个统一、简易的平台(支持SVN/Git两种模式、省去打开IDE、反复拉代码、查看无权限等繁琐操作),让每个人能快速进行Diff,培养同学diff代码的习惯;
2、目前公司开发模式统一切成Git,相比Git平台提供的能力,我们希望实现任意两个CommitId/分支之间进行diff的方式(两种Diff模式的优缺点);
3、参考业界其他互联网公司自研案例,自研的方案拓展性更强,且方便接入公司项目管理流程之中,使其能够平台化、提升效能;
CodeDiff接入到beetle中,与每一次编译做结合,开发人员可以增量查看每次编译的diff结果,测试人员可以看到每次提测基于首次编译的增量diff,也支持自主选择版本。
4、可以为所有基于代码差异的测试方法所使用,如CodeReview、代码覆盖率统计、代码静态检测、语法检测等。
1、基本思路
自研的CodeDiff平台支持SVN、Git两种模式,虽然这两种版本控制系统存在诸多不同(集中式/分布式、用法思想上等),但CodeDiff实现的基本思路是一致的:基于任意两个版本/分支进行代码比对,得出差异结果,再将差异结果进行解析并进行展现。
2、实现方案
SVN-SVNKit
纯Java的SVN版本连接库,整个连接底层由Java实现。一共提供两个层次的API,通过这两个API就可以基本实现与客户端相同效果的操作,不需要额外的支持:
Low-Level API:针对Subversion Repository的操作,相当于操作Repository的中间驱动,实现了对底层协议与Subversion仓库的对话,比较抽象,可以理解为一个包含版本控制的、抽象复杂的树结构。
High-Level API:针对Working Copy的一系列操作,将所有管理工作拷贝的操作逻辑分配在不同的SVN*Client中。不同的操作基于不同的SVN*Client去实现。例如:所有的工作拷贝的更新操作如checkout、update都有SVNUpdateClient这个类去执行。操作方法和参数与SVN客户端命令行相似,其底层实现实际上也调用了Low-Level API。
GIT-JGIT
纯Java的Git版本控制,提供了Git命令的Java API,通过调用API可实现创建本地仓库、远程操作代码库如clone、fetch、push、diff等命令,可以达到与客户端相同的操作效果。
举个栗子:将某个git工程的版本库clone到本地,git命令行:$ git clone [url]
Java代码实现:
/**
* 从git clone工程版本库到本地
* @param gitUrl git工程http地址
* @param destPath
* @return destPath 本地版本库地址
* @throws GitAPIException
* @throws IOException
*/
public String cloneMasterRepository(String gitUrl,String destPath) throws GitAPIException, IOException {
CredentialsProvider cp = checkPermissionForGit(gitUrl);
File file = new File(destPath);
long beginTime = System.currentTimeMillis();
CloneCommand cloneCommand = git.cloneRepository();
cloneCommand.setURI(gitUrl);
cloneCommand.setDirectory(file);
cloneCommand.setCredentialsProvider(cp);
cloneCommand.setCloneAllBranches(true);
cloneCommand.call();
if (file.exists()){
git = Git.open(file);
}
long endTime = System.currentTimeMillis();
logger.info("cloneMasterRepository time=" + (endTime - beginTime));
return destPath;
}
目前转转的研发模式已经切换至Git,接下来就以Git为例来展开介绍基于Git的CodeDiff具体是如何实现的:
Part1-差异内容的获取
(1)JGit Authentication:JGit验证机制大部分与本地Git相同,支持SSH协议和HTTP(S)协议,可以通过调用JGit提供的验证API来安全地连接远程Git库;
(2)通过实例化需要用到的git命令的方法来实现对本地仓库的操作。如CloneCommand,FetchCommand,CheckoutCommand等等,这些命令都有一个相同的基本类-TransportCommand,它提供了我们所实例的所有方法;
(3)拿到需要进行对比的两个版本参数后,通过调用git.diff()方法拿到基于这两个版本的差异结果,将结果交由处理器进行逐行解析最后返回;
Part2-全文件内容拼接
(4)拿到差异内容后,根据文件名在本地代码仓库查找目标文件,找到之后通过处理器对目标文件的内容进行逐行解析;
(5)根据文件修改类型(modify/add/remove)决定全文件内容的拼接策略,最后得到目标文件的完整内容后返回。
写在最后1、 CodeDiff整体方案的设计和实现经历了一版又一版的迭代优化,与beetle平台集成之后也更好地服务了技术同学的日常工作,真正实现不用拉代码一键diff的目的,希望CodeDiff可以真正融入我们测试工作的日常,成为辅助测试、把控风险的有效手段,让我们每一次发布上线变得更为可靠。
2、CodeDiff为代码覆盖率统计、CodeReview的实现提供了能力支撑,也实现了相应的拓展,同时还适用于所有基于代码差异的测试方法如代码静态检测、语法检测等,为测试方法的多样化探索过程提供了更多可能性。
▼更多精彩推荐,请关注我们▼