第6.2节 Android Agent开发<二>

发布于:2025-09-13 ⋅ 阅读:(12) ⋅ 点赞:(0)

JacocoReportSelectOper类的代码:

import os


class JacocoReportSelectOper(object):
    """
    处理增量报告中的Index.html文件,过滤文件内容
    """

    def correctIndexFile(self,packpath):
        """
        更新一个目录下的index.html文件,去掉不是本次更新的的记录项目
        :param packpath:
        :return:
        """
        #过滤目录下的文件
        selectfilelist=[]
        for i,j,k in os.walk(packpath):
            for filename in k:
                if filename.find("$")>-1 and filename.find("index.html")==-1:
                    tmpchange=filename[filename.index("$")+1:]
                    if tmpchange.find("$")>-1:
                        fnamejacoco=filename[0:filename.index("$")]+"."+tmpchange[0:tmpchange.index("$")]
                    else:
                        fnamejacoco=filename[0:filename.index("$")]+"."+tmpchange[0:tmpchange.index(".")]
                    if fnamejacoco not in selectfilelist and len(fnamejacoco)>0:
                        selectfilelist.append(fnamejacoco)
                if  filename.find("$")==-1 and filename.find("index.html")==-1 and len(filename)>0:
                    fnamejacoco=filename[0:filename.index(".")]
                    if fnamejacoco not in selectfilelist and len(fnamejacoco)>0:
                        selectfilelist.append(fnamejacoco)
        #print(selectfilelist)
        #处理该目录下的index.html文件
        reportfile=open(packpath+"index.html","r")
        reportcont=reportfile.read()
        tempreport=open(packpath+"tmpindex.html","w")
        #取测试报告的头部信息
        getheadcont=reportcont[0:reportcont.index("</thead>")+8]
        # print(getheadcont)
        tempreport.write(getheadcont)
        #过滤文件相关信息
        rmisslines=0
        rtotalline=0
        detailcont=reportcont[reportcont.index("</thead>")+8:reportcont.index("</tbody>")]
        detaillist=detailcont.split("</tr>")
        for filedetail in detaillist:
            for difffile in selectfilelist:
                if filedetail.find(difffile)>-1:
                    #处理行覆盖率信息
                    linedetail=filedetail[filedetail.find('id="h'):filedetail.find('id="j')]
                    fmisline=linedetail[linedetail.index(">")+1:linedetail.index("<")]
                    temlined=linedetail[linedetail.index("class")+6:linedetail.rindex("class")]
                    ftotalline=temlined[temlined.index(">")+1:temlined.index("<")]
                    if fmisline.find(",")>-1:
                        fmisline=fmisline[0:fmisline.index(",")]+fmisline[fmisline.index(",")+1:]
                    if ftotalline.find(",")>-1:
                        ftotalline=ftotalline[0:ftotalline.index(",")]+ftotalline[ftotalline.index(",")+1:]
                    rmisslines=rmisslines+int(fmisline)
                    rtotalline=rtotalline+int(ftotalline)
                    #增量覆盖率内容
                    tempreport.write(filedetail+"</tr>")
                    break

        print("最终的missed行:"+str(rmisslines)+",总行数:"+str(rtotalline))
        tfootcont='<tfoot><tr><td>Total</td><td class="bar">-</td><td class="ctr2">-</td><td class="bar">-</td><td class="ctr2">-</td><td class="ctr1">-</td><td class="ctr2">-</td><td class="ctr1">'+str(rmisslines)+'</td><td class="ctr2">'+str(rtotalline)+'</td><td class="ctr1">-</td><td class="ctr2">-</td><td class="ctr1">-</td><td class="ctr2">-</td></tr></tfoot>'
        tempreport.write(tfootcont)
        #写入尾部信息
        gettailcont=reportcont[reportcont.index("</tbody>"):]
        tempreport.write(gettailcont)
        tempreport.close()
        os.system("rm -rf "+packpath+"index.html")
        os.system("mv "+packpath+"tmpindex.html "+packpath+"index.html")
        print("临时报告生成完成:"+packpath+"tmpindex.html")

    def getReportHeader(self, branch):
        """生成增量覆盖率报告"""
        headcontent = '''<?xml version="1.0" encoding="UTF-8"?>
            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
            <html xmlns="http://www.w3.org/1999/xhtml" lang="zh">
            <head>
                    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
                    <link rel="stylesheet" href="jacoco-resources/report.css" type="text/css"/>
                    <title>Diff Coverage</title>
            </head>
            <body>
                <h1>Diff Coverage</h1>
            '''
        headcontent = headcontent + "<p>Diff: " + branch + "...HEAD, staged and unstaged changes</p>\r\n"
        return headcontent

    def getPackageLineMessage(self,rportpath):
        """
        获取指定包的覆行信息
        :param rportpath:
        :return:
        """
        reportfile=rportpath+"/index.html"
        # print("reportfile="+reportfile)
        rpcont=open(reportfile,"r").read()
        sumcont=rpcont[rpcont.rindex("<tfoot>")+178:rpcont.rindex("</tfoot>")-102]
        finalmsg=sumcont[0:sumcont.index("<")]+","+sumcont[sumcont.rindex(">")+1:]
        return finalmsg

    def createDiffReport(self,drpath,branch):
        """
        生成汇总覆盖率报告
        :param drpath:
        :param branch:
        :return:
        """
        #获取diff的文件包列表
        packagelist=[]
        for i,j,k in os.walk(drpath):
            for folder in j:
                if folder.find("jacoco-resources")==-1:
                    packagelist.append(folder)
        print(packagelist)
        reportcontent = "<table class=\"coverage\" cellspacing=\"0\" id=\"coveragetable\">\r\n<thead><tr><th>Pagckages</th><th>Diff Coverage (%) </th><th width=\"100\">Total Lines </th><th width=\"100\">Missing Lines </th></tr></thead>\r\n"
        totallines = 0
        mislines = 0
        for package in packagelist:
            linesdetail=self.getPackageLineMessage(drpath+package)
            fmissline=int(linesdetail[0:linesdetail.index(",")])
            ftotaline=int(linesdetail[linesdetail.index(",")+1:])
            #计算总行数
            totallines=totallines+ftotaline
            mislines=mislines+fmissline
            #计算覆盖率
            if ftotaline==0:
                miscovrate=100
            else:
                miscovrate=int(fmissline/ftotaline*100)
            # print("fmissline="+str(fmissline)+",ftotalline="+str(ftotaline)+",miscovrate="+str(miscovrate))
            #拼接内容
            reportcontent = reportcontent + "<tr><td><a href=\"./"+package+"/index.html\" class=\"el_package\">" +package+ "</a>  </td>"
            reportcontent = reportcontent + "<td class=\"bar\">" + "<img src=\"jacoco-resources/redbar.gif\" width=\"" + str(
                miscovrate) + "\" height=\"10\">"
            reportcontent = reportcontent + "<img src=\"jacoco-resources/greenbar.gif\" width=\"" + str(
                100-miscovrate) + "\" height=\"10\">  " + str(100-miscovrate) + "%</td>"
            # 2,总行数
            reportcontent = reportcontent + "<td class=\"ctr1\">" + str(ftotaline) + "</td>"
            # 3,没有覆盖的行数
            reportcontent = reportcontent + "<td class=\"ctr1\">" + str(fmissline) + "</td>"
            reportcontent = reportcontent + "</tr>\r\n"
        reportcontent = reportcontent + "</table>"
        # 添加头部信息及汇总信息
        covlines = totallines - mislines
        if totallines == 0:
            covrate=0
        else:
            covrate = float(covlines) / float(totallines) * 100
        headcontent = self.getReportHeader(branch)
        headcontent = headcontent + "<ul>\r\n<li><b>Total</b>: " + str(totallines) + " lines</li>\r\n"
        headcontent = headcontent + "<li><b>Missing</b>: " + str(mislines) + " lines</li>\r\n"
        headcontent = headcontent + "<li><b>Coverage</b>: " + str(round(covrate, 2)) + " %</li>\r\n</ul>\r\n"
        reportcontent = headcontent + reportcontent + "\r\n</body>\r\n</html>"
        # 汇总报告写入文件
        findreport = drpath + "index.html"
        rf = open(findreport, "w")
        rf.write(reportcontent)
        rf.close


if __name__=='__main__':
    jroper=JacocoReportSelectOper()
    packpath="/Users/************"
    print(jroper.getPackageLineMessage(packpath))

  

3,覆盖率合并模块

     jacoco merge合并覆盖率的前提是同一版本的不同覆盖率文件合并,如果合并不同的版本,类文件的变化的直接丢掉所有的相关覆盖率数据。而业务测试同学的诉求是,在集成测试阶段,同一分支可以打不同的包进行测试,最后要看一下整个集成测试阶段的覆盖率情况。这就涉及到对不同diff函数以及其调用链路上函数覆盖率的去除,同时需要保留diff类中没有变化的函数的覆盖率数据,具体方案请看覆盖率全并相应的内容。

(1)CorrectMethodsLocOfCovLines类,修改ec文件,添加需要保留的覆盖率数据

# coding: utf-8
import json
import shutil

from AndroidCovAgent.CommitsMergeOperation.GitCompareBranchOper import GitCompareBranchOper
from AndroidCovAgent.Utils.Utils import Utils
import os,requests


class CorrectMethodsLocOfCovLines(object):
    """
    根据覆盖率数据,校对受diff影响的函数的覆盖率情况
    @author SXF
    @date:2022-07-28
    """
    def __init__(self):
        self.diffcovdetail={}


    def anylysisECFileContent(self,propath,srccommit,keepbuildid):
        """
        解析受影响的函数,在指定的覆盖率数据中覆盖率的行号
        :param propath:
        :param ecfilename:
        :param effect_methods:
        :return:
        """
        curpath=os.getcwd()
        # 1,检测是否需要下载class文件
        descclasses=propath+"/build_classes_" + keepbuildid.strip()
        if not os.path.exists(descclasses):
            os.chdir(propath)
            classzipfile="build_classes_"+ keepbuildid.strip()+".zip"
            classurl = "https://*********/build_classes_" + keepbuildid.strip() + ".zip";
            downres=requests.get(classurl)
            with open(propath+"/"+classzipfile,'wb') as f:
                f.write(downres.content)
            f.close()
            #解压类文件压缩包
            shutil.unpack_archive("./"+classzipfile,descclasses)
        # 2,解析ec文件,获取针对diff的覆盖率信息
        ecfilepath=propath[0:propath.index(srccommit)]+"/"+srccommit+"_merged.ec"
        ecinfojson=propath+"/diffecfile.json"
        scriptpath=Utils.SCRIPT_FILE_PATH
        jacocoparse="java -jar "+scriptpath+"jacoco-parser2.0.jar -e "+ecfilepath+" -o "+ecinfojson+" --source "+propath+" --class "+descclasses
   
        os.system(jacocoparse)
        os.chdir(curpath)
        #3,读取Json文件,过滤覆盖的行号
        ecjsoncont={}
        with open(ecinfojson,"r") as loadf:
            ecjsoncont=json.load(loadf)

        for key in ecjsoncont.keys():
            detail=ecjsoncont.get(key)
            if len(detail.get("covered"))>0:
                newkey=detail.get("filename")
                newkey=newkey[newkey.index("packages"):]
                self.diffcovdetail[newkey]=detail.get("covered")
     

    def correctLinesOfMethods(self,linelist,methoddict):
        """
        根据受影响到的函数信息,校对行号
        :param linelist:
        :param methoddict:
        :return:
        """
        finallinelist=[]
        for method in methoddict.keys():
            linedetail=methoddict.get(method)
            olderloc=linedetail.get("olderloc")
            newloc=linedetail.get("newloc")
            effectmethodline=[]
            for line in linelist:
                if line>olderloc[0] and line<olderloc[1]:
                    tmpspan=line-olderloc[0]
                    effectmethodline.append(newloc[0]+tmpspan)
            if len(effectmethodline)>0:
                effectmethodline.sort()
                finallinelist.append(effectmethodline)
        return finallinelist

    def getMethodCovedInfo(self,linelist,methodlist):
        """
        获取覆盖率数据中,函数的覆盖情况
        :param linelist: 覆盖率文件中,对应类的覆盖行号
        :param methodlist: 方法列表
        :return:
        """
        finallinelist=[]
        for method in methodlist.keys():
            linedetail=methodlist.get(method)
            noeffectline=[]
            for line in linelist:
                if line>=linedetail[0] and line<=linedetail[1]:
                    noeffectline.append(line)
            if len(noeffectline)>0:
                noeffectline.sort()
                finallinelist.append(noeffectline)
        return finallinelist

    def correctMethodsCovInfo(self,effect_methods,noeffect_methods):
        """
        校准受diff影响的类的覆盖率数据
        :param effect_methods:
        :return:
        """
        finaldiffcovinfo={}
        #1,解析受影响的函数列表,在原覆盖率文件中的覆盖数据,并更新位置
        for key in self.diffcovdetail:
            if key in effect_methods.keys() and len(self.diffcovdetail[key])>0:
                # 校对行号,转换成jacoco格式的覆盖率数据
                newkey=key[key.index("com/"):key.index(".")]
                finaldiffcovinfo[newkey]=self.correctLinesOfMethods(self.diffcovdetail[key],effect_methods[key])

        #2,解析没有受的函数影响的函数列表,获取其在原覆盖率文件中的覆盖率数据
        for key in self.diffcovdetail:
            if key in noeffect_methods.keys() and len(self.diffcovdetail[key])>0:
                fnewkey=key[key.index("com/"):key.index(".")]
                if fnewkey in finaldiffcovinfo.keys() and len(finaldiffcovinfo[fnewkey])>0:
                    finaldiffcovinfo[fnewkey]=finaldiffcovinfo[fnewkey]+self.getMethodCovedInfo(self.diffcovdetail[key],noeffect_methods[key])
                else:
                    finaldiffcovinfo[fnewkey]=self.getMethodCovedInfo(self.diffcovdetail[key],noeffect_methods[key])

        #3,对finaldiffcovinfo中列表中的数据进行排序,保证行号按从小到大保存
        for key in finaldiffcovinfo.keys():
            finaldiffcovinfo[key].sort()

        #print(finaldiffcovinfo)
        return finaldiffcovinfo

    def getNeedModifyLineInfo(self,proname,srccommit,descommit,keepbuildid,username):
        """
        获取老版本中,需要保留的覆盖率信息
        :param proname: 项目名称
        :param srccommit: 源提交版本
        :param descommit: 目标提交版本
        :param keepbuildid: keep构建号
        :return:
        """
        #1,获取影响到的函数列表
        gitoper=GitCompareBranchOper()
        gitoper.get_diff_filelist(srccommit,descommit,proname,username)

        #2,获取新老版本中受影响的函数的行号
        locchangmethodlist=gitoper.correctChangeLocMethod(srccommit,proname,username)

        #3,获取在diff类中,位置及内容都没有受到影响的函数列表
        locnochangemethdlist=gitoper.getMethodsListLocHasNochange()


        #4,解析旧的覆盖率数据
        #获取老版本对应的文件夹路径
        oldfilefolder=os.path.join(Utils.ANDROID_COMMITS_MERGE_WORKSPACE, proname,username, srccommit)
        self.anylysisECFileContent(oldfilefolder,srccommit,keepbuildid)

        #3,校准需要保留覆盖数据
        needmodifyinfo=self.correctMethodsCovInfo(locchangmethodlist,locnochangemethdlist)

        return needmodifyinfo



if __name__ == '__main__':
    corrmethod=CorrectMethodsLocOfCovLines()
  

(2)MergeCommitsECFile去掉diff函数及调用链路上的函数,合并覆盖率数据

# coding: utf-8
import os
import sys
#添加本项目搜索路径
env_dist=os.environ
curenv=env_dist.get("AGENT_ENV")
if curenv!=None and curenv.find("prod")>-1:
    sys.path.append(os.path.abspath('/accuratemobileagent'))
else:
    sys.path.append(os.path.abspath('.'))

import simplejson, json
import requests, shutil
from flask import current_app

from AndroidCovAgent.CommitsMergeOperation.CorrectMethodsLocOfCovLines import CorrectMethodsLocOfCovLines
from AndroidCovAgent.CommitsMergeOperation.GitCompareBranchOper import GitCompareBranchOper
from AndroidCovAgent.Utils.Utils import Utils


class MergeCommitsECFile(object):
    """
    合并两个不同分支的覆盖率数据
    """

    def __init__(self):
        self.removedline = {}
        self.modifyline = {}

    def removeDiffMethodCovInfo(self, propath, branchname, srccommit, descommit, keepbuildid, username, proname):
        """
        根据diff函数,查询CCG,从老的覆盖率数据中去掉相关数据
        :param propath: 项目路径,以便解析调用链路上的函数信息
        :param branchname: 分支名
        :param srccommit: 开始版本
        :param descommit: 结束版本
        :param oldecfilepath: 老版本merged覆盖率文件路径
        :return:
        """
        mergedoperpath = os.path.join(Utils.ANDROID_COMMITS_MERGE_WORKSPACE, proname, username)
        # 1,获取需要删除的diff函数及调用链路上函数行
        gitcomoper = GitCompareBranchOper()
        self.removedline = gitcomoper.getAllNeedRemovedMethods(srccommit, descommit, proname, branchname, propath,username)
        # 2,删除老的覆盖率数据文件中的数据
        srccommitpath = mergedoperpath + "/" + srccommit + "_merged.ec"
        # 将结果写入json文件中
        removejson = mergedoperpath + "/" + srccommit + "_removedlines.json"
        refile = open(removejson, "w")
        refile.write(simplejson.dumps(self.removedline))
        refile.close()
        print("文件:" + removejson + "写入成功!")
        if os.path.getsize(removejson)>100:
            # class路径
            classpath = mergedoperpath + "/" + srccommit + "/build_classes_" + keepbuildid.strip()
            curpath=os.getcwd()
            srcpath=mergedoperpath + "/" + srccommit
            if not os.path.exists(classpath):
                #类文件不存在,下载对应的类文件,并解压
                os.makedirs(srcpath)
                os.chdir(srcpath)
                classzipfile="build_classes_"+ keepbuildid.strip()+".zip"
                classurl = "https://********/build_classes_" + keepbuildid.strip() + ".zip";
                print("下载文件:"+classurl)
                downres=requests.get(classurl)
                with open(srcpath+"/"+classzipfile,'wb') as f:
                    f.write(downres.content)
                f.close()
                #解压类文件压缩包
                shutil.unpack_archive("./"+classzipfile,classpath)
            os.chdir(curpath)
            # 删除ec文件中diff函数及调用链路上函数影响的行
            scriptpath=Utils.SCRIPT_FILE_PATH+"jacoco-parser2.0.jar"
       

            removecmd = "java -jar " + scriptpath + " -e " + srccommitpath + " -j " + removejson + " -c " + classpath + " -p reduce"
            print("执行去除覆盖率信息命令:" + removecmd)
            os.system(removecmd)
            print("去掉Diff函数及调用链路上的函数对应的覆盖率信息!")
        else:
            print("没有需要去掉覆盖率的函数列表!")

    def getEffectMethodCovInfo(self, propath, srccommit, descommit, keepbuildid, username, proname):
        """
        获取两个分支需要去掉和修改覆盖率信息
        :param srccommit:
        :param descommit:
        :return:
        """
        mergedoperpath = os.path.join(Utils.ANDROID_COMMITS_MERGE_WORKSPACE, proname, username)
        # 1,获取需要修正函数信息
        correctoper = CorrectMethodsLocOfCovLines()
        self.modifyline = correctoper.getNeedModifyLineInfo(proname, srccommit, descommit, keepbuildid,username)
        # 将结果写入json文件中
        needmodifyjson = mergedoperpath + "/" + descommit + "_modifiedlines.json"
        refile = open(needmodifyjson, "w")
        refile.write(simplejson.dumps(self.modifyline))
        refile.close()
        print("文件:" + needmodifyjson + "写入完成!")

    def modifyFinalCoverageInfo(self, propath, srccommit, descommit, desckeepid, username, proname):
        """
        通过解析因diff影响到的函数内容没有变化,位置变化引在忙的覆盖率数据丢失的情况;将相应的数据写回到最新的覆盖率文件中
        :param propath:项目路径
        :param srccommit:源版本
        :return:
        """
        mergedoperpath = os.path.join(Utils.ANDROID_COMMITS_MERGE_WORKSPACE, proname, username)
        srccommitpath = mergedoperpath + "/" + srccommit + "_merged.ec"
        # 3,合并两个merged的版本
        desccommitpath = mergedoperpath + "/" + descommit + "_merged.ec"
        twocommitsmerge = mergedoperpath + "/commits_merged_coverage.ec"

        jacococlipath=Utils.SCRIPT_FILE_PATH+"jacococli.jar"
        #jacococlipath = "/Users/sxf/Documents/精准测试/AccurateCode/AndroidCovAgentFlask/ScriptFiles/jacococli.jar"

        mergecmd = "java -jar " + jacococlipath + " merge " + srccommitpath + " " + desccommitpath + " --destfile " + twocommitsmerge
        os.system(mergecmd)

        # 4,再去修改合并后的ec文件
        needmodifyjson = mergedoperpath + "/" + descommit + "_modifiedlines.json"
        if os.path.getsize(needmodifyjson)>100:
            # 1,检测是否需要下载class文件
            descclasses = propath + "/build_classes_" + desckeepid.strip()
            if not os.path.exists(descclasses):
                os.chdir(propath)
                classzipfile = "build_classes_" + desckeepid.strip() + ".zip"
                classurl = "https://*******/build_classes_" + desckeepid.strip() + ".zip";
                downres = requests.get(classurl)
                with open(propath + "/" + classzipfile, 'wb') as f:
                    f.write(downres.content)
                f.close()
                # 解压类文件压缩包
                shutil.unpack_archive("./" + classzipfile, descclasses)

            if os.path.exists(needmodifyjson) and os.path.exists(twocommitsmerge):
                scriptpath=Utils.SCRIPT_FILE_PATH+"jacoco-parser2.0.jar"
        

                removecmd = "java -jar " + scriptpath + " -e " + twocommitsmerge + " -j " + needmodifyjson + " -c " + descclasses + " -p add"
                os.system(removecmd)
            else:
                print("文件:" + needmodifyjson + "或者" + twocommitsmerge + "不存在,请确认相关文件!")
        else:
            print("没有需要修改覆盖率的函数列表!")

        # 将全并后的文件更名为desc分支对应的ec,以便支持多版本合并
        if os.path.exists(desccommitpath):
            os.remove(desccommitpath)
        else:
            print(desccommitpath)
        rename = "mv " + twocommitsmerge + " " + desccommitpath
        os.system(rename)
        # 执行一些数据清除操作
        # 1,删除srccommit文件夹
        srcfolder = mergedoperpath + "/" + srccommit
        if os.path.exists(srcfolder):
            shutil.rmtree(srcfolder)
        else:
            print("srcfolder=" + srcfolder)

        # 2,删除desccommit文件夹
        if os.path.exists(mergedoperpath + "/" + descommit):
            shutil.rmtree(mergedoperpath + "/" + descommit)
        # 3,删除json文件
        if os.path.exists(mergedoperpath + "/" + srccommit + "_removedlines.json"):
            os.remove(mergedoperpath + "/" + srccommit + "_removedlines.json")
        if os.path.exists(mergedoperpath + "/" + descommit + "_modifiedlines.json"):
            os.remove(mergedoperpath + "/" + descommit + "_modifiedlines.json")

    def mergeAndMofidyTwoCommmitsCovData(self, propath, branchname, srcbuildid, srccomit, descbuildid, descomit,username, proname):
        """
        合并两个指定版本的覆盖率数据文件
        :param propath: 项目名称
        :param branchname: 分支名
        :param srcbuildid: 源版本keepbuildid
        :param srccomit: 源版本
        :param descbuildid: 目标版本Keepbuidid
        :param descomit: 目标版本
        :return:
        """
        self.removeDiffMethodCovInfo(propath, branchname, srccomit, descomit, srcbuildid, username, proname)
        print("删除Diff的函数及调用链路上的函数覆盖率数据!")
        self.getEffectMethodCovInfo(propath, srccomit, descomit, srcbuildid, username, proname)
        print("获取需要补充的覆盖率数据函数列表!")
        self.modifyFinalCoverageInfo(propath, srccomit, descomit, descbuildid, username, proname)
        print("生成最后地覆盖率数据文件!")

    def runMergeCommitsFormJson(self, propath, branchname, mergeinfo, username, proname):
        """
        通过读取合并版本信息的数据文件,循环进行覆盖率数据的合并
        :param propath: 项目源码路径
        :param branchname: 分支名称
        :param mergeinfo: 合并版本信息文件,以KeepBuidID升序组成的json文件
        :return:
        """
        mergedoperpath = os.path.join(Utils.ANDROID_COMMITS_MERGE_WORKSPACE, proname, username)
        # 1,读取需要合并的覆盖率信息文件
        with open(mergeinfo, "r") as readjson:
            json_data = json.load(readjson)
        flag = 0
        if len(json_data.keys())>1:
            #多个版本的情况
            for key in json_data.keys():
                if flag == 0:
                    srcbuildid = key
                    srccommit = json_data[key]
                    flag = flag + 1
                else:
                    descbuildid = key
                    descommit = json_data[key]
                    # 2,执行合并覆盖率操作
                    self.mergeAndMofidyTwoCommmitsCovData(propath, branchname, srcbuildid, srccommit, descbuildid,
                                                          descommit, username, proname)
                    # 替换src数据
                    srccommit = descommit
                    srcbuildid = descbuildid
        else:
            #只有一个版本的情况
            print("只有一个版本的情况下,不需要走合并覆盖率流程,直接生成报告!")

        print("多版本覆盖率文件合并完成!")


if __name__ == '__main__':
    mergeoper = MergeCommitsECFile()
    propath=sys.argv[1]
    branchname=sys.argv[2]
    mergeinfo=sys.argv[3]
    username=sys.argv[4]
    proname=sys.argv[5]
    mergeoper.runMergeCommitsFormJson(propath,branchname,mergeinfo,username,proname)

4,用例关联模块

     在做用例关联的时候,无论是手工还是自动化,核心问题就是需要解析出用例执行过程中覆盖了哪些函数,然后将用例信息与函数信息做关联,插入到数据库中。对于Android来说,就是要解析覆盖率EC文件,但是从网上查了很久都没有找到解析方案,后来从公司其他部门找到了一个工具jacoco-parser.jar,可以对覆盖率文件进行解析,于是就开发了解析覆盖率文件相关功能。

ClassOfProjectOperations类,解析覆盖率文件中覆盖的函数:

# coding=utf-8
#date 2022-03-22
import os

from flask import current_app

from AndroidCovAgent.CovRelateOperation.CreateReportForKeepClass import CreateReportForKeepClass
from AndroidCovAgent.Utils.Utils import Utils


class ClassOfProjectOperations():
    """
      处理项目中所有的Class文件
    """
    def anyliseCovInfo(self,jsoncont,username):
        """
        转化覆盖率文件信息,返回符合CCG查询的格式
        :param fileinfo:
        :return:
        """
        filejson= {}
        i=0
        for key in jsoncont.keys():
            ckcont=jsoncont[key]
            if len(ckcont["covered"])>0:
                filename=ckcont["filename"]
                #处理文件路径,去掉androidx相关的文件
                if filename.find("androidx/fragment/app")==-1:
                    filename=filename[filename.index(username)+len(username)+1:len(filename)]
                    covlinelist=ckcont["covered"]
                    lininfo=""
                    for line in covlinelist:
                        lininfo=lininfo+str(line)+",1;"
                    lininfo=lininfo[0:len(lininfo)-1]
                    filejson[filename]=lininfo
        current_app.logger.info("影响的文件个数:"+str(len(filejson.keys())))
        return filejson


    def getCovedFileListByEcFile(self,propath,ecfilename,keepbuildid):
        """
        查找项目中所有的kotlin class文件
        @param propath:项目路径
        @param ecfilename:ec 覆盖率数据文件名称
        @:param keepbuildid: Keep构建号
        :return:
        """
        createrfk=CreateReportForKeepClass()
        #获取class文件路径
        descclasses=createrfk.getBuildClassPath(propath)

        #数据文件路径
        utiloper=Utils()
        ecfilepath=utiloper.getAppPath(propath)+"/build/outputs/code-coverage/connected/"+ecfilename
        ecjson=ecfilename[ecfilename.index("-")+1:ecfilename.rindex(".")]
        #解析对应的ec文件
        ecinfojson=propath+"/ecfileparse_"+ecjson+".json"
        curpath = os.getcwd();
        scriptpath=Utils.SCRIPT_FILE_PATH
        jacocoparse="java -jar "+scriptpath+"jacoco-parser2.0.jar -e "+ecfilepath+" -o "+ecinfojson+" --source "+propath+" --class "+descclasses+" &"
        current_app.logger.info(jacocoparse)
        os.system(jacocoparse)
        current_app.logger.info("***********解析覆盖率数据文件完成**************")
       
       
if __name__=='__main__':
    copro=ClassOfProjectOperations()
    copro.getCovedFileListByEcFile("***","coverage.ec","9527")