文档章节

持续集成Java覆盖率合并

彼得
 彼得
发布于 2014/03/26 14:44
字数 1306
阅读 435
收藏 13
点赞 0
评论 0

原来:

后来:(丑了点,但是链接进去和上图中三个一样,但直观明了)

#! /usr/bin/python
# -*- coding: utf8 -*-

import os
import re
import sys
import datetime

'''
@author     :   U{peterguo<mailto: peterguo@vip.qq.com>}
@copyright  :   tencent
@date       :   2014-03-24
@version    :   1.0.0.0
@desc       :   1.统计当前目录下的覆盖率报表
                2.如果存在多份报表,则合并生成一个简单的总表
                3.支持Java项目(C++后续支持)
                
@note           1.生成的覆盖率总表为./coverage_report/index.html 点击链接失败则是因为相对路径问题
                4.调用时请配合如下shell脚本进行
                strParam=""
                for item in `find . -name "frame-summary.html"`
                do
                   subPrjName=`echo $item | awk -F"/" '{print $2}'`
                   strParam="$strParam $subPrjName:$item"
                done
                python ~/bin/merge_cov.py $strParam
'''

def RecursiveListLocDir(strPath, topdown = True):
    '''
    递归扫描目录下的所有文件
    '''
    vRet = []
    for root, dirs, files in os.walk(strPath, topdown):
        for name in files:
            vRet.append(os.path.join(root, name))
        for name in dirs:
            vRet.append(os.path.join(root, name) + "/")
    return vRet

class CovData(object):
    '''
    项目覆盖率 Java使用:mvn cobertura:cobertura Cpp使用:gcov
    '''    
    def __init__(self, strProjectName, strHtmlFilePath):
        '''
        strHtmlFilePath: 
            c++ : index.html
            java: frame-summary.html
        '''
        self.projectMame = strProjectName                           #项目名,按照目录级别获取
        self.strHtmlFilePath = strHtmlFilePath                      #记录下原始html,以便拼接链接
        self.strTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")   #生成时间
        
        self.strType = {"index.html":"cpp", "frame-summary.html":"java"}[os.path.basename(strHtmlFilePath)]
        
        if self.strType == "cpp":
            lRet = CovData.GetCppCovIndexHtml(strHtmlFilePath)
            
        if self.strType == "java":
            lRet = CovData.GetJavaCov(strHtmlFilePath)

        self.dLines  = {"Hit":lRet[0], "Total":lRet[1], "Cov":100.0*lRet[0]/(lRet[1]+0.0001)}
        self.dBranch = {"Hit":lRet[2], "Total":lRet[3], "Cov":100.0*lRet[2]/(lRet[3]+0.0001)}

    def showResult(self):
        '''
        按照一定格式打印出来
        '''
        print self.projectMame, self.strTime, self.strType, str(self.dLines), str(self.dBranch)
        
    @staticmethod
    def GetCppCovIndexHtmlOld(strHtmlFilePath):
        '''
        index.html
        '''
        vPath = strHtmlFilePath.split(os.sep)
        covData = CovData()
        covData.projectMame = vPath[-2] 

        cov_re = r"<td class=\"headerCovTableEntry(\D+)\">(\d+[\.]\d+)"
        
        f = open(strHtmlFilePath, 'r')
        html_text = f.read()
        
        cov_list = re.findall(cov_re,html_text)
        #行覆盖率
        covData.strLinesCov = str(cov_list[0][1])
        #函数覆盖率
        covData.strFuncCov = str(cov_list[1][1])
        #分支覆盖率
        covData.strBranchCov = str(cov_list[2][1])
        
        cov_re = r"<td class=\"headerCovTableEntry\">(\d+)"
        hit_total_list = re.findall(cov_re,html_text)
        covData.strLinesHit = str(hit_total_list[0])
        covData.strLinesTotal = str(hit_total_list[1])
        covData.strFuncHit = str(hit_total_list[2])
        covData.strFuncTotal = str(hit_total_list[3])
        covData.strBranchHit = str(hit_total_list[4])
        covData.strBranchTotal = str(hit_total_list[5])

        cov_re = r"<td class=\"headerValue\">(\d+[-]\d+[-]\d+)"
        time_list = re.findall(cov_re,html_text)
        #时间
        covData.strTime = (time_list[0])
        return covData
        
    @staticmethod      
    def GetCppCovIndexHtml(strHtmlFilePath):
        '''
        index.html
        '''
        fp = open(strHtmlFilePath, 'r')
        strCovHtml = fp.read()
        fp.close()
        
        #C++覆盖率直接可以获取,如下代码备用
        lObj = re.findall(r"<td class=\"headerCovTableEntry(\D+)\">(\d+[\.]\d+)", strCovHtml)
        fLinesCov = float(str(lObj[0][1]))
        fFuncCov = float(str(lObj[1][1]))
        fBranchCov = float(str(lObj[2][1]))

        lObj = re.findall(r"<td class=\"headerCovTableEntry\">(\d+)", strCovHtml)
        nLinesHit, nLinesTotal   = int(str(lObj[0])), int(str(lObj[1]))
        nFuncHit, nFuncTotal     = int(str(lObj[2])), int(str(lObj[3]))
        nBranchHit, nBranchTotal = int(str(lObj[4])), int(str(lObj[5]))
        
        #考虑到项目一般关注行覆盖率和分支覆盖率,这里忽略函数覆盖率
        return nLinesHit, nLinesTotal, nBranchHit, nBranchTotal
        
    @staticmethod  
    def GetJavaCov(strHtmlFilePath):
        '''
        frame-summary.html
        '''
        fp = open(strHtmlFilePath, 'r')
        strCovHtml = fp.read()
        fp.close()
        
        lObj = re.findall('''span class="text">[0-9]{1,}/[0-9]{1,}''', strCovHtml) 
        lTmp = re.split("[>/']", str(lObj[0:2]))
        
        nLineHit, nLinesTotal = int(lTmp[2]), int(lTmp[3]), 
        nBranchHit, nBranchTotal = int(lTmp[6]), int(lTmp[7])
        
        fLinePer = nLineHit * 100.0 / nLinesTotal
        fBranPer = nBranchHit * 100.0 / nBranchTotal
        
        #考虑到项目一般关注行覆盖率和分支覆盖率,这里忽略函数覆盖率
        return nLineHit, nLinesTotal, nBranchHit, nBranchTotal

    @staticmethod
    def DumpCov(loCov, strTargetHtml):
        '''
        拼接一个简单的html页面,里面带链接,可以跳转到真正的html覆盖率报表
        '''
        nLinesHit, nLinesTotal, nBranchHit, nBranchTotal = 0, 0, 0, 0
        
        print "\nMerging ... into.......... ", strTargetHtml   
       
        #生成html总报表 
        strReportHead = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><title>覆盖率报告</title></head><body><table align="center" width="70%" border="1pix"><thead><tr><td align="center">模块名称</td><td align="center">Hit/Total(行)</td><td align="center">行覆盖率</td><td align="center" >Hit/Total(分支)</td><td align="center">分支覆盖率</td></tr></thead><tbody>'''
        strReportTail = '''</tbody></table><script type="text/javascript"></body></html>''' 
        strReportRowFmt = '''<tr><td align="center">%s</td><td align="center">%d/%d</td><td align="center"><a href="%s">%.3f%%</td><td align="center">%d/%d</td><td align="center"><a href="%s">%.3f%%</td></tr>'''

        fp = file(strTargetHtml, "wt") 
        fp.write(strReportHead)
        for oCovData in loCov:
            oCovData.showResult()
            
            nLinesHit   += oCovData.dLines["Hit"]
            nLinesTotal += oCovData.dLines["Total"]            
            nBranchHit  += oCovData.dBranch["Hit"]            
            nBranchTotal+= oCovData.dBranch["Total"]          

            #模块覆盖率情况
            strSourceFileName = oCovData.strHtmlFilePath
            strRow = strReportRowFmt % (oCovData.projectMame, oCovData.dLines["Hit"], oCovData.dLines["Total"], "."+strSourceFileName, oCovData.dLines["Cov"], \
                                                              oCovData.dBranch["Hit"], oCovData.dBranch["Total"], "."+strSourceFileName, oCovData.dBranch["Cov"] )
            fp.write(strRow)  
            
        fLinesCov   = 100.0 * nLinesHit / (nLinesTotal + 0.0001)
        fBranchCov  = 100.0 * nBranchHit / (nBranchTotal + 0.0001)
        
        #总体覆盖率情况
        strSourceFileName = strTargetHtml
        strRow = strReportRowFmt % ("汇总", nLinesHit, nLinesTotal, "."+strSourceFileName, fLinesCov, nBranchHit, nBranchTotal, "."+strSourceFileName, fBranchCov)

        fp.write(strRow) 
        fp.write(strReportTail)
        fp.close()

        print "Summary: ", nLinesHit, nLinesTotal, fLinesCov, nBranchHit, nBranchTotal, fBranchCov
 

    @staticmethod
    def MergeCov(lParams, strTargetIndexHtml):
        loCov = []    
        for strParm in sys.argv[1:]:
            strProjectName, strCovHtml = strParm.split(":")
            oCovData = CovData(strProjectName, strCovHtml)
            oCovData.showResult()            
            loCov.append(oCovData)        
        CovData.DumpCov(loCov, strTargetIndexHtml)
        
def usage(strScriptName):
    print "Usage: python %s proj1:./abc/def/index.html proj2:./aab/def/index.html" % strScriptName
    print "Exam : python %s cpp:/usr/local/tomcat/webapps/jenkins/workspace/helloworld-cpp/coverage_result/index.html java:/usr/local/tomcat/webapps/jenkins/workspace/helloworld-freestyle/target/site/cobertura/frame-summary.html" % strScriptName
    sys.exit(0)

if __name__ == "__main__":
    if len(sys.argv) == 1:
        usage(sys.argv[0])

    if not os.path.exists("./coverage_report"): os.mkdir("./coverage_report") 
    CovData.MergeCov(sys.argv[1:], "./coverage_report/index.html")


典型构建脚本举例:

#! /bin/bash

#note   : build, ut, coverage, deploy
#author : peterguo
#date   : 2014.04.24

#处理补丁问题
/data/home/jenkins/bin/reverse_patch.sh

#findbugs html report
/usr/maven/bin/mvn compile site

#执行编译,ut,覆盖率
/usr/maven/bin/mvn install package assembly:assembly cobertura:cobertura findbugs:findbugs

#收集所有的单元测试结果
/bin/mkdir ./xml_test_report -p; /bin/cp $(/usr/bin/find . -name "TEST*xml") ./xml_test_report

#同时汇总出一份带链接的html汇总报表
strParam=""
for item in `find . -name "frame-summary.html"`
do
   subPrjName=`echo $item | awk -F"/" '{print $2}'`
   strParam="$strParam $subPrjName:$item"
done
python ~/bin/merge_cov.py $strParam

#部署到测试环境
SRC_PKG=`find ./target/ -name "jstorm-*tar.gz"`
/data/home/jenkins/bin/md5_upload.exp storm storm 10.187.139.144 $SRC_PKG /data/home/storm/deploy/$(basename $SRC_PKG)
/data/home/jenkins/bin/md5_upload.exp storm storm 10.187.139.145 $SRC_PKG /data/home/storm/deploy/$(basename $SRC_PKG)


© 著作权归作者所有

共有 人打赏支持
彼得

彼得

粉丝 39
博文 121
码字总数 38726
作品 0
深圳
程序员
Java 设计模式(10) —— 迭代器模式

一、迭代器模式 提供一种方法顺序访问一个聚合对象中的各个对象 二、示例 餐馆合并菜单:有一个中餐厅和一个西餐厅合并了,因此服务员服务的时候需要对菜单进行合并,可是 1.西餐厅的菜单是用...

磊_lei ⋅ 05/14 ⋅ 0

使用SonarQube Scanner for Maven 分析

特征 建议使用此分析器启动Java Maven项目的分析。 兼容性 Maven版本 2.X 3.X 兼容性 从maven-sonar-plugin 3.4.0.905开始,不再支持SonarQube <5.6。 如果使用5.6之前的SonarQube实例,则应...

如风达 ⋅ 04/26 ⋅ 0

Gradle学习(九)——构建环境

转载请注明出处:http://blog.csdn.net/lastsweetop/article/details/78914742 通过gradle.properties配置构建环境 为了更容易的配置用于构建的java进程,Gradle提供了几个选项。你可以在本地...

lastsweetop ⋅ 2017/12/27 ⋅ 0

跟我一起学docker(十)--jenkins的使用

什么是Jenkins? jenkins是一个广泛用于持续构建的可视化web工具,持续构建说得更直白点,就是各种项目的"自动化"编译、打包、分发部署。jenkins可以很好的支持各种语言(比如:java, c#, php...

IT人故事会 ⋅ 05/03 ⋅ 0

sharding-jdbc源码解析全集

sharding-jdbc源码解析之词法解析 sharding源码解析之api分析 sharding-jdbc源码解析之spring集成 sharding-jdbc源码解析之spring集成分片构造实现 sharding-jdbc源码解析之jdbc规范重写 sh...

天河2018 ⋅ 05/03 ⋅ 0

主流Java数据库连接池比较及前瞻

本文转载自微信公众号「工匠小猪猪的技术世界」 主流数据库连接池 常用的主流开源数据库连接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等 C3p0: 开源的JDBC连接池,实现了数据源和JND...

渣渣(Charles) ⋅ 04/30 ⋅ 0

《成神之路-基础篇》JVM——JVM参数及调优(已完结)

Java内存模型,Java内存管理,Java堆和栈,垃圾回收 本文是[《成神之路系列文章》][1]的第一篇,主要是关于JVM的一些介绍。 持续更新中 JVM参数及调优 JVM实用参数系列 成为Java GC专家(5)...

⋅ 05/05 ⋅ 0

JavaAgent-SandBox

1.前言 之前初步学习了javaAgent,并做了一份总结《JavaAgent学习笔记》。然后在看到《JVM-Sandbox 基于JVM的非侵入式运行期AOP解决方案》之后,接触到了集团的sandBox。并尝试使用这种有真正...

何度 ⋅ 05/09 ⋅ 0

Oracle Java SE 8 发行版更新:限制商业或生产用途

Oracle Java SE 8 发行版更新 Oracle Java SE 8 的公开更新仍面向单独的个人使用提供,至少持续至 2020 年底。 2019 年 1 月以后发布的 Oracle Java SE 8 公开更新将不向没有商用许可证的业务...

抢小孩糖吃 ⋅ 04/18 ⋅ 39

《成神之路-基础篇》JVM——JVM内存结构(已完结)

Java内存模型,Java内存管理,Java堆和栈,垃圾回收 本文是《成神之路系列文章》的第一篇,主要是关于JVM的一些介绍。 持续更新中 参考文章: Java虚拟机的内存组成以及堆内存介绍 Java堆和栈...

⋅ 05/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

apollo配置中心的学习笔记

公司现在配置文件太多了,导致配置文件修改起来还是非常麻烦的。在boss(业务运营支撑系统)中,配置文件是存放在jar包的,通过应用jar包来引用配置文件(区分不同环境)。这种方式虽然能够满足...

miaojiangmin ⋅ 2分钟前 ⋅ 0

Jena增删改查AP

插入、更新数据 public static void insert(){ String query = "PREFIX book: <http://www.book.com/jinyong/> \n" + " INSERT DATA \n" + ......

Vincent-Duan ⋅ 2分钟前 ⋅ 0

springMVC之与json数据交互方法

因为我也要返回json数据。所以需要这个注解@ResponseBody,把Java对象转换成json字符串 注意: 1、@RequestBody不能省,因为前台发过来的数据是json数据,得用这个注解去解析该怎么接收这些数...

颖伙虫 ⋅ 6分钟前 ⋅ 0

用实例域代替序号(31)

1、许多枚举天生就与一个单独的int 值相关联 ordinal 方法,返回枚举常量在类型中的数字位置 下述,枚举修改很不方便,不好维护 永远不要根据枚举的序数导出与他相关联的值 而是将他保存在一...

职业搬砖20年 ⋅ 8分钟前 ⋅ 0

并发编程---ConcurrentHashMap源码解析

ConcurrentHashMap是java中为了解决HashMap不能支持高并发而设计的新的实现。 ConcurrentHashMap的类结构 public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements C......

千古一梦888 ⋅ 11分钟前 ⋅ 0

微服务 WildFly Swarm 简介

我们将看到的最后一个Java微服务框架是一个相对较新的场景,它利用了 JBoss WildFly 应用服务器中已试过且受信任的 JavaEE 功能。WildFly Swarm 是 WildFly 应用服务器的一个完整的拆下来的组...

woshixin ⋅ 16分钟前 ⋅ 0

android apk 瘦身

头条APK瘦身之路 随着版本迭代,功能增加安装包体积也会慢慢增大。 今日头条576版本APK达到了25M,通过一系列的优化,到目前的607版本为12M。本文主要是介绍头条APK瘦身中用到的一些方法。 ...

GoldenVein ⋅ 20分钟前 ⋅ 1

mac机器学习开发环境部署及helloworld

一、下载并安装Anaconda2.7 https://repo.anaconda.com/archive/Anaconda2-5.2.0-MacOSX-x86_64.pkg 路径:/Users/shijun/anaconda2 二、运行Anaconda Navigator -> Environments -> base(ro......

八戒八戒八戒 ⋅ 31分钟前 ⋅ 0

关于日常开发的经验总结(Java),持续更新中

常量尽量使用枚举来表示,这样表现力会很强,因为枚举比一个常量类要有更多的扩展性 方法的入参和出参尽量不要使用Map,因为Map会让调用者感到迷惑,他不知道你里面装的什么,面向对象的开发...

小99 ⋅ 31分钟前 ⋅ 0

IDEA创建SpringMVC+Mybatis+Maven项目

视频如下(加载有点慢请见谅,服务器不太好): 视频

影狼 ⋅ 32分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部