Introduce daily bug stats chart
This commit introduces daily bug stats graphs. To do this, this commit also introduces nvd3 js library for enabling to use lineWithFocusChart. It is not same style chart of the main pages ones. Because stackedAreaWithFocusChart is a little bit buggy. So it sometimes shows wrong charts. And I also think lineWithFocusChart is better than the stackedArea chart because it is simple enough to understand the trend. Change-Id: Iacf22cddbd676d1447cfd9ae8ba1e7ce387720f6
This commit is contained in:
parent
b5f3d037ca
commit
f10ee2d6bd
@ -25,23 +25,33 @@ from jinja2 import FileSystemLoader
|
||||
from launchpadlib.launchpad import Launchpad
|
||||
|
||||
|
||||
def create_files(templatepath, outputpath, projects):
|
||||
def create_files(templatepath, outputpath, projects, config):
|
||||
# Create index file
|
||||
env = Environment(loader=FileSystemLoader(templatepath))
|
||||
indexfile = os.path.join(outputpath, "index.html")
|
||||
template = env.get_template('index.html')
|
||||
daily = config.get('daily')
|
||||
template.stream(projects=projects,
|
||||
openstack_status=openstack_status).dump(indexfile)
|
||||
openstack_status=openstack_status,
|
||||
daily=daily).dump(indexfile)
|
||||
|
||||
# Create each project file
|
||||
for project in projects:
|
||||
projectfile = os.path.join(outputpath, "%s.html" % project['project'])
|
||||
if 'height' in project:
|
||||
project['height'] = project['height'] - 30
|
||||
projectfile = os.path.join(outputpath,
|
||||
"%s.html" % project['project'])
|
||||
if not os.path.exists(projectfile):
|
||||
if 'height' in project:
|
||||
project['height'] = project['height'] - 30
|
||||
template = env.get_template('project.html')
|
||||
template.stream(project=project).dump(projectfile)
|
||||
|
||||
if daily:
|
||||
projectfile = os.path.join(outputpath,
|
||||
"%s-daily.html" % project['project'])
|
||||
if not os.path.exists(projectfile):
|
||||
template = env.get_template('project-daily.html')
|
||||
template.stream(project=project).dump(projectfile)
|
||||
|
||||
|
||||
def update_stats(outputpath, project_name, rotation, daily=False):
|
||||
|
||||
@ -175,7 +185,7 @@ if __name__ == '__main__':
|
||||
openstack_status = config.get('openstack_status')
|
||||
|
||||
# Create files in output directory, if needed
|
||||
create_files(templatepath, outputpath, projects)
|
||||
create_files(templatepath, outputpath, projects, config)
|
||||
|
||||
# Refresh JSON stats files
|
||||
launchpad = Launchpad.login_anonymously('bugdaystats', 'production',
|
||||
|
5
output/js/d3.min.js
vendored
Normal file
5
output/js/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
output/js/nv.d3.min.css
vendored
Normal file
2
output/js/nv.d3.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
output/js/nv.d3.min.css.map
Normal file
1
output/js/nv.d3.min.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["build/nv.d3.css"],"names":[],"mappings":"AAqBA,oBAfA,oBAgBI,KAAM,KAmXN,gBAAiB,WAhFrB,kBA+DA,uBAnWA,oBAfA,oBAmYI,gBAAiB,WAmErB,UAAW,UAJX,mBAvcA,eAsbA,uBA8BA,uCACI,eAAgB,KA+DpB,WA7QA,aAoRI,QAAS,MAST,sBAAuB,KAEvB,mBAAoB,KAtiBxB,eAEI,QAAS,EAuCb,2BA4JA,0DACI,QAAS,EAjMb,oBAEI,OAAQ,KACR,eAAgB,IAIpB,2BACI,eAAgB,IAGpB,gCACI,eAAgB,EAGpB,oBAEI,OAAQ,QAIZ,0BACI,0BACA,eAAgB,IAGpB,mCACI,YAAa,IAGjB,sCACA,uCACA,uCACI,YAAa,OAOjB,oBACI,aAAc,IAEd,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAG3C,0BACI,aAAc,EAGlB,2BACI,KAAM,QAGV,oBACI,KAAM,YAGV,2BACI,KAAM,cAKV,sCAFA,mCACA,6CAEI,eAAgB,EAEhB,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAK3C,8CACA,4CAHA,yCACA,mDAGI,aAAc,EAGlB,sCACA,6CACI,YAAa,IACb,KAAM,cACN,OAAQ,YAIZ,yBACE,aAAc,GAGhB,+BAIA,6BAHE,aAAc,EAOhB,6BACE,OAAQ,KAGV,uBACE,aAAc,MAGhB,gBAAkB,KAAM,KAAK,WAC7B,4BAA8B,aAAc,GAC5C,kCAAoC,aAAc,EAClD,2BAA6B,OAAQ,KAAM,aAAc,IACzD,mCAAqC,OAAQ,KAAM,KAAM,KAAM,aAAc,MAC7E,+BAAiC,OAAQ,KAAM,aAAc,MAC7D,8BAAgC,OAAQ,KAAM,aAAc,KAC5D,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,0BAA4B,UAAW,KAAM,YAAa,IAC1D,6BAA+B,KAAM,KAGrC,0BACI,KAAM,QACN,aAAc,GAElB,gCACI,aAAc,GAGlB,2CACI,aAAc,IAGlB,iDACI,aAAc,IAGlB,yDACI,OAAQ,QACR,KAAM,QAGV,yDACI,OAAQ,QACR,KAAM,QAGV,wDACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAIxE,uCACI,OAAQ,KAIZ,eACE,OAAQ,KACR,aAAc,MAEhB,eACE,OAAQ,KACR,eAAgB,GAElB,oBACE,aAAc,EAOhB,4BACI,aAAa,EACb,aAAa,EAGjB,8BACI,aAAa,EACb,aAAa,EAGjB,qDACI,aAAa,EACb,eAAe,EAQnB,kCACI,aAAc,IAGlB,wCACI,aAAc,EAElB,8BACI,KAAM,KAGV,8BACI,OAAQ,KAGZ,oDACI,aAAc,EACd,eAAgB,EAGpB,sDACI,aAAc,aACd,eAAgB,aAIpB,6CACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAKxE,iCADA,4CAEI,aAAc,IACd,aAAc,cACd,eAAgB,cAIpB,2BACI,OAAQ,KACR,eAAgB,EAChB,KAAM,KACN,aAAc,EAKlB,oBACI,OAAQ,UAUZ,aAEI,oBAAqB,KAErB,gBAAiB,KACjB,iBAAkB,KAClB,YAAa,KAEb,MAAM,KACN,OAAO,KAMX,0BAA2B,2BACvB,gBAAiB,EAAE,IAAI,KAAK,eAC5B,mBAAoB,EAAE,IAAI,KAAK,eAC/B,WAAY,EAAE,IAAI,KAAK,eAEvB,sBAAuB,IACvB,mBAAoB,IACpB,cAAe,IAInB,WACI,KAAM,IAAO,KAAK,MAGtB,aACI,KAAM,IAAK,KAAK,MAGpB,qBACI,KAAM,KACN,aAAc,EAGlB,gBACI,UAAW,KACX,YAAa,IAQjB,kBACI,aAAc,KAIlB,uBACI,KAAM,KACN,OAAQ,KAQZ,4BACI,OAAQ,QAGZ,qCACI,aAAc,EAIlB,wBACI,aAAc,YAGlB,+BACI,OAAQ,KACR,aAAc,GACd,KAAM,KACN,aAAc,GAOlB,aACE,WACE,aAAc,EACd,aAAc,GAIlB,oCACI,aAAc,IAGlB,0CACI,aAAc,IAGlB,6CACI,OAAQ,QAGZ,6CACI,OAAQ,QAIZ,uBACI,KAAM,KACN,OAAQ,KACR,eAAgB,GAIpB,uBACI,KAAM,KACN,eAAgB,GAGpB,4CAEI,KAAM,KACN,aAAc,GACd,OAAQ,KACR,gBAAiB,WAGrB,qCACI,aAAc,EACjB,aAAc,IAIf,8BACE,KAAM,KACN,OAAQ,KACR,aAAc,EACd,eAAgB,EAChB,iBAAkB,EAAG,EAUvB,2BACI,UAAW,KACX,KAAM,qBAGV,4BACI,OAAQ,KACR,aAAc,EAGlB,kBAhBI,WAAY,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OACvF,gBAAiB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5F,mBAAoB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAe/F,OAAQ,KACR,aAAc,IACd,eAAgB,EAIhB,aAAc,GAElB,yBACI,aAAc,EAKlB,4BACI,aAAc,EACd,eAAgB,EAIpB,iCACI,aAAc,KACd,eAAgB,GAGpB,kCACI,aAAc,EAWlB,wBACI,KAAM,KAOV,2CACI,OAAQ,KACR,aAAc,MAGlB,uBACA,yBACI,eAAgB,IA4LpB,+BAvIA,WAwII,eAAe,KA1LnB,oBACI,aAAc,EACd,eAAgB,EAGpB,kCACA,kCACI,aAAc,EACd,UAAW,KACX,YAAa,IAGjB,kCACI,OAAQ,KAGZ,oCACI,OAAQ,QACR,KAAM,QAGV,oCACI,OAAQ,QACR,KAAM,QAGV,wCACI,YAAa,IACb,UAAW,MAsEf,cAsCA,wBACI,YAAa,IA1GjB,kCACI,aAAc,GACd,eAAgB,EAChB,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAGxE,wCACI,aAAc,GAIlB,0CACI,eAAgB,EAChB,aAAc,EAIlB,WACI,SAAU,SAEV,MAAO,cACP,QAAS,IAET,QAAS,MAGT,YAAa,MACb,UAAW,KACX,WAAY,KAGZ,YAAa,OAGb,oBAAqB,KAErB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KAIb,WAAY,qBACZ,OAAQ,IAAI,MAAM,eAClB,cAAe,IAqBnB,cAgBA,aACI,OAAQ,EAER,WAAY,OAlChB,4BAA6B,6BACzB,WAAY,QAAQ,KAAK,OACzB,gBAAiB,QAAQ,KAAK,OAC9B,mBAAoB,QAAQ,KAAK,OAEjC,iBAAkB,MAClB,sBAAuB,MACvB,yBAA0B,MAG9B,uBACA,uBACI,QAAS,IAGb,cAEI,QAAS,IAAI,KACb,YAAa,KAEb,iBAAkB,sBAClB,MAAO,cAGP,cAAe,IAAI,MAAM,QAEzB,sBAAuB,IAAI,IAAI,EAAE,EACjC,mBAAoB,IAAI,IAAI,EAAE,EAC9B,cAAe,IAAI,IAAI,EAAE,EAG7B,aAEI,QAAS,IAAI,KAIjB,gBACI,QAAS,aACT,OAAQ,IAAI,EAGhB,iBACI,OAAQ,IACR,eAAe,EAInB,oBACI,QAAS,IAAI,IAAI,IAAI,EACrB,eAAgB,OAMpB,8BACI,YAAa,IAEjB,0BACI,WAAY,MACZ,YAAa,IAGjB,4BACI,MAAO,QAGX,iCACI,QAAS,IAAI,IAAI,IAAI,EACrB,oBAAqB,MACrB,oBAAqB,IACrB,iBAAkB,MAClB,iBAAkB,IAGtB,2CAGI,eAAgB,OAIhB,MAAO,KACP,OAAQ,KACR,OAAQ,IAAI,MAAM,KAGtB,mBACI,QAAS,IACT,WAAY,OAGhB,2BACI,eAAgB,KAChB,QAAS,KAUb,wBACI,OAAQ"}
|
11
output/js/nv.d3.min.js
vendored
Normal file
11
output/js/nv.d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
output/js/nv.d3.min.js.map
Normal file
1
output/js/nv.d3.min.js.map
Normal file
File diff suppressed because one or more lines are too long
41
output/js/package-triaging-daily.js
Normal file
41
output/js/package-triaging-daily.js
Normal file
@ -0,0 +1,41 @@
|
||||
function convData(jsondata) {
|
||||
var newEnt = [];
|
||||
var criticalEnt = [];
|
||||
var highEnt = [];
|
||||
var inProgEnt = [];
|
||||
var totalOpen = [];
|
||||
|
||||
var records = jsondata['records'];
|
||||
for (ent in records) {
|
||||
console.debug(records[ent]);
|
||||
var xval = records[ent]['date'] * 1000;
|
||||
newEnt.push({
|
||||
x: xval,
|
||||
y: records[ent]['new']
|
||||
});
|
||||
criticalEnt.push({
|
||||
x: xval,
|
||||
y: records[ent]['critical']
|
||||
});
|
||||
highEnt.push({
|
||||
x: xval,
|
||||
y: records[ent]['high']
|
||||
});
|
||||
inProgEnt.push({
|
||||
x: xval,
|
||||
y: records[ent]['inprogress']
|
||||
});
|
||||
totalOpen.push({
|
||||
x: xval,
|
||||
y: records[ent]['new']+records[ent]['incomplete']+records[ent]['inprogress']+records[ent]['confirmed']+records[ent]['triaged']
|
||||
});
|
||||
}
|
||||
var bugsData = [
|
||||
{ key: 'New', values: newEnt, area: false, type: 'line', color: 'pink' },
|
||||
{ key: 'Critical', values: criticalEnt, area: false, type: 'line', color: 'red'},
|
||||
{ key: 'High', values: highEnt, area: false, type: 'line', color: 'orange'},
|
||||
{ key: 'In Progress', values: inProgEnt, area: false, type: 'line', color: 'skyblue'},
|
||||
{ key: 'Total Open', values: totalOpen, area: false, type: 'line', color: 'lightgreen'}
|
||||
];
|
||||
return bugsData;
|
||||
}
|
@ -43,6 +43,12 @@
|
||||
<a href="{{ project.project }}-bug-stats.json">
|
||||
JSON FILE
|
||||
</a>
|
||||
{% if daily %}
|
||||
/ <a href="{{ project.project }}-daily.html">Daily Stats</a> / <a href="{{ project.project }}-bug-stats-daily.json">
|
||||
JSON FILE(DAILY)
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
52
templates/project-daily.html
Normal file
52
templates/project-daily.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf8" http-equiv="Content-Type"/>
|
||||
<title>
|
||||
{{ project.project|capitalize }} Bug Trend
|
||||
</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8">
|
||||
</script>
|
||||
<script language="javascript" src="js/nv.d3.min.js"></script>
|
||||
<link href="js/nv.d3.min.css" rel="stylesheet" type="text/css">
|
||||
<style>
|
||||
|
||||
html, body, #chart, svg {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="{{ project.project }}" style="width:100%;height:100%;">
|
||||
<svg></svg>
|
||||
</div>
|
||||
|
||||
<script language="javascript" src="js/package-triaging-daily.js"></script>
|
||||
<script type="text/javascript">
|
||||
var testdata;
|
||||
d3.json("{{ project.project }}-bug-stats-daily.json", function(error, dataSet){
|
||||
if(error) return console.warn(error);
|
||||
|
||||
nv.addGraph(function() {
|
||||
|
||||
var chart = nv.models.lineWithFocusChart();
|
||||
|
||||
chart.xAxis.tickFormat(function(d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
chart.x2Axis.tickFormat(function(d) { return d3.time.format('%m/%d')(new Date(d)); });
|
||||
chart.forceY([0]);
|
||||
|
||||
d3.select("#{{ project.project }} svg")
|
||||
.datum(convData(dataSet))
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user