Merge lp:~robru/bileto/kill-dashboard-dead into lp:bileto
- kill-dashboard-dead
- Merge into trunk
Proposed by
Robert Bruce Park
Status: | Merged |
---|---|
Approved by: | Robert Bruce Park |
Approved revision: | 240 |
Merged at revision: | 240 |
Proposed branch: | lp:~robru/bileto/kill-dashboard-dead |
Merge into: | lp:bileto |
Diff against target: |
1166 lines (+13/-1094) 8 files modified
tests/test_v1.py (+6/-0) tickets/static/dashboard.css (+0/-176) tickets/static/dashboard.html (+0/-146) tickets/static/dashboard.js (+0/-328) tickets/static/test/index.html (+0/-16) tickets/static/test/jenkins_silo_mock.js (+0/-1) tickets/static/test/test.js (+0/-426) tickets/v1.py (+7/-1) |
To merge this branch: | bzr merge lp:~robru/bileto/kill-dashboard-dead |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Robert Bruce Park (community) | Approve | ||
Review via email: mp+269544@code.launchpad.net |
Commit message
THIS! IS! SPARTAN!
Description of the change
(don't merge or go live with this before monday the 31st)
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
- 238. By Robert Bruce Park
-
Redirect dashboard to homepage.
- 239. By Robert Bruce Park
-
Import redirect.
Revision history for this message
Robert Bruce Park (robru) wrote : | # |
Looks good in staging.
review:
Approve
- 240. By Robert Bruce Park
-
Test.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:240
http://
Executed test runs:
Click here to trigger a rebuild:
http://
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'tests/test_v1.py' |
2 | --- tests/test_v1.py 2015-08-28 04:38:56 +0000 |
3 | +++ tests/test_v1.py 2015-08-28 20:11:22 +0000 |
4 | @@ -32,6 +32,12 @@ |
5 | sesh['teams'] = 'ubuntu-core-dev' |
6 | sesh['nickname'] = 'fritz' |
7 | |
8 | + def test_dashboard_redirect(self): |
9 | + """Ensure dashboard redirects to front page.""" |
10 | + ret = self.app.get('/static/dashboard.html', follow_redirects=False) |
11 | + self.assertIn(b'<a href="/">/</a>.', ret.data) |
12 | + self.assertEqual(ret.status_code, 302) |
13 | + |
14 | def test_models(self): |
15 | """Ensure Request.update works as expected.""" |
16 | req = Request() |
17 | |
18 | === removed file 'tickets/static/dashboard.css' |
19 | --- tickets/static/dashboard.css 2015-08-26 05:21:29 +0000 |
20 | +++ tickets/static/dashboard.css 1970-01-01 00:00:00 +0000 |
21 | @@ -1,176 +0,0 @@ |
22 | -html, body { |
23 | - background-color: white; |
24 | - color: black; |
25 | - margin: 0; |
26 | - padding: 0; |
27 | - text-align: center; |
28 | - font-size: small; |
29 | - font-family: Ubuntu, sans-serif; |
30 | -} |
31 | - |
32 | -a { |
33 | - color: #dd4814; |
34 | - font-weight: bold; |
35 | - text-decoration: none; |
36 | -} |
37 | - |
38 | -a:hover { |
39 | - text-decoration: underline; |
40 | -} |
41 | - |
42 | -.tiny { |
43 | - font-size: x-small; |
44 | -} |
45 | - |
46 | -.nowrap { |
47 | - white-space: nowrap; |
48 | -} |
49 | - |
50 | -#nav { |
51 | - display: block; |
52 | - width: 100%; |
53 | - background-color: #dd4814; |
54 | - color: white; |
55 | - padding: 1em; |
56 | - position: fixed; |
57 | -} |
58 | - |
59 | -#nav a { |
60 | - background-color: #dd4814; |
61 | - color: white; |
62 | - margin: 0 5px; |
63 | -} |
64 | - |
65 | -#nav li { |
66 | - display: inline-block; |
67 | -} |
68 | - |
69 | -#bubble_wrap { |
70 | - padding-top: 8em; |
71 | -} |
72 | - |
73 | -.bubble { |
74 | - text-align: left; |
75 | - width: 400px; |
76 | - display: inline-block; |
77 | - margin: .5em; |
78 | - vertical-align: top; |
79 | -} |
80 | - |
81 | -.buttons { |
82 | - text-align: center; |
83 | - border-top: 1px solid black; |
84 | - border-bottom: 1px solid black; |
85 | -} |
86 | - |
87 | -.buttons a { |
88 | - padding: 3px; |
89 | - margin: 1px; |
90 | - display: inline-block; |
91 | - border-radius: 5px; |
92 | -} |
93 | - |
94 | -.contents { |
95 | - margin: 10px 0 1em 10px; |
96 | -} |
97 | - |
98 | -p, ul, li { |
99 | - list-style: none; |
100 | - margin: 0; |
101 | - padding: 0; |
102 | -} |
103 | - |
104 | -.mp_list_show { |
105 | - padding-left: 1em; |
106 | -} |
107 | - |
108 | -.mp_list_show a { |
109 | - font-weight: normal; |
110 | -} |
111 | - |
112 | -.hover_mp .mp_list_hide a { |
113 | - background-color: #dd4814; |
114 | - color: white; |
115 | -} |
116 | - |
117 | -.hover_mp .mp_list_hide { |
118 | - margin-left: 2em; |
119 | - display: none; |
120 | - position: absolute; |
121 | - background-color: #dd4814; |
122 | - padding: 10px; |
123 | - border-radius: 0 10px 10px 10px; |
124 | - z-index: 200; |
125 | -} |
126 | - |
127 | -.hover_mp:hover .mp_list_hide { |
128 | - display: block; |
129 | -} |
130 | - |
131 | -.details { |
132 | - background-color: white; |
133 | - border-radius: 5px; |
134 | - padding: 0 0 3px 3px; |
135 | - float: right; |
136 | - margin: 10px 10px 1em 0; |
137 | -} |
138 | - |
139 | -.details a { |
140 | - display: block; |
141 | -} |
142 | - |
143 | -.status { |
144 | - font-weight: bold; |
145 | - clear: left; |
146 | - margin: 1em; |
147 | - border-radius: 5px; |
148 | - padding: 3px; |
149 | -} |
150 | - |
151 | -.description { |
152 | - font-size: xx-small; |
153 | -} |
154 | - |
155 | -.comments { |
156 | - font-size: xx-small; |
157 | - color: red; |
158 | -} |
159 | - |
160 | -.comment_author { |
161 | - font-weight: bold; |
162 | -} |
163 | - |
164 | -#svgbox { |
165 | - display: none; |
166 | - position: absolute; |
167 | - background-color: white; |
168 | - border: 1px solid black; |
169 | - border-radius: 10px; |
170 | -} |
171 | - |
172 | -.hover_svg:hover #svgbox { |
173 | - display: block; |
174 | -} |
175 | - |
176 | -#footer { |
177 | - margin-top: 1em; |
178 | -} |
179 | - |
180 | -#footer li { |
181 | - display: inline-block; |
182 | - margin: 1em; |
183 | -} |
184 | - |
185 | -#deprecation { |
186 | - font-weight: bold; |
187 | - background-color: red; |
188 | - color: white; |
189 | - width: 100%; |
190 | - padding: 1em; |
191 | -} |
192 | - |
193 | -#deprecation a { |
194 | - background-color: red; |
195 | - color: white; |
196 | - text-decoration: underline; |
197 | -} |
198 | |
199 | === removed file 'tickets/static/dashboard.html' |
200 | --- tickets/static/dashboard.html 2015-08-26 21:53:17 +0000 |
201 | +++ tickets/static/dashboard.html 1970-01-01 00:00:00 +0000 |
202 | @@ -1,146 +0,0 @@ |
203 | -<!DOCTYPE html> |
204 | -<html ng-app="CITrainWeb" ng-controller="appController"> |
205 | -<head> |
206 | -<meta charset="utf-8" /> |
207 | -<title>CI Train Silo Dashboard</title> |
208 | -<link rel="stylesheet" type="text/css" href="dashboard.css"> |
209 | -<link rel="icon" type="image/gif" href="train.gif"> |
210 | -<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular.min.js"></script> |
211 | -<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular-sanitize.min.js"></script> |
212 | -<script src="dashboard.js" charset="utf-8"></script> |
213 | -</head> |
214 | -<body> |
215 | - |
216 | -<ul id="nav"> |
217 | - <li ng-repeat="series in header.foundSeries"><a href="#?q={{series}}">{{series}}</a></li> |
218 | - <li ng-repeat="(distro, v) in distros"><a href="#?q={{distro}}/">{{distro}}</a></li> |
219 | - <li class="hover_svg"> |
220 | - <span class="tiny"> |
221 | - <a href="#?q="> |
222 | - {{header.activeSilos}} silos in use as of |
223 | - {{header.lastUpdated | date : 'yyyy-MM-dd HH:mm:ss'}} |
224 | - </a> |
225 | - </span> |
226 | - <div id="svgbox"> |
227 | - <svg ng-attr-width="{{(header.uniqueStats + 2) * 36}}" |
228 | - height="200" |
229 | - preserveAspectRatio="xMidYMid meet"> |
230 | - <g ng-repeat="status in header.statusStats"> |
231 | - <circle ng-attr-cx="{{svgPlaceX($index)}}" |
232 | - cy="30" |
233 | - ng-attr-r="{{(status[1] + 2) * 6}}" |
234 | - ng-attr-fill="{{getStatusColor(status[0])}}" |
235 | - opacity=".2"> |
236 | - </circle> |
237 | - <text ng-attr-x="{{svgPlaceX($index)}}" |
238 | - y="35" |
239 | - text-anchor="middle" |
240 | - fill="black"> |
241 | - {{status[1]}} |
242 | - </text> |
243 | - </g> |
244 | - <g ng-repeat="status in header.statusStats"> |
245 | - <a xlink:href="#?q=" ng-xlink-href="#?q={{status[0]}}"> |
246 | - <text ng-attr-x="{{svgPlaceX($index) - 10}}" |
247 | - y="50" |
248 | - fill="{{getStatusColor(status[0])}}" |
249 | - transform="rotate(45 {{svgPlaceX($index)}},50)"> |
250 | - {{status[0]}}... |
251 | - </text> |
252 | - </a> |
253 | - </g> |
254 | - </svg> |
255 | - </div> |
256 | - </li> |
257 | - <li><input type="search" ng-model="q" placeholder="Filter silos..." /></li> |
258 | - <li ng-repeat="link in links"> |
259 | - <a target="_blank" href="{{link[1]}}">{{link[0]}}</a> |
260 | - </li> |
261 | -<div id="deprecation"> <p>This dashboard page is now deprecated. Please use <a |
262 | -href="/">The Requests Page</a> exclusively, and please inform <a |
263 | -href="mailto:robert.park@canonical.com">robru</a> if there are any features |
264 | -missing from the request page that you need.</p> </div> |
265 | -</ul> |
266 | - |
267 | -<div id="bubble_wrap"> |
268 | - <div ng-repeat="siloname in silonames | filter:siloSearchFilter" |
269 | - id="{{siloname}}" |
270 | - class="bubble"> |
271 | - <div class="buttons"> |
272 | - <a href="#?q={{siloname}}" class="button">{{siloname}}</a> |
273 | - <a target="_blank" |
274 | - href="{{j.ppa_url}}/{{siloname}}" |
275 | - class="button">PPA</a> |
276 | - <a target="_blank" |
277 | - href="{{j.domain}}/{{j.root}}{{siloname.replace('/', '-')}}{{j.build}}{{j.suffix}}" |
278 | - class="button">Build</a> |
279 | - <a target="_blank" |
280 | - href="{{j.domain}}/{{j.root}}{{siloname.replace('/', '-')}}{{j.publish}}{{j.suffix}}" |
281 | - class="button">Publish</a> |
282 | - <a target="_blank" |
283 | - href="{{j.domain}}/{{j.root}}{{siloname.replace('/', '-')}}{{j.clean}}{{j.suffix}}" |
284 | - class="button">Clean</a> |
285 | - </div> |
286 | - <div class="details"> |
287 | - <a ng-repeat="lander in silos[siloname].landers" |
288 | - href="#?q={{lander}}">{{lander}}</a> |
289 | - <div class="tiny"> |
290 | - {{silos[siloname].displaySeries}} {{silos[siloname].dual}}<br /> |
291 | - {{silos[siloname].displayDest}}<br /> |
292 | - <a target="_blank" href="/#/?req={{silos[siloname].requestid}}">{{silos[siloname].requestid}}</a><br /> |
293 | - </div> |
294 | - </div> |
295 | - <div class="contents"> |
296 | - <div ng-repeat="package in silos[siloname].sources"> |
297 | - <p> |
298 | - <a target="_blank" href="{{lp_url}}{{siloname.split('/')[0]}}/+source/{{package}}">{{package}}</a> |
299 | - <a href="#?q={{package}}">…</a> |
300 | - </p> |
301 | - </div> |
302 | - <div class="hover_mp" ng-repeat="package in silos[siloname].pkgNames"> |
303 | - <p> |
304 | - <a target="_blank" href="{{lp_url}}{{siloname.split('/')[0]}}/+source/{{package}}">{{package}}</a> |
305 | - <a href="#?q={{package}}">…</a> |
306 | - </p> |
307 | - <ul class="mp_list_{{ q ? 'show' : 'hide' }}"> |
308 | - <li ng-repeat="mp in silos[siloname].mps[package]"> |
309 | - <a target="_blank" href="{{fixMergeURL(mp)}}">{{shortURL(mp)}}</a> |
310 | - </li> |
311 | - </ul> |
312 | - </div> |
313 | - </div> |
314 | - <div class="status" style="color: {{getSiloColor(siloname)}};"> |
315 | - <div class="jenkins_status"> |
316 | - <p ng-repeat="status in silos[siloname].longStatus" |
317 | - ng-bind-html="status"></p> |
318 | - </div> |
319 | - <div class="jenkins_url"> |
320 | - <a target="_blank" href="{{silos[siloname].global.status.url}}"> |
321 | - {{silos[siloname].displayLink}} |
322 | - </a> |
323 | - </div> |
324 | - <div class="tiny"> |
325 | - <span ng-show="silos[siloname] !== undefined"> |
326 | - {{silos[siloname].bileto.qa_signoff}} |
327 | - </span> |
328 | - </div> |
329 | - </div> |
330 | - <div class="description" ng-bind-html="silos[siloname].bileto.description" |
331 | - ng-show="silos[siloname] !== undefined"></div> |
332 | - <div class="comments" ng-show="silos[siloname] !== undefined"> |
333 | - <div ng-repeat="comment in silos[siloname].bileto.comments"> |
334 | - <span class="comment_author">{{comment.author}}: </span> |
335 | - <span ng-bind-html="linkify(comment.text)"></span> |
336 | - </div> |
337 | - </div> |
338 | -</div> |
339 | -</div> |
340 | - |
341 | -<ul id="footer"> |
342 | - <li ng-repeat="link in footerLinks"> |
343 | - <a target="_blank" href="{{link[1]}}">{{link[0]}}</a> |
344 | - </li> |
345 | -</ul> |
346 | - |
347 | -</body> |
348 | -</html> |
349 | |
350 | === removed file 'tickets/static/dashboard.js' |
351 | --- tickets/static/dashboard.js 2015-08-06 02:13:54 +0000 |
352 | +++ tickets/static/dashboard.js 1970-01-01 00:00:00 +0000 |
353 | @@ -1,328 +0,0 @@ |
354 | -var ROOT = '/static/json/'; |
355 | -var BILETO = '/v1/ticket/'; |
356 | -if (window.location.origin == 'file://') { |
357 | - var domain = 'https://requests.ci-train.ubuntu.com'; |
358 | - ROOT = domain + ROOT; |
359 | - BILETO = domain + BILETO; |
360 | -} |
361 | - |
362 | -// Figure out which browser's page visibility API we have. |
363 | -var visibilitychange = null; |
364 | -var hidden = null; |
365 | -['h', 'mozH', 'webkitH', 'msH', 'oH'].some(function(prefix) { |
366 | - hidden = prefix + 'idden'; |
367 | - if (hidden in document) { |
368 | - visibilitychange = prefix.slice(0, -1) + 'visibilitychange'; |
369 | - return true; // Found it, break loop! |
370 | - } |
371 | -}); |
372 | - |
373 | -STATUS_COLORS = { |
374 | - 'caught signal': 'red', |
375 | - 'uncaught exception': 'red', |
376 | - 'build failed': 'red', |
377 | - 'can t': 'red', |
378 | - 'failed to': 'red', |
379 | - 'free': 'purple', |
380 | - 'gave up': 'green', |
381 | - 'landed without': 'green', |
382 | - 'landed cleaning': 'green', |
383 | - 'merge failed': 'red', |
384 | - 'merging': 'green', |
385 | - 'migration all': 'blue', |
386 | - 'packages migrating': 'green', |
387 | - 'publication failed': 'red', |
388 | - 'publication needs': 'blue', |
389 | - 'reconfigure failed': 'red', |
390 | - 'silo ready': 'purple', |
391 | - 'silo dirty': 'olive', |
392 | -}; |
393 | - |
394 | -BILETO_COLORS = { |
395 | - 'qa granted': 'blue', |
396 | - 'publish without qa': 'blue', |
397 | - 'qa failed': 'red', |
398 | -}; |
399 | - |
400 | - |
401 | -function getStatusColor(status) { |
402 | - return STATUS_COLORS[nWords(status, 2).toLowerCase()] || 'black'; |
403 | -}; |
404 | - |
405 | -var app = angular.module('CITrainWeb', ['ngSanitize']); |
406 | - |
407 | -// This bit allows dynamic links inside SVGs. See |
408 | -// http://stackoverflow.com/questions/15895483/angular-ng-href-and-svg-xlink |
409 | -app.directive('ngXlinkHref', function () { |
410 | - return { |
411 | - priority: 99, |
412 | - link: function (scope, element, attrs) { |
413 | - attrs.$observe('ngXlinkHref', function(value) { |
414 | - if (!value) return; |
415 | - attrs.$set('xlink:href', value); |
416 | - }); |
417 | - } |
418 | - } |
419 | -}); |
420 | - |
421 | -function linkify(str) { |
422 | - return str.replace(/(https?:\/\/[^\s)]+)/ig, '<a target="_blank" href="$1">$1</a>') |
423 | - .replace(/>https?:\/\/([^<\/]+\/)?/g, ">"); |
424 | -} |
425 | - |
426 | -function excusify(str) { |
427 | - return str.replace( |
428 | - /^(Migration: )?(\S+)(.*is in the Proposed pocket)/, |
429 | - '<a target="_blank" href="http://people.canonical.com/~ubuntu-archive' + |
430 | - '/proposed-migration/update_excuses.html#$2">$2</a>$3'); |
431 | -} |
432 | - |
433 | -function fixMergeURL(url) { |
434 | - return url.replace('https://api.launchpad.net/devel/', |
435 | - 'https://code.launchpad.net/'); |
436 | -} |
437 | - |
438 | -function shortURL(url) { |
439 | - // Just the branch name from the merge URL |
440 | - return url.replace(/https?:\/\/[^\/]+\//, '') |
441 | - .replace(/^.*~([^\/]+\/){2}([^\/]+).*$/, "$2") |
442 | - .replace(/[_-]/g, ' '); |
443 | -} |
444 | - |
445 | -// Append this to AJAX URLs to prevent browser caching. |
446 | -function noCache() { |
447 | - return 'nocache=' + new Date().getTime(); |
448 | -} |
449 | - |
450 | -// Return first N words of a string. |
451 | -function nWords(phrase, n, regex) { |
452 | - return phrase.split(regex || /\W+/).splice(0, n).join(' '); |
453 | -} |
454 | - |
455 | -function searchFactory(getQuery, silos) { |
456 | - // If this function returns true, it means 'display this search result' |
457 | - // returning false hides that result from the list. |
458 | - return function(siloname) { |
459 | - var query = getQuery(); |
460 | - var regex = new RegExp(query, 'i'); |
461 | - |
462 | - if (siloname.match(regex)) { |
463 | - // Always display silos when referenced by name. This is necessary |
464 | - // because empty silos don't have the search strings, and therefore |
465 | - // empty silos don't show up at their own permalinks. |
466 | - return true; |
467 | - } else if (query) { |
468 | - var silo = silos[siloname]; |
469 | - if (silo) { |
470 | - // If a silo exists, show it only when it matches the search |
471 | - return !!silo.searchString.match(regex); |
472 | - } else if (query.match(/^free$/i)) { |
473 | - // If the search is for 'free' silos, show only free ones. |
474 | - return true; |
475 | - } else { |
476 | - // Hide empty silos when the search term isn't 'free' |
477 | - return false; |
478 | - } |
479 | - } else { |
480 | - // Show all silos when there is no search term. |
481 | - return true; |
482 | - } |
483 | - } |
484 | -} |
485 | - |
486 | -function setHeaderStatus(header, silos) { |
487 | - var silonames = Object.keys(silos); |
488 | - var stats = { }; |
489 | - header.activeSilos = silonames.length; |
490 | - header.lastUpdated = new Date(); |
491 | - header.foundSeries = {}; |
492 | - silonames.forEach(function(siloname) { |
493 | - var status = silos[siloname].shortStatus; |
494 | - var count = stats[status]; |
495 | - stats[status] = (count || 0) + 1; |
496 | - var series = silos[siloname].displaySeries; |
497 | - header.foundSeries[series] = series; |
498 | - }); |
499 | - header.uniqueStats = Object.keys(stats).length; |
500 | - var sortable = []; |
501 | - for (var stat in stats) { |
502 | - sortable.push([stat, stats[stat]]); |
503 | - } |
504 | - sortable.sort(function(a, b) { return b[1] - a[1]; }); |
505 | - header.statusStats = sortable; |
506 | -} |
507 | - |
508 | -function blankSiloStatus(silos) { |
509 | - return function(name) { |
510 | - return function() { |
511 | - delete silos[name]; |
512 | - } |
513 | - } |
514 | -} |
515 | - |
516 | -function setSiloStatus($http, silos, j) { |
517 | - return function(data) { |
518 | - var data = data || {}; |
519 | - var siloname = (data.siloname || ''); |
520 | - var global = data.global || {}; |
521 | - var series = global.series || ''; |
522 | - var dest = global.dest || ''; |
523 | - var mps = data.mps || {}; |
524 | - var requestid = data.requestid || 0; |
525 | - var status = global.status || {}; |
526 | - var message = status.message || ''; |
527 | - var url = status.url || ''; |
528 | - var ppa = global.ppa || ''; |
529 | - |
530 | - // Poll Bileto as well. |
531 | - data.bileto = (silos[siloname] || {}).bileto || {}; |
532 | - $http.get(BILETO + requestid).success(setBiletoStatus(data)); |
533 | - |
534 | - // Pre-compute some useful values for display in the template. |
535 | - data.displaySeries = series.replace(/^.*\//, ''); |
536 | - data.displayDest = dest.split('/').slice(-1)[0]; |
537 | - data.displayLink = shortURL(global.status.url); |
538 | - data.pkgNames = Object.keys(mps).sort(); |
539 | - data.shortStatus = nWords(message, 3, /\s/); |
540 | - data.longStatus = message.split('. ').map(linkify).map(excusify); |
541 | - data.statusColor = getStatusColor(data.shortStatus); |
542 | - |
543 | - // Discover what jenkins instance we are monitoring. |
544 | - j.ppa_url = ppa.split('/').slice(0, 6).join('/') |
545 | - .replace('api.', '').replace('/devel', ''); |
546 | - if (url.substring(0, 4) == 'http') { |
547 | - j.domain = url.split('/').slice(0, 3).join('/'); |
548 | - } |
549 | - |
550 | - // Build a string containing most relevant info to easily search against |
551 | - data.searchString = [ siloname, data.displaySeries, message ].join(' '); |
552 | - function searchAppender(string) { data.searchString += ' ' + string; } |
553 | - data.landers.forEach(searchAppender); |
554 | - data.pkgNames.forEach(searchAppender); |
555 | - data.sources.forEach(searchAppender); |
556 | - |
557 | - // Save the silo state for displaying in the template. |
558 | - silos[siloname] = data; |
559 | - } |
560 | -} |
561 | - |
562 | -function setBiletoStatus(silo) { |
563 | - return function(data) { |
564 | - data.requests.forEach(function(req) { |
565 | - req.color = BILETO_COLORS[(req.qa_signoff || '').toLowerCase()] || ''; |
566 | - silo.bileto = req; |
567 | - }); |
568 | - } |
569 | -} |
570 | - |
571 | -function svgPlaceX(i) { |
572 | - return (i + 1) * 30; |
573 | -} |
574 | - |
575 | -function appController($scope, $location, $http) { |
576 | - $scope.silos = {}; |
577 | - $scope.silonames = []; |
578 | - $scope.distros = {}; |
579 | - $scope.statusStats = {}; |
580 | - $scope.header = { uniqueStats: 0 }; |
581 | - $scope.linkify = linkify; |
582 | - |
583 | - $scope.lp_url = 'https://launchpad.net/'; |
584 | - |
585 | - // Jenkins URL components |
586 | - $scope.j = { |
587 | - root: '/job/', |
588 | - recon: '-0-reconfigure', |
589 | - build: '-1-build', |
590 | - publish: '-2-publish', |
591 | - clean: '-3-merge-clean', |
592 | - suffix: '/build?delay=0sec' |
593 | - }; |
594 | - |
595 | - // Handy links |
596 | - $scope.links = [ |
597 | - ['Team', 'https://wiki.ubuntu.com/citrain/LandingTeam'], |
598 | - ['Excuses', 'http://people.canonical.com/~ubuntu-archive/proposed-migration/update_excuses.html'], |
599 | - ['SRU', 'http://people.canonical.com/~ubuntu-archive/pending-sru.html'], |
600 | - ['Uploads', 'http://people.canonical.com/~ubuntu-archive/pending-sru.html#upload-queues'], |
601 | - ['RAW', '/static/json/index.txt'], |
602 | - ['Bileto', '/'], |
603 | - ['Jenkins', 'https://ci-train.ubuntu.com/'], |
604 | - ]; |
605 | - |
606 | - $scope.footerLinks = [ |
607 | - ['Get the Source', 'http://bazaar.launchpad.net/+branch/bileto/changes'], |
608 | - ['Run Unit Tests', 'test/index.html'], |
609 | - ]; |
610 | - |
611 | - $scope.getSiloColor = function(siloname) { |
612 | - var req = $scope.silos[siloname] || {}; |
613 | - if (!req.requestid || !req.shortStatus) { |
614 | - return 'black'; |
615 | - } |
616 | - var siloColor = req.statusColor || 'black'; |
617 | - var bileto = req.bileto || {}; |
618 | - var qaColor = bileto.color || 'black'; |
619 | - if (req.shortStatus.match(/packages built/i)) { |
620 | - return qaColor; |
621 | - } else { |
622 | - return siloColor; |
623 | - } |
624 | - }; |
625 | - |
626 | - function getQuery() { |
627 | - return $scope.q || ''; |
628 | - } |
629 | - |
630 | - function URLParams() { |
631 | - return $location.search(); |
632 | - } |
633 | - |
634 | - function URLWatcher(queryParams) { |
635 | - $scope.q = queryParams.q; |
636 | - } |
637 | - |
638 | - function URLSetter(newQ) { |
639 | - $location.search('q', newQ); |
640 | - } |
641 | - |
642 | - $scope.$watch(URLParams, URLWatcher); |
643 | - $scope.$watch('q', URLSetter); |
644 | - |
645 | - $scope.$watchCollection('silos', function() { |
646 | - setHeaderStatus($scope.header, $scope.silos); |
647 | - }); |
648 | - |
649 | - function fetchSilo(name) { |
650 | - $scope.distros[name.split(/\//)[0]] = true; |
651 | - $http.get(ROOT + name + '?' + noCache()) |
652 | - .success(setSiloStatus($http, $scope.silos, $scope.j)) |
653 | - .error(blankSiloStatus($scope.silos)(name)); |
654 | - } |
655 | - |
656 | - function fetchAllSilos() { |
657 | - // Abort refresh if nobody is looking. |
658 | - if (document[hidden]) return; |
659 | - $http.get(ROOT + 'index.txt' + '?' + noCache()) |
660 | - .success(function(data) { |
661 | - $scope.silonames = data.trim().split(/\n/); |
662 | - $scope.silonames.forEach(fetchSilo); |
663 | - }) |
664 | - .error(function(data, status, headers, config) { |
665 | - alert('Failed to fetch assigned silo index: ' + status); |
666 | - }); |
667 | - } |
668 | - |
669 | - fetchAllSilos(); |
670 | - setInterval(fetchAllSilos, 2 * 60 * 1000); |
671 | - if (visibilitychange) { |
672 | - document.addEventListener(visibilitychange, fetchAllSilos); |
673 | - } |
674 | - |
675 | - // Expose some functions to the scope for use in the template. |
676 | - $scope.fixMergeURL = fixMergeURL; |
677 | - $scope.getStatusColor = getStatusColor; |
678 | - $scope.shortURL = shortURL; |
679 | - $scope.siloSearchFilter = searchFactory(getQuery, $scope.silos); |
680 | - $scope.svgPlaceX = svgPlaceX; |
681 | -} |
682 | |
683 | === removed directory 'tickets/static/test' |
684 | === removed file 'tickets/static/test/index.html' |
685 | --- tickets/static/test/index.html 2015-06-18 20:45:11 +0000 |
686 | +++ tickets/static/test/index.html 1970-01-01 00:00:00 +0000 |
687 | @@ -1,16 +0,0 @@ |
688 | -<!DOCTYPE html> |
689 | -<html> |
690 | -<head> |
691 | -<meta charset="utf-8" /> |
692 | -<title>Unit Tests for CI Train Silo Dashboard</title> |
693 | -<link rel="shortcut icon" type="image/png" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine_favicon.png"> |
694 | -<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine.css"> |
695 | - |
696 | -<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine.js"></script> |
697 | -<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine-html.js"></script> |
698 | -<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/boot.js"></script> |
699 | -<script src="jenkins_silo_mock.js" charset="utf-8"></script> |
700 | -<script src="../dashboard.js" charset="utf-8"></script> |
701 | -<script src="test.js" charset="utf-8"></script> |
702 | -</head> |
703 | -</html> |
704 | |
705 | === removed file 'tickets/static/test/jenkins_silo_mock.js' |
706 | --- tickets/static/test/jenkins_silo_mock.js 2015-06-19 17:12:06 +0000 |
707 | +++ tickets/static/test/jenkins_silo_mock.js 1970-01-01 00:00:00 +0000 |
708 | @@ -1,1 +0,0 @@ |
709 | -var JENKINS_SILO_MOCK = {"siloname": "landing-008", "global": {"dest": "https://api.launchpad.net/devel/ubuntu/+archive/primary", "series": "https://api.launchpad.net/devel/ubuntu/utopic", "step": 1, "status": {"url": "https://ci-train.ubuntu.com/some/status/stuff", "message": "Packages built", "ping": true, "state": 3}, "ppa": "https://api.launchpad.net/devel/~ci-train-ppa-service/+archive/ubuntu/landing-008"}, "sources": [], "landers": ["tvoss", "slangasek"], "requestid": "1403854490728", "mps": {"indicator-datetime": ["https://api.launchpad.net/devel/~charlesk/indicator-datetime/make-gcc-version-explicit/+merge/224467"], "mediascanner2": ["https://api.launchpad.net/devel/~jpakkane/mediascanner2/gcc49/+merge/224648"], "unity-api": ["https://api.launchpad.net/devel/~unity-team/unity-api/require-g++-4.9/+merge/227299"], "process-cpp": ["https://api.launchpad.net/devel/~vorlon/process-cpp/explicit-gcc-version/+merge/226594"], "pay-service": ["https://api.launchpad.net/devel/~thomas-voss/pay-service/explicit-gcc-version/+merge/224763"], "dbus-cpp": ["https://api.launchpad.net/devel/~thomas-voss/dbus-cpp/explicit-gcc-version/+merge/224756"], "indicator-transfer": ["https://api.launchpad.net/devel/~charlesk/indicator-transfer/make-gcc-version-explicit/+merge/224473"], "unity-scopes-api": ["https://api.launchpad.net/devel/~unity-team/unity-scopes-api/require-g++-4.9-take-2/+merge/227391"], "trust-store": ["https://api.launchpad.net/devel/~thomas-voss/trust-store/explicit-gcc-version/+merge/224769"], "indicator-location": ["https://api.launchpad.net/devel/~charlesk/indicator-location/make-gcc-version-explicit/+merge/224474"], "platform-api": ["https://api.launchpad.net/devel/~vorlon/platform-api/explicit-gcc-version/+merge/226566"], "location-service": ["https://api.launchpad.net/devel/~thomas-voss/location-service/explicit-gcc-version/+merge/224776"], "unity-mir": ["https://api.launchpad.net/devel/~thomas-voss/unity-mir/explicit-gcc-version/+merge/224771"], "media-hub": ["https://api.launchpad.net/devel/~vorlon/media-hub/explicit-gcc-version/+merge/226567"], "net-cpp": ["https://api.launchpad.net/devel/~thomas-voss/net-cpp/explicit-gcc-version/+merge/224760"], "unity-scope-mediascanner": ["https://api.launchpad.net/devel/~jpakkane/unity-scope-mediascanner/gcc49/+merge/224650"]}}; |
710 | |
711 | === removed file 'tickets/static/test/test.js' |
712 | --- tickets/static/test/test.js 2015-08-04 06:45:24 +0000 |
713 | +++ tickets/static/test/test.js 1970-01-01 00:00:00 +0000 |
714 | @@ -1,426 +0,0 @@ |
715 | -if (visibilitychange) { |
716 | - describe('The page visibility API', function() { |
717 | - it('should be correctly detected.', function() { |
718 | - expect(hidden in document).toBe(true); |
719 | - }); |
720 | - }); |
721 | -} |
722 | - |
723 | -describe('The getStatusColor functon', function() { |
724 | - it('should know what statuses are red.', function() { |
725 | - expect(getStatusColor('Build failed: incorrect planetary alignment.')) |
726 | - .toBe('red'); |
727 | - expect(getStatusColor("Can't build: I don't like you.")) |
728 | - .toBe('red'); |
729 | - }); |
730 | - it('should know what statuses are green.', function() { |
731 | - expect(getStatusColor('Gave up on life.')) |
732 | - .toBe('green'); |
733 | - expect(getStatusColor('Landed: Cleaning out your bank account.')) |
734 | - .toBe('green'); |
735 | - }); |
736 | - it('should know what statuses are blue.', function() { |
737 | - expect(getStatusColor('Migration: All birds have flown home.')) |
738 | - .toBe('blue'); |
739 | - expect(getStatusColor('Publication needs: a swift kick in the pants.')) |
740 | - .toBe('blue'); |
741 | - }); |
742 | - it('should know what statuses are purple.', function() { |
743 | - expect(getStatusColor('Silo ready to be filled with grain.')) |
744 | - .toBe('purple'); |
745 | - expect(getStatusColor('Free')) |
746 | - .toBe('purple'); |
747 | - }); |
748 | - it('should be case insensitive.', function() { |
749 | - expect(getStatusColor('BUILD fAiled')).toBe('red'); |
750 | - expect(getStatusColor('miGRATion all')).toBe('blue'); |
751 | - }); |
752 | -}); |
753 | - |
754 | -describe('The linkify function', function() { |
755 | - it('should linkify URLs.', function() { |
756 | - expect(linkify('http://example.com')) |
757 | - .toBe('<a target="_blank" href="http://example.com">example.com</a>'); |
758 | - expect(linkify('http://example.com/foo')) |
759 | - .toBe('<a target="_blank" href="http://example.com/foo">foo</a>'); |
760 | - }); |
761 | - it('should handle multiple URLs.', function() { |
762 | - expect(linkify('Visit http://example.com today, but avoid http://example.com/badness at all costs.')) |
763 | - .toBe('Visit <a target="_blank" href="http://example.com">example.com</a> today, but avoid ' + |
764 | - '<a target="_blank" href="http://example.com/badness">badness</a> at all costs.'); |
765 | - }); |
766 | - it('should not touch ordinary strings.', function() { |
767 | - expect(linkify('No URL here!')).toBe('No URL here!'); |
768 | - }); |
769 | - it('should not linkify parenthesis.', function() { |
770 | - expect(linkify('(http://example.com)')) |
771 | - .toBe('(<a target="_blank" href="http://example.com">example.com</a>)'); |
772 | - }); |
773 | -}); |
774 | - |
775 | -describe('The excusify function', function() { |
776 | - it('should link to excuses directly.', function() { |
777 | - expect(excusify('')).toBe(''); |
778 | - expect(excusify('whargarble is in the Proposed pocket')) |
779 | - .toBe('<a target="_blank" href="http://people.canonical.com/~ubuntu-archive/' |
780 | - + 'proposed-migration/update_excuses.html#whargarble">whargarble</a>' |
781 | - + ' is in the Proposed pocket'); |
782 | - }); |
783 | -}); |
784 | - |
785 | -describe('The fixMergeURL function', function() { |
786 | - it('should link to the right place.', function() { |
787 | - expect(fixMergeURL('https://api.launchpad.net/devel/foobar')) |
788 | - .toBe('https://code.launchpad.net/foobar'); |
789 | - }); |
790 | - it('should not harm other URLs.', function() { |
791 | - expect(fixMergeURL('http://example.com')) |
792 | - .toBe('http://example.com'); |
793 | - }); |
794 | -}); |
795 | - |
796 | -describe('The shortURL function', function() { |
797 | - it('should drop the protocol and domain.', function() { |
798 | - expect(shortURL('http://example.com/foo')).toBe('foo'); |
799 | - expect(shortURL('http://example.com/bar/baz')).toBe('bar/baz'); |
800 | - }); |
801 | - it('should extract branch names from merges.', function() { |
802 | - expect(shortURL('https://code.launchpad.net/~vorlon/platform-api/explicit-gcc-version/+merge/226566')) |
803 | - .toBe('explicit gcc version'); |
804 | - expect(shortURL('https://code.launchpad.net/~compiz-team/compiz/compiz-0.9.11.2-version-bump/+merge/226511')) |
805 | - .toBe('compiz 0.9.11.2 version bump'); |
806 | - }); |
807 | - it('should convert underscores to spaces.', function() { |
808 | - expect(shortURL('well_hello_there-handsome')).toBe('well hello there handsome'); |
809 | - }); |
810 | -}); |
811 | - |
812 | -describe('The noCache function', function() { |
813 | - it('should return some numbers.', function() { |
814 | - expect(noCache()).toMatch(/^nocache=\d+$/); |
815 | - }); |
816 | -}); |
817 | - |
818 | -describe('The nWords function', function() { |
819 | - it('should ignore punctuation by default.', function() { |
820 | - expect(nWords('Ready? Set? Go!', 1)).toBe('Ready'); |
821 | - }); |
822 | - it('should let you override its regex.', function() { |
823 | - expect(nWords('Ready? Set? Go!', 1, /\s/)).toBe('Ready?'); |
824 | - }); |
825 | - it('should return the right number of words.', function() { |
826 | - var example = 'One two three four'; |
827 | - expect(nWords(example, 0)).toBe(''); |
828 | - expect(nWords(example, 1)).toBe('One'); |
829 | - expect(nWords(example, 2)).toBe('One two'); |
830 | - expect(nWords(example, 3)).toBe('One two three'); |
831 | - expect(nWords(example, 4)).toBe('One two three four'); |
832 | - expect(nWords(example, 5)).toBe('One two three four'); |
833 | - }); |
834 | -}); |
835 | - |
836 | -describe('The searchFactory function', function() { |
837 | - var silos = { |
838 | - 'landing-015': { |
839 | - searchString: 'foo bar baz' |
840 | - }, |
841 | - 'landing-010': { |
842 | - searchString: 'apple banana orange' |
843 | - }, |
844 | - }; |
845 | - function getQuery(q) { |
846 | - return function() { |
847 | - return q; |
848 | - } |
849 | - } |
850 | - it('should match only silo 1 when we search for silo 1.', function() { |
851 | - var search = searchFactory(getQuery('landing-001'), silos); |
852 | - expect(search('landing-001')).toBe(true); |
853 | - expect(search('landing-002')).toBe(false); |
854 | - var search = searchFactory(getQuery('001'), silos); |
855 | - expect(search('landing-001')).toBe(true); |
856 | - expect(search('landing-020')).toBe(false); |
857 | - }); |
858 | - it('should match the silos that have the stuff we are looking for.', function() { |
859 | - var search = searchFactory(getQuery('foo'), silos); |
860 | - expect(search('landing-003')).toBe(false); // false because it's empty |
861 | - expect(search('landing-010')).toBe(false); // false because it doesn't match |
862 | - expect(search('landing-015')).toBe(true); |
863 | - var search = searchFactory(getQuery('grill'), silos); |
864 | - expect(search('landing-003')).toBe(false); // false because it's empty |
865 | - expect(search('landing-010')).toBe(false); // false because it doesn't match |
866 | - expect(search('landing-015')).toBe(false); |
867 | - }); |
868 | - it('should be able to find free silos.', function() { |
869 | - var search = searchFactory(getQuery('Free'), silos); |
870 | - expect(search('landing-004')).toBe(true); |
871 | - expect(search('landing-015')).toBe(false); |
872 | - var search = searchFactory(getQuery('free'), silos); |
873 | - expect(search('landing-004')).toBe(true); |
874 | - expect(search('landing-015')).toBe(false); |
875 | - }); |
876 | - it('should show all silos when there is no search term.', function() { |
877 | - var search = searchFactory(getQuery(''), silos); |
878 | - expect(search('landing-001')).toBe(true); // true even though empty |
879 | - expect(search('landing-010')).toBe(true); // not empty, still true |
880 | - }); |
881 | - it('should allow regex search terms.', function() { |
882 | - var search = searchFactory(getQuery('foo|apple'), silos); |
883 | - expect(search('landing-010')).toBe(true); |
884 | - expect(search('landing-015')).toBe(true); |
885 | - expect(search('landing-011')).toBe(false); |
886 | - }); |
887 | -}); |
888 | - |
889 | -describe('The setHeaderStatus function', function() { |
890 | - var silos = { |
891 | - 'landing-001': { shortStatus: 'Hello' }, |
892 | - 'landing-003': { shortStatus: 'Goodbye' }, |
893 | - 'landing-005': { shortStatus: 'Error. Error.' }, |
894 | - 'landing-007': { shortStatus: 'Error. Error.' }, |
895 | - }; |
896 | - it('should calculate header stats accurately.', function() { |
897 | - var header = {}; |
898 | - setHeaderStatus(header, silos); |
899 | - expect(header.activeSilos).toBe(4); |
900 | - expect(header.lastUpdated instanceof Date).toBe(true); |
901 | - expect(header.statusStats).toEqual( |
902 | - [['Error. Error.', 2], ['Hello', 1], ['Goodbye', 1]]); |
903 | - }); |
904 | -}); |
905 | - |
906 | -describe('The blankSiloStatus function', function() { |
907 | - var silos = { |
908 | - 'landing-001': {}, |
909 | - 'landing-007': {}, |
910 | - 'landing-020': {}, |
911 | - }; |
912 | - var spreadsheet = silos; |
913 | - it('should delete stale statuses.', function() { |
914 | - expect(Object.keys(silos).length).toBe(3); |
915 | - blankSiloStatus(silos, spreadsheet)('landing-002')(); |
916 | - expect(Object.keys(silos).length).toBe(3); |
917 | - blankSiloStatus(silos, spreadsheet)('landing-001')(); |
918 | - expect(Object.keys(silos).length).toBe(2); |
919 | - blankSiloStatus(silos, spreadsheet)('landing-007')(); |
920 | - expect(Object.keys(silos).length).toBe(1); |
921 | - blankSiloStatus(silos, spreadsheet)('landing-020')(); |
922 | - expect(Object.keys(silos).length).toBe(0); |
923 | - blankSiloStatus(silos, spreadsheet)('landing-020')(); |
924 | - expect(Object.keys(silos).length).toBe(0); |
925 | - }); |
926 | -}); |
927 | - |
928 | -describe('The setSiloStatus function', function() { |
929 | - var httpMock = { |
930 | - 'get': function () { |
931 | - return { |
932 | - success: function() { return this }, |
933 | - error: function() { return this } |
934 | - } |
935 | - } |
936 | - }; |
937 | - var silos = {}; |
938 | - var j = {}; |
939 | - it('should precompute a bunch of stuff.', function() { |
940 | - spyOn(httpMock, 'get').and.callThrough(); |
941 | - setSiloStatus(httpMock, silos, j)(JENKINS_SILO_MOCK); |
942 | - var expected = { |
943 | - 'siloname': 'landing-008', |
944 | - 'global': { |
945 | - 'dest': 'https://api.launchpad.net/devel/ubuntu/+archive/primary', |
946 | - 'series': 'https://api.launchpad.net/devel/ubuntu/utopic', |
947 | - 'step': 1, |
948 | - 'status': { |
949 | - 'url': 'https://ci-train.ubuntu.com/some/status/stuff', |
950 | - 'message': 'Packages built', |
951 | - 'ping': true, |
952 | - 'state': 3 |
953 | - }, |
954 | - 'ppa': 'https://api.launchpad.net/devel/~ci-train-ppa-service/+archive/ubuntu/landing-008' |
955 | - }, |
956 | - 'sources': [], |
957 | - 'landers': [ |
958 | - 'tvoss', |
959 | - 'slangasek' |
960 | - ], |
961 | - 'requestid': '1403854490728', |
962 | - 'mps': { |
963 | - 'indicator-datetime': [ |
964 | - 'https://api.launchpad.net/devel/~charlesk/indicator-datetime/make-gcc-version-explicit/+merge/224467' |
965 | - ], |
966 | - 'mediascanner2': [ |
967 | - 'https://api.launchpad.net/devel/~jpakkane/mediascanner2/gcc49/+merge/224648' |
968 | - ], |
969 | - 'unity-api': [ |
970 | - 'https://api.launchpad.net/devel/~unity-team/unity-api/require-g++-4.9/+merge/227299' |
971 | - ], |
972 | - 'process-cpp': [ |
973 | - 'https://api.launchpad.net/devel/~vorlon/process-cpp/explicit-gcc-version/+merge/226594' |
974 | - ], |
975 | - 'pay-service': [ |
976 | - 'https://api.launchpad.net/devel/~thomas-voss/pay-service/explicit-gcc-version/+merge/224763' |
977 | - ], |
978 | - 'dbus-cpp': [ |
979 | - 'https://api.launchpad.net/devel/~thomas-voss/dbus-cpp/explicit-gcc-version/+merge/224756' |
980 | - ], |
981 | - 'indicator-transfer': [ |
982 | - 'https://api.launchpad.net/devel/~charlesk/indicator-transfer/make-gcc-version-explicit/+merge/224473' |
983 | - ], |
984 | - 'unity-scopes-api': [ |
985 | - 'https://api.launchpad.net/devel/~unity-team/unity-scopes-api/require-g++-4.9-take-2/+merge/227391' |
986 | - ], |
987 | - 'trust-store': [ |
988 | - 'https://api.launchpad.net/devel/~thomas-voss/trust-store/explicit-gcc-version/+merge/224769' |
989 | - ], |
990 | - 'indicator-location': [ |
991 | - 'https://api.launchpad.net/devel/~charlesk/indicator-location/make-gcc-version-explicit/+merge/224474' |
992 | - ], |
993 | - 'platform-api': [ |
994 | - 'https://api.launchpad.net/devel/~vorlon/platform-api/explicit-gcc-version/+merge/226566' |
995 | - ], |
996 | - 'location-service': [ |
997 | - 'https://api.launchpad.net/devel/~thomas-voss/location-service/explicit-gcc-version/+merge/224776' |
998 | - ], |
999 | - 'unity-mir': [ |
1000 | - 'https://api.launchpad.net/devel/~thomas-voss/unity-mir/explicit-gcc-version/+merge/224771' |
1001 | - ], |
1002 | - 'media-hub': [ |
1003 | - 'https://api.launchpad.net/devel/~vorlon/media-hub/explicit-gcc-version/+merge/226567' |
1004 | - ], |
1005 | - 'net-cpp': [ |
1006 | - 'https://api.launchpad.net/devel/~thomas-voss/net-cpp/explicit-gcc-version/+merge/224760' |
1007 | - ], |
1008 | - 'unity-scope-mediascanner': [ |
1009 | - 'https://api.launchpad.net/devel/~jpakkane/unity-scope-mediascanner/gcc49/+merge/224650' |
1010 | - ] |
1011 | - }, |
1012 | - 'displaySeries': 'utopic', |
1013 | - 'displayLink': 'some/status/stuff', |
1014 | - 'pkgNames': [ |
1015 | - 'dbus-cpp', |
1016 | - 'indicator-datetime', |
1017 | - 'indicator-location', |
1018 | - 'indicator-transfer', |
1019 | - 'location-service', |
1020 | - 'media-hub', |
1021 | - 'mediascanner2', |
1022 | - 'net-cpp', |
1023 | - 'pay-service', |
1024 | - 'platform-api', |
1025 | - 'process-cpp', |
1026 | - 'trust-store', |
1027 | - 'unity-api', |
1028 | - 'unity-mir', |
1029 | - 'unity-scope-mediascanner', |
1030 | - 'unity-scopes-api' |
1031 | - ], |
1032 | - 'shortStatus': 'Packages built', |
1033 | - 'longStatus': ['Packages built'], |
1034 | - 'statusColor': 'black', |
1035 | - 'searchString': 'landing-008 utopic Packages built tvoss slangasek dbus-cpp indicator-datetime indicator-location indicator-transfer location-service media-hub mediascanner2 net-cpp pay-service platform-api process-cpp trust-store unity-api unity-mir unity-scope-mediascanner unity-scopes-api' |
1036 | - }; |
1037 | - expect(j.ppa_url).toEqual('https://launchpad.net/~ci-train-ppa-service/+archive'); |
1038 | - expect(j.domain).toEqual('https://ci-train.ubuntu.com'); |
1039 | - for (attr in expected) { |
1040 | - expect(silos['landing-008'][attr]).toEqual(expected[attr]); |
1041 | - } |
1042 | - expect(httpMock.get).toHaveBeenCalled(); |
1043 | - var getCalls = httpMock.get.calls.all(); |
1044 | - expect(getCalls.length).toBe(1); |
1045 | - expect(getCalls[0].args).toEqual(['/v1/ticket/1403854490728']); |
1046 | - }); |
1047 | -}); |
1048 | - |
1049 | -describe('The svgPlaceX function', function() { |
1050 | - it('should do some math.', function() { |
1051 | - expect(svgPlaceX(0)).toBe(30); |
1052 | - expect(svgPlaceX(1)).toBe(60); |
1053 | - expect(svgPlaceX(2)).toBe(90); |
1054 | - expect(svgPlaceX(3)).toBe(120); |
1055 | - expect(svgPlaceX(4)).toBe(150); |
1056 | - expect(svgPlaceX(5)).toBe(180); |
1057 | - expect(svgPlaceX(6)).toBe(210); |
1058 | - expect(svgPlaceX(7)).toBe(240); |
1059 | - expect(svgPlaceX(8)).toBe(270); |
1060 | - expect(svgPlaceX(9)).toBe(300); |
1061 | - }); |
1062 | -}); |
1063 | - |
1064 | -describe('The appController function', function() { |
1065 | - var scopeMock = { |
1066 | - '$watch': function() {}, |
1067 | - '$watchCollection': function () {}, |
1068 | - }; |
1069 | - var locationMock = {}; |
1070 | - var httpMock = { |
1071 | - 'get': function () { |
1072 | - return { |
1073 | - success: function() { return this }, |
1074 | - error: function() { return this } |
1075 | - } |
1076 | - } |
1077 | - }; |
1078 | - httpMock.jsonp = httpMock.get; |
1079 | - it('should initialize some data structures.', function() { |
1080 | - appController(scopeMock, locationMock, httpMock); |
1081 | - expect(scopeMock.silos).toBeDefined(); |
1082 | - expect(scopeMock.statusStats).toBeDefined(); |
1083 | - expect(scopeMock.header.uniqueStats).toBe(0); |
1084 | - expect(scopeMock.silonames).toEqual([]); |
1085 | - }); |
1086 | - it('should know about jenkins.', function() { |
1087 | - appController(scopeMock, locationMock, httpMock); |
1088 | - expect(scopeMock.j.root).toBe('/job/'); |
1089 | - expect(scopeMock.j.recon).toBe('-0-reconfigure'); |
1090 | - expect(scopeMock.j.build).toBe('-1-build'); |
1091 | - expect(scopeMock.j.suffix).toBe('/build?delay=0sec'); |
1092 | - }); |
1093 | - it('should have some handy links for the header and footer bars.', function() { |
1094 | - appController(scopeMock, locationMock, httpMock); |
1095 | - expect(scopeMock.links).toBeDefined(); |
1096 | - expect(scopeMock.links.length).toBeGreaterThan(5); |
1097 | - expect(scopeMock.footerLinks).toBeDefined(); |
1098 | - expect(scopeMock.footerLinks.length).toBeGreaterThan(1); |
1099 | - }); |
1100 | - it('should be able to determine silo coloring.', function() { |
1101 | - appController(scopeMock, locationMock, httpMock); |
1102 | - expect(scopeMock.getSiloColor).toBeDefined(); |
1103 | - expect(scopeMock.getSiloColor('landing-001')).toBe('black'); |
1104 | - expect(scopeMock.getSiloColor('landing-002')).toBe('black'); |
1105 | - }); |
1106 | - it('should expose some functions to the template scope.', function() { |
1107 | - expect(scopeMock.fixMergeURL).toBe(fixMergeURL); |
1108 | - expect(scopeMock.getStatusColor).toBe(getStatusColor); |
1109 | - expect(scopeMock.shortURL).toBe(shortURL); |
1110 | - expect(scopeMock.svgPlaceX).toBe(svgPlaceX); |
1111 | - expect(scopeMock.siloSearchFilter).toBeDefined(); |
1112 | - }); |
1113 | - it('should call $watch twice.', function() { |
1114 | - spyOn(scopeMock, '$watch'); |
1115 | - appController(scopeMock, locationMock, httpMock); |
1116 | - expect(scopeMock.$watch).toHaveBeenCalled(); |
1117 | - var watchCalls = scopeMock.$watch.calls.all(); |
1118 | - expect(watchCalls[0].args[0].name).toBe('URLParams'); |
1119 | - expect(watchCalls[0].args[1].name).toBe('URLWatcher'); |
1120 | - expect(watchCalls[1].args[0]).toBe('q'); |
1121 | - expect(watchCalls[1].args[1].name).toBe('URLSetter'); |
1122 | - }); |
1123 | - it('should call $watchCollection.', function() { |
1124 | - spyOn(scopeMock, '$watchCollection'); |
1125 | - appController(scopeMock, locationMock, httpMock); |
1126 | - expect(scopeMock.$watchCollection).toHaveBeenCalled(); |
1127 | - var calls = scopeMock.$watchCollection.calls.all(); |
1128 | - expect(calls[0].args[0]).toBe('silos'); |
1129 | - expect(calls[0].args[1] instanceof Function).toBe(true); |
1130 | - }); |
1131 | - it('should call $http methods.', function() { |
1132 | - spyOn(httpMock, 'get').and.callThrough(); |
1133 | - spyOn(httpMock, 'jsonp').and.callThrough(); |
1134 | - appController(scopeMock, locationMock, httpMock); |
1135 | - expect(httpMock.get).toHaveBeenCalled(); |
1136 | - var getCalls = httpMock.get.calls.all(); |
1137 | - expect(getCalls.length).toBe(1); |
1138 | - expect(getCalls[0].args[0]).toMatch('^/static/json/index.txt\\?nocache='); |
1139 | - }); |
1140 | -}); |
1141 | |
1142 | === modified file 'tickets/v1.py' |
1143 | --- tickets/v1.py 2015-08-28 04:38:56 +0000 |
1144 | +++ tickets/v1.py 2015-08-28 20:11:22 +0000 |
1145 | @@ -13,7 +13,7 @@ |
1146 | /v1/errors: Dump error log (authenticated users only). |
1147 | """ |
1148 | |
1149 | -from flask import abort, jsonify, request, session |
1150 | +from flask import abort, jsonify, redirect, request, session |
1151 | from urllib.parse import urlencode |
1152 | from sqlalchemy import func, desc |
1153 | from contextlib import suppress |
1154 | @@ -77,6 +77,12 @@ |
1155 | return app.send_static_file('index.html') |
1156 | |
1157 | |
1158 | +@app.route('/static/dashboard.html', methods=['GET']) |
1159 | +def dashboard_redirect(): |
1160 | + """Redirect to the front page.""" |
1161 | + return redirect('/') |
1162 | + |
1163 | + |
1164 | @app.route('/v1/tickets', methods=['POST']) |
1165 | def create_or_update(): |
1166 | """Inject given JSON into db; either creating or updating a record.""" |
PASSED: Continuous integration, rev:237 jenkins. qa.ubuntu. com/job/ bileto- ci/47/
http://
Executed test runs:
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/bileto- ci/47/rebuild
http://