我们已有CI job把单元测试结果发布到Sonar中,但Sonar的界面,你懂的。我们希望只关注我们部门相关项目的CodeCoverage数据,以及具体不达标项目的模块。
查阅了Sonar的API文档,http://nemo.sonarqube.org/api_documentation。api/resources 可以利用。
例子:
请求:http://sonar.vip.qa.ebay.com/api/resources?resource=Scala&depth=0&metrics=coverage,test_success_density,it_coverage,total-quality&format=json&callback=jQuery19108647494609467685_1419918769346&_=1419918769347
回复:jQuery19108647494609467685_1419918769346([{"id":312828,"key":"Scala","name":"Scala","scope":"PRJ","qualifier":"SVW","date":"2014-12-29T20:31:18-0700","creationDate":"2014-07-25T12:06:48-0700","lname":"Scala","lang":"none","msr":[{"key":"coverage","val":76.0,"frmt_val":"76.0%"},{"key":"total-quality","val":86.6,"frmt_val":"86.6%"}]}]);
通过这个请求,我们就得到相应的覆盖率等数据。
我们只需要用javascript利用jQuery的Ajax调用,分析返回的数据,然后用表格的形式展示出来。
具体的代码很简单:
<!DOCTYPE html>
<html>
<head>
<script src="../javascripts/jquery.js" type="text/javascript"></script>
<link href="http://ir.qa.ebaystatic.com/z/mk/q0km4qa2bizklor5ltdsqgthq.css?dataUri=true" type="text/css" rel="stylesheet"></head>
<body bgcolor="transparent">
</head>
<body>
<style>
.table th {text-align:center}
</style>
<div class="span14">
<div id="divother"></div>
</div>
<script>
$(document).ready(function(){
//alert("hi");
populateQualityConfidenceTable();
});
function sortByProperty(property) {
//'use strict';
return function (a, b) {
var sortStatus = 0;
if (a[property] < b[property]) {
sortStatus = -1;
} else if (a[property] > b[property]) {
sortStatus = 1;
}
return sortStatus;
};
}
function printTableHeader(val){
var tableheader = "";
if(val.msr[0]!=undefined && val.msr[1]!=undefined){
if((val.lname.replace(/ /g,"") == "Scala") ) {
tableheader = '<tr class="table" style="text-align:center"><th colspan="1"><font color="blue"><a id="test" href="#" οnclick="openPage(\'http://sonar.vip.qa.ebay.com/dashboard/index/' + val.key + '\');return false;">' + val.lname.replace(/ /g,"") + '</a></font></th><th></th><th colspan="1">' + val.msr[0].frmt_val + '</th><th colspan="1">0.00</th><th colspan="1">0.00</th><th colspan="1">' + val.msr[1].frmt_val + '</th></tr>';
tableheader = tableheader + '<tr><td colspan="7" align="center"><b>' + val.lname.replace(/ /g,"") + ' Sub Components</b></td></tr>';
tableheader = tableheader + '<tr><th>Product</th><th colspan="1">Module</th><th>UT Coverage</th><th>Pass</th><th>FT Coverage</th><th><a id="qc" href="#" οnclick="openPage(\'http://docs.codehaus.org/display/SONAR/Total+Quality+Plugin\');return false;">Quality Confidence</a></th></tr>';
}else{
if(val.msr[1].frmt_val.replace(/%/,"")>=85){
tableheader = tableheader + '<tr bgcolor="#dedede"><td><a id="test" href="#" οnclick="openPage(\'http://sonar.vip.qa.ebay.com/dashboard/index/' + val.key + '\');return false;">' + val.lname.replace(/ /g,"") + '</a></td><td></td><td>' + val.msr[1].frmt_val + '</td><td>0.00</td><td>0.00</td><td >' + val.msr[0].frmt_val + '</td></tr>';
}else{
tableheader = tableheader + '<tr bgcolor="#dedede"><td><a id="test" href="#" οnclick="openPage(\'http://sonar.vip.qa.ebay.com/dashboard/index/' + val.key + '\');return false;">' + val.lname.replace(/ /g,"") + '</a></td><td></td><td bgcolor="red">' + val.msr[1].frmt_val + '</td><td>0.00</td><td>0.00</td><td >' + val.msr[0].frmt_val + '</td></tr>';
}
}
}
return tableheader;
}
function populateQualityConfidenceTable(){
sonar_baseurl_head = "http://sonar.vip.qa.ebay.com/api/resources?resource=";
var sonar_baseurl_tail_withzerodepth = "&depth=0&metrics=coverage,test_success_density,it_coverage,total-quality&format=json";
var sonar_baseurl_tail_withonedepth = "&depth=1&metrics=scoverage,test_success_density,it_coverage,total-quality&format=json";
var metric_scala_coverage = sonar_baseurl_head + "Scala" + sonar_baseurl_tail_withzerodepth;
var metric_sub_polyglot_coverage = sonar_baseurl_head + "Scala" + sonar_baseurl_tail_withonedepth;
var requestUrl = "";
var modules = 0;
//alert(metric_scala_coverage);
var table = '<table style="width:100%">';
$.ajax({
url : metric_scala_coverage + "&callback=?",
async : false,
dataType: 'json',
success:
function(polyjson)
{
$.ajax({
url : metric_sub_polyglot_coverage + "&callback=?",
async : false,
dataType: 'json',
success:
function(subpolyjson)
{
polyData = polyjson.concat(subpolyjson.sort(sortByProperty('lname')));
var dataArray = [polyData];
table = table + '<tr><th colspan="1">Product</th><th colspan="1">Module</th><th colspan="1">UT Coverage</th><th colspan="1">Pass</th><th colspan="1">FT Coverage</th><th colspan="1"><a id="qc" href="#" οnclick="openPage(\'http://docs.codehaus.org/display/SONAR/Total+Quality+Plugin\');return false;">Quality Confidence</a></th></tr>';
for (var j = 0; j < dataArray.length; j++) {
$.each(dataArray[j], function(i, val) {
if(val.lname.replace(/ /g,"") == "Scala"){
table = table + printTableHeader(val);
}
else{
if(val.lname.replace(/ /g,"") == "higgins"){
requestUrl = sonar_baseurl_head + "com.ebay.higgins" + sonar_baseurl_tail_withonedepth;
}else if(val.lname.replace(/ /g,"") == "squbs"){
requestUrl = sonar_baseurl_head + "com.ebay.squbs" + sonar_baseurl_tail_withonedepth;
}else if(val.lname.replace(/ /g,"") == "rocksqubs"){
requestUrl = sonar_baseurl_head + "com.ebay.rocksqubs" + sonar_baseurl_tail_withonedepth;
}else{
requestUrl = sonar_baseurl_head + "com.ebay.squbs.chnlsvc" + sonar_baseurl_tail_withonedepth;
}
$.ajax({
url : requestUrl + "&callback=?",
async : false,
dataType: 'json',
success:
function(json)
{
scalaData = json//.sort(sortByProperty('lname'));
var dataArray = [scalaData];
var subtable = ""
for (var k = 0; k < dataArray.length; k++) {
$.each(dataArray[k], function(l, val2) {
if(parseFloat(val2.msr[1].frmt_val.replace(/%/,""))>=85){
subtable = subtable + '<tr id="'+val2.lname.replace(/ /g,"")+'"><td></td><td><a id="test" href="#" οnclick="openPage(\'http://sonar.vip.qa.ebay.com/dashboard/index/' + val2.key + '\');return false;">' + val2.lname.replace(/ /g,"") + '</a></td><td>' + val2.msr[1].frmt_val + '</td><td>0.00</td><td>0.00</td><td >' + val2.msr[0].frmt_val + '</td></tr>';
}else{
subtable = subtable + '<tr bgcolor="yellow" id="'+val2.lname.replace(/ /g,"")+'"><td></td><td><a id="test" href="#" οnclick="openPage(\'http://sonar.vip.qa.ebay.com/dashboard/index/' + val2.key + '\');return false;">' + val2.lname.replace(/ /g,"") + '</a></td><td >' + val2.msr[1].frmt_val + '</td><td>0.00</td><td>0.00</td><td >' + val2.msr[0].frmt_val + '</td></tr>';
}
});
}
var tableheader = printTableHeader(val);
table = table + tableheader + subtable;
modules = modules + 1;
//alert(modules);
if(modules==4){
//alert("final");
table = table + '</table>';
var qc = $('<div class="coverageTable"><div id="coverageTable" style="border-color: #4271A5" align="center">'
+'<div align="center" id="tabletarget" style="width:99%;overflow: auto;">'
+ table
+ '</div></div></div>');
$('#divother').append(qc);
}
}
});
}
});
}
}
});
}
});
}
</script>
</body>
</html>
这里需要注意的是,Table的拼凑部分必须放在最里层的ajax回调函数中,否则不能保证先后顺序,会导致表格出现一些错乱。
由于我们的项目是Scala项目, 所以使用了Scoverage来做unit test,所以请求中,用scoverage替换了coverage