396 lines
12 KiB
JavaScript
396 lines
12 KiB
JavaScript
// Copyright 2012-2013 OpenStack Foundation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
window.zuul_enable_status_updates = true;
|
|
window.zuul_filter = [];
|
|
|
|
function format_time(ms, words) {
|
|
if (ms == null) {
|
|
return "unknown";
|
|
}
|
|
var seconds = (+ms)/1000;
|
|
var minutes = Math.floor(seconds/60);
|
|
var hours = Math.floor(minutes/60);
|
|
seconds = Math.floor(seconds % 60);
|
|
minutes = Math.floor(minutes % 60);
|
|
r = '';
|
|
if (words) {
|
|
if (hours) {
|
|
r += hours;
|
|
r += ' hr ';
|
|
}
|
|
r += minutes + ' min';
|
|
} else {
|
|
if (hours < 10) r += '0';
|
|
r += hours + ':';
|
|
if (minutes < 10) r += '0';
|
|
r += minutes + ':';
|
|
if (seconds < 10) r += '0';
|
|
r += seconds;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
function format_progress(elapsed, remaining) {
|
|
if (remaining != null) {
|
|
total = elapsed + remaining;
|
|
} else {
|
|
total = null;
|
|
}
|
|
r = '<progress class="change_progress" title="' +
|
|
format_time(elapsed, false) + ' elapsed, ' +
|
|
format_time(remaining, false)+' remaining" ' +
|
|
'value="'+elapsed+'" max="'+total+'">in progress</progress>';
|
|
return r;
|
|
}
|
|
|
|
function is_hide_project(project) {
|
|
var filters = window.zuul_filter;
|
|
if (filters.length == 0) {
|
|
return false;
|
|
}
|
|
var hide = true;
|
|
$.each(filters, function(filter_i, filter) {
|
|
if(project.indexOf(filter) != -1)
|
|
hide = false;
|
|
});
|
|
return hide;
|
|
}
|
|
|
|
function remove(l, idx) {
|
|
l[idx] = null;
|
|
while (l[l.length-1] === null) {
|
|
l.pop();
|
|
}
|
|
}
|
|
|
|
function create_tree(pipeline) {
|
|
var count = 0;
|
|
var pipeline_max_tree_columns = 1;
|
|
$.each(pipeline['change_queues'], function(change_queue_i, change_queue) {
|
|
var tree = [];
|
|
var max_tree_columns = 1;
|
|
var changes = [];
|
|
var last_tree_length = 0;
|
|
$.each(change_queue['heads'], function(head_i, head) {
|
|
$.each(head, function(change_i, change) {
|
|
changes[change['id']] = change;
|
|
change['_tree_position'] = change_i;
|
|
});
|
|
});
|
|
$.each(change_queue['heads'], function(head_i, head) {
|
|
$.each(head, function(change_i, change) {
|
|
count += 1;
|
|
var idx = tree.indexOf(change['id']);
|
|
if (idx > -1) {
|
|
change['_tree_index'] = idx;
|
|
remove(tree, idx);
|
|
} else {
|
|
change['_tree_index'] = 0;
|
|
}
|
|
change['_tree_branches'] = [];
|
|
change['_tree'] = [];
|
|
change['items_behind'].sort(function(a, b) {
|
|
return changes[b]['_tree_position'] - changes[a]['_tree_position'];
|
|
});
|
|
$.each(change['items_behind'], function(i, id) {
|
|
tree.push(id);
|
|
if (tree.length>last_tree_length && last_tree_length > 0)
|
|
change['_tree_branches'].push(tree.length-1);
|
|
});
|
|
if (tree.length > max_tree_columns) {
|
|
max_tree_columns = tree.length;
|
|
}
|
|
if (tree.length > pipeline_max_tree_columns) {
|
|
pipeline_max_tree_columns = tree.length;
|
|
}
|
|
change['_tree'] = tree.slice(0); // make a copy
|
|
last_tree_length = tree.length;
|
|
});
|
|
});
|
|
change_queue['_tree_columns'] = max_tree_columns;
|
|
});
|
|
pipeline['_tree_columns'] = pipeline_max_tree_columns;
|
|
return count;
|
|
}
|
|
|
|
function get_sparkline_url(pipeline_name) {
|
|
if (!(pipeline_name in window.zuul_sparkline_urls)) {
|
|
window.zuul_sparkline_urls[pipeline_name] = $.fn.graphite.geturl({
|
|
url: "http://graphite.openstack.org/render/",
|
|
from: "-8hours",
|
|
width: 100,
|
|
height: 16,
|
|
margin: 0,
|
|
hideLegend: true,
|
|
hideAxes: true,
|
|
hideGrid: true,
|
|
target: [
|
|
"color(stats.gauges.zuul.pipeline."+pipeline_name+".current_changes, '6b8182')",
|
|
],
|
|
});
|
|
}
|
|
return window.zuul_sparkline_urls[pipeline_name];
|
|
}
|
|
|
|
function format_pipeline(data) {
|
|
var count = create_tree(data);
|
|
var width = (16 * data['_tree_columns']) + 300;
|
|
var html = '<div class="pipeline" style="width:'+width+'"><h3 class="subhead">'+
|
|
data['name'];
|
|
|
|
html += '<span class="count"><img src="' + get_sparkline_url(data['name']);
|
|
html += '" title="8 hour history of changes in pipeline"/>';
|
|
|
|
if (count > 0) {
|
|
html += ' (' + count + ')';
|
|
}
|
|
html += '</span></h3>';
|
|
if (data['description'] != null) {
|
|
html += '<p>'+data['description']+'</p>';
|
|
}
|
|
|
|
$.each(data['change_queues'], function(change_queue_i, change_queue) {
|
|
$.each(change_queue['heads'], function(head_i, head) {
|
|
var projects = "";
|
|
var hide_queue = true;
|
|
$.each(head, function(change_i, change) {
|
|
projects += change['project'] + "|";
|
|
hide_queue &= is_hide_project(change['project']);
|
|
});
|
|
html += '<div project="' + projects + '" style="'
|
|
+ (hide_queue ? 'display:none;' : '') + '">';
|
|
|
|
if (data['change_queues'].length > 1 && head_i == 0) {
|
|
html += '<div> Change queue: ';
|
|
|
|
var name = change_queue['name'];
|
|
html += '<a title="' + name + '">';
|
|
if (name.length > 32) {
|
|
name = name.substr(0,32) + '...';
|
|
}
|
|
html += name + '</a></div>';
|
|
}
|
|
html += '<table>'
|
|
$.each(head, function(change_i, change) {
|
|
html += format_change(change, change_queue);
|
|
});
|
|
html += '</table></div>'
|
|
});
|
|
});
|
|
|
|
html += '</div>';
|
|
return html;
|
|
}
|
|
|
|
function safe_id(id) {
|
|
if (id === null) {
|
|
return "null";
|
|
}
|
|
return id.replace(',', '_');
|
|
}
|
|
|
|
function format_change(change, change_queue) {
|
|
var html = '<tr>';
|
|
|
|
for (var i=0; i<change_queue['_tree_columns']; i++) {
|
|
var cls = 'tree';
|
|
if (i < change['_tree'].length && change['_tree'][i] !== null) {
|
|
cls += ' line';
|
|
}
|
|
html += '<td class="'+cls+'">';
|
|
if (i == change['_tree_index']) {
|
|
if (change['failing_reasons'] && change['failing_reasons'].length > 0) {
|
|
html += '<img src="red.png" title="Failing because '+
|
|
change['failing_reasons'].join(', ')+'"/>';
|
|
} else {
|
|
html += '<img src="green.png" title="Succeeding"/>';
|
|
}
|
|
}
|
|
if (change['_tree_branches'].indexOf(i) != -1) {
|
|
if (change['_tree_branches'].indexOf(i) == change['_tree_branches'].length-1)
|
|
html += '<img src="line-angle.png"/>';
|
|
else
|
|
html += '<img src="line-t.png"/>';
|
|
}
|
|
html += '</td>';
|
|
}
|
|
|
|
html += '<td class="change-container">';
|
|
html += '<div class="change" id="' + safe_id(change['id']) + '"><div class="header">';
|
|
|
|
html += '<span class="project">' + change['project'] + '</span>';
|
|
var id = change['id'];
|
|
var url = change['url'];
|
|
if (id !== null) {
|
|
if (id.length == 40) {
|
|
id = id.substr(0,7);
|
|
}
|
|
html += '<span class="changeid">';
|
|
if (url !== null) {
|
|
html += '<a href="'+url+'">';
|
|
}
|
|
html += id;
|
|
if (url !== null) {
|
|
html += '</a>';
|
|
}
|
|
}
|
|
|
|
html += '</span><span class="time">';
|
|
html += format_time(change['remaining_time'], true);
|
|
html += '</span></div><div class="jobs">';
|
|
|
|
$.each(change['jobs'], function(i, job) {
|
|
result = job['result'];
|
|
var result_class = "result";
|
|
if (result === null) {
|
|
if (job['url'] !== null) {
|
|
result = 'in progress';
|
|
} else {
|
|
result = 'queued';
|
|
}
|
|
} else if (result == 'SUCCESS') {
|
|
result_class += " result_success";
|
|
} else if (result == 'FAILURE') {
|
|
result_class += " result_failure";
|
|
} else if (result == 'LOST') {
|
|
result_class += " result_unstable";
|
|
} else if (result == 'UNSTABLE') {
|
|
result_class += " result_unstable";
|
|
}
|
|
html += '<span class="job">';
|
|
if (job['url'] !== null) {
|
|
html += '<a href="'+job['url']+'">';
|
|
}
|
|
html += job['name'];
|
|
if (job['url'] !== null) {
|
|
html += '</a>';
|
|
}
|
|
html += ': ';
|
|
if (job['result'] === null && job['url'] !== null) {
|
|
html += format_progress(job['elapsed_time'], job['remaining_time']);
|
|
} else {
|
|
html += '<span class="result '+result_class+'">'+result+'</span>';
|
|
}
|
|
|
|
if (job['voting'] == false) {
|
|
html += ' (non-voting)';
|
|
}
|
|
html += '</span>';
|
|
});
|
|
|
|
html += '</div></div></td></tr>';
|
|
return html;
|
|
}
|
|
|
|
function update_timeout() {
|
|
if (!window.zuul_enable_status_updates) {
|
|
setTimeout(update_timeout, 5000);
|
|
return;
|
|
}
|
|
|
|
window.zuul_graph_update_count += 1;
|
|
|
|
update();
|
|
/* Only update graphs every minute */
|
|
if (window.zuul_graph_update_count > 11) {
|
|
window.zuul_graph_update_count = 0;
|
|
update_graphs();
|
|
}
|
|
|
|
setTimeout(update_timeout, 5000);
|
|
}
|
|
|
|
function update() {
|
|
var html = '';
|
|
|
|
$.getJSON('http://zuul.openstack.org/status.json', function(data) {
|
|
if ('message' in data) {
|
|
$("#message").attr('class', 'alertbox');
|
|
$("#message").html(data['message']);
|
|
} else {
|
|
$("#message").removeClass('alertbox');
|
|
$("#message").html('');
|
|
}
|
|
|
|
html += '<br style="clear:both"/>';
|
|
|
|
$.each(data['pipelines'], function(i, pipeline) {
|
|
html = html + format_pipeline(pipeline);
|
|
});
|
|
|
|
html += '<br style="clear:both"/>';
|
|
$("#pipeline-container").html(html);
|
|
|
|
$("#trigger_event_queue_length").html(
|
|
data['trigger_event_queue']['length']);
|
|
$("#result_event_queue_length").html(
|
|
data['result_event_queue']['length']);
|
|
|
|
});
|
|
}
|
|
|
|
function update_graphs() {
|
|
$('.graph').each(function(i, img) {
|
|
var newimg = new Image();
|
|
var parts = img.src.split('#');
|
|
newimg.src = parts[0] + '#' + new Date().getTime();
|
|
$(newimg).load(function (x) {
|
|
img.src = newimg.src;
|
|
});
|
|
});
|
|
|
|
$.each(window.zuul_sparkline_urls, function(name, url) {
|
|
var newimg = new Image();
|
|
var parts = url.split('#');
|
|
newimg.src = parts[0] + '#' + new Date().getTime();
|
|
$(newimg).load(function (x) {
|
|
window.zuul_sparkline_urls[name] = newimg.src;
|
|
});
|
|
});
|
|
}
|
|
|
|
$(function() {
|
|
window.zuul_graph_update_count = 0;
|
|
window.zuul_sparkline_urls = {};
|
|
update_timeout();
|
|
|
|
$(document).on({
|
|
'show.visibility': function() {
|
|
window.zuul_enable_status_updates = true;
|
|
update();
|
|
update_graphs();
|
|
},
|
|
'hide.visibility': function() {
|
|
window.zuul_enable_status_updates = false;
|
|
}
|
|
});
|
|
|
|
$('#projects_filter').live('keyup change', function () {
|
|
window.zuul_filter = $('#projects_filter').val().trim().split(',');
|
|
window.zuul_filter = window.zuul_filter.filter(function(n){
|
|
return n;
|
|
});
|
|
$.each($('div[project]'), function (idx, val) {
|
|
val = $(val);
|
|
var project = val.attr('project');
|
|
if (is_hide_project(project)) {
|
|
val.hide(100);
|
|
} else {
|
|
val.show(100);
|
|
}
|
|
})
|
|
});
|
|
});
|