hydra/src/root/common.tt
2014-10-07 13:35:31 +02:00

627 lines
22 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[%
USE date;
USE String;
USE HTML;
BLOCK renderDateTime;
date.format(timestamp, '%Y-%m-%d %H:%M:%S');
END;
BLOCK renderProjectName %]
<a [% IF inRow %]class="row-link"[% END %] href="[% c.uri_for('/project' project) %]"><tt>[% project %]</tt></a>
[% END;
BLOCK renderJobsetName %]
<a [% IF inRow %]class="row-link"[% END %] href="[% c.uri_for('/jobset' project jobset) %]"><tt>[% jobset %]</tt></a>
[% END;
BLOCK renderJobName %]
<a [% IF inRow %]class="row-link"[% END %] href="[% c.uri_for('/job' project jobset job) %]">[% job %]</a>
[% END;
BLOCK renderFullJobsetName %]
<tt>[% INCLUDE renderProjectName inRow=0 %]:[% INCLUDE renderJobsetName %]</tt>
[% END;
BLOCK renderFullJobName %]
<tt>[% IF !hideProjectName; INCLUDE renderProjectName inRow=0 %]:[% END; IF !hideJobsetName; INCLUDE renderJobsetName inRow=0 %]:[% END; INCLUDE renderJobName %]</tt>
[% END;
BLOCK renderFullJobNameOfBuild;
INCLUDE renderFullJobName project=build.get_column("project") jobset = build.get_column("jobset") job = build.get_column("job");
END;
BLOCK renderDuration;
IF duration >= 24 * 60 * 60; duration div (24 * 60 * 60) %]d&nbsp;[% END;
IF duration >= 60 * 60; duration div (60 * 60) % 24 %]h&nbsp;[% END;
IF duration >= 60; duration div 60 % 60 %]m&nbsp;[% END;
duration % 60 %]s[%
END;
BLOCK renderBuildListHeader %]
<table class="table table-striped table-condensed clickable-rows">
<thead>
<tr>
[% IF !hideResultInfo %]
<th></th>
[% END %]
[% IF showSchedulingInfo %]
<th></th>
[% END %]
<th>#</th>
[% IF showSchedulingInfo %]
<th>P</th>
[% END %]
[% IF !hideJobName %]
<th>Job</th>
[% END %]
<th>Release name</th>
<th>System</th>
<th>[% IF showSchedulingInfo %]Queued at[% ELSE %]Finished at[% END %]</th>
[% IF showDescription %]
<th>Description</th>
[% END %]
</tr>
</thead>
<tbody>
[% END;
BLOCK renderBuildListBody;
FOREACH build IN builds; %]
<tr>
[% IF !hideResultInfo %]
<td>
[% INCLUDE renderBuildStatusIcon size=16 busy=(showSchedulingInfo ? 1 : 0) buildstatus=build.buildstatus %]
</td>
[% END %]
[% IF showSchedulingInfo %]
<td>[% IF build.busy %]<span class="label label-success">Started</span>[% ELSE %]<span class="label">Queued</span>[% END %]</td>
[% END %]
<td><a class="row-link" href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td>
[% IF showSchedulingInfo %]
<td>[% build.priority %]</td>
[% END %]
[% IF !hideJobName %]
<td>[% INCLUDE renderFullJobNameOfBuild %]</td>
[% END %]
<td>[% !showSchedulingInfo and build.get_column('releasename') ? build.get_column('releasename') : build.nixname %]</td>
<td class="nowrap"><tt>[% build.system %]</tt></td>
<td class="nowrap">[% t = showSchedulingInfo ? build.timestamp : build.stoptime; IF t; date.format(showSchedulingInfo ? build.timestamp : build.stoptime, '%Y-%m-%d %H:%M:%S'); ELSE; "-"; END %]</td>
[% IF showDescription %]
<td>[% build.description %]</td>
[% END %]
</tr>
[% END;
IF linkToAll %]
<tr><td class="centered" colspan="5"><a href="[% linkToAll %]"><em>More...</em></a></td></tr>
[% END;
END;
BLOCK renderBuildListFooter %]
</tbody>
</table>
[% END;
BLOCK renderBuildList;
INCLUDE renderBuildListHeader;
INCLUDE renderBuildListBody;
INCLUDE renderBuildListFooter;
END;
BLOCK renderLink %]<a href="[% uri %]">[% title %]</a>[% END;
BLOCK renderViewJobName;
IF job.description; HTML.escape(job.description); ELSE %]<tt>[% job.job %]</tt> ([% job.attrs %])[% END;
END;
BLOCK maybeLink;
IF uri %]<a [% HTML.attributes(href => uri, class => class); IF confirmmsg +%] onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>[% content %]</a>[% ELSE; content; END;
END;
BLOCK renderSelection;
IF edit;
IF radiobuttons; %]
<div class="controls">
[% FOREACH name IN options.keys.sort %]
<label class="radio inline">
<input type="radio" [% HTML.attributes(id => param, name => param, value => name) %]
[% IF name == curValue; "checked='1'"; END %]>
[% options.$name %]
</input>
</label>
[% END %]
</div>
[% ELSE %]
<select [% HTML.attributes(id => param, name => param) %]>
[% FOREACH name IN options.keys.sort %]
<option [% IF name == curValue; "selected='selected'"; END; " "; HTML.attributes(value => name) %]>[% options.$name %]</option>
[% END %]
</select>
[% END;
ELSE;
options.$curValue;
END;
END;
BLOCK editString; %]
<input type="text" class="string" [% HTML.attributes(id => param, name => param, value => value) %] />
[% END;
BLOCK renderFullBuildLink;
INCLUDE renderFullJobNameOfBuild build=build %] <a href="[% c.uri_for('/build' build.id) %]">build [% build.id %]</a>[%
END;
BLOCK renderBuildLink; %]
<a href="[% c.uri_for('/build' build.id) %]">build [% build.id %]</a>
[% END;
BLOCK renderBuildStatusIcon;
finished = build != undef ? build.finished : 1;
busy = busy != undef ? busy : build.busy;
buildstatus = buildstatus != undef ? buildstatus : build.buildstatus;
IF finished;
IF buildstatus == 0 %]
<img src="[% c.uri_for("/static/images/checkmark_${size}.png") %]" alt="Succeeded" />
[% ELSIF buildstatus == 1 %]
<img src="[% c.uri_for("/static/images/error_${size}.png") %]" alt="Failed" />
[% ELSIF buildstatus == 2 || buildstatus == 5 %]
<img src="[% c.uri_for("/static/images/dependency_${size}.png") %]" alt="Dependency failed" />
[% ELSIF buildstatus == 3 %]
<img src="[% c.uri_for("/static/images/warning_${size}.png") %]" alt="Aborted" />
[% ELSIF buildstatus == 4 %]
<img src="[% c.uri_for("/static/images/forbidden_${size}.png") %]" alt="Cancelled" />
[% ELSIF buildstatus == 6 %]
<img src="[% c.uri_for("/static/images/error_${size}.png") %]" alt="Failed (with result)" />
[% ELSE %]
<img src="[% c.uri_for("/static/images/error_${size}.png") %]" alt="Failed" />
[% END;
ELSIF busy %]
<img src="[% c.uri_for("/static/images/help_${size}.png") %]" alt="Busy" />
[% ELSE %]
<img src="[% c.uri_for("/static/images/help_${size}.png") %]" alt="Scheduled" />
[% END;
END;
BLOCK renderStatus;
IF build.finished;
buildstatus = build.buildstatus;
IF icon; INCLUDE renderBuildStatusIcon size=16; END;
IF buildstatus == 0 %]
<strong>Success</strong>
[% ELSIF buildstatus == 1 %]
<span class="error">Build returned a non-zero exit code</span>
[% ELSIF buildstatus == 2 || buildstatus == 5 %]
<span class="error">A dependency of the build failed</span>
[% ELSIF buildstatus == 4 %]
<span class="error">Cancelled by user</span>
[% ELSIF buildstatus == 6 %]
<span class="error">Build failed (with result)</span>
[% ELSE %]
<span class="error">Aborted</span>
(Hydra failure; see <a href="#nix-error">below</a>)
[% END;
ELSIF build.busy %]
<strong>Build in progress</strong>
since [% INCLUDE renderDateTime timestamp = build.starttime;
ELSE %]
<strong>Scheduled to be built</strong>
[% END;
END;
BLOCK renderShortInputValue;
IF input.type == "build" || input.type == "sysbuild" %]
<a href="[% c.uri_for('/build' input.dependency.id) %]">[% input.dependency.id %]</a>
[% ELSIF input.type == "string" %]
<tt>"[% HTML.escape(input.value) %]"</tt>
[% ELSIF input.type == "nix" || input.type == "boolean" %]
<tt>[% HTML.escape(input.value) %]</tt>
[% ELSE %]
<tt>[% HTML.escape(input.uri) %][% IF input.revision %] (r[% HTML.escape(input.revision) %])[% END %]</tt>
[% END %]
[% END;
BLOCK renderDiffUri;
nouri = 1;
FOREACH m IN mappers;
base = m.baseuri;
url = bi1.uri;
path = url.replace(base, '');
IF url.match(base) %]
<a target="_blank" href="[% m.uri.replace('_path_', path).replace('_1_', bi1.revision).replace('_2_', bi2.revision) %]">[% contents %]</a>
[% nouri = 0;
END;
END;
IF nouri;
res = bi1.uri.split(' ');
url = res.0;
branch = res.1;
IF bi1.type == "hg" || bi1.type == "git" %]
<a target="_blank" href="[% HTML.escape("/api/scmdiff?uri=$url&rev1=$bi1.revision&rev2=$bi2.revision&type=$bi1.type&branch=$branch") %]">[% contents %]</a>
[% ELSE;
contents;
END;
END;
END;
BLOCK renderInputs; %]
<table class="table table-striped table-condensed">
<thead>
<tr><th>Name</th><th>Type</th><th>Value</th><th>Revision</th><th>Store path</th></tr>
</thead>
<tbody>
[% FOREACH input IN inputs %]
<tr>
<td><tt>[% input.name %]</tt></td>
<td>[% type = input.type; inputTypes.$type %]</td>
<td>
[% IF input.type == "build" || input.type == "sysbuild" %]
[% INCLUDE renderFullBuildLink build=input.dependency %]
[% ELSIF input.type == "string" %]
<tt>"[% HTML.escape(input.value) %]"</tt>
[% ELSIF input.type == "nix" || input.type == "boolean" %]
<tt>[% HTML.escape(input.value) %]</tt>
[% ELSE %]
<tt>[% HTML.escape(input.uri) %]</tt>
[% END %]
</td>
<td>[% IF input.revision %][% HTML.escape(input.revision) %][% END %]</td>
<td><tt>[% input.path %]</tt></td>
</tr>
[% END %]
</tbody>
</table>
[% END;
BLOCK renderInputDiff; %]
<table class="table table-striped table-condensed">
[% IF !nestedDiff %]
<tr><th>Input</th><th>Changes</th></tr>
[% END;
IF !nestLevel;
nestLevel = 0;
END;
IF nestLevel <= 3;
FOREACH bi1 IN inputs1;
deletedInput = 1;
FOREACH bi2 IN inputs2;
IF bi1.name == bi2.name;
IF bi1.type == bi2.type;
IF bi1.value != bi2.value || bi1.uri != bi2.uri %]
<tr><td><b>[% bi1.name %]</b></td><td><tt>[% INCLUDE renderShortInputValue input=bi1 %]</tt> to <tt>[% INCLUDE renderShortInputValue input=bi2 %]</tt></td></tr>
[% ELSIF bi1.uri == bi2.uri && bi1.revision != bi2.revision %]
[% IF bi1.type == "git" %]
<tr><td>
<b>[% bi1.name %]</b></td><td><tt>[% INCLUDE renderDiffUri contents=(bi1.revision.substr(0, 6) _ ' to ' _ bi2.revision.substr(0, 6)) %]</tt>
</td></tr>
[% ELSE %]
<tr><td>
<b>[% bi1.name %]</b></td><td><tt>[% INCLUDE renderDiffUri contents=(bi1.revision _ ' to ' _ bi2.revision) %]</tt>
</td></tr>
[% END %]
[% ELSIF bi1.dependency.id != bi2.dependency.id || bi1.path != bi2.path %]
<tr><td>
<b>[% bi1.name %]</b></td><td><tt>[% INCLUDE renderShortInputValue input=bi1 %]</tt> to <tt>[% INCLUDE renderShortInputValue input=bi2 %]</tt>
<br/>
<br/>
[% INCLUDE renderInputDiff inputs1=bi1.dependency.inputs inputs2=bi2.dependency.inputs nestedDiff=1 nestLevel=nestLevel+1 %]
</td></tr>
[% END %]
[% ELSE %]
<tr><td><b>[% bi1.name %]</b></td><td>Changed input type from '[% type = bi1.type; inputTypes.$type %]' to '[% type = bi2.type; inputTypes.$type %]'</td></tr>
[% END;
deletedInput = 0;
END;
END;
IF deletedInput == 1 %]
<tr><td><b>[% bi1.name %]</b></td><td>Input not present in this build.</td></tr>
[% END;
END;
END %]
</table>
[% END;
BLOCK renderPager %]
<ul class="pager">
<li [% IF page == 1 %]class="disabled"[% END %]><a href="[% "$baseUri?page=1" %]">« First</a></li>
<li [% IF page == 1 %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (page - 1) %]"> Previous</a></li>
<li [% IF page * resultsPerPage >= total %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (page + 1) %]">Next </a></li>
<li [% IF page * resultsPerPage >= total %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (total - 1) div resultsPerPage + 1 %]">Last »</a></li>
</ul>
[% END;
BLOCK renderShortEvalInput;
IF input.type == "svn" || input.type == "svn-checkout" || input.type == "bzr" || input.type == "bzr-checkout" %]
r[% input.revision %]
[% ELSIF input.type == "git" %]
<tt>[% input.revision.substr(0, 7) %]</tt>
[% ELSIF input.type == "build" || input.type == "sysbuild" %]
<a href="[% c.uri_for('/build' input.get_column('dependency')) %]">[% input.get_column('dependency') %]</a>
[% ELSE %]
<tt>[% input.revision %]</tt>
[% END;
END;
BLOCK renderEvals %]
<table class="table table-condensed table-striped clickable-rows">
<thead>
<tr>
[% IF !jobset && !build %]
<th>Jobset</th>
[% END %]
<th>#</th>
<th style="width: 10em">Date</th>
<th>Input changes</th>
<th colspan='2' style="width: 25em">Success</th>
</tr>
</thead>
<tbody>
[% FOREACH e IN evals;
eval = e.eval;
link = c.uri_for(c.controller('JobsetEval').action_for('view'), [eval.id]) %]
<tr>
[% IF !jobset && !build %]
<td>[% INCLUDE renderFullJobsetName project=eval.get_column('project') jobset=eval.get_column('jobset') %]</td>
[% END %]
<td><a class="row-link" href="[% link %]">[% eval.id %]</a></td>
<td class="nowrap">[% INCLUDE renderDateTime timestamp = eval.timestamp %]</td>
<td>
[% IF e.changedInputs.size > 0;
sep='';
FOREACH input IN e.changedInputs;
sep; %] [% input.name %] → [% INCLUDE renderShortEvalInput input=input;
sep=', ';
END;
ELSE %]
-
[% END %]
</td>
<td align='right' class="nowrap">
<span class="label label-success">[% e.nrSucceeded %]</span>
[% IF e.nrFailed > 0 %]
<span class="label label-important">[% e.nrFailed %]</span>
[% END %]
[% IF e.nrScheduled > 0 %]
<span class="label">[% e.nrScheduled %]</span>
[% END %]
</td>
<td align='right' class="nowrap">
[% IF e.diff > 0 %]
<span class='label label-success'><strong>+[% e.diff %]</strong></span>
[% ELSIF e.diff < 0 && e.nrScheduled == 0 %]
<span class='label label-important'><strong>[% e.diff %]</strong></span>
[% END %]
</td>
</tr>
[% END;
IF linkToAll %]
<tr><td class="centered" colspan="5"><a href="[% linkToAll %]"><em>More...</em></a></td></tr>
[% END %]
</tbody>
</table>
[% END;
BLOCK renderLogLinks %]
(<a [% IF inRow %]class="row-link"[% END %] href="[% url %]">log</a>, <a href="[% "$url/raw" %]">raw</a>, <a href="[% "$url/tail-reload" %]">tail</a>)
[% END;
BLOCK makeLazyTab %]
<div id="[% tabName %]" class="tab-pane">
<center><img src="[% c.uri_for("/static/images/ajax-loader.gif") %]" alt="Loading..." /></center>
</div>
<script>
$(function() { makeLazyTab("[% tabName %]", "[% uri %]"); });
</script>
[% END;
BLOCK makePopover %]
<div class="btn hydra-popover [% classes %]" data-toggle="popover" data-html="true" [% HTML.attributes('data-content' => content, 'data-placement' => placement || 'bottom') %]>
[% title %]
</div>
[% END;
BLOCK menuItem %]
<li class="[% IF "${root}${curUri}" == uri %]active[% END %]" [% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>
<a [% HTML.attributes(href => uri) %] [%+ IF modal %]data-toggle="modal"[% END %]>
[% IF icon %]<i class="[% icon %] icon-black"></i> [%+ END %]
[% title %]
</a>
</li>
[% END;
BLOCK makeStar %]
<span class="star" data-post="[% starUri %]">[% IF starred; "★"; ELSE; "☆"; END %]</span>
[% END;
BLOCK renderJobsetOverview %]
<table class="table table-striped table-condensed clickable-rows">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Description</th>
<th>Last evaluated</th>
<th colspan="2">Success</th>
</tr>
</thead>
<tbody>
[% FOREACH j IN jobsets %]
[% successrate = 0 %]
<tr>
<td>
[% IF j.get_column('nrscheduled') > 0 %]
<img src="[% c.uri_for("/static/images/help_16.png") %]" alt="Scheduled" />
[% ELSIF j.get_column('nrfailed') == 0 %]
<img src="[% c.uri_for("/static/images/checkmark_16.png") %]" alt="Succeeded" />
[% ELSIF j.get_column('nrfailed') > 0 && j.get_column('nrsucceeded') > 0 %]
<img src="[% c.uri_for("/static/images/error_some_16.png") %]" alt="Some Failed" />
[% ELSE %]
<img src="[% c.uri_for("/static/images/error_16.png") %]" alt="All Failed" />
[% END %]
</td>
<td><span class="[% IF !j.enabled %]disabled-jobset[% END %] [%+ IF j.hidden %]hidden-jobset[% END %]">[% IF showProject; INCLUDE renderFullJobsetName project=j.get_column('project') jobset=j.name inRow=1; ELSE; INCLUDE renderJobsetName project=j.get_column('project') jobset=j.name inRow=1; END %]</span></td>
<td>[% HTML.escape(j.description) %]</td>
<td>[% IF j.lastcheckedtime; INCLUDE renderDateTime timestamp = j.lastcheckedtime; ELSE; "-"; END %]</td>
[% IF j.get_column('nrtotal') > 0 %]
[% successrate = ( j.get_column('nrsucceeded') / j.get_column('nrtotal') )*100 %]
[% IF j.get_column('nrscheduled') > 0 %]
[% class = 'label' %]
[% ELSIF successrate < 25 %]
[% class = 'label label-important' %]
[% ELSIF successrate < 75 %]
[% class = 'label label-warning' %]
[% ELSIF successrate <= 100 %]
[% class = 'label label-success' %]
[% END %]
[% END %]
<td><span class="[% class %]">[% successrate FILTER format('%d') %]%</span></td>
<td>
[% IF j.get_column('nrsucceeded') > 0 %]
<span class="label label-success">[% j.get_column('nrsucceeded') %]</span>
[% END %]
[% IF j.get_column('nrfailed') > 0 %]
<span class="label label-important">[% j.get_column('nrfailed') %]</span>
[% END %]
[% IF j.get_column('nrscheduled') > 0 %]
<span class="label label">[% j.get_column('nrscheduled') %]</span>
[% END %]
</td>
</tr>
[% END %]
</tbody>
</table>
[% END;
BLOCK includeFlot %]
<script src="[% c.uri_for("/static/js/flot/jquery.flot.min.js") %]" type="text/javascript"></script>
<script src="[% c.uri_for("/static/js/flot/jquery.flot.time.min.js") %]" type="text/javascript"></script>
<script src="[% c.uri_for("/static/js/flot/jquery.flot.selection.min.js") %]" type="text/javascript"></script>
[% END;
BLOCK createChart %]
<div id="[%id%]-chart" style="width: 1000px; height: 400px;"></div>
<div id="[%id%]-overview" style="margin-top: 20px; margin-left: 50px; margin-right: 50px; width: 900px; height: 100px"></div>
<script type="text/javascript">
$(function() {
requestJSON({
url: "[%dataUrl%]",
success: function(data) {
var ids = [];
var d = [];
var max = 0;
data.forEach(function(x) {
var t = x.timestamp * 1000;
ids[t] = x.id;
d.push([t, x.value [% IF yaxis == "mib" %] / (1024.0 * 1024.0)[% END %]]);
max = Math.max(t, max);
});
var options = {
xaxis: { mode: "time" },
yaxis: { min: 0 },
selection: { mode: "x" },
points: { show: true },
lines: { show: true },
grid: {
clickable: true,
hoverable: true,
hoverFill: '#444',
hoverRadius: 4,
},
};
var plot = $.plot($("#[%id%]-chart"), [d], options);
var overview = $.plot($("#[%id%]-overview"), [d], {
series: {
lines: { show: true, lineWidth: 1 },
shadowSize: 0
},
xaxis: { ticks: [], mode: "time" },
yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
selection: { mode: "x" }
});
// now connect the two
$("#[%id%]-chart").bind("plotselected", function (event, ranges) {
var ymax = 0;
d.forEach(function(x) {
if (x[0] < ranges.xaxis.from) return;
if (x[0] > ranges.xaxis.to) return;
ymax = Math.max(x[1], ymax);
});
// do the zooming
plot = $.plot($("#[%id%]-chart"), [d],
$.extend(true, {}, options, {
xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
yaxis: { min: 0, max: ymax * 1.1 }
}));
// don't fire event on the overview to prevent eternal loop
overview.setSelection(ranges, true);
});
$("#[%id%]-overview").bind("plotselected", function (event, ranges) {
plot.setSelection(ranges);
});
$("#[%id%]-chart").bind("plotclick", function (e, pos, item) {
if (item) {
plot.highlight(item.series, item.datapoint);
buildid = data[item.dataIndex].id;
window.location = "/build/"+buildid;
}
});
// Zoom in to the last two months by default.
plot.setSelection({ xaxis: { from: max - 60 * 24 * 60 * 60 * 1000, to: max } });
}
});
});
</script>
[% END;
%]