原来:
后来:(丑了点,但是链接进去和上图中三个一样,但直观明了)
#! /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)