Merge lp:~allanlesage/qa-coverage-dashboard/initial-mega-merge into lp:qa-coverage-dashboard

Proposed by Allan LeSage
Status: Merged
Merged at revision: 758
Proposed branch: lp:~allanlesage/qa-coverage-dashboard/initial-mega-merge
Merge into: lp:qa-coverage-dashboard
Diff against target: 1233 lines (+362/-419)
24 files modified
common/static/css/style.css (+5/-0)
common/templates/layout.html (+5/-21)
gaps/api.py (+87/-46)
gaps/dashboard.py (+2/-2)
gaps/management/commands/c2dconfigutils/cu2dOutputCi.py (+3/-0)
gaps/models.py (+43/-7)
gaps/templates/branch_list.html (+0/-2)
gaps/templates/build.html (+1/-1)
gaps/templates/gaps_layout.html (+0/-4)
gaps/templates/integration_list.html (+1/-1)
gaps/templates/job.html (+1/-1)
gaps/templates/job_list.html (+1/-1)
gaps/templates/main.html (+0/-2)
gaps/templates/project_detail.html (+49/-38)
gaps/templates/project_list.html (+8/-10)
gaps/templates/stack_detail.html (+43/-37)
gaps/templates/stack_list.html (+49/-16)
gaps/templatetags/gaps_extras.py (+7/-8)
gaps/urls.py (+3/-8)
gaps/urls_api.py (+9/-82)
gaps/util/add.py (+2/-0)
gaps/views.py (+33/-128)
qa_dashboard/settings.py (+5/-3)
qa_dashboard/urls.py (+5/-1)
To merge this branch: bzr merge lp:~allanlesage/qa-coverage-dashboard/initial-mega-merge
Reviewer Review Type Date Requested Status
Chris Gagnon Pending
Review via email: mp+210458@code.launchpad.net

Description of the change

Initial mega merge of what we're demo-ing as the QA Coverage Dashboard, we will now have a normal MP-review process :) .

To post a comment you must log in.
Revision history for this message
Chris Gagnon (chris.gagnon) wrote :

move this out of the html, it's using a lot of the same code

467 +<script type="text/javascript">
468 + d3.json('{% url "gaps_api_project" project.name %}', function(data) {
469 + nv.addGraph(function() {
470 + var chart = nv.models.lineChart()
471 + .width(1100).height(400);
472 + chart.forceY([0, 1]);
473 + chart.xAxis
474 + .axisLabel('Date')
475 + .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));})
476 +
477 + chart.yAxis
478 + .axisLabel('%')
479 + .tickFormat(d3.format('%'))
480 + d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart);
481 +
482 + nv.utils.windowResize(chart.update);
483 +
484 + return chart;
485 + });
486 + });
487 +</script>

640 +<script type="text/javascript">
641 + d3.json('{% url 'gaps_api_stack' stack.name %}', function(data) {
642 + nv.addGraph(function() {
643 + var chart = nv.models.lineChart()
644 + .width(900).height(400);
645 + chart.forceY([0, 1]);
646 + chart.xAxis
647 + .axisLabel('Date')
648 + .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));})
649 + chart.yAxis
650 + .axisLabel('%')
651 + .tickFormat(d3.format('%'))
652 + d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart);
653 + nv.utils.windowResize(chart.update);
654 + return chart;
655 + });
656 + });
657 +</script>

758 +<script type="text/javascript">
759 + d3.json('{% url 'gaps_api_stack_list' %}', function(data) {
760 + nv.addGraph(function() {
761 + var chart = nv.models.lineChart()
762 + .width(900).height(400);
763 + chart.forceY([0, 1]);
764 + chart.xAxis
765 + .axisLabel('Date')
766 + .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));})
767 + chart.yAxis
768 + .axisLabel('%')
769 + .tickFormat(d3.format('%'))
770 + d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart);
771 + nv.utils.windowResize(chart.update);
772 + return chart;
773 + });
774 + });
775 +</script>

Can we move the properties in the model to the api?

Revision history for this message
Allan LeSage (allanlesage) wrote :

Agreed with Chris to push this to trunk and file bugs for his two requests: bug 1302788 and bug 1302786 .

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'common/static/css/style.css'
--- common/static/css/style.css 2013-12-02 13:35:26 +0000
+++ common/static/css/style.css 2014-03-11 17:00:08 +0000
@@ -12,6 +12,11 @@
12 color: white !important;12 color: white !important;
13}13}
1414
15.black {
16 background-color: #000000;
17 color: white !important;
18}
19
15.error {20.error {
16 background-color: #ffabab;21 background-color: #ffabab;
17}22}
1823
=== modified file 'common/templates/layout.html'
--- common/templates/layout.html 2014-03-05 23:18:33 +0000
+++ common/templates/layout.html 2014-03-11 17:00:08 +0000
@@ -11,7 +11,7 @@
11 <link href='{% static "css/jquery.dataTables.css" %}' rel='stylesheet' type='text/css' />11 <link href='{% static "css/jquery.dataTables.css" %}' rel='stylesheet' type='text/css' />
12 <link href='{% static "css/style.css" %}' rel='stylesheet' type='text/css' />12 <link href='{% static "css/style.css" %}' rel='stylesheet' type='text/css' />
13 <link href='{% static "css/new-style.css" %}' rel='stylesheet' type='text/css' />13 <link href='{% static "css/new-style.css" %}' rel='stylesheet' type='text/css' />
14 <title>{% block page_name %}{% endblock %} | Ubuntu CI Dashboard</title>14 <title>{% block page_name %}{% endblock %}Ubuntu QA Test Coverage Dashboard</title>
15 <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js' type="text/javascript"></script>15 <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js' type="text/javascript"></script>
16 <script src='{% static "js/jquery.dataTables.min.js" %}' type="text/javascript"></script>16 <script src='{% static "js/jquery.dataTables.min.js" %}' type="text/javascript"></script>
17 {% block extra_headers %}17 {% block extra_headers %}
@@ -19,32 +19,16 @@
19 {% analytics %}19 {% analytics %}
20 </head>20 </head>
21 <body>21 <body>
22 <div class="header-login">22 <header class="banner global" role="banner">
23 <div class="header-login-container">23 <nav role="navigation" class="nav-primary nav-right">
24 <ul>
25 {% if user.is_authenticated %}
26 <li>Logged in as: <strong><a href="{% url edit_profile %}">{{ user.username }}</a></strong></li>
27 {% if user.is_staff %}
28 <li><a href="/admin" title="Admin">Admin</a></li>
29 {% endif %}
30 <li><a href="{% url 'logout' %}" title="Log Out: {{ user.username }}">Log out</a></li>
31 {% else %}
32 <li><a href="/openid/login/?next={{ login_next }}" title="Log In">Log in</a></li>
33 {% endif %}
34 </ul>
35 </div>
36 </div>
37 <header class="banner global" role="banner">
38 <nav role="navigation" class="nav-primary nav-right">
39 <div class="logo">24 <div class="logo">
40 <a class="logo-ubuntu" href='{% url 'index' %}'>25 <a class="logo-ubuntu" href='{% url 'index' %}'>
41 <img width="118" height="27" src="//assets.ubuntu.com/sites/ubuntu/latest/u/img/logos/logo-ubuntu-orange.png" alt="Ubuntu" />26 <img width="118" height="27" src="//assets.ubuntu.com/sites/ubuntu/latest/u/img/logos/logo-ubuntu-orange.png" alt="Ubuntu" />
42 <span>ci</span>27 <span></span>
43 </a>28 </a>
44 </div>29 </div>
45 <ul>30 <ul>
46 {% plugin_links url %}31 {% plugin_links url %}
47 <li><a href="https://jenkins.qa.ubuntu.com/view/Trusty/view/AutoPkgTest/">Proposed</a></li>
48 </ul>32 </ul>
49 </nav>33 </nav>
50 </header>34 </header>
@@ -82,7 +66,7 @@
82 <p>&copy; 2012 - {% now "Y" %} Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd.66 <p>&copy; 2012 - {% now "Y" %} Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd.
83 <a href="https://bugs.launchpad.net/qa-dashboard/+filebug" target="_blank">Report a bug on this site</a></p>67 <a href="https://bugs.launchpad.net/qa-dashboard/+filebug" target="_blank">Report a bug on this site</a></p>
84 <ul class="inline clear">68 <ul class="inline clear">
85 <li class='info'>CI Dashboard</li>69 <li class='info'>QA Coverage Dashboard</li>
86 <li class='info'>version: {{ dash_version }}</li>70 <li class='info'>version: {{ dash_version }}</li>
87 <li class='info'>revno: {{ dash_revno }}</li>71 <li class='info'>revno: {{ dash_revno }}</li>
88 </ul>72 </ul>
8973
=== modified file 'gaps/api.py'
--- gaps/api.py 2014-02-20 19:19:28 +0000
+++ gaps/api.py 2014-03-11 17:00:08 +0000
@@ -1,5 +1,5 @@
1# QA Dashboard1# QA Coverage Dashboard
2# Copyright 2012-2013 Canonical Ltd.2# Copyright 2012-2014 Canonical Ltd.
33
4# This program is free software: you can redistribute it and/or modify it4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU Affero General Public License version 3, as5# under the terms of the GNU Affero General Public License version 3, as
@@ -13,59 +13,100 @@
13# You should have received a copy of the GNU Affero General Public License13# You should have received a copy of the GNU Affero General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.14# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16import json
16import logging17import logging
17import json18
18from django.shortcuts import get_object_or_40419from django.shortcuts import get_object_or_404
19from django.utils.dateformat import format20from django.utils.dateformat import format
2021
21from common.utils import JSONResponse22from common.utils import JSONResponse
22from gaps.models import GapsProject, JenkinsBuild23from gaps.models import (CoverageBuild,
24 CoverageData,
25 CoverageProject,
26 CoverageStack,
27 JenkinsBuild,
28 StackCoverageObservation)
2329
24logger = logging.getLogger('qa_dashboard')30logger = logging.getLogger('qa_dashboard')
2531
2632
27def project(request, name):33def project(request, name):
28 project = get_object_or_404(34 project = get_object_or_404(
29 GapsProject,35 CoverageProject,
30 launchpad_project__name=name,36 name=name)
31 release__name='head',37 coverage_datas = CoverageData.objects.filter(
32 )38 coverage_build__project=project).order_by(
3339 '-coverage_build__ran_at')
34 coverage_builds = JenkinsBuild.objects.filter(40 data = []
35 jenkins_job=project.autolanding_primary_job,41 line_coverage_data = {
36 coverage_report__isnull=False,42 'key': 'Line coverage',
37 ).order_by('timestamp')43 'color': '#DD4814'
3844 }
39 data = []45 branch_coverage_data = {
40 line_data = {46 'key': 'Branch coverage',
41 'key': 'Line coverage',47 'color': '#772953'
42 'color': '#DD4814'48 }
43 }49 line_coverage_values = []
44 branch_data = {50 branch_coverage_values = []
45 'key': 'Branch coverage',51 for coverage_data in coverage_datas:
46 'color': '#772953'52 line_coverage_values.append(
47 }53 {'y': float(coverage_data.line_coverage),
4854 'x': format(coverage_data.coverage_build.ran_at, 'U'),})
49 line_values = []55 branch_coverage_values.append(
50 branch_values = []56 {'y': float(coverage_data.branch_coverage),
5157 'x': format(coverage_data.coverage_build.ran_at, 'U'),})
52 for build in coverage_builds:58 line_coverage_data['values'] = line_coverage_values
53 ld = dict(59 branch_coverage_data['values'] = branch_coverage_values
54 y=build.line_coverage,60 data.append(line_coverage_data)
55 x=format(build.timestamp, 'U'),61 data.append(branch_coverage_data)
56 )62 data = json.dumps(data)
57 bd = dict(63 return JSONResponse(data)
58 y=build.branch_coverage,64
59 x=format(build.timestamp, 'U'),65def stack(request, name):
60 )66 stack = get_object_or_404(
61 line_values.append(ld)67 CoverageStack,
62 branch_values.append(bd)68 name=name)
63 line_data['values'] = line_values69 line_coverage_data = {
64 branch_data['values'] = branch_values70 'key': 'Line coverage',
6571 'color': '#DD4814'
66 data.append(line_data)72 }
67 data.append(branch_data)73 branch_coverage_data = {
6874 'key': 'Branch coverage',
69 data = json.dumps(data)75 'color': '#772953'
7076 }
77 observations = StackCoverageObservation.objects.filter(
78 stack=stack).order_by('-timestamp')
79 line_coverage_values = []
80 branch_coverage_values = []
81 # TODO: more Pythonic pls
82 for observation in observations:
83 line_coverage_values.append(
84 {'y': float(observation.line_coverage),
85 'x': format(observation.timestamp, 'U'),})
86 branch_coverage_values.append(
87 {'y': float(observation.branch_coverage),
88 'x': format(observation.timestamp, 'U'),})
89 line_coverage_data['values'] = line_coverage_values
90 branch_coverage_data['values'] = branch_coverage_values
91 data = []
92 data.append(line_coverage_data)
93 data.append(branch_coverage_data)
94 data = json.dumps(data)
95 return JSONResponse(data)
96
97def stack_list(request):
98 stacks = CoverageStack.objects.all()
99 data = []
100 for stack in stacks:
101 line_coverage_data = {'key': stack.name}
102 observations = StackCoverageObservation.objects.filter(
103 stack=stack).order_by('-timestamp')
104 line_coverage_values = []
105 for observation in observations:
106 line_coverage_values.append(
107 {'y': float(observation.line_coverage),
108 'x': format(observation.timestamp, 'U'),})
109 line_coverage_data['values'] = line_coverage_values
110 data.append(line_coverage_data)
111 data = json.dumps(data)
71 return JSONResponse(data)112 return JSONResponse(data)
72113
=== modified file 'gaps/dashboard.py'
--- gaps/dashboard.py 2014-02-20 20:06:08 +0000
+++ gaps/dashboard.py 2014-03-11 17:00:08 +0000
@@ -25,14 +25,14 @@
25 URL_PATTERNS = patterns(25 URL_PATTERNS = patterns(
26 '',26 '',
27 url(r'^gaps/', include('gaps.urls')),27 url(r'^gaps/', include('gaps.urls')),
28 #url(r'^api/gaps/idle/', include('gaps.urls_api')),28 url(r'^api/gaps/', include('gaps.urls_api')),
29 )29 )
3030
31 LINKS = [31 LINKS = [
32 {32 {
33 'name': 'gaps',33 'name': 'gaps',
34 'url': reverse_lazy('gaps_overview'),34 'url': reverse_lazy('gaps_overview'),
35 'label': 'Gaps',35 'label': 'Coverage',
36 'index': 100,36 'index': 100,
37 },37 },
38 ]38 ]
3939
=== modified file 'gaps/management/commands/c2dconfigutils/cu2dOutputCi.py'
--- gaps/management/commands/c2dconfigutils/cu2dOutputCi.py 2014-03-05 15:53:44 +0000
+++ gaps/management/commands/c2dconfigutils/cu2dOutputCi.py 2014-03-11 17:00:08 +0000
@@ -126,6 +126,9 @@
126 stacks = os.listdir('stacks/{}'.format(pocket))126 stacks = os.listdir('stacks/{}'.format(pocket))
127 for stack in stacks:127 for stack in stacks:
128 stack_name = str(stack).split('.')[0]128 stack_name = str(stack).split('.')[0]
129 if stack_name not in ['qa']:
130 print "skipping stack {}".format(stack_name)
131 continue
129 f_path = os.path.join(132 f_path = os.path.join(
130 local_path, '../stacks/{}/{}'.format(pocket, stack))133 local_path, '../stacks/{}/{}'.format(pocket, stack))
131 stack_list.append({'file': f_path,134 stack_list.append({'file': f_path,
132135
=== modified file 'gaps/models.py'
--- gaps/models.py 2014-03-06 22:13:30 +0000
+++ gaps/models.py 2014-03-11 17:00:08 +0000
@@ -14,6 +14,43 @@
14 """14 """
15 name = models.CharField(max_length=64)15 name = models.CharField(max_length=64)
1616
17 @property
18 def last_coverage_observation(self):
19 try:
20 return StackCoverageObservation.objects.filter(
21 stack=self).order_by('-timestamp')[0]
22 except IndexError:
23 return None
24
25 def refresh_coverage_observations(self):
26 StackCoverageObservation.objects.filter(stack=self).delete()
27 # for each coveragedata relevant to this stack, make a new observation (and compute coverages)
28 coverage_projects = CoverageProject.objects.filter(stack=self)
29 coverage_datas = CoverageData.objects.filter(
30 coverage_build__project__in=coverage_projects)
31 for coverage_data in coverage_datas:
32 observation = StackCoverageObservation(
33 stack=self,
34 timestamp=coverage_data.coverage_build.ran_at)
35 observation.compute_coverage()
36
37 @property
38 def percent_reporting(self):
39 coverage_projects = CoverageProject.objects.filter(stack=self)
40 coverage_data_exists_count = 0
41 for coverage_project in coverage_projects:
42 if coverage_project.last_coverage_data is not None:
43 coverage_data_exists_count = coverage_data_exists_count + 1
44 # TODO: this is arguably better but sqlite3 doesn't support distinct
45 #coverage_datas = CoverageData.objects.filter(
46 # coverage_build__project__in=coverage_projects).distinct(
47 # 'coverage_build__project')
48 try:
49 return float(coverage_data_exists_count) / float(len(coverage_projects))
50 except ZeroDivisionError:
51 # I suppose this is possible?
52 return 0.0
53
17 def __unicode__(self):54 def __unicode__(self):
18 return self.name55 return self.name
1956
@@ -24,22 +61,21 @@
24 stack = models.ManyToManyField(CoverageStack)61 stack = models.ManyToManyField(CoverageStack)
2562
26 @property63 @property
27 def line_coverage(self):64 def last_build(self):
28 coverage_builds = CoverageBuild.objects.filter(
29 project=self)
30 try:65 try:
31 return CoverageData.objects.filter(66 return CoverageBuild.objects.filter(
32 coverage_build__in=coverage_builds)[0].line_coverage67 project=self).order_by('-ran_at')[0]
33 except IndexError:68 except IndexError:
34 return None69 return None
3570
36 @property71 @property
37 def branch_coverage(self):72 def last_coverage_data(self):
38 coverage_builds = CoverageBuild.objects.filter(73 coverage_builds = CoverageBuild.objects.filter(
39 project=self)74 project=self)
40 try:75 try:
41 return CoverageData.objects.filter(76 return CoverageData.objects.filter(
42 coverage_build__in=coverage_builds)[0].branch_coverage77 coverage_build__in=coverage_builds).order_by(
78 '-coverage_build__ran_at')[0]
43 except IndexError:79 except IndexError:
44 return None80 return None
4581
4682
=== modified file 'gaps/templates/branch_list.html'
--- gaps/templates/branch_list.html 2014-02-20 19:19:28 +0000
+++ gaps/templates/branch_list.html 2014-03-11 17:00:08 +0000
@@ -1,8 +1,6 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
33
4{% block page_name %}PS-QA Dashboard{% endblock %}
5
6{% block content %}4{% block content %}
7<script type='text/javascript'>5<script type='text/javascript'>
8 //<![CDATA[6 //<![CDATA[
97
=== modified file 'gaps/templates/build.html'
--- gaps/templates/build.html 2014-02-20 19:19:28 +0000
+++ gaps/templates/build.html 2014-03-11 17:00:08 +0000
@@ -1,7 +1,7 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
33
4{% block page_name %}PS-QA Dashboard{% endblock %}4{% block page_name %}QA Coverage Dashboard{% endblock %}
55
6{% block content %}6{% block content %}
7{{ build.timestamp }}7{{ build.timestamp }}
88
=== modified file 'gaps/templates/gaps_layout.html'
--- gaps/templates/gaps_layout.html 2014-03-05 23:18:33 +0000
+++ gaps/templates/gaps_layout.html 2014-03-11 17:00:08 +0000
@@ -1,5 +1,1 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% block sub_nav_links %}
3<li {% ifequal url.1 'stacks' %}class="active"{% endifequal %}><a class="sub-nav-item" href='{% url 'gaps_overview' %}'>Integration</a></li>
4<li {% ifequal url.1 'project' %}class="active"{% endifequal %}><a class="sub-nav-item" href='{% url 'projects' %}'>Projects</a></li>
5{% endblock %}
62
=== modified file 'gaps/templates/integration_list.html'
--- gaps/templates/integration_list.html 2014-02-20 20:20:57 +0000
+++ gaps/templates/integration_list.html 2014-03-11 17:00:08 +0000
@@ -1,7 +1,7 @@
1{% extends "gaps_layout.html" %}1{% extends "gaps_layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
33
4{% block page_name %}PS-QA Dashboard{% endblock %}4{% block page_name %}QA Coverage Dashboard{% endblock %}
55
6{% block content %}6{% block content %}
7<script type='text/javascript'>7<script type='text/javascript'>
88
=== modified file 'gaps/templates/job.html'
--- gaps/templates/job.html 2014-02-20 19:19:28 +0000
+++ gaps/templates/job.html 2014-03-11 17:00:08 +0000
@@ -1,7 +1,7 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
33
4{% block page_name %}PS-QA Dashboard{% endblock %}4{% block page_name %}QA Coverage Dashboard{% endblock %}
55
6{% block content %}6{% block content %}
7<script type='text/javascript'>7<script type='text/javascript'>
88
=== modified file 'gaps/templates/job_list.html'
--- gaps/templates/job_list.html 2014-02-20 19:19:28 +0000
+++ gaps/templates/job_list.html 2014-03-11 17:00:08 +0000
@@ -1,7 +1,7 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
33
4{% block page_name %}PS-QA Dashboard{% endblock %}4{% block page_name %}QA Coverage Dashboard{% endblock %}
55
6{% block content %}6{% block content %}
7<script type='text/javascript'>7<script type='text/javascript'>
88
=== modified file 'gaps/templates/main.html'
--- gaps/templates/main.html 2014-02-20 19:19:28 +0000
+++ gaps/templates/main.html 2014-03-11 17:00:08 +0000
@@ -1,8 +1,6 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
33
4{% block page_name %}PS-QA Dashboard{% endblock %}
5
6{% block content %}4{% block content %}
7<script type='text/javascript'>5<script type='text/javascript'>
8 //<![CDATA[6 //<![CDATA[
97
=== modified file 'gaps/templates/project_detail.html'
--- gaps/templates/project_detail.html 2014-02-21 17:55:09 +0000
+++ gaps/templates/project_detail.html 2014-03-11 17:00:08 +0000
@@ -1,30 +1,63 @@
1{% extends "layout.html" %}1{% extends "layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
3{% load percentage %}3{% load percentage %}
44{% block extra_headers %}
5{% block page_name %}PS-QA Dashboard{% endblock %}5<link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.css" rel="stylesheet" />
6<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.min.js"></script>
7<!-- need to switch back to cdnjs when bugs are fixed
8<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.js"></script>-->
9<script type="text/javascript" src="//6df403e3d98e2ac67ac2-180150c581869d2c4c18db9c9e3179c4.r40.cf1.rackcdn.com/nv.d3.js"></script>
10{% endblock extra_headers %}
611
7{% block content %}12{% block content %}
13<style>
14 #line-chart svg {
15 height: 400px;
16 width: 1100px;
17 }
18</style>
8<script type='text/javascript'>19<script type='text/javascript'>
9 //<![CDATA[20 //<![CDATA[
10 $(document).ready(function() {21 $(document).ready(function() {
11 $(".data-table").dataTable({22 $(".data-table").dataTable({
12 "bPaginate": false,23 "bPaginate": false,
13 "aaSorting": [[0, 'desc']]24 "aaSorting": [[2, 'desc']]
14 });25 });
15 });26 });
16 //]]>27 //]]>
17</script>28</script>
29<script type="text/javascript">
30 d3.json('{% url "gaps_api_project" project.name %}', function(data) {
31 nv.addGraph(function() {
32 var chart = nv.models.lineChart()
33 .width(1100).height(400);
34 chart.forceY([0, 1]);
35 chart.xAxis
36 .axisLabel('Date')
37 .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));})
38
39 chart.yAxis
40 .axisLabel('%')
41 .tickFormat(d3.format('%'))
42 d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart);
43
44 nv.utils.windowResize(chart.update);
45
46 return chart;
47 });
48 });
49</script>
18<div class='grid_15'>50<div class='grid_15'>
19 <h2>51 <h2>
20 Project: {{ project.name }}52 Project: {{ project.name }}
21 </h2>53 </h2>
22</div>54</div>
23<div class='grid_2'>
24 <ul class='left_nav'>
25 </ul>
26</div>
27<div class='grid_13'>55<div class='grid_13'>
56 <div class="grid_13">
57 <div id="line-chart">
58 <svg></svg>
59 </div>
60 </div>
28 {% if project.report_url %}61 {% if project.report_url %}
29 <table>62 <table>
30 <tr>63 <tr>
@@ -45,48 +78,26 @@
45 <table class='data-table basic wide'>78 <table class='data-table basic wide'>
46 <thead>79 <thead>
47 <tr>80 <tr>
48 <th>Name</th>81 <th>Jenkins Build</th>
49 <th>Line Coverage</th>82 <th>Line Coverage</th>
50 <th>Branch Coverage</th>83 <th>Branch Coverage</th>
51 </tr>84 </tr>
52 </thead>85 </thead>
53 <tbody>86 <tbody>
54 {% for job in job_list %}87 {% for coverage_data in coverage_datas %}
55 <tr>88 <tr>
56 <td>89 <td>
57 <a href='{% url jobs %}{{ job.name }}'>{{ job.name }}</a>90 <a href='{{ coverage_data.coverage_build.url }}'>{{ coverage_data.coverage_build.ran_at }}</a>
58 </td>91 </td>
59 <td>92 <td>
60 {{ job.line_coverage|percentage }}93 {{ coverage_data.line_coverage|percentage }}
61 </td>94 </td>
62 <td>95 <td>
63 {{ job.branch_coverage|percentage }}96 {{ coverage_data.branch_coverage|percentage }}
64 </td>97 </td>
65 </tr>98 </tr>
66 {% endfor %}99 {% endfor %}
67 </tbody>100 </tbody>
68 </table>101 </table>
69 <div class='grid_13'>
70 <div id='historical_coverage_chart' style='width: 800px; height: 320px'></div>
71 </div>
72</div>102</div>
73<script type="text/javascript" src="http://www.google.com/jsapi"></script>
74<script type="text/javascript">
75    google.load('visualization', '1', {packages: ['corechart', 'annotatedtimeline']});
76 function draw_historical_coverage_chart() {
77 var historical_coverage_data = new google.visualization.DataTable({{ json_data|safe }});
78 var historical_coverage_options = {
79 title: 'Test Coverage Trend',
80 displayRangeSelector: false,
81 thickness: 2,
82 max: 1.0,
83 min: 0.0,
84 numberFormats: "##.#%",
85 colors: ["DD4814", "77216F", "5E2750", "2C001E", "AEA79F", "333333", "000000"]
86 };
87 var historical_coverage_chart = new google.visualization.AnnotatedTimeLine(document.getElementById('historical_coverage_chart'));
88 historical_coverage_chart.draw(historical_coverage_data, historical_coverage_options);
89 }
90 google.setOnLoadCallback(draw_historical_coverage_chart);
91</script>
92{% endblock %}103{% endblock %}
93104
=== modified file 'gaps/templates/project_list.html'
--- gaps/templates/project_list.html 2014-03-05 23:18:33 +0000
+++ gaps/templates/project_list.html 2014-03-11 17:00:08 +0000
@@ -2,15 +2,13 @@
2{% load dashboard_extras %}2{% load dashboard_extras %}
3{% load percentage %}3{% load percentage %}
44
5{% block page_name %}PS-QA Dashboard{% endblock %}
6
7{% block content %}5{% block content %}
8<script type='text/javascript'>6<script type='text/javascript'>
9 //<![CDATA[7 //<![CDATA[
10 $(document).ready(function() {8 $(document).ready(function() {
11 $(".data-table").dataTable({9 $(".data-table").dataTable({
12 "bPaginate": false,10 "bPaginate": false,
13 "aaSorting": [[0, 'desc']]11 "aaSorting": [[2, 'desc']]
14 });12 });
15 });13 });
16 //]]>14 //]]>
@@ -67,13 +65,13 @@
67 <a href='{% url 'projects' %}{{ project.name }}'>{{ project.name }}</a>65 <a href='{% url 'projects' %}{{ project.name }}'>{{ project.name }}</a>
68 </td>66 </td>
69 <td>67 <td>
70 {{ project.name }}68 {{ project.last_build.ran_at }}
71 </td>69 </td>
72 <td>70 <td>
73 {{ project.line_coverage|percentage }}71 {{ project.last_coverage_data.line_coverage|percentage }}
74 </td>72 </td>
75 <td>73 <td>
76 {{ project.branch_coverage|percentage }}74 {{ project.last_coverage_data.branch_coverage|percentage }}
77 </td>75 </td>
78 </tr>76 </tr>
79 {% endfor %}77 {% endfor %}
8078
=== modified file 'gaps/templates/stack_detail.html'
--- gaps/templates/stack_detail.html 2014-03-06 22:13:30 +0000
+++ gaps/templates/stack_detail.html 2014-03-11 17:00:08 +0000
@@ -1,11 +1,22 @@
1{% extends "gaps_layout.html" %}1{% extends "gaps_layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
3{% load ci_extras %}3{% load gaps_extras %}
4{% load percentage %}4{% load percentage %}
55{% block extra_headers %}
6{% block page_name %}PS-QA Dashboard{% endblock %}6<link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.css" rel="stylesheet" />
7<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.min.js"></script>
8<!-- need to switch back to cdnjs when bugs are fixed
9<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.js"></script>-->
10<script type="text/javascript" src="//6df403e3d98e2ac67ac2-180150c581869d2c4c18db9c9e3179c4.r40.cf1.rackcdn.com/nv.d3.js"></script>
11{% endblock extra_headers %}
712
8{% block content %}13{% block content %}
14<style>
15 #line-chart svg {
16 height: 400px;
17 width: 1100px;
18 }
19</style>
9<script type='text/javascript'>20<script type='text/javascript'>
10 //<![CDATA[21 //<![CDATA[
11 $(document).ready(function() {22 $(document).ready(function() {
@@ -16,6 +27,24 @@
16 });27 });
17 //]]>28 //]]>
18</script>29</script>
30<script type="text/javascript">
31 d3.json('{% url 'gaps_api_stack' stack.name %}', function(data) {
32 nv.addGraph(function() {
33 var chart = nv.models.lineChart()
34 .width(900).height(400);
35 chart.forceY([0, 1]);
36 chart.xAxis
37 .axisLabel('Date')
38 .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));})
39 chart.yAxis
40 .axisLabel('%')
41 .tickFormat(d3.format('%'))
42 d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart);
43 nv.utils.windowResize(chart.update);
44 return chart;
45 });
46 });
47</script>
19<div class='grid_15'>48<div class='grid_15'>
20 <h2>49 <h2>
21 Stack: {{ stack.name }}50 Stack: {{ stack.name }}
@@ -33,7 +62,10 @@
33 {% endfor %}62 {% endfor %}
34 </ul>63 </ul>
35</div>64</div>
36<div class='grid_13'>65 <div class="grid_13">
66 <div id="line-chart">
67 <svg></svg>
68 </div>
37 <table class='data-table basic wide'>69 <table class='data-table basic wide'>
38 <thead>70 <thead>
39 <tr>71 <tr>
@@ -50,43 +82,17 @@
50 <a href='{% url 'projects' %}{{ project.name }}/'>{{ project.name }}</a>82 <a href='{% url 'projects' %}{{ project.name }}/'>{{ project.name }}</a>
51 </td>83 </td>
52 <td>84 <td>
53 {{ project.timestamp }}85 {{ project.last_build.ran_at }}
54 </td>86 </td>
55 <td>87 <td>
56 {{ project.line_coverage|percentage }}88 {{ project.last_coverage_data.line_coverage|percentage }}
57 </td>89 </td>
58 <td>90 <td>
59 {{ project.branch_coverage|percentage }}91 {{ project.last_coverage_data.branch_coverage|percentage }}
60 </td>92 </td>
61 </tr>93 </tr>
62 {% endfor %}94 {% endfor %}
63 </tbody>95 </tbody>
64 </table>96 </table>
65 <div class='grid_13'>
66 {% if project_list %}
67 <div id='historical_coverage_chart' style='width: 800px; height: 320px'></div>
68 {% endif %}
69 </div>
70</div>97</div>
71<script type="text/javascript" src="http://www.google.com/jsapi"></script>
72<script type="text/javascript">
73    google.load('visualization', '1', {packages: ['corechart', 'annotatedtimeline']});
74 function draw_historical_coverage_chart() {
75 var historical_coverage_data = new google.visualization.DataTable({{ json_data|safe }});
76 var historical_coverage_options = {
77 title: 'Test Coverage Trend',
78 displayRangeSelector: false,
79 thickness: 2,
80 max: 1.0,
81 min: 0.0,
82 numberFormats: "##.#%",
83 colors: ["DD4814", "77216F", "5E2750", "2C001E", "AEA79F", "333333", "000000"]
84 };
85 var historical_coverage_chart = new google.visualization.AnnotatedTimeLine(document.getElementById('historical_coverage_chart'));
86 historical_coverage_chart.draw(historical_coverage_data, historical_coverage_options);
87 }
88
89 google.setOnLoadCallback(draw_historical_coverage_chart);
90
91 </script>
92{% endblock %}98{% endblock %}
9399
=== modified file 'gaps/templates/stack_list.html'
--- gaps/templates/stack_list.html 2014-03-06 22:13:30 +0000
+++ gaps/templates/stack_list.html 2014-03-11 17:00:08 +0000
@@ -1,10 +1,22 @@
1{% extends "gaps_layout.html" %}1{% extends "gaps_layout.html" %}
2{% load dashboard_extras %}2{% load dashboard_extras %}
3{% load ci_extras %}3{% load gaps_extras %}
44{% load percentage %}
5{% block page_name %}PS-QA Dashboard{% endblock %}5{% block extra_headers %}
6<link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.css" rel="stylesheet" />
7<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.min.js"></script>
8<!-- need to switch back to cdnjs when bugs are fixed
9<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.js"></script>-->
10<script type="text/javascript" src="//6df403e3d98e2ac67ac2-180150c581869d2c4c18db9c9e3179c4.r40.cf1.rackcdn.com/nv.d3.js"></script>
11{% endblock extra_headers %}
612
7{% block content %}13{% block content %}
14<style>
15 #line-chart svg {
16 height: 400px;
17 width: 1100px;
18 }
19</style>
8<script type='text/javascript'>20<script type='text/javascript'>
9 //<![CDATA[21 //<![CDATA[
10 $(document).ready(function() {22 $(document).ready(function() {
@@ -15,6 +27,24 @@
15 });27 });
16 //]]>28 //]]>
17</script>29</script>
30<script type="text/javascript">
31 d3.json('{% url 'gaps_api_stack_list' %}', function(data) {
32 nv.addGraph(function() {
33 var chart = nv.models.lineChart()
34 .width(900).height(400);
35 chart.forceY([0, 1]);
36 chart.xAxis
37 .axisLabel('Date')
38 .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));})
39 chart.yAxis
40 .axisLabel('%')
41 .tickFormat(d3.format('%'))
42 d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart);
43 nv.utils.windowResize(chart.update);
44 return chart;
45 });
46 });
47</script>
18<div class='grid_15'>48<div class='grid_15'>
19 <h2>49 <h2>
20 {% if show_filter %}50 {% if show_filter %}
@@ -26,7 +56,7 @@
26</div>56</div>
27<div class='grid_2'>57<div class='grid_2'>
28 <h3 class='nav-title'>58 <h3 class='nav-title'>
29 RELEASE FILTER59
30 </h3>60 </h3>
31 <ul class='left_nav'>61 <ul class='left_nav'>
32 <li>62 <li>
@@ -39,14 +69,17 @@
39 {% endfor %}69 {% endfor %}
40 </ul>70 </ul>
41</div>71</div>
42<div class='grid_13'>72<div class="grid_13">
73<div id="line-chart">
74 <svg></svg>
75</div>
43 <table class='data-table basic wide'>76 <table class='data-table basic wide'>
44 <thead>77 <thead>
45 <tr>78 <tr>
46 <th>Name</th>79 <th>Name</th>
47 <th>Publish Status</th>80 <th>Projects Reporting</th>
48 <th>Last Build</th>81 <th>Line Coverage</th>
49 <th>Last Publish</th>82 <th>Branch Coverage</th>
50 </tr>83 </tr>
51 </thead>84 </thead>
52 <tbody>85 <tbody>
@@ -55,14 +88,14 @@
55 <td>88 <td>
56 <a href='{% url 'stacks' %}{{ stack.name }}/'>{{ stack.name }}</a>89 <a href='{% url 'stacks' %}{{ stack.name }}/'>{{ stack.name }}</a>
57 </td>90 </td>
58 <td class='{{ stack.status|stack_status_color }}'>91 <td class='{{ stack.percent_reporting|percent_reporting_color }}'>
59 {{ stack.status }}92 {{ stack.percent_reporting|percentage }}
60 </td>93 </td>
61 <td>94 <td>
62 {{ stack.last_build.timestamp }}95 {{ stack.last_coverage_observation.line_coverage|percentage }}
63 </td>96 </td>
64 <td>97 <td>
65 {{ stack.last_publish }}98 {{ stack.last_coverage_observation.branch_coverage|percentage }}
66 </td>99 </td>
67 </tr>100 </tr>
68 {% endfor %}101 {% endfor %}
69102
=== renamed file 'gaps/templatetags/ci_extras.py' => 'gaps/templatetags/gaps_extras.py'
--- gaps/templatetags/ci_extras.py 2014-02-20 19:19:28 +0000
+++ gaps/templatetags/gaps_extras.py 2014-03-11 17:00:08 +0000
@@ -1,16 +1,15 @@
1import logging
2
1from django import template3from django import template
2import logging
34
4logger = logging.getLogger('qa_dashboard')
5register = template.Library()5register = template.Library()
66
7
8@register.filter7@register.filter
9def stack_status_color(value):8def percent_reporting_color(value):
10 if value is None:9 if value == 0.0:
11 return ""10 return "black"
12 if value == "Published":11 if value == 1.0:
13 return "green"12 return "green"
14 if value.startswith("Manual"):13 if value >= 0.9:
15 return "yellow"14 return "yellow"
16 return "red"15 return "red"
1716
=== modified file 'gaps/urls.py'
--- gaps/urls.py 2014-03-05 23:18:33 +0000
+++ gaps/urls.py 2014-03-11 17:00:08 +0000
@@ -23,15 +23,10 @@
2323
24urlpatterns = patterns(24urlpatterns = patterns(
25 'gaps.views',25 'gaps.views',
26 #url(r'^$', redirect_to, {'url': 'project', 'permanent': False},26 url(r'^$', RedirectView.as_view(url='project', permanent=False),
27 # name='gaps_overview'),27 name='gaps_overview'),
28 url(r'^$', RedirectView.as_view(url='project', permanent=False), name='gaps_overview'),
29 url(r'^stack/$', 'stack_list', name='stacks'),28 url(r'^stack/$', 'stack_list', name='stacks'),
30 url(r'^stack/(?P<stack_name>[^/]+)/$', 'stack'),29 url(r'^stack/(?P<name>[^/]+)/$', 'stack'),
31 url(r'^project/$', 'project_list', name='projects'),30 url(r'^project/$', 'project_list', name='projects'),
32 url(r'^project/(?P<name>[^/]+)/$', 'project'),31 url(r'^project/(?P<name>[^/]+)/$', 'project'),
33 url(r'^job/$', 'job_list', name='jobs'),
34 url(r'^job/(?P<job_name>[^/]+)/$', 'job'),
35 url(r'^job/(?P<job_name>[^/]+)/(?P<build_number>\d+)/$',
36 'build'),
37)32)
3833
=== modified file 'gaps/urls_api.py'
--- gaps/urls_api.py 2014-02-20 19:19:28 +0000
+++ gaps/urls_api.py 2014-03-11 17:00:08 +0000
@@ -17,86 +17,13 @@
1717
18urlpatterns = patterns(18urlpatterns = patterns(
19 'gaps.api',19 'gaps.api',
20 url(r'^images/$', 'images', name='gaps_api_images'),20 url(r'^project/(?P<name>[^/]+)/$',
21 url(21 'project',
22 r'^image/(?P<image_id>\d+)/$',22 name='gaps_api_project'),
23 'image_detail',23 url(r'^stack/$',
24 name='gaps_api_image_detail',24 'stack_list',
25 ),25 name='gaps_api_stack_list'),
26 url(r'^upgrades/$', 'upgrades', name='gaps_api_upgrades'),26 url(r'^stack/(?P<name>[^/]+)/$',
27 url(27 'stack',
28 r'^upgrade/(?P<upgrade_id>\d+)/$',28 name='gaps_api_stack'),
29 'upgrade_detail',
30 name='gaps_api_upgrade_detail',
31 ),
32 url(r'^machines/$', 'machines', name='gaps_api_machines'),
33 url(
34 r'^machine/(?P<machine_id>\d+)/$',
35 'machine_detail',
36 name='gaps_api_machine_detail',
37 ),
38 url(
39 r'^result/(?P<result_id>\d+)/$',
40 'result_detail',
41 name='gaps_api_result_detail',
42 ),
43 url(
44 r'^image/(?P<image_id>\d+)/machine/(?P<machine_id>\d+)/results/$',
45 'image_machine_results',
46 name='gaps_api_image_machine_results',
47 ),
48 url(
49 r'^image/(?P<image_id>\d+)/machine/(?P<machine_id>\d+)/metrics/$',
50 'image_machine_metrics',
51 name='gaps_api_image_machine_metrics',
52 ),
53 url(
54 r'^upgrade/(?P<upgrade_id>\d+)/machine/(?P<machine_id>\d+)/results/$',
55 'upgrade_machine_results',
56 name='gaps_api_upgrade_machine_results',
57 ),
58 url(
59 r'^upgrade/(?P<upgrade_id>\d+)/machine/(?P<machine_id>\d+)/metrics/$',
60 'upgrade_machine_metrics',
61 name='gaps_api_upgrade_machine_metrics',
62 ),
63 url(
64 r'^upgrade/machine/(?P<machine_id>\d+)/(?P<arch>\w+)/' +
65 '(?P<variant>\w+)/metric/(?P<metric>\w+)/$',
66 'upgrade_machine_arch_metrics',
67 name='gaps_api_upgrade_machine_arch_metrics',
68 ),
69 url(
70 r'^image/machine/(?P<machine_id>\d+)/(?P<arch>\w+)/' +
71 '(?P<variant>\w+)/metric/(?P<metric>\w+)/$',
72 'image_machine_arch_metrics',
73 name='gaps_api_image_machine_arch_metrics',
74 ),
75 url(
76 r'^image/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/$',
77 'image_machine_arch_processes',
78 name='gaps_api_image_machine_arch_processes',
79 ),
80 url(
81 r'^image/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/' +
82 r'(?P<process>.+)/$',
83 'image_machine_arch_processes',
84 name='gaps_api_image_machine_arch_processes',
85 ),
86 url(
87 r'^upgrade/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/$',
88 'upgrade_machine_arch_processes',
89 name='gaps_api_upgrade_machine_arch_processes',
90 ),
91 url(
92 r'^upgrade/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/' +
93 r'(?P<process>.+)/$',
94 'upgrade_machine_arch_processes',
95 name='gaps_api_upgrade_machine_arch_processes',
96 ),
97 url(
98 r'result/(?P<result_id>\d+)/processes/$',
99 'result_processes',
100 name='gaps_api_result_processes',
101 ),
102)29)
10330
=== modified file 'gaps/util/add.py'
--- gaps/util/add.py 2014-03-06 17:01:11 +0000
+++ gaps/util/add.py 2014-03-11 17:00:08 +0000
@@ -7,6 +7,7 @@
7 CoverageData,7 CoverageData,
8 CoverageProject,8 CoverageProject,
9 CoverageStack,9 CoverageStack,
10 StackCoverageObservation
10)11)
11from gaps.util import extractor, jenkins_pull12from gaps.util import extractor, jenkins_pull
1213
@@ -79,3 +80,4 @@
79 total_count=coverage_info.total,80 total_count=coverage_info.total,
80 coverage_build=build,81 coverage_build=build,
81 )82 )
83 stack.refresh_coverage_observations()
8284
=== modified file 'gaps/views.py'
--- gaps/views.py 2014-03-06 22:13:30 +0000
+++ gaps/views.py 2014-03-11 17:00:08 +0000
@@ -5,6 +5,8 @@
5from django.shortcuts import get_object_or_4045from django.shortcuts import get_object_or_404
6import gviz_api6import gviz_api
77
8from common.bread_crumbs import (BreadCrumb,
9 BreadCrumbTrail)
8from gaps.models import (CoverageProject,10from gaps.models import (CoverageProject,
9 CoverageBuild,11 CoverageBuild,
10 CoverageData,12 CoverageData,
@@ -14,146 +16,49 @@
14logger = logging.getLogger('qa_dashboard')16logger = logging.getLogger('qa_dashboard')
1517
1618
17def build(request, job_name, build_number):19@BreadCrumb("Stacks")
18 jenkins_build = CoverageBuild.objects.get(jenkins_job__name=job_name,
19 number=build_number)
20 runs = JenkinsRun.objects.filter(jenkins_build=jenkins_build)
21 t = loader.get_template('build.html')
22 c = Context({'build': jenkins_build,
23 'runs': runs, })
24 return HttpResponse(t.render(c))
25
26
27def job_list(request):
28 show_filter = request.GET.get('show')
29 logger.debug("Filter: %s" % show_filter)
30 if show_filter is None or show_filter not in BRANCH_FILTER_TYPES:
31 show_filter = 'all'
32
33 job_list = JenkinsJob.objects.all().order_by('-name')
34 if show_filter == 'all':
35 out_list = job_list
36 else:
37 out_list = []
38 for j in job_list:
39 if j.name.endswith(show_filter):
40 out_list.append(j)
41
42 # TODO Remove fake data
43 for j in out_list:
44 j.series = 'raring'
45 j.arch = 'amd64, armhf, i386'
46 j.last_run_data = ''
47 j.build_count = 40
48 j.duration = 1200
49 j.test_count = 120
50 j.coverage_rate = 0.55
51 j.coverage_rate_pct = 55
52 j.bug_count = 0
53
54 t = loader.get_template('job_list.html')
55 c = Context({
56 'job_list': out_list,
57 })
58 return HttpResponse(t.render(c))
59
60def job(request, job_name):
61 result_filter = request.GET.get('show')
62 logger.debug("Filter: %s" % result_filter)
63 job = JenkinsJob.objects.get(name=job_name)
64 result_list = JenkinsResult.objects.all()
65 if result_filter is None or result_filter not in [
66 result.name for result in result_list]:
67 logger.debug("we believe the filter isn't in the list")
68 result_filter = 'all'
69 if result_filter == 'all':
70 build_list = CoverageBuild.objects.filter(
71 jenkins_job=job)
72 else:
73 build_list = CoverageBuild.objects.filter(
74 jenkins_job=job,
75 result__name=result_filter)
76 t = loader.get_template('job.html')
77 c = Context({
78 'job': job,
79 'build_list': build_list,
80 'result_list': result_list,
81 })
82 return HttpResponse(t.render(c))
83
84def stack_list(request):20def stack_list(request):
85 stack_list = CoverageStack.objects.all()21 stack_list_ = CoverageStack.objects.all()
86 t = loader.get_template('stack_list.html')22 t = loader.get_template('stack_list.html')
87 c = Context({'stack_list': stack_list})23 c = Context({'stack_list': stack_list_,
24 'bread_crumb_trail': BreadCrumbTrail.leading_to(
25 stack_list)})
88 return HttpResponse(t.render(c))26 return HttpResponse(t.render(c))
8927
90def stack(request, stack_name):28@BreadCrumb("Stack", parent=stack_list, needs=['name'])
91 stack = CoverageStack.objects.get(name=stack_name)29def stack(request, name):
30 stack_ = CoverageStack.objects.get(name=name)
92 stack_list = CoverageStack.objects.all()31 stack_list = CoverageStack.objects.all()
93 project_list = CoverageProject.objects.filter(32 project_list = CoverageProject.objects.filter(
94 stack__name=stack_name)33 stack__name=name)
95 coverage_builds = CoverageBuild.objects.filter(
96 project__in=project_list)
97 data = []
98 for build in coverage_builds:
99 # for every time point, compute and cache stack coverage percentages
100 observation, observation_created = StackCoverageObservation.objects.get_or_create(
101 stack=stack,
102 timestamp=build.ran_at)
103 if observation_created:
104 observation.compute_coverage()
105 data.append({'timestamp': observation.timestamp,
106 'line coverage': float(observation.line_coverage),
107 'branch coverage': float(observation.branch_coverage)})
108 columns_order = ['timestamp',
109 "line coverage",
110 "branch coverage"]
111 description = {"timestamp": ("Date", "timestamp"),
112 "line coverage": ("number", "line coverage"),
113 "branch coverage": ("number", "branch coverage")}
114 data_table = gviz_api.DataTable(description)
115 data_table.LoadData(data)
116 json_data = data_table.ToJSon(columns_order=columns_order,
117 order_by="timestamp")
118 t = loader.get_template('stack_detail.html')34 t = loader.get_template('stack_detail.html')
119 c = Context({'stack': stack,35 c = Context({'stack': stack_,
120 'stack_list': stack_list,36 'stack_list': stack_list,
121 'project_list': project_list,37 'project_list': project_list,
122 'coverage_builds': coverage_builds,38 'bread_crumb_trail': BreadCrumbTrail.leading_to(
123 'json_data': json_data})39 stack, name=stack_.name)})
124 return HttpResponse(t.render(c))40 return HttpResponse(t.render(c))
12541
42@BreadCrumb("Projects")
43def project_list(request):
44 project_list_ = CoverageProject.objects.all()
45 t = loader.get_template('project_list.html')
46 c = Context({'project_list': project_list_,
47 'bread_crumb_trail': BreadCrumbTrail.leading_to(
48 project_list)})
49 return HttpResponse(t.render(c))
50
51@BreadCrumb('Project', parent=stack, needs=['name'])
126def project(request, name):52def project(request, name):
127 project = get_object_or_404(53 project_ = get_object_or_404(
128 CoverageProject,54 CoverageProject,
129 name=name)55 name=name)
130 data = []
131 coverage_datas = CoverageData.objects.filter(56 coverage_datas = CoverageData.objects.filter(
132 coverage_build__project=project).order_by(57 coverage_build__project=project_).order_by(
133 '-coverage_build__ran_at')58 '-coverage_build__ran_at')[:10]
134 for coverage_data in coverage_datas:
135 data.append({'timestamp': coverage_data.coverage_build.ran_at,
136 'line coverage': float(coverage_data.line_coverage),
137 'branch coverage': float(coverage_data.branch_coverage)})
138 columns_order = ['timestamp',
139 "line coverage",
140 "branch coverage"]
141 description = {"timestamp": ("Date", "timestamp"),
142 "line coverage": ("number", "line coverage"),
143 "branch coverage": ("number", "branch coverage")}
144 data_table = gviz_api.DataTable(description)
145 data_table.LoadData(data)
146 json_data = data_table.ToJSon(columns_order=columns_order,
147 order_by="ran_at")
148 t = loader.get_template('project_detail.html')59 t = loader.get_template('project_detail.html')
149 c = Context({'stack': stack,60 c = Context({'project': project_,
150 'project': project,61 'coverage_datas': coverage_datas,
151 'job_list': job_list,62 'bread_crumb_trail': BreadCrumbTrail.leading_to(
152 'json_data': json_data})63 project, name=project_.name)})
153 return HttpResponse(t.render(c))
154
155def project_list(request):
156 project_list = CoverageProject.objects.all()
157 t = loader.get_template('project_list.html')
158 c = Context({'project_list': project_list})
159 return HttpResponse(t.render(c))64 return HttpResponse(t.render(c))
16065
=== modified file 'qa_dashboard/settings.py'
--- qa_dashboard/settings.py 2014-02-20 19:19:28 +0000
+++ qa_dashboard/settings.py 2014-03-11 17:00:08 +0000
@@ -24,9 +24,11 @@
2424
2525
26ALLOWED_HOSTS = [26ALLOWED_HOSTS = [
27 'reports.qa.ubuntu.com',27 # temporary!
28 'ci.ubuntu.com',28 '*',
29 'rootstock.canonical.com',29# 'reports.qa.ubuntu.com',
30# 'ci.ubuntu.com',
31# 'rootstock.canonical.com',
30]32]
3133
32ADMINS = (34ADMINS = (
3335
=== modified file 'qa_dashboard/urls.py'
--- qa_dashboard/urls.py 2014-02-20 19:19:28 +0000
+++ qa_dashboard/urls.py 2014-03-11 17:00:08 +0000
@@ -16,13 +16,17 @@
16import sys16import sys
1717
18from django.conf.urls import include, patterns, url18from django.conf.urls import include, patterns, url
19from django.views.generic import RedirectView
1920
20from django.contrib import admin21from django.contrib import admin
21admin.autodiscover()22admin.autodiscover()
2223
23urlpatterns = patterns(24urlpatterns = patterns(
24 '',25 '',
25 url(r'^$', 'common.views.index', name='index'),26 # Restore this when we've merged with qa_dashboard of course :) .
27 #url(r'^$', 'common.views.index', name='index'),
28 url(r'^$', RedirectView.as_view(url='gaps/stack', permanent=False),
29 name='index'),
26 url(r'^edit/$', 'common.views.edit_profile', name='edit_profile'),30 url(r'^edit/$', 'common.views.edit_profile', name='edit_profile'),
27 url(r'^admin/', include(admin.site.urls)),31 url(r'^admin/', include(admin.site.urls)),
28 url(r'^\+oops$', 'common.views.cause_oops', name='cause-oops'),32 url(r'^\+oops$', 'common.views.cause_oops', name='cause-oops'),

Subscribers

People subscribed via source and target branches

to all changes: