一种软件代码片段历史追溯的方法与流程

文档序号:19323860发布日期:2019-12-04 00:51阅读:610来源:国知局
一种软件代码片段历史追溯的方法与流程

本发明属于计算机软件技术领域,涉及一种软件代码片段历史追溯的方法。



背景技术:

软件项目的代码在其生命周期中一般会经过多次修改,除了代码本身的变更,这个过程中还产生了大量的issue(缺陷信息)和commit(提交信息)。了解软件代码的变更历史信息对于软件开发人员和软件维护人员都具有重要意义。但是现有的版本控制系统(例如git)只能支持以文件为基本单位去追溯代码的历史,当开发者想了解某个方法或者某几行代码的变更历史时,需要从大量所在文件的历史信息中去筛选查找,会耗费较多时间。

为了解决上述问题,研究者进行了代码片段历史追溯相关的工作。典型的,franciscoservant通过建立代码历史图,以代码行匹配为基础,提出一种模糊的代码历史分析方法(参考franciscoservantandjamesa.jones.2017.fuzzyfine-grainedcode-historyanalysis.inproceedingsofthe39thinternationalconferenceonsoftwareengineering(icse'17).ieeepress,piscataway,nj,usa,746-757.doi:https://doi.org/10.1109/icse.2017.7)。但是,这些工作一般都是按行来匹配前后版本的代码,缺少对代码结构的考虑,而且没有将issue的信息纳入代码的历史加以考虑。

随着软件项目的不断演化,代码历史越发冗长,代码长度也不断增加,有必要发明一种针对软件代码片段的历史进行追溯的方法。用户通过输入想要查看相应历史的代码片段,该方法能够从相关版本库中挖掘仅和该代码片段相关的修改历史记录,并以较好的形式展示给用户。



技术实现要素:

为了克服现有版本控制系统难以方便地追溯查看细粒度的代码片段的修改历史的问题,本发明提供一种软件代码片段历史的追溯方法。通过本发明提供的方法和工具,能够有效地从软件项目git库和相关issue数据中挖掘、分析一个代码片段的修改历史,并以时间轴的形式展示给用户,帮助用户更好地理解代码片段的修改过程。

本发明的具体工作流程如图1所示,具体分为三个步骤:git数据和issue数据的收集与解析、基于ast(抽象语法树)的代码片段历史的追溯、代码片段变更历史时间轴的生成与展示。

(1)git数据和issue数据的收集与解析:给定一个用java语言编写的目标软件项目,自动采集该目标软件项目代码历史相关的git数据和issue数据,并将其解析为待处理的信息格式。git版本控制系统记录了软件项目代码提交的历史,包括所有版本的commit(提交信息),其中每一个commit中包含了commitmessage(提交描述)、提交者、提交时间等等。jira缺陷追踪系统管理了所有的issue。为此,本发明首先从软件项目的git版本控制系统中采集该项目的代码提交信息(得到该目标软件项目的git库),从软件项目的jira缺陷追踪系统中采集该目标软件项目的issue数据;其次,通过开源工具jgit解析git库,将commit和issue分别作为实体存入到图数据库neo4j中。如果一次提交信息中描述了相关的issueid号,则建立该次提交和issue之间的关联,为后续工作奠定基础。

(2)基于ast的代码片段历史的追溯:用户输入最终版本的代码片段,并指定其所属的类型(类、方法、连续代码行)。在此基础上,本发明首先扫描对应git库中最终版本的所有java代码类文件,通过字符串匹配方式定位到该代码片段所属最终版本的类文件,并使用jgit工具从git库中解析这个类文件的所有版本。其次,本发明利用开源工具gumtree对类文件的各个版本代码构建抽象语法树ast,并且对相邻版本的两棵ast的节点进行匹配,对各个相邻版本代码之间的对应关系进行细致分析。具体的,首先需要定位代码片段所在最终版本的ast节点(不同类型代码片段作不同处理,输入的是一个类,那么就通过类名匹配对应到类节点,输入的是一个方法,就通过方法签名匹配对应到方法节点,如果输入的是连续代码行,通过字符串匹配方式定位到包含该连续代码行的方法节点)。之后使用gumtree工具对相邻两个版本的ast树的节点进行匹配,从最终版本ast定位到的节点匹配到前一个版本ast上的节点,再对前一个版本的ast节点也进行相同操作,定位到再上一个版本的ast节点,直到某个版本没有匹配到的ast节点,本发明只追溯到该版本为止。这样得到输入的代码片段在一系列版本所对应的ast节点。对于输入代码片段的是一个类或者是一个方法,各版本ast节点所对应的代码片段就是其在各个版本的内容。对于输入的是一行或者连续的代码行,其各版本ast节点对应的代码片段中还可能包括其他代码行,需要进一步确定哪些是所需的代码片段。通过将最终版本的代码片段和前一个版本对应的代码片段进行行-行匹配,获得上一个版本中相关代码片段的内容。依次类推,直到某一版本找不到匹配的ast节点或者其中匹配不到相应的代码行为止。

(3)代码片段变更历史时间轴的生成与展示:当得到输入代码片段在各个版本的内容之后,比较相邻两个版本所得的代码片段是否相同,如果某个版本的内容和它前一版本的内容相同,就说明代码片段在这个版本没有修改,将其过滤。通过过滤,只保留代码片段发生更改的commit提交,并以timeline(时间轴)的方式展示。如果这些发生更改的提交的commitmessage中包含issueid号,则展示出其有关的issue信息,比如一代码片段的commitmessage存在issueid号,则将该issueid号对应的issue关联显示到该代码片段中。实际上,在冗长的commit提交历史中,只有部分的commit提交修改了这段代码。为了给开发者提供更加友好的交互界面,增强其对指定代码片段历史的了解,本文以timeline的形式展示代码片段的历史。由于代码片段没有发生改变的提交被较好地过滤,timeline可以帮助开发人员更简洁地理解代码片段的历史。

针对上述目的,本发明所采用的技术方案如图2所示,具体包括:

(1)git数据和issue数据的收集与解析模块

该模块用于收集并解析软件项目代码相关的历史信息,包括软件项目的git数据和issue数据,并根据git数据中commit的issueid号将commit和issue进行关联,为后续代码片段历史追溯做好准备。具体为:

对于git数据,首先从github下载了指定软件项目的源代码,其中包含该项目最终版本的代码,还包括一个.git文件夹,该文件夹包含了管理该项目git库的所有信息。之后,采用开源工具jgit对其进行解析。由于git版本控制系统内部采用了比较高效的存储方式,不同版本间代码混杂,本发明采用一种两阶段的解析过程来解析git库,第一阶段解析出所有不同的commit的内容,第二阶段再针对输入的代码片段,解析目标软件项目中其所属类文件在每一个commit时的具体内容。

对于issue数据,首先通过爬虫从jira相应网站爬取得到json格式文件,之后对特定格式的json文件进行解析,即可得到issue的数据。北京大学软件研究所资源库小组在snowgraph项目中为apache基金会下的一百多个软件项目收集好了issue的数据,本文工作使用了这部分数据。

从git库解析出的历史信息中,对于每一个commit中包含的commitmessage,其首部常常会显示某个issueid,表示本次提交是为了解决该issue。通过java正则表达式匹配,提取commitmessage上的id,将其和相应的issue进行关联,将结果保存到neo4j图数据库中,为后续展示代码片段的历史信息做准备。

(2)基于ast的代码片段历史追溯模块

该模块通过对前后版本的代码的抽象语法树ast进行分析,追溯代码片段的历史。方法首先对用户可能输入的代码片段的类型进行了分类,包括四种类型:一个类、一个方法、一行代码、多行连续的代码行(要求这连续的代码行必须在某个方法体中,也即不会跨多个方法),并且给用户提供相应的选项。当用户选择类型并输入相应类型的代码片段之后,方法的主要步骤如下:

首先构建该代码片段所在文件的所有版本的ast树,并且定位到最终版本的ast树中包含输入代码片段的ast节点(对于一个类的代码片段,是类节点,对于一个方法或者连续的代码行,是方法节点)。其次基于开源的工具gumtree对相邻版本间代码的ast树节点进行匹配,该工具在匹配时使用了一种自顶向下的贪心算法,首先找到两棵ast树一系列高度递减的同构子树,将这些同构子树的节点进行匹配,随后基于同构子树匹配到的节点,再采用自底向上的方式利用未匹配节点的子节点的匹配情况寻找更多的匹配节点。本发明在不同版本间以所匹配的ast节点为过渡进行追溯,定位到指定代码片段在各个版本所属的ast节点(一开始输入代码片段对应最终版本asti节点,通过最终版本和前一版本ast树节点的匹配,假设asti匹配到asti-1,得到前一版本所属ast节点asti-1,再通过前一版本和再前一个版本ast节点的匹配,假设asti-1匹配到asti-2,得到再前一个版本的ast节点)以及通过ast节点转换成的代码的内容。之后再根据需要进行代码行匹配,找到输入代码片段在不同版本时的内容。在此过程中,不同粒度的代码片段在处理过程中稍有不同,下面分情况介绍:

2.1)一个类或方法的代码片段:首先构建该代码片段所在的最终版本的类文件的ast树,通过类名或者方法签名的匹配,定位到其所属的ast节点,是类节点或方法节点。之后根据前一个版本ast树上该ast节点的匹配关系,追溯该ast节点在前一版本的ast树中的匹配ast节点,依次类推,直至遇到某一版本找不到任何匹配的节点为止,之后将这些版本追溯到的ast节点转换成对应的代码片段,对于类和方法类型的输入,这些代码片段就是输入的代码片段在不同版本时的内容。

2.2)一行或者多行类型的代码片段,首先构建该代码片段所在文件最终版本的ast树,通过找到代码内容完全包含代码片段的方法类型的ast节点,获得该ast节点对应的代码内容,其中可能还有其他代码片段,之后以ast节点为过渡,找到前一版本所匹配的ast节点,再利用代码行匹配的方式,对输入的代码片段和前一个版本ast节点对应的代码片段中的代码行进行匹配,找到代码片段在前一版本的内容。依此类推。关于代码行的匹配,本发明采用基于最小编辑距离的文本相似度的计算方法来计算前后两行代码之间的相似度。首先利用动态规划方法,将两个代码行看作两个字符串,计算两个代码行之间的最小编辑操作的次数(最小编辑操作是指一个字符串通过插入一个字符,删除一个字符,修改一个字符这三种操作变成另一个字符串所需的最小操作次数,可以用动态规划方法求解),再根据两个代码行的长度和最小编辑操作的次数来计算它们之间的基于最小编辑距离的文本相似度。在具体匹配时,本发明首先会去除空行,之后对输入的每一行代码,都计算其与前一版本ast节点所对应的每一行代码的相似度,并设定相应的阈值,若低于阈值,相似度过低,则认为该行代码是新添加的,之前版本不存在。否则,取其中得到最大相似度的代码行作为该行代码前一版本的内容。对所有的代码行均进行此操作,即可得到前一版本的内容。依次类推,得到输入代码片段在所有版本的内容。

(3)代码片段变更历史时间轴的生成与展示模块

对于输入的代码片段,其在历史上的每一个commit提交所对应的版本中可能存在变化,也可能不变。本发明只呈现出代码片段发生变化时所对应的版本,对于中间没有发生变化的那些连续区间的版本,本发明只展示最初提交的一次历史信息。为了实现这样的目标,本发明基于以上对代码片段历史的追溯过程,得到指定代码片段在各个版本的内容,之后对相邻两个版本间指定代码片段的内容进行比较,判断该代码片段在这两个版本之间是否发生变化。若后一版本的指定代码片段的内容与前一版本相同,本发明则不予展示。

经过这样的去重过滤过程之后,本发明得到了指定代码片段发生变化的那些commit提交。根据git数据和issue数据的收集与解析阶段commit和issue之间所建立的关联,可以得到相关的issue信息,把所有这些信息按照时间顺序排序加以展示,构成一个timeline返回给用户即可。

在工具原型开发方面,本发明总体上采用了前后端分离的架构。后端包括git数据和issue数据的收集与解析模块、基于ast的代码片段历史追溯模块,采用java语言编写,并且使用了springboot框架。前端包括代码片段变更历史时间轴的生成与展示模块,采用typescript语言编写,使用了react框架。工具首先会在后端离线收集并解析好相关的历史信息,之后前端用户输入要查看历史信息的代码片段,工具将其发送至后端,在后端追溯其历史并将结果返回至前端,并以时间轴的形式展示。在前后端通信方面,本发明在前端使用类库jquery实现异步发送请求,后端springboot框架采用注解的方式针对不同的url访问请求做不同处理。在前端展示方面,为了生成较为优美的富文本代码编辑器,本发明采用开源的工具react-ace;为了更好地展示代码片段前后版本的差异,本发明采用开源的工具ace-diff,其能够比较好地将前后版本代码的差异可视化。react是一个视图层框架,前端每个部分通过编写继承自react.component的类来代表一个组件,当某个组件需要数据时,不同组件之间有数据依赖,为了避免组件之间通信导致数据层层传递的复杂性,本发明采用redux这个javascript状态容器,它将整个应用状态存储到一个地方称为store,组件通过派发(dispatch)行为(action)给store,而不是直接与其他组件通信。组件内部通过订阅store中的状态(state)来刷新自己的视图。

本发明的有益效果是:

用户将想要查看历史的一段代码输入系统,系统能够快速准确地从版本库中找到相关修改记录,并过滤大量冗余信息,以时间轴的形式向用户展示仅和该代码片段相关的修改历史信息。通过点击相应按钮,还可以进一步查看时间轴上每个节点代码片段前后版本的差异以及相应的issue信息,提高了用户进行代码历史追溯的方便程度和浏览速度。

附图说明

图1是本发明的方法工作流程图。

图2是本发明的工具架构图。

具体实施方式

为使本发明的上述特征和优点能更明显易懂,下文特举实施例,并配合所附图作详细说明如下:

随机抽取一个开源软件apachelucene项目中的代码片段。很多时候,开发者会以一个api/方法为单位来选取这些代码片段。而对于多行或单行的代码片段,本发明主要是通过分析ast树中方法类型的节点进行追溯的,其要查看的commit数量不多于其所属的方法相关的commit数量。下面展示了本发明随机选取的一个代码片段:lucene项目下tokenizer类中的setreader方法,共有9行。

通过本发明的方法和工具,用户可以看到这段代码一共经历了6次修改。按照时间从前向后的具体变更过程如下:

第一次变更是一个从无到有的过程。其定义了setreader方法的方法体。

在第二次变更中,其在方法体的最后添加了一条assert语句,并且将该方法的类型设置成了final。

在第三次变更中,其增加了一个针对该函数参数的条件判断,如果输入input为null就抛出异常,并且对判断条件之后的赋值语句也进行了相应的修改。

在第四次变更中,其在方法体中增加了一个else条件判断。

在第五次变更中,更改了该方法的最后一条语句,将assert_setreadertestpoint()修改为setreadertestpoint()。

在最后一次变更中,将setreader方法签名上抛出异常部分进行了删除。

在该案例中,对于输入的代码片段,工具通过对输入的代码片段进行解析,可以得到setreader方法的签名。之后在追溯代码片段历史的时候,对每一次变更,前后版本中setreader方法所对应的ast树节点都得到了匹配,所以可以追溯出setreader方法,进而可以得到其对应的代码行。从上面的过程可以看到,本发明工具可以很好地展示出该代码片段的变更历史。

本发明最终可以采用变更历史时间轴展示各阶段的代码片段。时间轴上每一个节点处的内容依次如下:首先是本次代码变更提交的commitmessage,之后有三个点击按钮,分别是showdifferencewithperversion(展示与之前版本的差异)、showissue(展示变更原因)、showcurrentcode(展示当前状态代码)。点击这些按钮,分别可以看到代码片段和前一个版本之间的差异、本次提交有关的issue、以及本次提交之后代码片段的具体内容。

以上实施例仅用以说明本发明的技术方案而非对其进行限制,本领域的普通技术人员可以对本发明的技术方案进行修改或者等同替换,而不脱离本发明的精神和范围,本发明的保护范围应以权利要求书所述为准。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1