OLD | NEW |
(Empty) | |
| 1 <!-- |
| 2 The common.js file must be included before this file. |
| 3 |
| 4 This in an HTML Import-able file that contains the definition |
| 5 of the following elements: |
| 6 |
| 7 <buildbot-dash-sk> |
| 8 |
| 9 To use this file import it: |
| 10 |
| 11 <link href="/res/imp/buildbot-dash-sk.html" rel="import" /> |
| 12 |
| 13 Usage: |
| 14 |
| 15 <buildbot-dash-sk></buildbot-dash-sk> |
| 16 --> |
| 17 <polymer-element name="buildbot-dash-sk"> |
| 18 <template> |
| 19 <style> |
| 20 paper-button { |
| 21 text-transform: none; |
| 22 } |
| 23 h1 { |
| 24 font-size: 1.7em; |
| 25 margin-bottom: 2px; |
| 26 margin-top: 5px; |
| 27 } |
| 28 #controls { |
| 29 width: 200px; |
| 30 } |
| 31 .control { |
| 32 margin: 5px; |
| 33 padding: 10px; |
| 34 border: 1px solid #eeeeee; |
| 35 font-size: 12px; |
| 36 } |
| 37 .control > h2 { |
| 38 font-size: 16px; |
| 39 } |
| 40 #maincontent { |
| 41 padding-top: 10px; |
| 42 } |
| 43 </style> |
| 44 <div id="maincontent"> |
| 45 <div id="spinner" horizontal layout center fit> |
| 46 <div vertical layout center flex> |
| 47 <paper-spinner active></paper-spinner> |
| 48 </div> |
| 49 </div> |
| 50 <div id="chart_container" horizontal layout> |
| 51 <div id="controls"> |
| 52 <div class="control"> |
| 53 <h2>Results from last</h2> |
| 54 <paper-button id="time_select_button" on-click="{{openTimeSelect}}
"> |
| 55 <div id="time_select_label"></div> |
| 56 <core-icon icon="arrow-drop-down"></core-icon> |
| 57 </paper-button> |
| 58 <paper-dropdown id="time_select"> |
| 59 <core-menu id="time_menu" selected=0 on-core-select="{{timeSelec
ted}}"> |
| 60 <paper-item value=24>24 hours</paper-item> |
| 61 <paper-item value=72>3 days</paper-item> |
| 62 <paper-item value=168>1 week</paper-item> |
| 63 <paper-item value=336>2 weeks</paper-item> |
| 64 </core-menu> |
| 65 </paper-dropdown> |
| 66 </div> |
| 67 <input-list-sk |
| 68 id="include_builders" |
| 69 heading="Include Patterns" |
| 70 values="{{include}}" |
| 71 on-change="{{processBuilds}}"></input-list-sk> |
| 72 <input-list-sk |
| 73 id="exclude_builders" |
| 74 heading="Exclude Patterns" |
| 75 values="{{exclude}}" |
| 76 on-change="{{processBuilds}}"></input-list-sk> |
| 77 <div class="control"> |
| 78 <h2>Excluded Builders</h2> |
| 79 <ul> |
| 80 <template repeat="{{bot in excludedBots}}"> |
| 81 <li>{{bot}}</li> |
| 82 </template> |
| 83 </ul> |
| 84 </div> |
| 85 </div> |
| 86 <div id="charts" flex> |
| 87 <bar-chart-sk heading="Build Times" id="build_times_chart"></bar-cha
rt-sk> |
| 88 <bar-chart-sk heading="Step Times" id="step_times_chart"></bar-chart
-sk> |
| 89 <bar-chart-sk heading="Build Failure Rate" id="build_failure_rate_ch
art"></bar-chart-sk> |
| 90 <bar-chart-sk heading="Step Failure Rate" id="step_failure_rate_char
t"></bar-chart-sk> |
| 91 </div> |
| 92 </div> |
| 93 </div> |
| 94 </template> |
| 95 <script> |
| 96 (function() { |
| 97 function mean(data) { |
| 98 // TODO(borenet): Use a more stable algorithm. |
| 99 var sum = 0; |
| 100 for (var i = 0; i < data.length; i++) { |
| 101 sum += data[i]; |
| 102 } |
| 103 return sum / data.length; |
| 104 } |
| 105 |
| 106 Polymer({ |
| 107 created: function() { |
| 108 this.builds = []; |
| 109 this.buildTimes = {}; |
| 110 this.stepTimes = {}; |
| 111 this.buildResults = {}; |
| 112 this.stepResults = {}; |
| 113 |
| 114 this.include = []; |
| 115 this.exclude = []; |
| 116 this.excludedBots = []; |
| 117 |
| 118 var palette = [ |
| 119 "#03DCFB", "#00C2DD", "#008699", "#006C7C", "#00535E", // Blue |
| 120 "#FFAE00", "#FFAE00", "#FAAB00", "#CA8A00", "#9A6900", // Yellow |
| 121 "#FF1300", "#FF1300", "#FA1200", "#CA0F00", "#9A0B00", // Red |
| 122 ]; |
| 123 var paletteRowLen = 5; |
| 124 this.colors = [ |
| 125 palette[2*paletteRowLen+3], |
| 126 palette[1*paletteRowLen+3], |
| 127 palette[0*paletteRowLen+3], |
| 128 ]; |
| 129 }, |
| 130 |
| 131 reloadBuilds: function(start, end) { |
| 132 console.time("loadData"); |
| 133 url = "/json/builds"; |
| 134 if (!!start) { |
| 135 url += "?start=" + start; |
| 136 if (!!end) { |
| 137 url += "&end=" + end; |
| 138 } |
| 139 } |
| 140 this.$.spinner.style.display = "flex"; |
| 141 this.$.chart_container.style.display = "none"; |
| 142 var that = this; |
| 143 sk.get(url).then(JSON.parse).then(function(json) { |
| 144 console.timeEnd("loadData"); |
| 145 that.builds = json; |
| 146 that.processBuilds(); |
| 147 that.$.spinner.style.display = "none"; |
| 148 that.$.chart_container.style.display = "flex"; |
| 149 }); |
| 150 }, |
| 151 |
| 152 includeBuilder: function(builder) { |
| 153 for (var i = 0; i < this.exclude.length; i++) { |
| 154 if (builder.match(this.exclude[i])) { |
| 155 return false; |
| 156 } |
| 157 } |
| 158 for (var i = 0; i < this.include.length; i++) { |
| 159 if (!builder.match(this.include[i])) { |
| 160 return false; |
| 161 } |
| 162 } |
| 163 return true; |
| 164 }, |
| 165 |
| 166 processBuilds: function() { |
| 167 console.time("processBuilds"); |
| 168 this.buildTimes = {}; |
| 169 this.stepTimes = {}; |
| 170 this.buildResults = {}; |
| 171 this.stepResults = {}; |
| 172 this.excludedBots = []; |
| 173 |
| 174 for (var i = 0; i < this.builds.length; i++) { |
| 175 var build = this.builds[i]; |
| 176 if (!this.includeBuilder(build.Builder)) { |
| 177 this.excludedBots.push(build.Builder); |
| 178 continue; |
| 179 } |
| 180 |
| 181 var duration = build.Finished - build.Started; |
| 182 if (!this.buildTimes[build.Builder]) { |
| 183 this.buildTimes[build.Builder] = []; |
| 184 } |
| 185 this.buildTimes[build.Builder].push(duration); |
| 186 |
| 187 if (!this.buildResults[build.Builder]) { |
| 188 this.buildResults[build.Builder] = []; |
| 189 } |
| 190 this.buildResults[build.Builder].push(build.Results == 0 ? 0 : 1); |
| 191 |
| 192 for (var j = 0; j < build.Steps.length; j++) { |
| 193 var step = build.Steps[j]; |
| 194 // Always exclude these steps. |
| 195 if (step.Name == "steps" || step.Name == "Uncaught Exception") { |
| 196 continue; |
| 197 } |
| 198 var stepDuration = step.Finished - step.Started; |
| 199 if (!this.stepTimes[step.Name]) { |
| 200 this.stepTimes[step.Name] = []; |
| 201 } |
| 202 this.stepTimes[step.Name].push(stepDuration); |
| 203 |
| 204 if (!this.stepResults[step.Name]) { |
| 205 this.stepResults[step.Name] = []; |
| 206 } |
| 207 this.stepResults[step.Name].push(step.Results == 0 ? 0 : 1); |
| 208 } |
| 209 } |
| 210 |
| 211 console.timeEnd("processBuilds"); |
| 212 this.drawCharts(); |
| 213 }, |
| 214 |
| 215 drawCharts: function() { |
| 216 console.time("drawCharts"); |
| 217 // Draw charts. |
| 218 |
| 219 // Build times. |
| 220 this.$.build_times_chart.colors = this.colors; |
| 221 this.$.build_times_chart.columns = [ |
| 222 ["string", "Builder"], |
| 223 ["number", "Time (s)"], |
| 224 ]; |
| 225 this.$.build_times_chart.data = this.generateStats(this.buildTimes, mean
); |
| 226 |
| 227 // Step times. |
| 228 this.$.step_times_chart.colors = this.colors; |
| 229 this.$.step_times_chart.columns = [ |
| 230 ["string", "Step"], |
| 231 ["number", "Time (s)"], |
| 232 ]; |
| 233 this.$.step_times_chart.data = this.generateStats(this.stepTimes, mean); |
| 234 |
| 235 // Build failure rate. |
| 236 this.$.build_failure_rate_chart.colors = this.colors; |
| 237 this.$.build_failure_rate_chart.columns = [ |
| 238 ["string", "Builder"], |
| 239 ["number", "Failure Rate"], |
| 240 ]; |
| 241 this.$.build_failure_rate_chart.data = this.generateStats(this.buildResu
lts, mean); |
| 242 |
| 243 // Step failure rate. |
| 244 this.$.step_failure_rate_chart.colors = this.colors; |
| 245 this.$.step_failure_rate_chart.columns = [ |
| 246 ["string", "Step"], |
| 247 ["number", "Failure Rate"], |
| 248 ]; |
| 249 this.$.step_failure_rate_chart.data = this.generateStats(this.stepResult
s, mean); |
| 250 |
| 251 console.timeEnd("drawCharts"); |
| 252 }, |
| 253 |
| 254 generateStats: function(data, aggregator) { |
| 255 var stats = []; |
| 256 for (var series in data) { |
| 257 stats.push([series, aggregator(data[series])]); |
| 258 } |
| 259 stats.sort(function(a, b) { |
| 260 return b[1] - a[1]; |
| 261 }); |
| 262 return stats; |
| 263 }, |
| 264 |
| 265 openTimeSelect: function() { |
| 266 this.$.time_select.open(); |
| 267 }, |
| 268 |
| 269 timeSelected: function(e) { |
| 270 this.$.time_select.close(); |
| 271 if (e.detail.isSelected) { |
| 272 this.$.time_select_label.innerHTML = e.detail.item.innerHTML; |
| 273 this.updateTimePeriod(e.detail.item.getAttribute("value")); |
| 274 } |
| 275 }, |
| 276 |
| 277 updateTimePeriod: function(timePeriod) { |
| 278 var now = Math.round(new Date().getTime() / 1000); |
| 279 this.reloadBuilds(now - timePeriod * 3600, now); |
| 280 }, |
| 281 }); |
| 282 })(); |
| 283 </script> |
| 284 </polymer-element> |
OLD | NEW |