* HydraFrontend -> Hydra.

This commit is contained in:
Eelco Dolstra
2008-11-25 10:53:42 +00:00
parent 4b478eb8df
commit fadd7a0448
48 changed files with 0 additions and 0 deletions

374
src/Hydra/root/build.tt Normal file
View File

@ -0,0 +1,374 @@
[% WRAPPER layout.tt title="Hydra Overview" %]
[% PROCESS common.tt %]
[% USE HTML %]
[% USE date %]
[% USE mibs=format("%.2f") %]
<h1>
Job <tt>[% build.project.name %]:[% build.attrname %]</tt> build [% id %]
[% IF !build.finished %]
[% IF build.schedulingInfo.busy %]
(currently building)
[% ELSE %]
(scheduled)
[% END %]
[% END %]
</h1>
<h2>Information</h2>
<table>
<tr>
<th>Build ID:</th>
<td>[% build.id %]</td>
</tr>
<tr>
<th>Time added:</th>
<td>[% date.format(build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
</tr>
<tr>
<th>Status:</th>
<td>
[% IF build.finished %]
[% IF build.resultInfo.buildstatus == 0 %]
<img src="/static/images/success.gif" />
<strong>Success</strong>
[% ELSIF build.resultInfo.buildstatus == 1 %]
<img src="/static/images/failure.gif" />
<span class="error">Build returned a non-zero exit code</span>
[% ELSIF build.resultInfo.buildstatus == 2 %]
<img src="/static/images/failure.gif" />
<span class="error">A dependency of the build failed</span>
[% ELSE %]
<img src="/static/images/failure.gif" />
<span class="error">Build failed</span>
(see <a href="#nix-error">below</a>)
[% END %]
[% ELSIF build.schedulingInfo.busy %]
<strong>Build in progress</strong>
[% ELSE %]
<strong>Scheduled to be built</strong>
[% END %]
</td>
</tr>
<tr>
<th>Project:</th>
<td><a href="[% c.uri_for('/project' build.project.name) %]"><tt>[% build.project.name %]</tt></a></td>
</tr>
<tr>
<th>Jobset:</th>
<td><tt>[% build.jobset.name %]</tt></td>
</tr>
<tr>
<th>Job name:</th>
<td><a href="[% c.uri_for('/job' build.project.name build.attrname) %]"><tt>[% build.attrname %]</tt></a></td>
</tr>
<tr>
<th>Nix name:</th>
<td><tt>[% build.nixname %]</tt></td>
</tr>
<tr>
<th>Description:</th>
<td>[% build.description %]</td>
</tr>
<tr>
<th>System:</th>
<td><tt>[% build.system %]</tt></td>
</tr>
<tr>
<th>Derivation store path:</th>
<td><tt>[% build.drvpath %]</tt></td>
</tr>
<tr>
<th>Output store path:</th>
<td><tt>[% build.outpath %]</tt></td>
</tr>
[% IF build.finished %]
<tr>
<th>Build started:</th>
<td>[% IF build.resultInfo.starttime %][% date.format(build.resultInfo.starttime, '%Y-%m-%d %H:%M:%S') %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Build finished:</th>
<td>[% IF build.resultInfo.stoptime %][% date.format(build.resultInfo.stoptime, '%Y-%m-%d %H:%M:%S') %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Duration (seconds):</th>
<td>
[% IF build.resultInfo.iscachedbuild %]
<em>(cached build)</em>
[% ELSE %]
[% build.resultInfo.stoptime - build.resultInfo.starttime %]
[% END %]
</td>
</tr>
[% IF build.resultInfo.logfile %]
<tr>
<th>Logfile:</th>
<td>
<a href="[% c.uri_for('/log' build.id) %]"><strong>Available</strong></a>
</td>
</tr>
[% END %]
[% ELSE %]
<tr>
<th>Priority:</th>
<td>[% build.schedulingInfo.priority %]</td>
</tr>
[% IF build.schedulingInfo.busy %]
<tr>
<th>Logfile:</th>
<td><tt>[% build.schedulingInfo.logfile %]</tt></td>
</tr>
[% END %]
[% END %]
</table>
<h2>Build inputs</h2>
<table class="tablesorter">
<thead>
<tr><th>Name</th><th>Type</th><th>What</th><th>Store path</th></tr>
</thead>
<tbody>
[% FOREACH input IN build.inputs -%]
<tr>
<td><tt>[% input.name %]</tt></td>
<td><tt>[% type = input.type; inputTypes.$type %]</tt></td>
<td>
[% IF input.type == "build" %]
<a href="[% c.uri_for('/build' input.dependency.id) %]">Job <tt>[% input.dependency.project.name %]:[% input.dependency.attrname %]</tt> build [% input.dependency.id %]</a>
[% ELSIF input.type == "string" %]
<tt>"[% input.value %]"</tt>
[% ELSE %]
<tt>[% input.uri %]</tt>
[% END %]
</td>
<td><tt>[% input.path %]</tt></td>
</tr>
[% END -%]
</tbody>
</table>
[% IF build.buildsteps %]
<h2 id="buildsteps">Build steps</h2>
<table class="tablesorter">
<thead>
<tr><th>Nr</th><th>What</th><th>Duration</th><th>Status</th></tr>
</thead>
<tbody>
[% FOREACH step IN build.buildsteps -%]
<tr>
<td>[% step.stepnr %]</td>
<td>
[% IF step.type == 0 %]
Build of <tt>[% step.outpath %]</tt>
[% ELSE %]
Substitution of <tt>[% step.outpath %]</tt>
[% END %]
</td>
<td>
[% IF step.busy == 0 %]
[% step.stoptime - step.starttime %]s
[% ELSE %]
[% IF build.finished %]
[% build.resultInfo.stoptime - step.starttime %]s
[% ELSE %]
[% curTime - step.starttime %]s
[% END %]
[% END %]
</td>
<td>
[% IF step.busy == 1 %]
[% IF build.finished %]
<span class="error">Aborted</span>
[% ELSE %]
<strong>Building</strong>
[% END %]
[% ELSIF step.status == 0 %]
Succeeded
[% ELSE %]
<span class="error">Failed: [% HTML.escape(step.errormsg) %]</span>
[% END %]
[% IF step.logfile %]
(<a href="[% c.uri_for('/nixlog' build.id step.stepnr) %]">log</a>)
[% END %]
</td>
</tr>
[% END %]
</tbody>
</table>
[% END %]
[% IF build.finished %]
[% IF build.resultInfo.errormsg %]
<h2 id="nix-error">Nix error output</h2>
<pre class="buildlog">
[% HTML.escape(build.resultInfo.errormsg) -%]
</pre>
[% END %]
[% IF build.buildproducts %]
<h2>Build products</h2>
<ul class="productList">
[% FOREACH product IN build.buildproducts -%]
<li class="product">
[% SWITCH product.type %]
[% CASE "nix-build" %]
<a href="[% c.uri_for('/closure' build.id product.productnr) %]">
<img src="/static/images/nix-build.png" alt="Source" />
Nix build of path <tt>[% product.path %]</tt>
</a>
[<a class="productDetailsToggle" href="javascript:">help</a>]
<div class="help productDetails">
<p>If you have Nix installed on your machine, this build and all
its dependencies can be unpacked into your local Nix store by
doing:</p>
<pre>$ gunzip < [% HTML.escape(build.nixname) %].closure.gz | nix-store --import</pre>
or to download and unpack in one command:
<pre>$ curl [% c.uri_for('/closure' build.id product.productnr) %] | gunzip | nix-store --import</pre>
<p>The package can then be found in the path <tt>[%
product.path %]</tt>. If you get the error message “imported
archive lacks a signature”, you should make sure that you have
sufficient access rights to the Nix store, e.g., run the
command as <tt>root</tt>.</p>
</div>
[% CASE "file" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
[% SWITCH product.subtype %]
[% CASE "source-dist" %]
<img src="/static/images/source-dist.png" alt="Source" /> Source distribution <tt>[% product.name %]</tt>
[% CASE "rpm" %]
<img src="/static/images/rpm.png" alt="RPM" /> RPM package <tt>[% product.name %]</tt>
[% CASE "deb" %]
<img src="/static/images/debian.png" alt="RPM" /> Debian package <tt>[% product.name %]</tt>
[% CASE DEFAULT %]
File <tt>[% product.name %]</tt> of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[<a class="productDetailsToggle" href="javascript:">details</a>]
<div class="productDetails">
<table>
<tr>
<th>URL:</th>
<td>
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<tt>[% c.uri_for('/download' build.id product.productnr product.name) %]</tt>
</a>
</td>
</tr>
<tr><th>File size:</th><td>[% product.filesize %] bytes ([% mibs(product.filesize / (1024 * 1024)) %] MiB)</td></tr>
<tr><th>SHA-1 hash:</th><td>[% product.sha1hash %]</td></tr>
<tr><th>SHA-256 hash:</th><td>[% product.sha256hash %]</td></tr>
<tr><th>Full path:</th><td><tt>[% product.path %]</tt></td></tr>
</table>
</div>
[% CASE "report" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<img src="/static/images/report.png" alt="Report" />
[% SWITCH product.subtype %]
[% CASE "coverage" %]
Code coverage analysis report
[% CASE DEFAULT %]
Report of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[% CASE "doc" %]
<a href="[% c.uri_for('/download' build.id product.productnr product.name) %]">
<img src="/static/images/document.png" alt="Document" />
[% SWITCH product.subtype %]
[% CASE "readme" %]
“README” file
[% CASE DEFAULT %]
Documentation of type <tt>[% product.subtype %]</tt>
[% END %]
</a>
[% CASE DEFAULT %]
Something of type <tt>[% product.type %]</tt>
[% END %]
</li>
[% END -%]
</ul>
<script>
$(document).ready(function() {
$('.productDetailsToggle').toggle(
function () { $(".productDetails", $(this).parents(".product")).fadeIn(); },
function () { $(".productDetails", $(this).parents(".product")).hide(); }
);
});
</script>
[% END %]
[% IF build.dependents %]
<h2>Used by</h2>
<p>The following builds have used this build as an input:</p>
<table class="tablesorter">
<thead>
<tr><th>Build</th><th>Input name</th><th>System</th><th>Timestamp</th></tr>
</thead>
<tbody>
[% FOREACH input IN build.dependents -%]
<tr>
<td><a href="[% c.uri_for('/build' input.build.id) %]">Job <tt>[% input.build.project.name %]:[% input.build.attrname %]</tt> build [% input.build.id %]</a></td>
<td><tt>[% input.name %]</tt></td>
<td><tt>[% input.build.system %]</tt></td>
<td>[% date.format(input.build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
</tr>
[% END -%]
</tbody>
</table>
[% END %]
[% ELSIF build.schedulingInfo.busy %]
<h2>Log</h2>
<pre class="buildlog">
[% HTML.escape(logtext) -%]
</pre>
[% END %]
[% END %]

9
src/Hydra/root/common.tt Normal file
View File

@ -0,0 +1,9 @@
[% inputTypes =
{ "svn" = "Subversion checkout"
, "cvs" = "CVS checkout"
, "tarball" = "Download of a tarball"
, "string" = "String value"
, "path" = "Local path"
, "build" = "Build output"
}
%]

8
src/Hydra/root/error.tt Normal file
View File

@ -0,0 +1,8 @@
[% WRAPPER layout.tt title="Hydra Overview" %]
[% USE HTML %]
<h1>Error</h1>
<p>I'm very sorry, but an error occurred: <span class="error-msg">[% HTML.escape(error) %]</span></p>
[% END %]

79
src/Hydra/root/index.tt Normal file
View File

@ -0,0 +1,79 @@
[% WRAPPER layout.tt title="Hydra Overview" %]
[% USE date %]
<h1>Hydra Overview</h1>
<h2>Queue</h2>
[% IF scheduled.size == 0 %]
<p>The queue is empty.</p>
[% ELSE %]
<table class="tablesorter">
<thead>
<tr><th>#</th><th>Priority</th><th>Project</th><th>Job</th><th>System</th><th>Timestamp</th><th>Description</th></tr>
</thead>
<tbody>
[% FOREACH build IN scheduled -%]
<tr [% IF build.schedulingInfo.busy %]class="runningJob"[% END %] >
<td><a href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td>
<td>[% build.schedulingInfo.priority %]</td>
<td><tt>[% build.project.name %]</tt></td>
<td><tt>[% build.attrname %]</tt></td>
<td><tt>[% build.system %]</tt></td>
<td>[% date.format(build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
<td>[% build.description %]</td>
</tr>
[% END -%]
</tbody>
</table>
[% END %]
<h2>Job status</h2>
<p>Below are the latest builds for each job.</p>
<table class="tablesorter">
<thead>
<tr><th></th><th>#</th><th>Project</th><th>Job</th><th>System</th><th>Timestamp</th><th>Description</th></tr>
</thead>
<tbody>
[% FOREACH build IN latestBuilds -%]
[% INCLUDE "short-build-info.tt" %]
[% END -%]
</tbody>
</table>
<h2>All builds</h2>
<p>Number of builds: [% allBuilds.size %]</p>
<table class="tablesorter">
<thead>
<tr><th></th><th>#</th><th>Project</th><th>Job</th><th>System</th><th>Timestamp</th><th>Description</th></tr>
</thead>
<tbody>
[% FOREACH build IN allBuilds -%]
[% INCLUDE "short-build-info.tt" %]
[% END -%]
</tbody>
</table>
<h2>Projects</h2>
<ul>
[% FOREACH project IN projects -%]
<li><a href="[% c.uri_for('/project' project.name) %]"><tt>[% project.name %]</tt></a></li>
[% END -%]
</ul>
[% END %]

16
src/Hydra/root/job.tt Normal file
View File

@ -0,0 +1,16 @@
[% WRAPPER layout.tt title="Hydra Overview" %]
<h1>All builds for job <tt>[% curProject.name %]:[% jobName %]</tt></h1>
<table class="tablesorter">
<thead>
<tr><th></th><th>Id</th><th>Project</th><th>Job</th><th>System</th><th>Timestamp</th><th>Description</th></tr>
</thead>
<tbody>
[% FOREACH build IN builds -%]
[% INCLUDE "short-build-info.tt" %]
[% END -%]
</tbody>
</table>
[% END %]

122
src/Hydra/root/layout.tt Normal file
View File

@ -0,0 +1,122 @@
[% USE date -%]
[% USE HTML -%]
<?xml version="1.0" encoding="UTF-8"?>
[% BLOCK makeLink %]
<li [% IF curUri == uri %]class="active"[% END %]>
<div class="title"><a href="[% uri %]">[% title %]</a></div>
</li>
[% END %]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>[% title %]</title>
<link rel="stylesheet" href="/static/css/hydra.css" type="text/css" />
<link rel="stylesheet" href="/static/css/logfile.css" type="text/css" />
<script type="text/javascript" src="/static/js/jquery-pack.js"></script>
<script type="text/javascript" src="/static/js/tablesorter/jquery.tablesorter.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("table.tablesorter").tablesorter();
/* Set the appearance of the toggle depending on whether the
corresponding subtree is initially shown or hidden. */
$(".logTreeToggle").map(function() {
if ($(this).siblings("ul:hidden").length == 0) {
$(this).text("-");
} else {
$(this).text("+");
}
});
/* When a toggle is clicked, show or hide the subtree. */
$(".logTreeToggle").click(function() {
if ($(this).siblings("ul:hidden").length != 0) {
$(this).siblings("ul").show();
$(this).text("-");
} else {
$(this).siblings("ul").hide();
$(this).text("+");
}
});
/* Implementation of the expand all link. */
$(".logTreeExpandAll").click(function() {
$(".logTreeToggle", $(this).siblings(".toplevel")).map(function() {
$(this).siblings("ul").show();
$(this).text("-");
});
});
/* Implementation of the collapse all link. */
$(".logTreeCollapseAll").click(function() {
$(".logTreeToggle", $(this).siblings(".toplevel")).map(function() {
$(this).siblings("ul").hide();
$(this).text("+");
});
});
});
</script>
</head>
<body>
<div id="container">
<div id="leftnavbar">
<ul class="menu">
<li>
<div class="title">Hydra</div>
<ul class="submenu">
[% INCLUDE makeLink uri = c.uri_for('/') title = "Overview" %]
[% INCLUDE makeLink uri = c.uri_for('/queue') title = "Queue" %]
[% INCLUDE makeLink uri = c.uri_for('/latest') title = "Latest builds" %]
[% INCLUDE makeLink uri = c.uri_for('/all') title = "All builds" %]
[% INCLUDE makeLink uri = c.uri_for('/search') title = "Search builds" %]
</ul>
</li>
<li>
<div class="title">Projects</div>
<ul class="submenu">
[% FOREACH project IN projects %]
<li [% IF curUri == c.uri_for('/project' project.name) %]class="active"[% END %]>
<div class="title"><a href="[% c.uri_for('/project' project.name) %]">[% HTML.escape(project.displayname) %]</a></div>
[% IF curProject.name == project.name %]
<ul class="subsubmenu">
[% INCLUDE makeLink uri = c.uri_for('/project' project.name 'edit') title = "Edit" %]
[% INCLUDE makeLink uri = c.uri_for('/project' project.name 'status') title = "Status" %]
[% INCLUDE makeLink uri = c.uri_for('/project' project.name 'all') title = "All builds" %]
</ul>
[% END %]
</li>
[% END %]
</ul>
</li>
<li>
<div class="title">Admin</div>
<ul class="submenu">
[% INCLUDE makeLink uri = c.uri_for('/users') title = "Users" %]
[% INCLUDE makeLink uri = c.uri_for('/createproject') title = "Create a project" %]
</ul>
</li>
</ul>
</div>
<div id="content">
[% content %]
<div id="footer">
<hr />
Generated at [% date.format %].
</div>
</div>
</div>
</body>
</html>

9
src/Hydra/root/log.tt Normal file
View File

@ -0,0 +1,9 @@
[% WRAPPER layout.tt title="Hydra Overview" %]
<h1>Logfile for <tt>[% build.project.name %]:[% build.attrname %]</tt> build [% build.id %][%IF step %], step [% step.stepnr %] (<tt>[% step.outpath %]</tt>)[% END %]</h1>
<div class="buildlog">
[% logtext -%]
</div>
[% END %]

296
src/Hydra/root/project.tt Normal file
View File

@ -0,0 +1,296 @@
[% WRAPPER layout.tt title="Hydra Overview" %]
[% PROCESS common.tt %]
[% USE HTML %]
[% BLOCK renderSelection %]
[% IF edit %]
<select [% HTML.attributes(id => param, name => param) %]>
[% FOREACH name IN options.keys.sort %]
<option [% HTML.attributes(value => name) %] [% IF name == curValue; "selected='selected'"; END %]>[% options.$name %]</option>
[% END %]
</select>
[% ELSE %]
[% options.$curValue %]
[% END %]
[% END %]
[% BLOCK maybeEditString %]
[% IF edit %]
<input type="text" class="string [% extraClass %]" [% HTML.attributes(id => param, name => param, value => value) %] />
[% ELSE %]
[% HTML.escape(value) %]
[% END %]
[% END %]
[% BLOCK renderInputAlt %]
[% IF edit %]<button type="button" onclick='$(this).parents(".inputalt").remove()'><img src="/static/images/failure.gif" alt="Delete value" /></button>[% END -%]
[% INCLUDE maybeEditString param=param value=alt.value %]
[% IF edit %]<br />[% END %]
[% END %]
[% BLOCK renderInput %]
<tr class="input [% extraClass %]" id="[% id %]">
<td>
[% IF edit %]<button type="button" onclick='$(this).parents(".input").remove()'><img src="/static/images/failure.gif" alt="Delete input" /></button>[% END -%]
<tt>[% INCLUDE maybeEditString param="$baseName-name" value=input.name extraClass="shortString" %]</tt>
</td>
<td>
[% INCLUDE renderSelection curValue=input.type param="$baseName-type" options=inputTypes %]
</td>
<td class="inputalts" id="[% baseName %]">
[% FOREACH alt IN input.jobsetinputalts -%]
<tt class="inputalt">
[% IF input.type == "string" && !edit %]
"[% HTML.escape(alt.value) %]"
[% ELSE %]
[% INCLUDE renderInputAlt alt=alt param="$baseName-values" %]
[% END %]
</tt>
[% END %]
[% IF edit %]<button type="button" onclick='return false' class="add-inputalt">+</button>[% END %]
</td>
</tr>
[% END %]
[% BLOCK renderJobset %]
<div class="jobset[% IF edit %] jobset-edit[% END %]" id="[% "jobset-$baseName" %]">
<h3>
[% IF edit %]<button type="button" onclick='$(this).parents(".jobset").remove()'><img src="/static/images/failure.gif" alt="Delete value" /></button>[% END %]
[% IF jobset %]Jobset <tt>[% jobset.name %]</tt>[% ELSE %]New jobset[% END %]
</h3>
<h4>Information</h4>
<table>
[% IF edit %]
<tr>
<th>Identifier:</th>
<td>[% INCLUDE maybeEditString param="jobset-$baseName-name" value=jobset.name %]</td>
</tr>
[% END %]
<tr>
<th>Description:</th>
<td>[% INCLUDE maybeEditString param="jobset-$baseName-description" value=jobset.description %]</td>
</tr>
<tr>
<th>Nix expression:</th>
<td>
<tt>[% INCLUDE maybeEditString param="jobset-$baseName-nixexprpath" value=jobset.nixexprpath extraClass="shortString" %]</tt> in input
<tt>[% INCLUDE maybeEditString param="jobset-$baseName-nixexprinput" value=jobset.nixexprinput extraClass="shortString" %]</tt>
</td>
</tr>
</table>
<h4>Inputs</h4>
<table class="tablesorter">
<thead>
<tr><th>Input name</th><th>Type</th><th>Values</th></tr>
</thead>
<tbody class="inputs">
[% FOREACH input IN jobset.jobsetinputs -%]
[% INCLUDE renderInput input=input baseName="jobset-$baseName-input-$input.name" %]
[% END %]
[% IF edit %]
<tr>
<td colspan="3"><button type="button" class="add-input">Add a new input</button></td>
</tr>
[% END %]
</tbody>
</table>
</div>
[% END %]
[% IF edit %]
<form action="[% IF create %][% c.uri_for('/createproject/submit') %][% ELSE %][% c.uri_for('/project' curProject.name 'submit') %][% END %]" method="post">
[% END %]
[% IF create %]
<h1>New Project</h1>
[% ELSE %]
<h1>Project <tt>[% curProject.name %]</tt></h1>
[% END %]
<h2>General information</h2>
<table>
[% IF edit %]
<tr>
<th>Identifier:</th>
<td><tt>[% INCLUDE maybeEditString param="name" value=curProject.name %]</tt></td>
</tr>
[% END %]
<tr>
<th>Display name:</th>
<td>[% INCLUDE maybeEditString param="displayname" value=curProject.displayname %]</td>
</tr>
<tr>
<th>Description:</th>
<td>[% INCLUDE maybeEditString param="description" value=curProject.description %]</td>
</tr>
<tr>
<th>Enabled:</th>
<td>
[% INCLUDE renderSelection param="enabled" curValue=curProject.enabled options={"1" = "Yes", "0" = "No"} %]
</td>
</tr>
</table>
<h2>Jobsets</h2>
[% IF curProject.jobsets && curProject.jobsets.size > 0 || edit %]
[% IF edit %]
<p><button type="button" id="add-jobset">Add a new jobset</button></p>
<div id="jobset-template" class="template">
[% INCLUDE renderJobset jobset="" baseName="template" %]
</div>
<table class="template"> <!-- dummy wrapper needed because “hidden” trs are visible anyway -->
[% INCLUDE renderInput input="" extraClass="template" id="input-template" baseName="input-template" %]
</table>
<tt class="inputalt template" id="inputalt-template">
[% INCLUDE renderInputAlt alt=alt %]
</tt>
<script>
$(document).ready(function() {
var id = 0;
$("#add-jobset").click(function() {
var newid = "jobset-" + id++;
var x = $("#jobset-template").clone(true).attr("id", newid).insertAfter($("#jobset-template")).slideDown("fast");
$("#jobset-template", x).attr("id", newid);
$("#jobset-template-name", x).attr("name", newid + "-name");
$("#jobset-template-description", x).attr("name", newid + "-description");
$("#jobset-template-nixexprpath", x).attr("name", newid + "-nixexprpath");
$("#jobset-template-nixexprinput", x).attr("name", newid + "-nixexprinput");
return false;
});
$(".add-input").click(function() {
var jobset = $(this).parents(".jobset");
var inputid = jobset.attr("id");
var newid = inputid + "-input-" + id++;
var x = $("#input-template").clone(true).attr("id", "").insertBefore($(this).parents("tr")).show();
$("#input-template-name", x).attr("name", newid + "-name");
$("#input-template-type", x).attr("name", newid + "-type");
$("#input-template", x).attr("id", newid);
return false;
});
$(".add-inputalt").click(function() {
var x = $("#inputalt-template").clone(true).insertBefore($(this)).attr("id", "").show();
$("input", x).attr("name", x.parents(".inputalts").attr("id") + "-values");
});
});
</script>
[% END %]
[% FOREACH jobset IN curProject.jobsets -%]
[% INCLUDE renderJobset jobset=jobset baseName=jobset.name %]
[% END -%]
[% ELSE %]
<p>No jobsets have been defined yet.</p>
[% END %]
[% IF !edit %]
<h2>Jobs</h2>
[% IF jobName && jobNames.size > 0 %]
<ul>
[% FOREACH jobName IN jobNames -%]
<li><a href="[% c.uri_for('/job' curProject.name jobName.attrname) %]"><tt>[% jobName.attrname %]</tt></a></li>
[% END %]
</ul>
[% ELSE %]
<p>No builds have been performed or scheduled.</p>
[% END %]
<h2>Statistics</h2>
<table>
<tr>
<th>Finished builds:</th>
<td>[% finishedBuilds %]</td>
</tr>
<tr>
<th><img src="/static/images/success.gif" /> Succeeded builds:</th>
<td>[% succeededBuilds %]</td>
</tr>
<tr>
<th><img src="/static/images/failure.gif" /> Failed builds:</th>
<td>[% finishedBuilds - succeededBuilds %]</td>
</tr>
<tr>
<th>Total build time:</th>
<td>[% totalBuildTime %]s</td>
</tr>
<tr>
<th>Scheduled builds:</th>
<td>[% scheduledBuilds %]</td>
</tr>
<tr>
<th>Currently executing builds:</th>
<td>[% busyBuilds %]</td>
</tr>
</table>
[% END %]
[% IF edit %]
<hr />
<p><button type="submit"><img src="/static/images/success.gif" />[%IF create %]Create[% ELSE %]Apply changes[% END %]</button></p>
</form>
[% IF !create %]
<form action="[% c.uri_for('/project' curProject.name 'delete') %]" method="post">
<p><button id="delete-project" type="submit"><img src="/static/images/failure.gif" />Delete this project</button></p>
</form>
<script>
$("#delete-project").click(function() {
return confirm("Are you sure you want to delete this project?");
});
</script>
[% END %]
[% END %]
[% END %]

View File

@ -0,0 +1,17 @@
[% USE date %]
<tr>
<td>
[% IF build.resultInfo.buildstatus == 0 %]
<img src="/static/images/success.gif" />
[% ELSE %]
<img src="/static/images/failure.gif" />
[% END %]
</td>
<td><a href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td>
<td><a href="[% c.uri_for('/project' build.project.name) %]"><tt>[% build.project.name %]</tt></a></td>
<td><a href="[% c.uri_for('/job' build.project.name build.attrname) %]"><tt>[% build.attrname %]</tt></a></td>
<td><tt>[% build.system %]</tt></td>
<td>[% date.format(build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td>
<td>[% build.description %]</td>
</tr>

View File

@ -0,0 +1,397 @@
body {
font-family: sans-serif;
background: white;
margin: 2em 1em 2em 1em;
}
h1, h2, h3 {
font-weight: bold;
color: #005aa0;
}
h1 {
font-size: 220%;
}
h2 {
font-size: 130%;
margin-top: 1em;
}
h3 {
font-size: 100%;
}
table {
empty-cells: show;
border-collapse: collapse;
border-spacing: 0px;
margin-bottom: 1em;
}
th {
text-align: center;
font-weight: bold;
}
td, th {
padding: 2px 5px;
border: solid black 1px;
}
td {
vertical-align: top;
}
th {
background: #ffffc0;
}
td.pkgname {
font-size: 140%;
font-weight: bold;
color: #005aa0;
background: #ffffe0;
}
td.pkgname table {
border: none;
border-spacing: 0px;
}
td.pkgname table td {
border: none;
}
td.pkgname td.pkgname {
width: 100%;
}
td.reltype {
font-weight: bold;
color: #400000;
}
td.date, span.date, span.svnrev {
color: #400000;
}
a:link { color: #0048b3; }
a:visited { color: #002a6a; }
a:hover { background: #ffffcd; }
span.relname {
font-weight: bold;
}
span.filename, span.command {
font-family: monospace;
}
span.md5 {
font-family: monospace;
color: #400000;
}
.failurewarning {
font-weight: bold;
color: red;
}
p.failurewarning {
font-size: 120%;
}
span.system {
font-style: italic;
}
table.derivationList {
margin-left: 2em;
margin-right: 2em;
}
table.derivationList, table.derivationList td, table.derivationList th {
border: 1px solid #808080;
}
table.derivationList tr.odd {
background: #f0f0f0;
}
table.derivationList td {
vertical-align: top;
}
table.derivationList td.system {
font-style: italic;
}
a {
text-decoration: none;
}
a:hover, a:visited:hover {
text-decoration: underline;
}
img {
border-style: none;
}
table.buildfarmResults td, table.buildfarmResults th {
border: none;
}
td.buildfarmMainColumn {
background-color: #E0E0E0;
border: solid;
}
.error-msg {
color: red;
white-space: pre;
}
.error {
color: red;
font-weight: bold;
}
pre.buildlog {
border: 1px solid black;
padding: 0.3em;
white-space: pre-wrap;
}
div.buildlog {
border: 1px solid black;
padding: 0.3em;
}
ul.productList {
list-style: none;
padding-left: 1em;
}
ul.productList li {
margin-top: 1em;
}
tr.runningJob {
background-color: #ff3030;
color: white;
}
.productDetails {
display: none;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 3em;
}
.template {
display: none;
}
.template {
display: none;
}
div.jobset {
border: solid black 1px;
-moz-border-radius: 1em;
border-radius: 1em;
padding-left: 1em;
padding-right: 1em;
margin-bottom: 1em;
}
div.jobset-edit {
background-color: #f8f8f8;
}
div.jobset-edit h3, div.jobset h3 {
margin-top: 0.5em;
}
div.help {
border: solid black 1px;
padding-left: 1em;
padding-right: 1em;
}
div.help pre {
padding-left: 1.5em;
color: #400000;
}
/* Sortable tables */
table.tablesorter {
text-align: left;
}
table.tablesorter thead tr .header {
background-image: url(/static/js/tablesorter/themes/blue/bg.gif);
background-repeat: no-repeat;
background-position: center right;
cursor: pointer;
}
table.tablesorter thead tr .headerSortUp {
background-image: url(/static/js/tablesorter/themes/blue/asc.gif);
}
table.tablesorter thead tr .headerSortDown {
background-image: url(/static/js/tablesorter/themes/blue/desc.gif);
}
table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
background-color: #ffe000;
}
table.tablesorter thead tr th {
padding-right: 1.5em;
}
/* Navbar */
#leftnavbar {
position: absolute;
left: 0px;
width: 13em;
border-right: 1px solid gray;
}
#content {
position: absolute;
left: 13em;
margin-left: 1em;
margin-right: 1em;
}
h1 {
margin-top: 0em;
}
#leftnavbar ul.menu {
display: block;
padding: 0 0 0 0;
margin: 0 0 0 0;
margin-left: 1em;
margin-right: 1em;
}
#leftnavbar ul.menu a {
color: #005aa0;
}
#leftnavbar ul.menu > li {
list-style: none;
margin: 0 0 0 0;
padding: 0 0 0 0;
margin-bottom: 1.5em;
}
#leftnavbar ul.menu > li > div.title {
text-align: center;
font-weight: bold;
border-width: 0px;
border-bottom-width: 1px;
border-style: solid;
border-color: #c0c0c0;
padding-bottom: 0.5em;
}
#leftnavbar ul.submenu {
padding: 0 0 0 0;
margin-left: 0em;
margin-right: 0em;
}
#leftnavbar ul.submenu > li {
font-size: 90%;
list-style: none;
border-width: 0px;
border-bottom-width: 1px;
border-style: solid;
border-color: #c0c0c0;
margin: 0 0 0 0;
padding: 0 0 0 0;
}
#leftnavbar ul.submenu > li > div.title {
padding-left: 1.3em;
padding-top: 0.5em;
padding-bottom: 0.5em;
background-image: url(/static/images/arrow-right.gif);
background-repeat: no-repeat;
background-position: 0.3em center;
}
#leftnavbar ul.submenu > li.active > div.title {
background-image: url(/static/images/arrow-right-active.gif);
background-color: #eef2ff;
font-weight: bold;
color: #606060;
}
#leftnavbar ul.subsubmenu {
padding-left: 0;
}
#leftnavbar ul.subsubmenu > li {
font-size: 90%;
list-style: none;
margin: 0 0 0 0;
padding: 0 0 0 0;
border-width: 0px;
border-top-width: 1px;
border-style: solid;
border-color: #c0c0c0;
}
#leftnavbar ul.subsubmenu > li > div.title {
padding-left: 3.3em;
padding-top: 0.5em;
padding-bottom: 0.5em;
background-image: url(/static/images/arrow-right.gif);
background-repeat: no-repeat;
background-position: 2.3em center;
}
#leftnavbar ul.subsubmenu > li.active > div.title {
background-image: url(/static/images/arrow-right-active.gif);
background-color: #eef2ff;
font-weight: bold;
color: #606060;
}
#footer {
font-size: 80%;
}
/* Editing */
input.string {
font-family: sans-serif;
font-size: 100%;
background-color: #fffff0;
width: 20em;
}
input.shortString {
width: 7em;
}
select {
background-color: #fffff0;
}
button {
background-color: #f0f0e0;
}

View File

@ -0,0 +1,89 @@
ul.nesting, ul.toplevel {
padding: 0;
margin: 0;
}
ul.toplevel {
list-style-type: none;
}
.line, .head {
padding-top: 0em;
}
ul.nesting li.line, ul.nesting li.lastline {
position: relative;
list-style-type: none;
}
ul.nesting li.line {
padding-left: 2.0em;
}
ul.nesting li.lastline {
padding-left: 2.1em; // for the 0.1em border-left in .lastline > .lineconn
}
li.line {
border-left: 0.1em solid #6185a0;
}
li.line > span.lineconn, li.lastline > span.lineconn {
position: absolute;
height: 0.65em;
left: 0em;
width: 1.5em;
border-bottom: 0.1em solid #6185a0;
}
li.lastline > span.lineconn {
border-left: 0.1em solid #6185a0;
}
em.storeref {
color: #500000;
position: relative;
width: 100%;
}
em.storeref:hover {
background-color: #eeeeee;
}
*.popup {
display: none;
/* background: url('http://losser.st-lab.cs.uu.nl/~mbravenb/menuback.png') repeat; */
background: #ffffcd;
border: solid #555555 1px;
position: absolute;
top: 0em;
left: 0em;
margin: 0;
padding: 0;
z-index: 100;
}
em.storeref:hover span.popup {
display: inline;
}
.logTreeToggle {
text-decoration: none;
font-family: monospace;
font-size: larger;
}
.errorLine {
color: #ff0000;
font-weight: bold;
}
.prio3 {
font-style: italic;
}
code {
white-space: pre-wrap;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B