Merge lp:~allanlesage/qa-coverage-dashboard/initial-mega-merge into lp:qa-coverage-dashboard
- initial-mega-merge
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Gagnon | Pending | ||
Review via email: mp+210458@code.launchpad.net |
Commit message
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 : | # |
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
1 | === modified file 'common/static/css/style.css' | |||
2 | --- common/static/css/style.css 2013-12-02 13:35:26 +0000 | |||
3 | +++ common/static/css/style.css 2014-03-11 17:00:08 +0000 | |||
4 | @@ -12,6 +12,11 @@ | |||
5 | 12 | color: white !important; | 12 | color: white !important; |
6 | 13 | } | 13 | } |
7 | 14 | 14 | ||
8 | 15 | .black { | ||
9 | 16 | background-color: #000000; | ||
10 | 17 | color: white !important; | ||
11 | 18 | } | ||
12 | 19 | |||
13 | 15 | .error { | 20 | .error { |
14 | 16 | background-color: #ffabab; | 21 | background-color: #ffabab; |
15 | 17 | } | 22 | } |
16 | 18 | 23 | ||
17 | === modified file 'common/templates/layout.html' | |||
18 | --- common/templates/layout.html 2014-03-05 23:18:33 +0000 | |||
19 | +++ common/templates/layout.html 2014-03-11 17:00:08 +0000 | |||
20 | @@ -11,7 +11,7 @@ | |||
21 | 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' /> |
22 | 12 | <link href='{% static "css/style.css" %}' rel='stylesheet' type='text/css' /> | 12 | <link href='{% static "css/style.css" %}' rel='stylesheet' type='text/css' /> |
23 | 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' /> |
25 | 14 | <title>{% block page_name %}{% endblock %} | Ubuntu CI Dashboard</title> | 14 | <title>{% block page_name %}{% endblock %}Ubuntu QA Test Coverage Dashboard</title> |
26 | 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> |
27 | 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> |
28 | 17 | {% block extra_headers %} | 17 | {% block extra_headers %} |
29 | @@ -19,32 +19,16 @@ | |||
30 | 19 | {% analytics %} | 19 | {% analytics %} |
31 | 20 | </head> | 20 | </head> |
32 | 21 | <body> | 21 | <body> |
50 | 22 | <div class="header-login"> | 22 | <header class="banner global" role="banner"> |
51 | 23 | <div class="header-login-container"> | 23 | <nav role="navigation" class="nav-primary nav-right"> |
35 | 24 | <ul> | ||
36 | 25 | {% if user.is_authenticated %} | ||
37 | 26 | <li>Logged in as: <strong><a href="{% url edit_profile %}">{{ user.username }}</a></strong></li> | ||
38 | 27 | {% if user.is_staff %} | ||
39 | 28 | <li><a href="/admin" title="Admin">Admin</a></li> | ||
40 | 29 | {% endif %} | ||
41 | 30 | <li><a href="{% url 'logout' %}" title="Log Out: {{ user.username }}">Log out</a></li> | ||
42 | 31 | {% else %} | ||
43 | 32 | <li><a href="/openid/login/?next={{ login_next }}" title="Log In">Log in</a></li> | ||
44 | 33 | {% endif %} | ||
45 | 34 | </ul> | ||
46 | 35 | </div> | ||
47 | 36 | </div> | ||
48 | 37 | <header class="banner global" role="banner"> | ||
49 | 38 | <nav role="navigation" class="nav-primary nav-right"> | ||
52 | 39 | <div class="logo"> | 24 | <div class="logo"> |
53 | 40 | <a class="logo-ubuntu" href='{% url 'index' %}'> | 25 | <a class="logo-ubuntu" href='{% url 'index' %}'> |
54 | 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" /> |
56 | 42 | <span>ci</span> | 27 | <span></span> |
57 | 43 | </a> | 28 | </a> |
58 | 44 | </div> | 29 | </div> |
59 | 45 | <ul> | 30 | <ul> |
60 | 46 | {% plugin_links url %} | 31 | {% plugin_links url %} |
61 | 47 | <li><a href="https://jenkins.qa.ubuntu.com/view/Trusty/view/AutoPkgTest/">Proposed</a></li> | ||
62 | 48 | </ul> | 32 | </ul> |
63 | 49 | </nav> | 33 | </nav> |
64 | 50 | </header> | 34 | </header> |
65 | @@ -82,7 +66,7 @@ | |||
66 | 82 | <p>© 2012 - {% now "Y" %} Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd. | 66 | <p>© 2012 - {% now "Y" %} Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd. |
67 | 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> |
68 | 84 | <ul class="inline clear"> | 68 | <ul class="inline clear"> |
70 | 85 | <li class='info'>CI Dashboard</li> | 69 | <li class='info'>QA Coverage Dashboard</li> |
71 | 86 | <li class='info'>version: {{ dash_version }}</li> | 70 | <li class='info'>version: {{ dash_version }}</li> |
72 | 87 | <li class='info'>revno: {{ dash_revno }}</li> | 71 | <li class='info'>revno: {{ dash_revno }}</li> |
73 | 88 | </ul> | 72 | </ul> |
74 | 89 | 73 | ||
75 | === modified file 'gaps/api.py' | |||
76 | --- gaps/api.py 2014-02-20 19:19:28 +0000 | |||
77 | +++ gaps/api.py 2014-03-11 17:00:08 +0000 | |||
78 | @@ -1,5 +1,5 @@ | |||
81 | 1 | # QA Dashboard | 1 | # QA Coverage Dashboard |
82 | 2 | # Copyright 2012-2013 Canonical Ltd. | 2 | # Copyright 2012-2014 Canonical Ltd. |
83 | 3 | 3 | ||
84 | 4 | # This program is free software: you can redistribute it and/or modify it | 4 | # This program is free software: you can redistribute it and/or modify it |
85 | 5 | # under the terms of the GNU Affero General Public License version 3, as | 5 | # under the terms of the GNU Affero General Public License version 3, as |
86 | @@ -13,59 +13,100 @@ | |||
87 | 13 | # You should have received a copy of the GNU Affero General Public License | 13 | # You should have received a copy of the GNU Affero General Public License |
88 | 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/>. |
89 | 15 | 15 | ||
90 | 16 | import json | ||
91 | 16 | import logging | 17 | import logging |
93 | 17 | import json | 18 | |
94 | 18 | from django.shortcuts import get_object_or_404 | 19 | from django.shortcuts import get_object_or_404 |
95 | 19 | from django.utils.dateformat import format | 20 | from django.utils.dateformat import format |
96 | 20 | 21 | ||
97 | 21 | from common.utils import JSONResponse | 22 | from common.utils import JSONResponse |
99 | 22 | from gaps.models import GapsProject, JenkinsBuild | 23 | from gaps.models import (CoverageBuild, |
100 | 24 | CoverageData, | ||
101 | 25 | CoverageProject, | ||
102 | 26 | CoverageStack, | ||
103 | 27 | JenkinsBuild, | ||
104 | 28 | StackCoverageObservation) | ||
105 | 23 | 29 | ||
106 | 24 | logger = logging.getLogger('qa_dashboard') | 30 | logger = logging.getLogger('qa_dashboard') |
107 | 25 | 31 | ||
108 | 26 | 32 | ||
109 | 27 | def project(request, name): | 33 | def project(request, name): |
110 | 28 | project = get_object_or_404( | 34 | project = get_object_or_404( |
153 | 29 | GapsProject, | 35 | CoverageProject, |
154 | 30 | launchpad_project__name=name, | 36 | name=name) |
155 | 31 | release__name='head', | 37 | coverage_datas = CoverageData.objects.filter( |
156 | 32 | ) | 38 | coverage_build__project=project).order_by( |
157 | 33 | 39 | '-coverage_build__ran_at') | |
158 | 34 | coverage_builds = JenkinsBuild.objects.filter( | 40 | data = [] |
159 | 35 | jenkins_job=project.autolanding_primary_job, | 41 | line_coverage_data = { |
160 | 36 | coverage_report__isnull=False, | 42 | 'key': 'Line coverage', |
161 | 37 | ).order_by('timestamp') | 43 | 'color': '#DD4814' |
162 | 38 | 44 | } | |
163 | 39 | data = [] | 45 | branch_coverage_data = { |
164 | 40 | line_data = { | 46 | 'key': 'Branch coverage', |
165 | 41 | 'key': 'Line coverage', | 47 | 'color': '#772953' |
166 | 42 | 'color': '#DD4814' | 48 | } |
167 | 43 | } | 49 | line_coverage_values = [] |
168 | 44 | branch_data = { | 50 | branch_coverage_values = [] |
169 | 45 | 'key': 'Branch coverage', | 51 | for coverage_data in coverage_datas: |
170 | 46 | 'color': '#772953' | 52 | line_coverage_values.append( |
171 | 47 | } | 53 | {'y': float(coverage_data.line_coverage), |
172 | 48 | 54 | 'x': format(coverage_data.coverage_build.ran_at, 'U'),}) | |
173 | 49 | line_values = [] | 55 | branch_coverage_values.append( |
174 | 50 | branch_values = [] | 56 | {'y': float(coverage_data.branch_coverage), |
175 | 51 | 57 | 'x': format(coverage_data.coverage_build.ran_at, 'U'),}) | |
176 | 52 | for build in coverage_builds: | 58 | line_coverage_data['values'] = line_coverage_values |
177 | 53 | ld = dict( | 59 | branch_coverage_data['values'] = branch_coverage_values |
178 | 54 | y=build.line_coverage, | 60 | data.append(line_coverage_data) |
179 | 55 | x=format(build.timestamp, 'U'), | 61 | data.append(branch_coverage_data) |
180 | 56 | ) | 62 | data = json.dumps(data) |
181 | 57 | bd = dict( | 63 | return JSONResponse(data) |
182 | 58 | y=build.branch_coverage, | 64 | |
183 | 59 | x=format(build.timestamp, 'U'), | 65 | def stack(request, name): |
184 | 60 | ) | 66 | stack = get_object_or_404( |
185 | 61 | line_values.append(ld) | 67 | CoverageStack, |
186 | 62 | branch_values.append(bd) | 68 | name=name) |
187 | 63 | line_data['values'] = line_values | 69 | line_coverage_data = { |
188 | 64 | branch_data['values'] = branch_values | 70 | 'key': 'Line coverage', |
189 | 65 | 71 | 'color': '#DD4814' | |
190 | 66 | data.append(line_data) | 72 | } |
191 | 67 | data.append(branch_data) | 73 | branch_coverage_data = { |
192 | 68 | 74 | 'key': 'Branch coverage', | |
193 | 69 | data = json.dumps(data) | 75 | 'color': '#772953' |
194 | 70 | 76 | } | |
195 | 77 | observations = StackCoverageObservation.objects.filter( | ||
196 | 78 | stack=stack).order_by('-timestamp') | ||
197 | 79 | line_coverage_values = [] | ||
198 | 80 | branch_coverage_values = [] | ||
199 | 81 | # TODO: more Pythonic pls | ||
200 | 82 | for observation in observations: | ||
201 | 83 | line_coverage_values.append( | ||
202 | 84 | {'y': float(observation.line_coverage), | ||
203 | 85 | 'x': format(observation.timestamp, 'U'),}) | ||
204 | 86 | branch_coverage_values.append( | ||
205 | 87 | {'y': float(observation.branch_coverage), | ||
206 | 88 | 'x': format(observation.timestamp, 'U'),}) | ||
207 | 89 | line_coverage_data['values'] = line_coverage_values | ||
208 | 90 | branch_coverage_data['values'] = branch_coverage_values | ||
209 | 91 | data = [] | ||
210 | 92 | data.append(line_coverage_data) | ||
211 | 93 | data.append(branch_coverage_data) | ||
212 | 94 | data = json.dumps(data) | ||
213 | 95 | return JSONResponse(data) | ||
214 | 96 | |||
215 | 97 | def stack_list(request): | ||
216 | 98 | stacks = CoverageStack.objects.all() | ||
217 | 99 | data = [] | ||
218 | 100 | for stack in stacks: | ||
219 | 101 | line_coverage_data = {'key': stack.name} | ||
220 | 102 | observations = StackCoverageObservation.objects.filter( | ||
221 | 103 | stack=stack).order_by('-timestamp') | ||
222 | 104 | line_coverage_values = [] | ||
223 | 105 | for observation in observations: | ||
224 | 106 | line_coverage_values.append( | ||
225 | 107 | {'y': float(observation.line_coverage), | ||
226 | 108 | 'x': format(observation.timestamp, 'U'),}) | ||
227 | 109 | line_coverage_data['values'] = line_coverage_values | ||
228 | 110 | data.append(line_coverage_data) | ||
229 | 111 | data = json.dumps(data) | ||
230 | 71 | return JSONResponse(data) | 112 | return JSONResponse(data) |
231 | 72 | 113 | ||
232 | === modified file 'gaps/dashboard.py' | |||
233 | --- gaps/dashboard.py 2014-02-20 20:06:08 +0000 | |||
234 | +++ gaps/dashboard.py 2014-03-11 17:00:08 +0000 | |||
235 | @@ -25,14 +25,14 @@ | |||
236 | 25 | URL_PATTERNS = patterns( | 25 | URL_PATTERNS = patterns( |
237 | 26 | '', | 26 | '', |
238 | 27 | url(r'^gaps/', include('gaps.urls')), | 27 | url(r'^gaps/', include('gaps.urls')), |
240 | 28 | #url(r'^api/gaps/idle/', include('gaps.urls_api')), | 28 | url(r'^api/gaps/', include('gaps.urls_api')), |
241 | 29 | ) | 29 | ) |
242 | 30 | 30 | ||
243 | 31 | LINKS = [ | 31 | LINKS = [ |
244 | 32 | { | 32 | { |
245 | 33 | 'name': 'gaps', | 33 | 'name': 'gaps', |
246 | 34 | 'url': reverse_lazy('gaps_overview'), | 34 | 'url': reverse_lazy('gaps_overview'), |
248 | 35 | 'label': 'Gaps', | 35 | 'label': 'Coverage', |
249 | 36 | 'index': 100, | 36 | 'index': 100, |
250 | 37 | }, | 37 | }, |
251 | 38 | ] | 38 | ] |
252 | 39 | 39 | ||
253 | === modified file 'gaps/management/commands/c2dconfigutils/cu2dOutputCi.py' | |||
254 | --- gaps/management/commands/c2dconfigutils/cu2dOutputCi.py 2014-03-05 15:53:44 +0000 | |||
255 | +++ gaps/management/commands/c2dconfigutils/cu2dOutputCi.py 2014-03-11 17:00:08 +0000 | |||
256 | @@ -126,6 +126,9 @@ | |||
257 | 126 | stacks = os.listdir('stacks/{}'.format(pocket)) | 126 | stacks = os.listdir('stacks/{}'.format(pocket)) |
258 | 127 | for stack in stacks: | 127 | for stack in stacks: |
259 | 128 | stack_name = str(stack).split('.')[0] | 128 | stack_name = str(stack).split('.')[0] |
260 | 129 | if stack_name not in ['qa']: | ||
261 | 130 | print "skipping stack {}".format(stack_name) | ||
262 | 131 | continue | ||
263 | 129 | f_path = os.path.join( | 132 | f_path = os.path.join( |
264 | 130 | local_path, '../stacks/{}/{}'.format(pocket, stack)) | 133 | local_path, '../stacks/{}/{}'.format(pocket, stack)) |
265 | 131 | stack_list.append({'file': f_path, | 134 | stack_list.append({'file': f_path, |
266 | 132 | 135 | ||
267 | === modified file 'gaps/models.py' | |||
268 | --- gaps/models.py 2014-03-06 22:13:30 +0000 | |||
269 | +++ gaps/models.py 2014-03-11 17:00:08 +0000 | |||
270 | @@ -14,6 +14,43 @@ | |||
271 | 14 | """ | 14 | """ |
272 | 15 | name = models.CharField(max_length=64) | 15 | name = models.CharField(max_length=64) |
273 | 16 | 16 | ||
274 | 17 | @property | ||
275 | 18 | def last_coverage_observation(self): | ||
276 | 19 | try: | ||
277 | 20 | return StackCoverageObservation.objects.filter( | ||
278 | 21 | stack=self).order_by('-timestamp')[0] | ||
279 | 22 | except IndexError: | ||
280 | 23 | return None | ||
281 | 24 | |||
282 | 25 | def refresh_coverage_observations(self): | ||
283 | 26 | StackCoverageObservation.objects.filter(stack=self).delete() | ||
284 | 27 | # for each coveragedata relevant to this stack, make a new observation (and compute coverages) | ||
285 | 28 | coverage_projects = CoverageProject.objects.filter(stack=self) | ||
286 | 29 | coverage_datas = CoverageData.objects.filter( | ||
287 | 30 | coverage_build__project__in=coverage_projects) | ||
288 | 31 | for coverage_data in coverage_datas: | ||
289 | 32 | observation = StackCoverageObservation( | ||
290 | 33 | stack=self, | ||
291 | 34 | timestamp=coverage_data.coverage_build.ran_at) | ||
292 | 35 | observation.compute_coverage() | ||
293 | 36 | |||
294 | 37 | @property | ||
295 | 38 | def percent_reporting(self): | ||
296 | 39 | coverage_projects = CoverageProject.objects.filter(stack=self) | ||
297 | 40 | coverage_data_exists_count = 0 | ||
298 | 41 | for coverage_project in coverage_projects: | ||
299 | 42 | if coverage_project.last_coverage_data is not None: | ||
300 | 43 | coverage_data_exists_count = coverage_data_exists_count + 1 | ||
301 | 44 | # TODO: this is arguably better but sqlite3 doesn't support distinct | ||
302 | 45 | #coverage_datas = CoverageData.objects.filter( | ||
303 | 46 | # coverage_build__project__in=coverage_projects).distinct( | ||
304 | 47 | # 'coverage_build__project') | ||
305 | 48 | try: | ||
306 | 49 | return float(coverage_data_exists_count) / float(len(coverage_projects)) | ||
307 | 50 | except ZeroDivisionError: | ||
308 | 51 | # I suppose this is possible? | ||
309 | 52 | return 0.0 | ||
310 | 53 | |||
311 | 17 | def __unicode__(self): | 54 | def __unicode__(self): |
312 | 18 | return self.name | 55 | return self.name |
313 | 19 | 56 | ||
314 | @@ -24,22 +61,21 @@ | |||
315 | 24 | stack = models.ManyToManyField(CoverageStack) | 61 | stack = models.ManyToManyField(CoverageStack) |
316 | 25 | 62 | ||
317 | 26 | @property | 63 | @property |
321 | 27 | def line_coverage(self): | 64 | def last_build(self): |
319 | 28 | coverage_builds = CoverageBuild.objects.filter( | ||
320 | 29 | project=self) | ||
322 | 30 | try: | 65 | try: |
325 | 31 | return CoverageData.objects.filter( | 66 | return CoverageBuild.objects.filter( |
326 | 32 | coverage_build__in=coverage_builds)[0].line_coverage | 67 | project=self).order_by('-ran_at')[0] |
327 | 33 | except IndexError: | 68 | except IndexError: |
328 | 34 | return None | 69 | return None |
329 | 35 | 70 | ||
330 | 36 | @property | 71 | @property |
332 | 37 | def branch_coverage(self): | 72 | def last_coverage_data(self): |
333 | 38 | coverage_builds = CoverageBuild.objects.filter( | 73 | coverage_builds = CoverageBuild.objects.filter( |
334 | 39 | project=self) | 74 | project=self) |
335 | 40 | try: | 75 | try: |
336 | 41 | return CoverageData.objects.filter( | 76 | return CoverageData.objects.filter( |
338 | 42 | coverage_build__in=coverage_builds)[0].branch_coverage | 77 | coverage_build__in=coverage_builds).order_by( |
339 | 78 | '-coverage_build__ran_at')[0] | ||
340 | 43 | except IndexError: | 79 | except IndexError: |
341 | 44 | return None | 80 | return None |
342 | 45 | 81 | ||
343 | 46 | 82 | ||
344 | === modified file 'gaps/templates/branch_list.html' | |||
345 | --- gaps/templates/branch_list.html 2014-02-20 19:19:28 +0000 | |||
346 | +++ gaps/templates/branch_list.html 2014-03-11 17:00:08 +0000 | |||
347 | @@ -1,8 +1,6 @@ | |||
348 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
349 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
350 | 3 | 3 | ||
351 | 4 | {% block page_name %}PS-QA Dashboard{% endblock %} | ||
352 | 5 | |||
353 | 6 | {% block content %} | 4 | {% block content %} |
354 | 7 | <script type='text/javascript'> | 5 | <script type='text/javascript'> |
355 | 8 | //<![CDATA[ | 6 | //<![CDATA[ |
356 | 9 | 7 | ||
357 | === modified file 'gaps/templates/build.html' | |||
358 | --- gaps/templates/build.html 2014-02-20 19:19:28 +0000 | |||
359 | +++ gaps/templates/build.html 2014-03-11 17:00:08 +0000 | |||
360 | @@ -1,7 +1,7 @@ | |||
361 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
362 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
363 | 3 | 3 | ||
365 | 4 | {% block page_name %}PS-QA Dashboard{% endblock %} | 4 | {% block page_name %}QA Coverage Dashboard{% endblock %} |
366 | 5 | 5 | ||
367 | 6 | {% block content %} | 6 | {% block content %} |
368 | 7 | {{ build.timestamp }} | 7 | {{ build.timestamp }} |
369 | 8 | 8 | ||
370 | === modified file 'gaps/templates/gaps_layout.html' | |||
371 | --- gaps/templates/gaps_layout.html 2014-03-05 23:18:33 +0000 | |||
372 | +++ gaps/templates/gaps_layout.html 2014-03-11 17:00:08 +0000 | |||
373 | @@ -1,5 +1,1 @@ | |||
374 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
375 | 2 | {% block sub_nav_links %} | ||
376 | 3 | <li {% ifequal url.1 'stacks' %}class="active"{% endifequal %}><a class="sub-nav-item" href='{% url 'gaps_overview' %}'>Integration</a></li> | ||
377 | 4 | <li {% ifequal url.1 'project' %}class="active"{% endifequal %}><a class="sub-nav-item" href='{% url 'projects' %}'>Projects</a></li> | ||
378 | 5 | {% endblock %} | ||
379 | 6 | 2 | ||
380 | === modified file 'gaps/templates/integration_list.html' | |||
381 | --- gaps/templates/integration_list.html 2014-02-20 20:20:57 +0000 | |||
382 | +++ gaps/templates/integration_list.html 2014-03-11 17:00:08 +0000 | |||
383 | @@ -1,7 +1,7 @@ | |||
384 | 1 | {% extends "gaps_layout.html" %} | 1 | {% extends "gaps_layout.html" %} |
385 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
386 | 3 | 3 | ||
388 | 4 | {% block page_name %}PS-QA Dashboard{% endblock %} | 4 | {% block page_name %}QA Coverage Dashboard{% endblock %} |
389 | 5 | 5 | ||
390 | 6 | {% block content %} | 6 | {% block content %} |
391 | 7 | <script type='text/javascript'> | 7 | <script type='text/javascript'> |
392 | 8 | 8 | ||
393 | === modified file 'gaps/templates/job.html' | |||
394 | --- gaps/templates/job.html 2014-02-20 19:19:28 +0000 | |||
395 | +++ gaps/templates/job.html 2014-03-11 17:00:08 +0000 | |||
396 | @@ -1,7 +1,7 @@ | |||
397 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
398 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
399 | 3 | 3 | ||
401 | 4 | {% block page_name %}PS-QA Dashboard{% endblock %} | 4 | {% block page_name %}QA Coverage Dashboard{% endblock %} |
402 | 5 | 5 | ||
403 | 6 | {% block content %} | 6 | {% block content %} |
404 | 7 | <script type='text/javascript'> | 7 | <script type='text/javascript'> |
405 | 8 | 8 | ||
406 | === modified file 'gaps/templates/job_list.html' | |||
407 | --- gaps/templates/job_list.html 2014-02-20 19:19:28 +0000 | |||
408 | +++ gaps/templates/job_list.html 2014-03-11 17:00:08 +0000 | |||
409 | @@ -1,7 +1,7 @@ | |||
410 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
411 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
412 | 3 | 3 | ||
414 | 4 | {% block page_name %}PS-QA Dashboard{% endblock %} | 4 | {% block page_name %}QA Coverage Dashboard{% endblock %} |
415 | 5 | 5 | ||
416 | 6 | {% block content %} | 6 | {% block content %} |
417 | 7 | <script type='text/javascript'> | 7 | <script type='text/javascript'> |
418 | 8 | 8 | ||
419 | === modified file 'gaps/templates/main.html' | |||
420 | --- gaps/templates/main.html 2014-02-20 19:19:28 +0000 | |||
421 | +++ gaps/templates/main.html 2014-03-11 17:00:08 +0000 | |||
422 | @@ -1,8 +1,6 @@ | |||
423 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
424 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
425 | 3 | 3 | ||
426 | 4 | {% block page_name %}PS-QA Dashboard{% endblock %} | ||
427 | 5 | |||
428 | 6 | {% block content %} | 4 | {% block content %} |
429 | 7 | <script type='text/javascript'> | 5 | <script type='text/javascript'> |
430 | 8 | //<![CDATA[ | 6 | //<![CDATA[ |
431 | 9 | 7 | ||
432 | === modified file 'gaps/templates/project_detail.html' | |||
433 | --- gaps/templates/project_detail.html 2014-02-21 17:55:09 +0000 | |||
434 | +++ gaps/templates/project_detail.html 2014-03-11 17:00:08 +0000 | |||
435 | @@ -1,30 +1,63 @@ | |||
436 | 1 | {% extends "layout.html" %} | 1 | {% extends "layout.html" %} |
437 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
438 | 3 | {% load percentage %} | 3 | {% load percentage %} |
441 | 4 | 4 | {% block extra_headers %} | |
442 | 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" /> |
443 | 6 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.min.js"></script> | ||
444 | 7 | <!-- need to switch back to cdnjs when bugs are fixed | ||
445 | 8 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.js"></script>--> | ||
446 | 9 | <script type="text/javascript" src="//6df403e3d98e2ac67ac2-180150c581869d2c4c18db9c9e3179c4.r40.cf1.rackcdn.com/nv.d3.js"></script> | ||
447 | 10 | {% endblock extra_headers %} | ||
448 | 6 | 11 | ||
449 | 7 | {% block content %} | 12 | {% block content %} |
450 | 13 | <style> | ||
451 | 14 | #line-chart svg { | ||
452 | 15 | height: 400px; | ||
453 | 16 | width: 1100px; | ||
454 | 17 | } | ||
455 | 18 | </style> | ||
456 | 8 | <script type='text/javascript'> | 19 | <script type='text/javascript'> |
457 | 9 | //<![CDATA[ | 20 | //<![CDATA[ |
458 | 10 | $(document).ready(function() { | 21 | $(document).ready(function() { |
459 | 11 | $(".data-table").dataTable({ | 22 | $(".data-table").dataTable({ |
460 | 12 | "bPaginate": false, | 23 | "bPaginate": false, |
462 | 13 | "aaSorting": [[0, 'desc']] | 24 | "aaSorting": [[2, 'desc']] |
463 | 14 | }); | 25 | }); |
464 | 15 | }); | 26 | }); |
465 | 16 | //]]> | 27 | //]]> |
466 | 17 | </script> | 28 | </script> |
467 | 29 | <script type="text/javascript"> | ||
468 | 30 | d3.json('{% url "gaps_api_project" project.name %}', function(data) { | ||
469 | 31 | nv.addGraph(function() { | ||
470 | 32 | var chart = nv.models.lineChart() | ||
471 | 33 | .width(1100).height(400); | ||
472 | 34 | chart.forceY([0, 1]); | ||
473 | 35 | chart.xAxis | ||
474 | 36 | .axisLabel('Date') | ||
475 | 37 | .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));}) | ||
476 | 38 | |||
477 | 39 | chart.yAxis | ||
478 | 40 | .axisLabel('%') | ||
479 | 41 | .tickFormat(d3.format('%')) | ||
480 | 42 | d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart); | ||
481 | 43 | |||
482 | 44 | nv.utils.windowResize(chart.update); | ||
483 | 45 | |||
484 | 46 | return chart; | ||
485 | 47 | }); | ||
486 | 48 | }); | ||
487 | 49 | </script> | ||
488 | 18 | <div class='grid_15'> | 50 | <div class='grid_15'> |
489 | 19 | <h2> | 51 | <h2> |
490 | 20 | Project: {{ project.name }} | 52 | Project: {{ project.name }} |
491 | 21 | </h2> | 53 | </h2> |
492 | 22 | </div> | 54 | </div> |
493 | 23 | <div class='grid_2'> | ||
494 | 24 | <ul class='left_nav'> | ||
495 | 25 | </ul> | ||
496 | 26 | </div> | ||
497 | 27 | <div class='grid_13'> | 55 | <div class='grid_13'> |
498 | 56 | <div class="grid_13"> | ||
499 | 57 | <div id="line-chart"> | ||
500 | 58 | <svg></svg> | ||
501 | 59 | </div> | ||
502 | 60 | </div> | ||
503 | 28 | {% if project.report_url %} | 61 | {% if project.report_url %} |
504 | 29 | <table> | 62 | <table> |
505 | 30 | <tr> | 63 | <tr> |
506 | @@ -45,48 +78,26 @@ | |||
507 | 45 | <table class='data-table basic wide'> | 78 | <table class='data-table basic wide'> |
508 | 46 | <thead> | 79 | <thead> |
509 | 47 | <tr> | 80 | <tr> |
511 | 48 | <th>Name</th> | 81 | <th>Jenkins Build</th> |
512 | 49 | <th>Line Coverage</th> | 82 | <th>Line Coverage</th> |
513 | 50 | <th>Branch Coverage</th> | 83 | <th>Branch Coverage</th> |
514 | 51 | </tr> | 84 | </tr> |
515 | 52 | </thead> | 85 | </thead> |
516 | 53 | <tbody> | 86 | <tbody> |
518 | 54 | {% for job in job_list %} | 87 | {% for coverage_data in coverage_datas %} |
519 | 55 | <tr> | 88 | <tr> |
520 | 56 | <td> | 89 | <td> |
528 | 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> |
529 | 58 | </td> | 91 | </td> |
530 | 59 | <td> | 92 | <td> |
531 | 60 | {{ job.line_coverage|percentage }} | 93 | {{ coverage_data.line_coverage|percentage }} |
532 | 61 | </td> | 94 | </td> |
533 | 62 | <td> | 95 | <td> |
534 | 63 | {{ job.branch_coverage|percentage }} | 96 | {{ coverage_data.branch_coverage|percentage }} |
535 | 64 | </td> | 97 | </td> |
536 | 65 | </tr> | 98 | </tr> |
537 | 66 | {% endfor %} | 99 | {% endfor %} |
538 | 67 | </tbody> | 100 | </tbody> |
539 | 68 | </table> | 101 | </table> |
540 | 69 | <div class='grid_13'> | ||
541 | 70 | <div id='historical_coverage_chart' style='width: 800px; height: 320px'></div> | ||
542 | 71 | </div> | ||
543 | 72 | </div> | 102 | </div> |
544 | 73 | <script type="text/javascript" src="http://www.google.com/jsapi"></script> | ||
545 | 74 | <script type="text/javascript"> | ||
546 | 75 | Â Â google.load('visualization', '1', {packages: ['corechart', 'annotatedtimeline']}); | ||
547 | 76 | function draw_historical_coverage_chart() { | ||
548 | 77 | var historical_coverage_data = new google.visualization.DataTable({{ json_data|safe }}); | ||
549 | 78 | var historical_coverage_options = { | ||
550 | 79 | title: 'Test Coverage Trend', | ||
551 | 80 | displayRangeSelector: false, | ||
552 | 81 | thickness: 2, | ||
553 | 82 | max: 1.0, | ||
554 | 83 | min: 0.0, | ||
555 | 84 | numberFormats: "##.#%", | ||
556 | 85 | colors: ["DD4814", "77216F", "5E2750", "2C001E", "AEA79F", "333333", "000000"] | ||
557 | 86 | }; | ||
558 | 87 | var historical_coverage_chart = new google.visualization.AnnotatedTimeLine(document.getElementById('historical_coverage_chart')); | ||
559 | 88 | historical_coverage_chart.draw(historical_coverage_data, historical_coverage_options); | ||
560 | 89 | } | ||
561 | 90 | google.setOnLoadCallback(draw_historical_coverage_chart); | ||
562 | 91 | </script> | ||
563 | 92 | {% endblock %} | 103 | {% endblock %} |
564 | 93 | 104 | ||
565 | === modified file 'gaps/templates/project_list.html' | |||
566 | --- gaps/templates/project_list.html 2014-03-05 23:18:33 +0000 | |||
567 | +++ gaps/templates/project_list.html 2014-03-11 17:00:08 +0000 | |||
568 | @@ -2,15 +2,13 @@ | |||
569 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
570 | 3 | {% load percentage %} | 3 | {% load percentage %} |
571 | 4 | 4 | ||
572 | 5 | {% block page_name %}PS-QA Dashboard{% endblock %} | ||
573 | 6 | |||
574 | 7 | {% block content %} | 5 | {% block content %} |
575 | 8 | <script type='text/javascript'> | 6 | <script type='text/javascript'> |
576 | 9 | //<![CDATA[ | 7 | //<![CDATA[ |
577 | 10 | $(document).ready(function() { | 8 | $(document).ready(function() { |
578 | 11 | $(".data-table").dataTable({ | 9 | $(".data-table").dataTable({ |
579 | 12 | "bPaginate": false, | 10 | "bPaginate": false, |
581 | 13 | "aaSorting": [[0, 'desc']] | 11 | "aaSorting": [[2, 'desc']] |
582 | 14 | }); | 12 | }); |
583 | 15 | }); | 13 | }); |
584 | 16 | //]]> | 14 | //]]> |
585 | @@ -67,13 +65,13 @@ | |||
586 | 67 | <a href='{% url 'projects' %}{{ project.name }}'>{{ project.name }}</a> | 65 | <a href='{% url 'projects' %}{{ project.name }}'>{{ project.name }}</a> |
587 | 68 | </td> | 66 | </td> |
588 | 69 | <td> | 67 | <td> |
596 | 70 | {{ project.name }} | 68 | {{ project.last_build.ran_at }} |
597 | 71 | </td> | 69 | </td> |
598 | 72 | <td> | 70 | <td> |
599 | 73 | {{ project.line_coverage|percentage }} | 71 | {{ project.last_coverage_data.line_coverage|percentage }} |
600 | 74 | </td> | 72 | </td> |
601 | 75 | <td> | 73 | <td> |
602 | 76 | {{ project.branch_coverage|percentage }} | 74 | {{ project.last_coverage_data.branch_coverage|percentage }} |
603 | 77 | </td> | 75 | </td> |
604 | 78 | </tr> | 76 | </tr> |
605 | 79 | {% endfor %} | 77 | {% endfor %} |
606 | 80 | 78 | ||
607 | === modified file 'gaps/templates/stack_detail.html' | |||
608 | --- gaps/templates/stack_detail.html 2014-03-06 22:13:30 +0000 | |||
609 | +++ gaps/templates/stack_detail.html 2014-03-11 17:00:08 +0000 | |||
610 | @@ -1,11 +1,22 @@ | |||
611 | 1 | {% extends "gaps_layout.html" %} | 1 | {% extends "gaps_layout.html" %} |
612 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
614 | 3 | {% load ci_extras %} | 3 | {% load gaps_extras %} |
615 | 4 | {% load percentage %} | 4 | {% load percentage %} |
618 | 5 | 5 | {% block extra_headers %} | |
619 | 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" /> |
620 | 7 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.min.js"></script> | ||
621 | 8 | <!-- need to switch back to cdnjs when bugs are fixed | ||
622 | 9 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.js"></script>--> | ||
623 | 10 | <script type="text/javascript" src="//6df403e3d98e2ac67ac2-180150c581869d2c4c18db9c9e3179c4.r40.cf1.rackcdn.com/nv.d3.js"></script> | ||
624 | 11 | {% endblock extra_headers %} | ||
625 | 7 | 12 | ||
626 | 8 | {% block content %} | 13 | {% block content %} |
627 | 14 | <style> | ||
628 | 15 | #line-chart svg { | ||
629 | 16 | height: 400px; | ||
630 | 17 | width: 1100px; | ||
631 | 18 | } | ||
632 | 19 | </style> | ||
633 | 9 | <script type='text/javascript'> | 20 | <script type='text/javascript'> |
634 | 10 | //<![CDATA[ | 21 | //<![CDATA[ |
635 | 11 | $(document).ready(function() { | 22 | $(document).ready(function() { |
636 | @@ -16,6 +27,24 @@ | |||
637 | 16 | }); | 27 | }); |
638 | 17 | //]]> | 28 | //]]> |
639 | 18 | </script> | 29 | </script> |
640 | 30 | <script type="text/javascript"> | ||
641 | 31 | d3.json('{% url 'gaps_api_stack' stack.name %}', function(data) { | ||
642 | 32 | nv.addGraph(function() { | ||
643 | 33 | var chart = nv.models.lineChart() | ||
644 | 34 | .width(900).height(400); | ||
645 | 35 | chart.forceY([0, 1]); | ||
646 | 36 | chart.xAxis | ||
647 | 37 | .axisLabel('Date') | ||
648 | 38 | .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));}) | ||
649 | 39 | chart.yAxis | ||
650 | 40 | .axisLabel('%') | ||
651 | 41 | .tickFormat(d3.format('%')) | ||
652 | 42 | d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart); | ||
653 | 43 | nv.utils.windowResize(chart.update); | ||
654 | 44 | return chart; | ||
655 | 45 | }); | ||
656 | 46 | }); | ||
657 | 47 | </script> | ||
658 | 19 | <div class='grid_15'> | 48 | <div class='grid_15'> |
659 | 20 | <h2> | 49 | <h2> |
660 | 21 | Stack: {{ stack.name }} | 50 | Stack: {{ stack.name }} |
661 | @@ -33,7 +62,10 @@ | |||
662 | 33 | {% endfor %} | 62 | {% endfor %} |
663 | 34 | </ul> | 63 | </ul> |
664 | 35 | </div> | 64 | </div> |
666 | 36 | <div class='grid_13'> | 65 | <div class="grid_13"> |
667 | 66 | <div id="line-chart"> | ||
668 | 67 | <svg></svg> | ||
669 | 68 | </div> | ||
670 | 37 | <table class='data-table basic wide'> | 69 | <table class='data-table basic wide'> |
671 | 38 | <thead> | 70 | <thead> |
672 | 39 | <tr> | 71 | <tr> |
673 | @@ -50,43 +82,17 @@ | |||
674 | 50 | <a href='{% url 'projects' %}{{ project.name }}/'>{{ project.name }}</a> | 82 | <a href='{% url 'projects' %}{{ project.name }}/'>{{ project.name }}</a> |
675 | 51 | </td> | 83 | </td> |
676 | 52 | <td> | 84 | <td> |
684 | 53 | {{ project.timestamp }} | 85 | {{ project.last_build.ran_at }} |
685 | 54 | </td> | 86 | </td> |
686 | 55 | <td> | 87 | <td> |
687 | 56 | {{ project.line_coverage|percentage }} | 88 | {{ project.last_coverage_data.line_coverage|percentage }} |
688 | 57 | </td> | 89 | </td> |
689 | 58 | <td> | 90 | <td> |
690 | 59 | {{ project.branch_coverage|percentage }} | 91 | {{ project.last_coverage_data.branch_coverage|percentage }} |
691 | 60 | </td> | 92 | </td> |
692 | 61 | </tr> | 93 | </tr> |
693 | 62 | {% endfor %} | 94 | {% endfor %} |
694 | 63 | </tbody> | 95 | </tbody> |
695 | 64 | </table> | 96 | </table> |
696 | 65 | <div class='grid_13'> | ||
697 | 66 | {% if project_list %} | ||
698 | 67 | <div id='historical_coverage_chart' style='width: 800px; height: 320px'></div> | ||
699 | 68 | {% endif %} | ||
700 | 69 | </div> | ||
701 | 70 | </div> | 97 | </div> |
702 | 71 | <script type="text/javascript" src="http://www.google.com/jsapi"></script> | ||
703 | 72 | <script type="text/javascript"> | ||
704 | 73 | Â Â google.load('visualization', '1', {packages: ['corechart', 'annotatedtimeline']}); | ||
705 | 74 | function draw_historical_coverage_chart() { | ||
706 | 75 | var historical_coverage_data = new google.visualization.DataTable({{ json_data|safe }}); | ||
707 | 76 | var historical_coverage_options = { | ||
708 | 77 | title: 'Test Coverage Trend', | ||
709 | 78 | displayRangeSelector: false, | ||
710 | 79 | thickness: 2, | ||
711 | 80 | max: 1.0, | ||
712 | 81 | min: 0.0, | ||
713 | 82 | numberFormats: "##.#%", | ||
714 | 83 | colors: ["DD4814", "77216F", "5E2750", "2C001E", "AEA79F", "333333", "000000"] | ||
715 | 84 | }; | ||
716 | 85 | var historical_coverage_chart = new google.visualization.AnnotatedTimeLine(document.getElementById('historical_coverage_chart')); | ||
717 | 86 | historical_coverage_chart.draw(historical_coverage_data, historical_coverage_options); | ||
718 | 87 | } | ||
719 | 88 | |||
720 | 89 | google.setOnLoadCallback(draw_historical_coverage_chart); | ||
721 | 90 | |||
722 | 91 | </script> | ||
723 | 92 | {% endblock %} | 98 | {% endblock %} |
724 | 93 | 99 | ||
725 | === modified file 'gaps/templates/stack_list.html' | |||
726 | --- gaps/templates/stack_list.html 2014-03-06 22:13:30 +0000 | |||
727 | +++ gaps/templates/stack_list.html 2014-03-11 17:00:08 +0000 | |||
728 | @@ -1,10 +1,22 @@ | |||
729 | 1 | {% extends "gaps_layout.html" %} | 1 | {% extends "gaps_layout.html" %} |
730 | 2 | {% load dashboard_extras %} | 2 | {% load dashboard_extras %} |
734 | 3 | {% load ci_extras %} | 3 | {% load gaps_extras %} |
735 | 4 | 4 | {% load percentage %} | |
736 | 5 | {% block page_name %}PS-QA Dashboard{% endblock %} | 5 | {% block extra_headers %} |
737 | 6 | <link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.css" rel="stylesheet" /> | ||
738 | 7 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.min.js"></script> | ||
739 | 8 | <!-- need to switch back to cdnjs when bugs are fixed | ||
740 | 9 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/nvd3/0.9/nv.d3.js"></script>--> | ||
741 | 10 | <script type="text/javascript" src="//6df403e3d98e2ac67ac2-180150c581869d2c4c18db9c9e3179c4.r40.cf1.rackcdn.com/nv.d3.js"></script> | ||
742 | 11 | {% endblock extra_headers %} | ||
743 | 6 | 12 | ||
744 | 7 | {% block content %} | 13 | {% block content %} |
745 | 14 | <style> | ||
746 | 15 | #line-chart svg { | ||
747 | 16 | height: 400px; | ||
748 | 17 | width: 1100px; | ||
749 | 18 | } | ||
750 | 19 | </style> | ||
751 | 8 | <script type='text/javascript'> | 20 | <script type='text/javascript'> |
752 | 9 | //<![CDATA[ | 21 | //<![CDATA[ |
753 | 10 | $(document).ready(function() { | 22 | $(document).ready(function() { |
754 | @@ -15,6 +27,24 @@ | |||
755 | 15 | }); | 27 | }); |
756 | 16 | //]]> | 28 | //]]> |
757 | 17 | </script> | 29 | </script> |
758 | 30 | <script type="text/javascript"> | ||
759 | 31 | d3.json('{% url 'gaps_api_stack_list' %}', function(data) { | ||
760 | 32 | nv.addGraph(function() { | ||
761 | 33 | var chart = nv.models.lineChart() | ||
762 | 34 | .width(900).height(400); | ||
763 | 35 | chart.forceY([0, 1]); | ||
764 | 36 | chart.xAxis | ||
765 | 37 | .axisLabel('Date') | ||
766 | 38 | .tickFormat(function(d){return d3.time.format('%Y%m%d')(new Date(d * 1000));}) | ||
767 | 39 | chart.yAxis | ||
768 | 40 | .axisLabel('%') | ||
769 | 41 | .tickFormat(d3.format('%')) | ||
770 | 42 | d3.select('#line-chart svg').datum(data).transition().duration(500).call(chart); | ||
771 | 43 | nv.utils.windowResize(chart.update); | ||
772 | 44 | return chart; | ||
773 | 45 | }); | ||
774 | 46 | }); | ||
775 | 47 | </script> | ||
776 | 18 | <div class='grid_15'> | 48 | <div class='grid_15'> |
777 | 19 | <h2> | 49 | <h2> |
778 | 20 | {% if show_filter %} | 50 | {% if show_filter %} |
779 | @@ -26,7 +56,7 @@ | |||
780 | 26 | </div> | 56 | </div> |
781 | 27 | <div class='grid_2'> | 57 | <div class='grid_2'> |
782 | 28 | <h3 class='nav-title'> | 58 | <h3 class='nav-title'> |
784 | 29 | RELEASE FILTER | 59 | |
785 | 30 | </h3> | 60 | </h3> |
786 | 31 | <ul class='left_nav'> | 61 | <ul class='left_nav'> |
787 | 32 | <li> | 62 | <li> |
788 | @@ -39,14 +69,17 @@ | |||
789 | 39 | {% endfor %} | 69 | {% endfor %} |
790 | 40 | </ul> | 70 | </ul> |
791 | 41 | </div> | 71 | </div> |
793 | 42 | <div class='grid_13'> | 72 | <div class="grid_13"> |
794 | 73 | <div id="line-chart"> | ||
795 | 74 | <svg></svg> | ||
796 | 75 | </div> | ||
797 | 43 | <table class='data-table basic wide'> | 76 | <table class='data-table basic wide'> |
798 | 44 | <thead> | 77 | <thead> |
799 | 45 | <tr> | 78 | <tr> |
800 | 46 | <th>Name</th> | 79 | <th>Name</th> |
804 | 47 | <th>Publish Status</th> | 80 | <th>Projects Reporting</th> |
805 | 48 | <th>Last Build</th> | 81 | <th>Line Coverage</th> |
806 | 49 | <th>Last Publish</th> | 82 | <th>Branch Coverage</th> |
807 | 50 | </tr> | 83 | </tr> |
808 | 51 | </thead> | 84 | </thead> |
809 | 52 | <tbody> | 85 | <tbody> |
810 | @@ -55,14 +88,14 @@ | |||
811 | 55 | <td> | 88 | <td> |
812 | 56 | <a href='{% url 'stacks' %}{{ stack.name }}/'>{{ stack.name }}</a> | 89 | <a href='{% url 'stacks' %}{{ stack.name }}/'>{{ stack.name }}</a> |
813 | 57 | </td> | 90 | </td> |
822 | 58 | <td class='{{ stack.status|stack_status_color }}'> | 91 | <td class='{{ stack.percent_reporting|percent_reporting_color }}'> |
823 | 59 | {{ stack.status }} | 92 | {{ stack.percent_reporting|percentage }} |
824 | 60 | </td> | 93 | </td> |
825 | 61 | <td> | 94 | <td> |
826 | 62 | {{ stack.last_build.timestamp }} | 95 | {{ stack.last_coverage_observation.line_coverage|percentage }} |
827 | 63 | </td> | 96 | </td> |
828 | 64 | <td> | 97 | <td> |
829 | 65 | {{ stack.last_publish }} | 98 | {{ stack.last_coverage_observation.branch_coverage|percentage }} |
830 | 66 | </td> | 99 | </td> |
831 | 67 | </tr> | 100 | </tr> |
832 | 68 | {% endfor %} | 101 | {% endfor %} |
833 | 69 | 102 | ||
834 | === renamed file 'gaps/templatetags/ci_extras.py' => 'gaps/templatetags/gaps_extras.py' | |||
835 | --- gaps/templatetags/ci_extras.py 2014-02-20 19:19:28 +0000 | |||
836 | +++ gaps/templatetags/gaps_extras.py 2014-03-11 17:00:08 +0000 | |||
837 | @@ -1,16 +1,15 @@ | |||
838 | 1 | import logging | ||
839 | 2 | |||
840 | 1 | from django import template | 3 | from django import template |
841 | 2 | import logging | ||
842 | 3 | 4 | ||
843 | 4 | logger = logging.getLogger('qa_dashboard') | ||
844 | 5 | register = template.Library() | 5 | register = template.Library() |
845 | 6 | 6 | ||
846 | 7 | |||
847 | 8 | @register.filter | 7 | @register.filter |
852 | 9 | def stack_status_color(value): | 8 | def percent_reporting_color(value): |
853 | 10 | if value is None: | 9 | if value == 0.0: |
854 | 11 | return "" | 10 | return "black" |
855 | 12 | if value == "Published": | 11 | if value == 1.0: |
856 | 13 | return "green" | 12 | return "green" |
858 | 14 | if value.startswith("Manual"): | 13 | if value >= 0.9: |
859 | 15 | return "yellow" | 14 | return "yellow" |
860 | 16 | return "red" | 15 | return "red" |
861 | 17 | 16 | ||
862 | === modified file 'gaps/urls.py' | |||
863 | --- gaps/urls.py 2014-03-05 23:18:33 +0000 | |||
864 | +++ gaps/urls.py 2014-03-11 17:00:08 +0000 | |||
865 | @@ -23,15 +23,10 @@ | |||
866 | 23 | 23 | ||
867 | 24 | urlpatterns = patterns( | 24 | urlpatterns = patterns( |
868 | 25 | 'gaps.views', | 25 | 'gaps.views', |
872 | 26 | #url(r'^$', redirect_to, {'url': 'project', 'permanent': False}, | 26 | url(r'^$', RedirectView.as_view(url='project', permanent=False), |
873 | 27 | # name='gaps_overview'), | 27 | name='gaps_overview'), |
871 | 28 | url(r'^$', RedirectView.as_view(url='project', permanent=False), name='gaps_overview'), | ||
874 | 29 | url(r'^stack/$', 'stack_list', name='stacks'), | 28 | url(r'^stack/$', 'stack_list', name='stacks'), |
876 | 30 | url(r'^stack/(?P<stack_name>[^/]+)/$', 'stack'), | 29 | url(r'^stack/(?P<name>[^/]+)/$', 'stack'), |
877 | 31 | url(r'^project/$', 'project_list', name='projects'), | 30 | url(r'^project/$', 'project_list', name='projects'), |
878 | 32 | url(r'^project/(?P<name>[^/]+)/$', 'project'), | 31 | url(r'^project/(?P<name>[^/]+)/$', 'project'), |
879 | 33 | url(r'^job/$', 'job_list', name='jobs'), | ||
880 | 34 | url(r'^job/(?P<job_name>[^/]+)/$', 'job'), | ||
881 | 35 | url(r'^job/(?P<job_name>[^/]+)/(?P<build_number>\d+)/$', | ||
882 | 36 | 'build'), | ||
883 | 37 | ) | 32 | ) |
884 | 38 | 33 | ||
885 | === modified file 'gaps/urls_api.py' | |||
886 | --- gaps/urls_api.py 2014-02-20 19:19:28 +0000 | |||
887 | +++ gaps/urls_api.py 2014-03-11 17:00:08 +0000 | |||
888 | @@ -17,86 +17,13 @@ | |||
889 | 17 | 17 | ||
890 | 18 | urlpatterns = patterns( | 18 | urlpatterns = patterns( |
891 | 19 | 'gaps.api', | 19 | 'gaps.api', |
974 | 20 | url(r'^images/$', 'images', name='gaps_api_images'), | 20 | url(r'^project/(?P<name>[^/]+)/$', |
975 | 21 | url( | 21 | 'project', |
976 | 22 | r'^image/(?P<image_id>\d+)/$', | 22 | name='gaps_api_project'), |
977 | 23 | 'image_detail', | 23 | url(r'^stack/$', |
978 | 24 | name='gaps_api_image_detail', | 24 | 'stack_list', |
979 | 25 | ), | 25 | name='gaps_api_stack_list'), |
980 | 26 | url(r'^upgrades/$', 'upgrades', name='gaps_api_upgrades'), | 26 | url(r'^stack/(?P<name>[^/]+)/$', |
981 | 27 | url( | 27 | 'stack', |
982 | 28 | r'^upgrade/(?P<upgrade_id>\d+)/$', | 28 | name='gaps_api_stack'), |
901 | 29 | 'upgrade_detail', | ||
902 | 30 | name='gaps_api_upgrade_detail', | ||
903 | 31 | ), | ||
904 | 32 | url(r'^machines/$', 'machines', name='gaps_api_machines'), | ||
905 | 33 | url( | ||
906 | 34 | r'^machine/(?P<machine_id>\d+)/$', | ||
907 | 35 | 'machine_detail', | ||
908 | 36 | name='gaps_api_machine_detail', | ||
909 | 37 | ), | ||
910 | 38 | url( | ||
911 | 39 | r'^result/(?P<result_id>\d+)/$', | ||
912 | 40 | 'result_detail', | ||
913 | 41 | name='gaps_api_result_detail', | ||
914 | 42 | ), | ||
915 | 43 | url( | ||
916 | 44 | r'^image/(?P<image_id>\d+)/machine/(?P<machine_id>\d+)/results/$', | ||
917 | 45 | 'image_machine_results', | ||
918 | 46 | name='gaps_api_image_machine_results', | ||
919 | 47 | ), | ||
920 | 48 | url( | ||
921 | 49 | r'^image/(?P<image_id>\d+)/machine/(?P<machine_id>\d+)/metrics/$', | ||
922 | 50 | 'image_machine_metrics', | ||
923 | 51 | name='gaps_api_image_machine_metrics', | ||
924 | 52 | ), | ||
925 | 53 | url( | ||
926 | 54 | r'^upgrade/(?P<upgrade_id>\d+)/machine/(?P<machine_id>\d+)/results/$', | ||
927 | 55 | 'upgrade_machine_results', | ||
928 | 56 | name='gaps_api_upgrade_machine_results', | ||
929 | 57 | ), | ||
930 | 58 | url( | ||
931 | 59 | r'^upgrade/(?P<upgrade_id>\d+)/machine/(?P<machine_id>\d+)/metrics/$', | ||
932 | 60 | 'upgrade_machine_metrics', | ||
933 | 61 | name='gaps_api_upgrade_machine_metrics', | ||
934 | 62 | ), | ||
935 | 63 | url( | ||
936 | 64 | r'^upgrade/machine/(?P<machine_id>\d+)/(?P<arch>\w+)/' + | ||
937 | 65 | '(?P<variant>\w+)/metric/(?P<metric>\w+)/$', | ||
938 | 66 | 'upgrade_machine_arch_metrics', | ||
939 | 67 | name='gaps_api_upgrade_machine_arch_metrics', | ||
940 | 68 | ), | ||
941 | 69 | url( | ||
942 | 70 | r'^image/machine/(?P<machine_id>\d+)/(?P<arch>\w+)/' + | ||
943 | 71 | '(?P<variant>\w+)/metric/(?P<metric>\w+)/$', | ||
944 | 72 | 'image_machine_arch_metrics', | ||
945 | 73 | name='gaps_api_image_machine_arch_metrics', | ||
946 | 74 | ), | ||
947 | 75 | url( | ||
948 | 76 | r'^image/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/$', | ||
949 | 77 | 'image_machine_arch_processes', | ||
950 | 78 | name='gaps_api_image_machine_arch_processes', | ||
951 | 79 | ), | ||
952 | 80 | url( | ||
953 | 81 | r'^image/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/' + | ||
954 | 82 | r'(?P<process>.+)/$', | ||
955 | 83 | 'image_machine_arch_processes', | ||
956 | 84 | name='gaps_api_image_machine_arch_processes', | ||
957 | 85 | ), | ||
958 | 86 | url( | ||
959 | 87 | r'^upgrade/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/$', | ||
960 | 88 | 'upgrade_machine_arch_processes', | ||
961 | 89 | name='gaps_api_upgrade_machine_arch_processes', | ||
962 | 90 | ), | ||
963 | 91 | url( | ||
964 | 92 | r'^upgrade/machine/(?P<machine_id>\d+)/arch/(?P<arch>\w+)/process/' + | ||
965 | 93 | r'(?P<process>.+)/$', | ||
966 | 94 | 'upgrade_machine_arch_processes', | ||
967 | 95 | name='gaps_api_upgrade_machine_arch_processes', | ||
968 | 96 | ), | ||
969 | 97 | url( | ||
970 | 98 | r'result/(?P<result_id>\d+)/processes/$', | ||
971 | 99 | 'result_processes', | ||
972 | 100 | name='gaps_api_result_processes', | ||
973 | 101 | ), | ||
983 | 102 | ) | 29 | ) |
984 | 103 | 30 | ||
985 | === modified file 'gaps/util/add.py' | |||
986 | --- gaps/util/add.py 2014-03-06 17:01:11 +0000 | |||
987 | +++ gaps/util/add.py 2014-03-11 17:00:08 +0000 | |||
988 | @@ -7,6 +7,7 @@ | |||
989 | 7 | CoverageData, | 7 | CoverageData, |
990 | 8 | CoverageProject, | 8 | CoverageProject, |
991 | 9 | CoverageStack, | 9 | CoverageStack, |
992 | 10 | StackCoverageObservation | ||
993 | 10 | ) | 11 | ) |
994 | 11 | from gaps.util import extractor, jenkins_pull | 12 | from gaps.util import extractor, jenkins_pull |
995 | 12 | 13 | ||
996 | @@ -79,3 +80,4 @@ | |||
997 | 79 | total_count=coverage_info.total, | 80 | total_count=coverage_info.total, |
998 | 80 | coverage_build=build, | 81 | coverage_build=build, |
999 | 81 | ) | 82 | ) |
1000 | 83 | stack.refresh_coverage_observations() | ||
1001 | 82 | 84 | ||
1002 | === modified file 'gaps/views.py' | |||
1003 | --- gaps/views.py 2014-03-06 22:13:30 +0000 | |||
1004 | +++ gaps/views.py 2014-03-11 17:00:08 +0000 | |||
1005 | @@ -5,6 +5,8 @@ | |||
1006 | 5 | from django.shortcuts import get_object_or_404 | 5 | from django.shortcuts import get_object_or_404 |
1007 | 6 | import gviz_api | 6 | import gviz_api |
1008 | 7 | 7 | ||
1009 | 8 | from common.bread_crumbs import (BreadCrumb, | ||
1010 | 9 | BreadCrumbTrail) | ||
1011 | 8 | from gaps.models import (CoverageProject, | 10 | from gaps.models import (CoverageProject, |
1012 | 9 | CoverageBuild, | 11 | CoverageBuild, |
1013 | 10 | CoverageData, | 12 | CoverageData, |
1014 | @@ -14,146 +16,49 @@ | |||
1015 | 14 | logger = logging.getLogger('qa_dashboard') | 16 | logger = logging.getLogger('qa_dashboard') |
1016 | 15 | 17 | ||
1017 | 16 | 18 | ||
1085 | 17 | def build(request, job_name, build_number): | 19 | @BreadCrumb("Stacks") |
1019 | 18 | jenkins_build = CoverageBuild.objects.get(jenkins_job__name=job_name, | ||
1020 | 19 | number=build_number) | ||
1021 | 20 | runs = JenkinsRun.objects.filter(jenkins_build=jenkins_build) | ||
1022 | 21 | t = loader.get_template('build.html') | ||
1023 | 22 | c = Context({'build': jenkins_build, | ||
1024 | 23 | 'runs': runs, }) | ||
1025 | 24 | return HttpResponse(t.render(c)) | ||
1026 | 25 | |||
1027 | 26 | |||
1028 | 27 | def job_list(request): | ||
1029 | 28 | show_filter = request.GET.get('show') | ||
1030 | 29 | logger.debug("Filter: %s" % show_filter) | ||
1031 | 30 | if show_filter is None or show_filter not in BRANCH_FILTER_TYPES: | ||
1032 | 31 | show_filter = 'all' | ||
1033 | 32 | |||
1034 | 33 | job_list = JenkinsJob.objects.all().order_by('-name') | ||
1035 | 34 | if show_filter == 'all': | ||
1036 | 35 | out_list = job_list | ||
1037 | 36 | else: | ||
1038 | 37 | out_list = [] | ||
1039 | 38 | for j in job_list: | ||
1040 | 39 | if j.name.endswith(show_filter): | ||
1041 | 40 | out_list.append(j) | ||
1042 | 41 | |||
1043 | 42 | # TODO Remove fake data | ||
1044 | 43 | for j in out_list: | ||
1045 | 44 | j.series = 'raring' | ||
1046 | 45 | j.arch = 'amd64, armhf, i386' | ||
1047 | 46 | j.last_run_data = '' | ||
1048 | 47 | j.build_count = 40 | ||
1049 | 48 | j.duration = 1200 | ||
1050 | 49 | j.test_count = 120 | ||
1051 | 50 | j.coverage_rate = 0.55 | ||
1052 | 51 | j.coverage_rate_pct = 55 | ||
1053 | 52 | j.bug_count = 0 | ||
1054 | 53 | |||
1055 | 54 | t = loader.get_template('job_list.html') | ||
1056 | 55 | c = Context({ | ||
1057 | 56 | 'job_list': out_list, | ||
1058 | 57 | }) | ||
1059 | 58 | return HttpResponse(t.render(c)) | ||
1060 | 59 | |||
1061 | 60 | def job(request, job_name): | ||
1062 | 61 | result_filter = request.GET.get('show') | ||
1063 | 62 | logger.debug("Filter: %s" % result_filter) | ||
1064 | 63 | job = JenkinsJob.objects.get(name=job_name) | ||
1065 | 64 | result_list = JenkinsResult.objects.all() | ||
1066 | 65 | if result_filter is None or result_filter not in [ | ||
1067 | 66 | result.name for result in result_list]: | ||
1068 | 67 | logger.debug("we believe the filter isn't in the list") | ||
1069 | 68 | result_filter = 'all' | ||
1070 | 69 | if result_filter == 'all': | ||
1071 | 70 | build_list = CoverageBuild.objects.filter( | ||
1072 | 71 | jenkins_job=job) | ||
1073 | 72 | else: | ||
1074 | 73 | build_list = CoverageBuild.objects.filter( | ||
1075 | 74 | jenkins_job=job, | ||
1076 | 75 | result__name=result_filter) | ||
1077 | 76 | t = loader.get_template('job.html') | ||
1078 | 77 | c = Context({ | ||
1079 | 78 | 'job': job, | ||
1080 | 79 | 'build_list': build_list, | ||
1081 | 80 | 'result_list': result_list, | ||
1082 | 81 | }) | ||
1083 | 82 | return HttpResponse(t.render(c)) | ||
1084 | 83 | |||
1086 | 84 | def stack_list(request): | 20 | def stack_list(request): |
1088 | 85 | stack_list = CoverageStack.objects.all() | 21 | stack_list_ = CoverageStack.objects.all() |
1089 | 86 | t = loader.get_template('stack_list.html') | 22 | t = loader.get_template('stack_list.html') |
1091 | 87 | c = Context({'stack_list': stack_list}) | 23 | c = Context({'stack_list': stack_list_, |
1092 | 24 | 'bread_crumb_trail': BreadCrumbTrail.leading_to( | ||
1093 | 25 | stack_list)}) | ||
1094 | 88 | return HttpResponse(t.render(c)) | 26 | return HttpResponse(t.render(c)) |
1095 | 89 | 27 | ||
1098 | 90 | def stack(request, stack_name): | 28 | @BreadCrumb("Stack", parent=stack_list, needs=['name']) |
1099 | 91 | stack = CoverageStack.objects.get(name=stack_name) | 29 | def stack(request, name): |
1100 | 30 | stack_ = CoverageStack.objects.get(name=name) | ||
1101 | 92 | stack_list = CoverageStack.objects.all() | 31 | stack_list = CoverageStack.objects.all() |
1102 | 93 | project_list = CoverageProject.objects.filter( | 32 | project_list = CoverageProject.objects.filter( |
1127 | 94 | stack__name=stack_name) | 33 | stack__name=name) |
1104 | 95 | coverage_builds = CoverageBuild.objects.filter( | ||
1105 | 96 | project__in=project_list) | ||
1106 | 97 | data = [] | ||
1107 | 98 | for build in coverage_builds: | ||
1108 | 99 | # for every time point, compute and cache stack coverage percentages | ||
1109 | 100 | observation, observation_created = StackCoverageObservation.objects.get_or_create( | ||
1110 | 101 | stack=stack, | ||
1111 | 102 | timestamp=build.ran_at) | ||
1112 | 103 | if observation_created: | ||
1113 | 104 | observation.compute_coverage() | ||
1114 | 105 | data.append({'timestamp': observation.timestamp, | ||
1115 | 106 | 'line coverage': float(observation.line_coverage), | ||
1116 | 107 | 'branch coverage': float(observation.branch_coverage)}) | ||
1117 | 108 | columns_order = ['timestamp', | ||
1118 | 109 | "line coverage", | ||
1119 | 110 | "branch coverage"] | ||
1120 | 111 | description = {"timestamp": ("Date", "timestamp"), | ||
1121 | 112 | "line coverage": ("number", "line coverage"), | ||
1122 | 113 | "branch coverage": ("number", "branch coverage")} | ||
1123 | 114 | data_table = gviz_api.DataTable(description) | ||
1124 | 115 | data_table.LoadData(data) | ||
1125 | 116 | json_data = data_table.ToJSon(columns_order=columns_order, | ||
1126 | 117 | order_by="timestamp") | ||
1128 | 118 | t = loader.get_template('stack_detail.html') | 34 | t = loader.get_template('stack_detail.html') |
1130 | 119 | c = Context({'stack': stack, | 35 | c = Context({'stack': stack_, |
1131 | 120 | 'stack_list': stack_list, | 36 | 'stack_list': stack_list, |
1132 | 121 | 'project_list': project_list, | 37 | 'project_list': project_list, |
1137 | 122 | 'coverage_builds': coverage_builds, | 38 | 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1138 | 123 | 'json_data': json_data}) | 39 | stack, name=stack_.name)}) |
1139 | 124 | return HttpResponse(t.render(c)) | 40 | return HttpResponse(t.render(c)) |
1140 | 125 | 41 | ||
1141 | 42 | @BreadCrumb("Projects") | ||
1142 | 43 | def project_list(request): | ||
1143 | 44 | project_list_ = CoverageProject.objects.all() | ||
1144 | 45 | t = loader.get_template('project_list.html') | ||
1145 | 46 | c = Context({'project_list': project_list_, | ||
1146 | 47 | 'bread_crumb_trail': BreadCrumbTrail.leading_to( | ||
1147 | 48 | project_list)}) | ||
1148 | 49 | return HttpResponse(t.render(c)) | ||
1149 | 50 | |||
1150 | 51 | @BreadCrumb('Project', parent=stack, needs=['name']) | ||
1151 | 126 | def project(request, name): | 52 | def project(request, name): |
1153 | 127 | project = get_object_or_404( | 53 | project_ = get_object_or_404( |
1154 | 128 | CoverageProject, | 54 | CoverageProject, |
1155 | 129 | name=name) | 55 | name=name) |
1156 | 130 | data = [] | ||
1157 | 131 | coverage_datas = CoverageData.objects.filter( | 56 | coverage_datas = CoverageData.objects.filter( |
1174 | 132 | coverage_build__project=project).order_by( | 57 | coverage_build__project=project_).order_by( |
1175 | 133 | '-coverage_build__ran_at') | 58 | '-coverage_build__ran_at')[:10] |
1160 | 134 | for coverage_data in coverage_datas: | ||
1161 | 135 | data.append({'timestamp': coverage_data.coverage_build.ran_at, | ||
1162 | 136 | 'line coverage': float(coverage_data.line_coverage), | ||
1163 | 137 | 'branch coverage': float(coverage_data.branch_coverage)}) | ||
1164 | 138 | columns_order = ['timestamp', | ||
1165 | 139 | "line coverage", | ||
1166 | 140 | "branch coverage"] | ||
1167 | 141 | description = {"timestamp": ("Date", "timestamp"), | ||
1168 | 142 | "line coverage": ("number", "line coverage"), | ||
1169 | 143 | "branch coverage": ("number", "branch coverage")} | ||
1170 | 144 | data_table = gviz_api.DataTable(description) | ||
1171 | 145 | data_table.LoadData(data) | ||
1172 | 146 | json_data = data_table.ToJSon(columns_order=columns_order, | ||
1173 | 147 | order_by="ran_at") | ||
1176 | 148 | t = loader.get_template('project_detail.html') | 59 | t = loader.get_template('project_detail.html') |
1187 | 149 | c = Context({'stack': stack, | 60 | c = Context({'project': project_, |
1188 | 150 | 'project': project, | 61 | 'coverage_datas': coverage_datas, |
1189 | 151 | 'job_list': job_list, | 62 | 'bread_crumb_trail': BreadCrumbTrail.leading_to( |
1190 | 152 | 'json_data': json_data}) | 63 | project, name=project_.name)}) |
1181 | 153 | return HttpResponse(t.render(c)) | ||
1182 | 154 | |||
1183 | 155 | def project_list(request): | ||
1184 | 156 | project_list = CoverageProject.objects.all() | ||
1185 | 157 | t = loader.get_template('project_list.html') | ||
1186 | 158 | c = Context({'project_list': project_list}) | ||
1191 | 159 | return HttpResponse(t.render(c)) | 64 | return HttpResponse(t.render(c)) |
1192 | 160 | 65 | ||
1193 | === modified file 'qa_dashboard/settings.py' | |||
1194 | --- qa_dashboard/settings.py 2014-02-20 19:19:28 +0000 | |||
1195 | +++ qa_dashboard/settings.py 2014-03-11 17:00:08 +0000 | |||
1196 | @@ -24,9 +24,11 @@ | |||
1197 | 24 | 24 | ||
1198 | 25 | 25 | ||
1199 | 26 | ALLOWED_HOSTS = [ | 26 | ALLOWED_HOSTS = [ |
1203 | 27 | 'reports.qa.ubuntu.com', | 27 | # temporary! |
1204 | 28 | 'ci.ubuntu.com', | 28 | '*', |
1205 | 29 | 'rootstock.canonical.com', | 29 | # 'reports.qa.ubuntu.com', |
1206 | 30 | # 'ci.ubuntu.com', | ||
1207 | 31 | # 'rootstock.canonical.com', | ||
1208 | 30 | ] | 32 | ] |
1209 | 31 | 33 | ||
1210 | 32 | ADMINS = ( | 34 | ADMINS = ( |
1211 | 33 | 35 | ||
1212 | === modified file 'qa_dashboard/urls.py' | |||
1213 | --- qa_dashboard/urls.py 2014-02-20 19:19:28 +0000 | |||
1214 | +++ qa_dashboard/urls.py 2014-03-11 17:00:08 +0000 | |||
1215 | @@ -16,13 +16,17 @@ | |||
1216 | 16 | import sys | 16 | import sys |
1217 | 17 | 17 | ||
1218 | 18 | from django.conf.urls import include, patterns, url | 18 | from django.conf.urls import include, patterns, url |
1219 | 19 | from django.views.generic import RedirectView | ||
1220 | 19 | 20 | ||
1221 | 20 | from django.contrib import admin | 21 | from django.contrib import admin |
1222 | 21 | admin.autodiscover() | 22 | admin.autodiscover() |
1223 | 22 | 23 | ||
1224 | 23 | urlpatterns = patterns( | 24 | urlpatterns = patterns( |
1225 | 24 | '', | 25 | '', |
1227 | 25 | url(r'^$', 'common.views.index', name='index'), | 26 | # Restore this when we've merged with qa_dashboard of course :) . |
1228 | 27 | #url(r'^$', 'common.views.index', name='index'), | ||
1229 | 28 | url(r'^$', RedirectView.as_view(url='gaps/stack', permanent=False), | ||
1230 | 29 | name='index'), | ||
1231 | 26 | url(r'^edit/$', 'common.views.edit_profile', name='edit_profile'), | 30 | url(r'^edit/$', 'common.views.edit_profile', name='edit_profile'), |
1232 | 27 | url(r'^admin/', include(admin.site.urls)), | 31 | url(r'^admin/', include(admin.site.urls)), |
1233 | 28 | url(r'^\+oops$', 'common.views.cause_oops', name='cause-oops'), | 32 | url(r'^\+oops$', 'common.views.cause_oops', name='cause-oops'), |
move this out of the html, it's using a lot of the same code
467 +<script type="text/ javascript" > function( ) { lineChart( ) 1100).height( 400); function( d){return d3.time. format( '%Y%m%d' )(new Date(d * 1000));}) d3.format( '%')) '#line- chart svg').datum( data).transitio n().duration( 500).call( chart); windowResize( chart.update) ;
468 + d3.json('{% url "gaps_api_project" project.name %}', function(data) {
469 + nv.addGraph(
470 + var chart = nv.models.
471 + .width(
472 + chart.forceY([0, 1]);
473 + chart.xAxis
474 + .axisLabel('Date')
475 + .tickFormat(
476 +
477 + chart.yAxis
478 + .axisLabel('%')
479 + .tickFormat(
480 + d3.select(
481 +
482 + nv.utils.
483 +
484 + return chart;
485 + });
486 + });
487 +</script>
640 +<script type="text/ javascript" > function( ) { lineChart( ) 900).height( 400); function( d){return d3.time. format( '%Y%m%d' )(new Date(d * 1000));}) d3.format( '%')) '#line- chart svg').datum( data).transitio n().duration( 500).call( chart); windowResize( chart.update) ;
641 + d3.json('{% url 'gaps_api_stack' stack.name %}', function(data) {
642 + nv.addGraph(
643 + var chart = nv.models.
644 + .width(
645 + chart.forceY([0, 1]);
646 + chart.xAxis
647 + .axisLabel('Date')
648 + .tickFormat(
649 + chart.yAxis
650 + .axisLabel('%')
651 + .tickFormat(
652 + d3.select(
653 + nv.utils.
654 + return chart;
655 + });
656 + });
657 +</script>
758 +<script type="text/ javascript" > stack_list' %}', function(data) { function( ) { lineChart( ) 900).height( 400); function( d){return d3.time. format( '%Y%m%d' )(new Date(d * 1000));}) d3.format( '%')) '#line- chart svg').datum( data).transitio n().duration( 500).call( chart); windowResize( chart.update) ;
759 + d3.json('{% url 'gaps_api_
760 + nv.addGraph(
761 + var chart = nv.models.
762 + .width(
763 + chart.forceY([0, 1]);
764 + chart.xAxis
765 + .axisLabel('Date')
766 + .tickFormat(
767 + chart.yAxis
768 + .axisLabel('%')
769 + .tickFormat(
770 + d3.select(
771 + nv.utils.
772 + return chart;
773 + });
774 + });
775 +</script>
Can we move the properties in the model to the api?