* Improved the navigation bar: don't include all projects (since that
[?]
Apr 2, 2009, 4:15 PM
ODNCGFQ5FPKFI624BVMLW7PJ2EFJOR3TY66OCZM42UNNTWBCF2TQCDependencies
- [2]
G2YVJTFT* Trim some significant whitespace. - [3]
CV5HAOSH - [4]
KVPYKWZ7* Allow `-' in project/jobset names. - [5]
6ULJO5NI* Urgh. `-' had special significance in HTML form parameters... - [6]
T2232OBS* Add some DB indices to make the /releases page much faster. - [7]
ZNFDFJHG* Provide a redirect to the latest successful release in a release set - [8]
US27ZTX5* HydraFrontend -> Hydra. - [9]
BA46C5LN* Pretty-print the logs. - [10]
PBFZEQLZ - [11]
S66BOMVU* Added authentication. - [12]
7Z3YOKCV* PROCESS -> INCLUDE in most cases. INCLUDE does proper scoping of - [13]
K5BEBWKM - [14]
TQKGQ5R3 - [15]
YTZOC7C5* Editing of jobset inputs. - [16]
RP6WDKE2 - [17]
IN272KZW* Automatically keep all builds in the latest successful release in - [18]
JD27RBKM - [19]
CS7T2XFI - [20]
NDL67SQT* XHTML validity. - [21]
IK53RV4V - [22]
JK2QWPH6 - [23]
FHF6IZJQ* Basic release management: releases are now dynamically computed as - [24]
3E6IP3R3* Add the name of the jobset to ReleaseSetJobs, otherwise we can't - [25]
RI4S7SYT* Job status: show the active jobs. - [26]
M552HLIA* Support variant builds. - [27]
SZZ3PFYF - [28]
W6DC6K4I* Happy Javascript hacking. - [29]
I35CIZI7 - [30]
GCHNNFZP - [31]
TP3PFR5K - [32]
H5REHM3M - [33]
UAPS46BQ - [34]
YTSIRIMK* Separate job status and all builds pages. - [35]
UVMFS73T* Some jQuery / CSS hackery. - [36]
67P45PY4 - [37]
LQNBKF3D - [38]
H7CNGK4O* Log evaluation errors etc. in the DB. - [39]
G6HJY2V4 - [40]
IGNQFFV7* Put the release sets in the navbar. - [41]
DVNWJXWW* Generic declaration of build products. - [42]
DGVPFNCU* Grabbed a logo. TODO: check copyright status. - [43]
B72GLND4 - [44]
7YBYT2LQ - [45]
RU7AQO7U* Role-based access control. Only admins can create projects. Only - [46]
E2ZY5TE5 - [47]
HK32XC42 - [48]
D5QIOJGP* Move everything up one directory. - [49]
J5UVLXOK* Start of a basic Catalyst web interface. - [50]
5NO7NCKT* Refactoring. - [51]
642UCPJM* Get rid of a warning. - [52]
UWVMQIAC* Refactoring. - [53]
HJLYC753* Adding input value alternatives. - [54]
IE3SRMWZ* Show global and per-project statistics. - [55]
5IK6NYKF - [56]
LBNVQXUB* Build the /build stuff in a separate controller. - [57]
KR7QIG6Z - [58]
HCKFTNQ6 - [59]
BVOPAMLS - [60]
WYN733ST* Store build duration, handle cached builds. - [61]
YAPITGB3* Boolean inputs. - [62]
JLDUSNUO* Unify rendering of finished and scheduled builds. - [63]
BHZXGT2H* Channels: provide an index page that lists all the packages in the - [64]
AKAZKCR6* At top-level and for each project, provide two channels: "latest" - [65]
3HZY24CX* Make jobsets viewable under - [66]
KFFNFE4D - [67]
L2E6EVE2* Merged the Build and Job tables. - [68]
7UJ5YV4V* Provide a channel for each project containing all the latest - [69]
SHZLOM5M* eval-jobs -> hydra_eval_jobs. - [70]
NLJJZVHO* Use ->update({...}) properly. - [71]
3ZCEPLNO - [72]
FPK5LF53* Put the project-related actions in a separate controller. Put the - [73]
2AUODJBT - [74]
GNIEG2GC* Disambiguate jobs by jobset name. I.e. jobs with the same name in - [75]
2GK5DOU7* Downloading closures. - [76]
DEMSSSB2* Controller for jobs which inherits all actions in ListBuilds. So - [77]
2AIIYGI5* Show job status and all builds for a project. - [78]
KOTB7BKV - [79]
7ZHHVD6Q* Inputs of type "build" must now be declared explicitly. - [80]
7LKUAIGC - [81]
LQ5QEDVV - [82]
JFZNAYJX* Showing releases. - [83]
ELCI5T2A* Show the latest build for each job. - [84]
OIUIYIV2* Give releases a timestamp. - [85]
WHAFVCEI
Change contents
- edit in src/lib/Hydra/Controller/Job.pm at line 18
sub overview : Chained('job') PathPart('') Args(0) {my ($self, $c) = @_; - edit in src/lib/Hydra/Controller/Job.pm at line 23
$c->stash->{template} = 'job.tt'; - replacement in src/lib/Hydra/Controller/Job.pm at line 25
sub index : Chained('job') PathPart('') Args(0) {getBuildStats($c, scalar $c->stash->{job}->builds);}sub all : Chained('job') PathPart Args(0) { - replacement in src/lib/Hydra/Controller/Jobset.pm at line 25
$c->go($self->action_for("all"));$c->stash->{template} = 'jobset.tt';getBuildStats($c, scalar $c->stash->{jobset}->builds);$c->stash->{activeJobs} = [$c->stash->{jobset}->jobs->search({active => 1})];$c->stash->{inactiveJobs} = [$c->stash->{jobset}->jobs->search({active => 0})]; - edit in src/lib/Hydra/Controller/Jobset.pm at line 42
}sub edit : Chained('jobset') PathPart Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});$c->stash->{template} = 'jobset.tt';$c->stash->{edit} = 1;}sub submit : Chained('jobset') PathPart Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});requirePost($c);$c->model('DB')->schema->txn_do(sub {updateJobset($c, $c->stash->{jobset});});$c->res->redirect($c->uri_for($self->action_for("index"),[$c->stash->{project}->name, $c->stash->{jobset}->name]));}sub delete : Chained('jobset') PathPart Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});requirePost($c);$c->model('DB')->schema->txn_do(sub {$c->stash->{jobset}->delete;});$c->res->redirect($c->uri_for($c->controller('Project')->action_for("view"),[$c->stash->{project}->name]));}sub updateJobset {my ($c, $jobset) = @_;my $jobsetName = trim $c->request->params->{"name"};error($c, "Invalid jobset name: $jobsetName") unless $jobsetName =~ /^[[:alpha:]][\w\-]*$/;# The Nix expression path must be relative and can't contain ".." elements.my $nixExprPath = trim $c->request->params->{"nixexprpath"};error($c, "Invalid Nix expression path: $nixExprPath") if $nixExprPath !~ /^$relPathRE$/;my $nixExprInput = trim $c->request->params->{"nixexprinput"};error($c, "Invalid Nix expression input name: $nixExprInput") unless $nixExprInput =~ /^\w+$/;$jobset->update({ name => $jobsetName, description => trim($c->request->params->{"description"}), nixexprpath => $nixExprPath, nixexprinput => $nixExprInput});my %inputNames;# Process the inputs of this jobset.foreach my $param (keys %{$c->request->params}) {next unless $param =~ /^input-(\w+)-name$/;my $baseName2 = $1;next if $baseName2 eq "template";print STDERR "GOT INPUT: $baseName2\n";my $inputName = trim $c->request->params->{"input-$baseName2-name"};error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/;my $inputType = trim $c->request->params->{"input-$baseName2-type"};error($c, "Invalid input type: $inputType") unless$inputType eq "svn" || $inputType eq "cvs" || $inputType eq "tarball" ||$inputType eq "string" || $inputType eq "path" || $inputType eq "boolean" ||$inputType eq "build";$inputNames{$inputName} = 1;my $input;if ($baseName2 =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry$input = $jobset->jobsetinputs->create({ name => $inputName, type => $inputType});} else { # it's an existing input$input = ($jobset->jobsetinputs->search({name => $baseName2}))[0];die unless defined $input;$input->update({name => $inputName, type => $inputType});}# Update the values for this input. Just delete all the# current ones, then create the new values.$input->jobsetinputalts->delete_all;my $values = $c->request->params->{"input-$baseName2-values"};$values = [] unless defined $values;$values = [$values] unless ref($values) eq 'ARRAY';my $altnr = 0;foreach my $value (@{$values}) {print STDERR "VALUE: $value\n";my $value = trim $value;error($c, "Invalid Boolean value: $value") if$inputType eq "boolean" && !($value eq "true" || $value eq "false");$input->jobsetinputalts->create({altnr => $altnr++, value => $value});}}# Get rid of deleted inputs.my @inputs = $jobset->jobsetinputs->all;foreach my $input (@inputs) {$input->delete unless defined $inputNames{$input->name};} - edit in src/lib/Hydra/Controller/Project.pm at line 26
$c->stash->{releaseSets} = [$c->stash->{project}->releasesets->all]; - replacement in src/lib/Hydra/Controller/Project.pm at line 45
error($c, "Request must be POSTed.") if $c->request->method ne "POST";requirePost($c); - replacement in src/lib/Hydra/Controller/Project.pm at line 51
$c->res->redirect($c->uri_for($self->action_for("view"), $c->req->captures));$c->res->redirect($c->uri_for($self->action_for("view"), [$c->stash->{project}->name])); - replacement in src/lib/Hydra/Controller/Project.pm at line 59
error($c, "Request must be POSTed.") if $c->request->method ne "POST";requirePost($c); - edit in src/lib/Hydra/Controller/Project.pm at line 109
}sub create_jobset : Chained('project') PathPart('create-jobset') Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});$c->stash->{template} = 'jobset.tt';$c->stash->{create} = 1;$c->stash->{edit} = 1;}sub create_jobset_submit : Chained('project') PathPart('create-jobset/submit') Args(0) {my ($self, $c) = @_;requireProjectOwner($c, $c->stash->{project});my $jobsetName = trim $c->request->params->{name};$c->model('DB')->schema->txn_do(sub {# Note: $jobsetName is validated in updateProject, which will# abort the transaction if the name isn't valid.my $jobset = $c->stash->{project}->jobsets->create({name => $jobsetName, nixexprinput => "", nixexprpath => ""});Hydra::Controller::Jobset::updateJobset($c, $jobset);});$c->res->redirect($c->uri_for($c->controller('Jobset')->action_for("index"),[$c->stash->{project}->name, $jobsetName])); - edit in src/lib/Hydra/Controller/Project.pm at line 150
$project->name($projectName);$project->displayname($displayName);$project->description(trim $c->request->params->{description});$project->homepage(trim $c->request->params->{homepage});$project->enabled(trim($c->request->params->{enabled}) eq "1" ? 1 : 0); - edit in src/lib/Hydra/Controller/Project.pm at line 151
my $owner = $project->owner; - replacement in src/lib/Hydra/Controller/Project.pm at line 153
my $owner = trim $c->request->params->{owner};$owner = trim $c->request->params->{owner}; - edit in src/lib/Hydra/Controller/Project.pm at line 156
$project->owner($owner); - edit in src/lib/Hydra/Controller/Project.pm at line 157[7.4653]→[7.4653:4957](∅→∅),[7.4957]→[4.118:218](∅→∅),[4.218]→[7.5053:5514](∅→∅),[7.5053]→[7.5053:5514](∅→∅)
$project->update;my %jobsetNames;foreach my $param (keys %{$c->request->params}) {next unless $param =~ /^jobset-(\w+)-name$/;my $baseName = $1;next if $baseName eq "template";my $jobsetName = trim $c->request->params->{"jobset-$baseName-name"};error($c, "Invalid jobset name: $jobsetName") unless $jobsetName =~ /^[[:alpha:]][\w\-]*$/;# The Nix expression path must be relative and can't contain ".." elements.my $nixExprPath = trim $c->request->params->{"jobset-$baseName-nixexprpath"};error($c, "Invalid Nix expression path: $nixExprPath") if $nixExprPath !~ /^$relPathRE$/;my $nixExprInput = trim $c->request->params->{"jobset-$baseName-nixexprinput"};error($c, "Invalid Nix expression input name: $nixExprInput") unless $nixExprInput =~ /^\w+$/; - replacement in src/lib/Hydra/Controller/Project.pm at line 158[7.5515]→[7.5515:6045](∅→∅),[7.6045]→[5.0:163](∅→∅),[5.163]→[7.61:238](∅→∅),[7.6160]→[7.61:238](∅→∅),[7.238]→[7.6375:7172](∅→∅),[7.6375]→[7.6375:7172](∅→∅),[7.7172]→[7.0:132](∅→∅),[7.132]→[7.7263:7773](∅→∅),[7.7263]→[7.7263:7773](∅→∅),[7.7773]→[7.239:313](∅→∅),[7.313]→[7.7889:9162](∅→∅),[7.7889]→[7.7889:9162](∅→∅)
$jobsetNames{$jobsetName} = 1;my $jobset;my $description = trim $c->request->params->{"jobset-$baseName-description"};if ($baseName =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry$jobset = $project->jobsets->create({ name => $jobsetName, description => $description, nixexprpath => $nixExprPath, nixexprinput => $nixExprInput});} else { # it's an existing jobsetmy $oldName = trim $c->request->params->{"jobset-$baseName-oldName"};$jobset = ($project->jobsets->search({name => $oldName}))[0] or die;$jobset->update({ name => $jobsetName, description => $description, nixexprpath => $nixExprPath, nixexprinput => $nixExprInput });}my %inputNames;# Process the inputs of this jobset.foreach my $param (keys %{$c->request->params}) {next unless $param =~ /^jobset-$baseName-input-(\w+)-name$/;my $baseName2 = $1;next if $baseName2 eq "template";print STDERR "GOT INPUT: $baseName2\n";my $inputName = trim $c->request->params->{"jobset-$baseName-input-$baseName2-name"};error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/;my $inputType = trim $c->request->params->{"jobset-$baseName-input-$baseName2-type"};error($c, "Invalid input type: $inputType") unless$inputType eq "svn" || $inputType eq "cvs" || $inputType eq "tarball" ||$inputType eq "string" || $inputType eq "path" || $inputType eq "boolean" ||$inputType eq "build";$inputNames{$inputName} = 1;my $input;if ($baseName2 =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry$input = $jobset->jobsetinputs->create({ name => $inputName, type => $inputType});} else { # it's an existing jobset$input = ($jobset->jobsetinputs->search({name => $baseName2}))[0];die unless defined $input;$input->update({name => $inputName, type => $inputType});}# Update the values for this input. Just delete all the# current ones, then create the new values.$input->jobsetinputalts->delete_all;my $values = $c->request->params->{"jobset-$baseName-input-$baseName2-values"};$values = [] unless defined $values;$values = [$values] unless ref($values) eq 'ARRAY';my $altnr = 0;foreach my $value (@{$values}) {print STDERR "VALUE: $value\n";my $value = trim $value;error($c, "Invalid Boolean value: $value") if$inputType eq "boolean" && !($value eq "true" || $value eq "false");$input->jobsetinputalts->create({altnr => $altnr++, value => $value});}}# Get rid of deleted inputs.my @inputs = $jobset->jobsetinputs->all;foreach my $input (@inputs) {$input->delete unless defined $inputNames{$input->name};}}# Get rid of deleted jobsets, i.e., ones that are no longer submitted in the parameters.my @jobsets = $project->jobsets->all;foreach my $jobset (@jobsets) {$jobset->delete unless defined $jobsetNames{$jobset->name};}$project->update({ name => $projectName, displayname => $displayName, description => trim($c->request->params->{description}), homepage => trim($c->request->params->{homepage}), enabled => trim($c->request->params->{enabled}) eq "1" ? 1 : 0, owner => $owner}); - edit in src/lib/Hydra/Controller/Root.pm at line 16
$c->stash->{projects} = [$c->model('DB::Projects')->search({}, {order_by => 'displayname'})]; - replacement in src/lib/Hydra/Controller/Root.pm at line 23
$c->stash->{template} = 'index.tt';$c->stash->{template} = 'overview.tt';$c->stash->{projects} = [$c->model('DB::Projects')->search({}, {order_by => 'displayname'})]; - edit in src/lib/Hydra/Controller/Root.pm at line 65[7.57]→[7.57:233](∅→∅),[7.233]→[7.1916:1994](∅→∅),[7.1994]→[7.1098:1135](∅→∅),[7.1135]→[7.355:417](∅→∅),[7.355]→[7.355:417](∅→∅),[7.417]→[7.0:2](∅→∅),[7.3]→[7.3:4](∅→∅),[7.83]→[7.83:84](∅→∅)
sub releasesets :Local {my ($self, $c, $projectName) = @_;$c->stash->{template} = 'releasesets.tt';my $project = $c->model('DB::Projects')->find($projectName);notFound($c, "Project $projectName doesn't exist.") if !defined $project;$c->stash->{project} = $project;$c->stash->{releaseSets} = [$project->releasesets->all];} - replacement in src/lib/Hydra/Helper/CatalystUtils.pm at line 12
requireLogin requireProjectOwner requireAdminrequireLogin requireProjectOwner requireAdmin requirePost - edit in src/lib/Hydra/Helper/CatalystUtils.pm at line 126
}sub requirePost {my ($c) = @_;error($c, "Request must be POSTed.") if $c->request->method ne "POST"; - file deletion: index.tt index.tt index.tt[7.857]→[7.971:1003](∅→∅),[7.1003]→[7.10713:10713](∅→∅),[7.1486]→[7.1715:1747](∅→∅),[7.1747]→[7.10713:10713](∅→∅),[7.7332]→[7.11185:11217](∅→∅),[7.11217]→[7.10713:10713](∅→∅)
<h1>Hydra Overview</h1>[% PROCESS common.tt %][% END %][% INCLUDE showBuildStats %]<h2>Statistics</h2>[% WRAPPER layout.tt title="Overview" %] - file deletion: releasesets.tt releasesets.tt[7.1486]→[7.2052:2090](∅→∅),[7.2090]→[7.10100:10100](∅→∅),[7.857]→[7.10469:10507](∅→∅),[7.10507]→[7.10100:10100](∅→∅)
[% WRAPPER layout.tt title="Release Sets" %][% PROCESS common.tt %]<h1>Release Sets</h1><ul>[% FOREACH releaseSet IN releaseSets %][% END %]</ul>[% END %][% ELSE %][% END %]<p>[<a href="[% c.uri_for('/create_releaseset' project.name) %]">Create a new release set</a>]</p><p>Project <tt>[% project.name %]</tt> has no release sets.</p><li></li><a href="[% c.uri_for('/releases' project.name releaseSet.name) %]"><tt>[% releaseSet.name %]</tt></a>[<a href="[% c.uri_for('/releases' project.name releaseSet.name "edit") %]">Edit</a>]<p>Project <tt>[% project.name %]</tt> has the following release sets:</p>[% IF releaseSets.size > 0 %] - replacement in src/root/build.tt at line 6
[% project = build.get_column('project') %][% jobset = build.get_column('jobset') %][% job = build.get_column('job') %][% project = build.project %][% jobset = build.jobset %][% job = build.job %] - replacement in src/root/build.tt at line 11
Job <tt>[% project %]:[% jobset %]:[% job %]</tt> build [% id %]Job <tt>[% project.name %]:[% jobset.name %]:[% job.name %]</tt> build [% id %] - replacement in src/root/build.tt at line 80
<td>[% INCLUDE renderProjectName %]</td><td>[% INCLUDE renderProjectName project=project.name %]</td> - replacement in src/root/build.tt at line 84
<td>[% INCLUDE renderJobsetName %]</td><td>[% INCLUDE renderJobsetName project=project.name jobset=jobset.name %]</td> - replacement in src/root/build.tt at line 88
<td>[% INCLUDE renderJobName %]</td><td>[% INCLUDE renderJobName project=project.name jobset=jobset.name job=job.name %]</td> - edit in src/root/common.tt at line 2
[% USE HTML %] - edit in src/root/common.tt at line 143
[% END -%][% BLOCK maybeLink -%][% IF uri %]<a [% HTML.attributes(href => uri) %]>[% content %]</a>[% ELSE; content; END -%][% END -%][% 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 -%] - file addition: job.tt[7.1486]
[% WRAPPER layout.tt title="Job ‘$project.name:$jobset.name:$job.name’" %][% PROCESS common.tt %]<h1>Job <tt>[% project.name %]:[% jobset.name %]:[% job.name %]</tt></h1><h2>Channels</h2><p>This job provides the following Nix channels:</p><ul><li><a href="[% c.uri_for('/job' project.name jobset.name job.name'channel' 'latest') %]"><tt>latest</tt></a> — contains the latestsuccessful build for each platform.</li><li><a href="[% c.uri_for('/job' project.name jobset.name job.name'channel' 'all') %]"><tt>all</tt></a> — contains every successfulbuild of this job.</li></ul><h2>Statistics</h2>[% INCLUDE showBuildStats %][% END %] - file addition: jobset.tt[7.1486]
[% WRAPPER layout.tt title=(edit ? (create ? "New Jobset in Project ‘$project.name’" : "Editing Jobset ‘$project.name:$jobset.name’") : "Jobset ‘$project.name:$jobset.name’") %][% PROCESS common.tt %][% IF edit %]<form action="[% IF create %][% c.uri_for('/project' project.name 'create-jobset/submit') %][% ELSE %][% c.uri_for('/jobset' project.name jobset.name 'submit') %][% END %]" method="post">[% END %][% IF create %]<h1>New Jobset in Project <tt>[% project.name %]</tt></h1>[% ELSE %]<h1>Jobset <tt>[% project.name %]:[% jobset.name %]</tt></h1>[% END %][% BLOCK renderInputAlt %][% IF edit %]<button type="button" onclick='$(this).parents(".inputalt").remove()'><img src="/static/images/failure.gif" alt="Delete value" /></button>[% INCLUDE maybeEditString param=param value=alt.value %]<br />[% ELSE %][% INCLUDE maybeEditString param=param value=alt.value %][% END %][% END %][% BLOCK renderInput %]<tr class="input [% extraClass %]" [% IF id %]id="[% id %]"[% END %]><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 %]<h2>Information[% IF !edit %] <a class="smallLink" href="[% c.uri_for('/jobset' project.name jobset.name 'edit') %]">[Edit]</a>[% END %]</h2><table class="layoutTable">[% IF edit %]<tr><th>Identifier:</th><td>[% INCLUDE maybeEditString param="name" value=jobset.name %]</td></tr>[% END %]<tr><th>Description:</th><td>[% INCLUDE maybeEditString param="description" value=jobset.description %]</td></tr><tr><th>Nix expression:</th><td><tt>[% INCLUDE maybeEditString param="nixexprpath" value=jobset.nixexprpath extraClass="shortString" %]</tt> in input<tt>[% INCLUDE maybeEditString param="nixexprinput" value=jobset.nixexprinput extraClass="shortString" %]</tt></td></tr>[% IF !edit %]<tr><th>Last checked:</th><td>[% IF jobset.lastcheckedtime %][% INCLUDE renderDateTime timestamp = jobset.lastcheckedtime -%][% IF jobset.errormsg -%]<em>, evaluation error</em>:<pre class="multiLineMsg error">[% HTML.escape(jobset.errormsg) %]</pre>[% ELSE %], <em>no errors</em>[% END %][% ELSE %]<em>never</em>[% END %]</td></tr>[% END %]</table><h3>Inputs</h3><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="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>[% IF !edit %]<h2>Jobs</h2><p>This jobset currently contains the following [% activeJobs.size %] jobs:<blockquote>[% IF activeJobs.size == 0 %]<em>(none)</em>[% END %][% FOREACH j IN activeJobs %] [% INCLUDE renderJobName project=project.name jobset=jobset.name job=j.name %] [% END %]</blockquote></p><p>This jobset used to contain the following [% inactiveJobs.size %] jobs:<blockquote>[% IF inactiveJobs.size == 0 %]<em>(none)</em>[% END %][% FOREACH j IN inactiveJobs %] [% INCLUDE renderJobName project=project.name jobset=jobset.name job=j.name %] [% END %]</blockquote></p><h2>Channels</h2><p>This jobset provides the following Nix channels:</p><ul><li><a href="[% c.uri_for('/jobset' project.name jobset.name 'channel''latest') %]"><tt>latest</tt></a> — contains the latest successfulbuild of every job in this jobset.</li><li><a href="[% c.uri_for('/jobset' project.name jobset.name 'channel''all') %]"><tt>all</tt></a> — contains every successful,non-garbage-collected build of every job in this project.</li></ul><h2>Statistics</h2>[% INCLUDE showBuildStats %][% END %][% IF edit %]<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 type="text/javascript">$(document).ready(function() {var id = 0;$(".add-input").click(function() {var newid = "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><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('/jobset' project.name jobset.name 'delete') %]" method="post"><p><button id="delete-jobset" type="submit"><img src="/static/images/failure.gif" />Delete this jobset</button></p></form><script type="text/javascript">$("#delete-jobset").click(function() {return confirm("Are you sure you want to delete this jobset?");});</script>[% END %][% END %][% END %] - edit in src/root/layout.tt at line 6[7.25]→[7.126:127](∅→∅),[7.1190]→[7.126:127](∅→∅),[7.11236]→[7.126:127](∅→∅),[7.127]→[7.1404:1432](∅→∅),[7.1432]→[7.148:266](∅→∅),[7.148]→[7.148:266](∅→∅),[7.266]→[7.1433:1451](∅→∅),[7.1451]→[7.266:284](∅→∅),[7.266]→[7.266:284](∅→∅),[7.11275]→[7.11275:11276](∅→∅),[7.11276]→[7.1452:1526](∅→∅)
[% BLOCK makeLinkWrapped %]<li [% IF curUri == uri %]class="active"[% END %]><div class="title"><a href="[% uri %]">[% title %]</a></div>[% content %]</li>[% END %][% BLOCK makeLink -%][% INCLUDE makeLinkWrapped content="" -%][% END %] - replacement in src/root/layout.tt at line 75[7.3682]→[3.0:80](∅→∅),[3.80]→[7.68:77](∅→∅),[7.68]→[7.68:77](∅→∅),[7.77]→[7.1191:1232](∅→∅),[7.3682]→[7.1191:1232](∅→∅),[7.1232]→[7.3726:3769](∅→∅),[7.3726]→[7.3726:3769](∅→∅),[7.3769]→[7.1233:1266](∅→∅),[7.1266]→[7.286:442](∅→∅),[7.3786]→[7.286:442](∅→∅),[7.442]→[7.2186:2274](∅→∅),[7.530]→[7.530:612](∅→∅),[7.700]→[7.4018:4052](∅→∅),[7.4018]→[7.4018:4052](∅→∅),[7.4052]→[7.1267:1283](∅→∅),[7.1283]→[7.4110:4156](∅→∅),[7.4110]→[7.4110:4156](∅→∅),[7.4156]→[7.1284:1317](∅→∅),[7.1317]→[7.2041:2385](∅→∅),[7.2385]→[7.1599:1643](∅→∅),[7.1599]→[7.1599:1643](∅→∅),[7.2938]→[7.1648:1767](∅→∅),[7.1767]→[7.1755:1868](∅→∅),[7.1755]→[7.1755:1868](∅→∅),[7.1868]→[7.1528:2413](∅→∅),[7.2413]→[7.713:745](∅→∅),[7.713]→[7.713:745](∅→∅),[7.746]→[7.8138:8246](∅→∅),[7.3096]→[7.8138:8246](∅→∅),[7.1868]→[7.8138:8246](∅→∅),[7.8246]→[7.1868:1944](∅→∅),[7.1868]→[7.1868:1944](∅→∅),[7.521]→[7.4352:4410](∅→∅),[7.1172]→[7.4352:4410](∅→∅),[7.1944]→[7.4352:4410](∅→∅),[7.4352]→[7.4352:4410](∅→∅),[7.4410]→[7.1945:1961](∅→∅),[7.1961]→[7.4468:4511](∅→∅),[7.4468]→[7.4468:4511](∅→∅),[7.4511]→[7.1962:1995](∅→∅),[7.1995]→[7.4361:4611](∅→∅),[7.4611]→[7.11641:11738](∅→∅),[7.1351]→[7.4682:4730](∅→∅),[7.3037]→[7.4682:4730](∅→∅),[7.4707]→[7.4682:4730](∅→∅),[7.11738]→[7.4682:4730](∅→∅),[7.4682]→[7.4682:4730](∅→∅)
<div id="logo"><img src="/static/images/hydra.png" alt="Hydra" /></div><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('/jobstatus') title = "Job status" %][% INCLUDE makeLink uri = c.uri_for('/all') title = "All 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 project.name == project_.name %]<ul class="subsubmenu">[% INCLUDE makeLink uri = c.uri_for('/project' project.name 'jobstatus') title = "Job status" %][% INCLUDE makeLink uri = c.uri_for('/project' project.name 'all') title = "All builds" %][% WRAPPER makeLinkWrapped uri = c.uri_for('/releasesets' project.name) title = "Releases" %][% IF project.releasesets && project.releasesets.size > 0 %]<ul class="subsubsubmenu">[% FOREACH releaseset IN project.releasesets %][% myUri = c.uri_for('/releases' project.name releaseset.name) %]<li [% IF curUri == myUri %]class="active"[% END %]><div class="title"><a href="[% myUri %]">[% HTML.escape(releaseset.description ? releaseset.description : releaseset.name) %]</a></div></li>[% END %]</ul>[% END %][% END %][% INCLUDE makeLink uri = c.uri_for('/project' project.name 'edit') title = "Edit" %]</ul>[% END %]</li>[% END %]</ul></li><li><div class="title">Admin</div><ul class="submenu">[% IF c.user_exists %][% INCLUDE makeLink uri = c.uri_for('/logout') title = "Logout" %][% ELSE %][% INCLUDE makeLink uri = c.uri_for('/login') title = "Login" %][% END %][% INCLUDE makeLink uri = c.uri_for('/create-project') title = "Create project" %]</ul></li></ul><div id="logo"><a class="no-hover" href="/"><img src="/static/images/hydra.png" alt="Hydra" /></a></div>[% PROCESS navbar.tt %] - file addition: navbar.tt[7.1486]
[% BLOCK makeLinkWrapped %]<li [% IF curUri == uri %]class="active"[% END %]><div class="title"><a href="[% uri %]">[% title %]</a></div>[% content %]</li>[% END %][% BLOCK makeLink -%][% INCLUDE makeLinkWrapped content="" -%][% END %][% BLOCK makeSubMenu %][% extra = collapsed ? "collapsed" : "" %]<li class="submenu"><div class="title [% extra %]"><a class="[% collapsed ? "submenuToggleCollapsed" : "submenuToggleExpanded" %]"href="javascript:">[% HTML.escape(title) %]</a></div><ul class="submenu [% extra %]">[% content %]</ul></li>[% END %]<ul class="menu">[% WRAPPER makeSubMenu title="Hydra" collapsed=0 %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Root').action_for('index'))title = "Overview" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Root').action_for('queue'))title = "Queue" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Root').action_for('all'))title = "All builds" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Root').action_for('jobstatus'))title = "Job status" %][% END %][% IF project %][% WRAPPER makeSubMenu title="Project" collapsed=(jobset || job) %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Project').action_for('view'), [project.name])title = "Overview" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Project').action_for('all'), [project.name])title = "All builds" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Project').action_for('jobstatus'), [project.name])title = "Job status" %][% END %][% END %][% IF jobset %][% WRAPPER makeSubMenu title="Jobset" collapsed=job %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Jobset').action_for('index'), [project.name, jobset.name])title = "Overview" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Jobset').action_for('all'), [project.name, jobset.name])title = "All builds" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Jobset').action_for('jobstatus'), [project.name, jobset.name])title = "Job status" %][% END %][% END %][% IF job %][% WRAPPER makeSubMenu title="Job" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Job').action_for('index'), [project.name, jobset.name, job.name])title = "Overview" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Job').action_for('all'), [project.name, jobset.name, job.name])title = "All builds" %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Job').action_for('jobstatus'), [project.name, jobset.name, job.name])title = "Job status" %][% END %][% END %][% WRAPPER makeSubMenu title="Admin" collapsed=0 %][% IF c.user_exists %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Root').action_for('logout'))title = "Logout" %][% ELSE %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Root').action_for('login'))title = "Login" %][% END %][% INCLUDE makeLinkuri = c.uri_for(c.controller('Project').action_for('create'))title = "Create project" %][% END %]</ul><script type="text/javascript">$(document).ready(function() {$('.submenuToggleExpanded').toggle(function () { $(".submenu", $(this).parents(".submenu")).slideUp(); },function () { $(".submenu", $(this).parents(".submenu")).slideDown(); });$('.submenuToggleCollapsed').toggle(function () { $(".submenu", $(this).parents(".submenu")).slideDown(); },function () { $(".submenu", $(this).parents(".submenu")).slideUp(); });});</script> - file addition: overview.tt[7.1486]
[% WRAPPER layout.tt title="Overview" %][% PROCESS common.tt %]<h1>Hydra Overview</h1><p>Welcome to Hydra, the <a href="http://nixos.org/">Nix-based</a>continuous build system. Hydra continuously builds, tests andreleases software packages from source repositories. <ahref="http://nixos.org/hydra"><em>[Read more...]</em></a></p><h2>Projects</h2><p>The following projects are hosted on this server:</p><table class="tablesorter"><thead><tr><th>Id</th><th>Name</th><th>Description</th></tr></thead><tbody>[% FOREACH p IN projects %]<tr class="clickable [% IF odd %] odd [% END; odd = !odd %]"onclick="window.location = '[% c.uri_for('/project' p.name) %]'"><td>[% INCLUDE renderProjectName project = p.name %]</td><td>[% HTML.escape(p.displayname) %]</td><td>[% WRAPPER maybeLink uri=p.homepage %][% HTML.escape(p.description) %][% END %]</td></tr>[% END %]</tbody></table><h2>Channels</h2><p>This server provides the following global Nix channels:</p><ul><li><a href="[% c.uri_for('channel' 'latest') %]"><tt>latest</tt></a> —contains the latest successful build of every job.</li><li><a href="[% c.uri_for('channel' 'all') %]"><tt>all</tt></a> —contains every successful, non-garbage-collected build of every job.</li></ul><h2>Statistics</h2>[% INCLUDE showBuildStats %][% END %] - edit in src/root/project.tt at line 3
[% USE HTML %] - edit in src/root/project.tt at line 5[7.1716]→[7.3208:3236](∅→∅),[7.3236]→[7.3083:3099](∅→∅),[7.3083]→[7.3083:3099](∅→∅),[7.3099]→[7.3237:3512](∅→∅),[7.2134]→[7.3193:3206](∅→∅),[7.3512]→[7.3193:3206](∅→∅),[7.3876]→[7.3193:3206](∅→∅),[7.3193]→[7.3193:3206](∅→∅),[7.3206]→[7.3513:3541](∅→∅),[7.3541]→[7.3877:3901](∅→∅),[7.3235]→[7.3877:3901](∅→∅),[7.3901]→[2.0:40](∅→∅),[2.40]→[7.3586:3710](∅→∅),[7.3586]→[7.3586:3710](∅→∅),[7.3710]→[2.41:97](∅→∅),[2.97]→[7.28:57](∅→∅),[7.28]→[7.28:57](∅→∅),[7.57]→[7.2888:3209](∅→∅),[7.312]→[7.3247:3257](∅→∅),[7.3209]→[7.3247:3257](∅→∅),[7.4301]→[7.3247:3257](∅→∅),[7.3247]→[7.3247:3257](∅→∅),[7.3257]→[7.484:485](∅→∅),[7.485]→[7.3257:3258](∅→∅),[7.3257]→[7.3257:3258](∅→∅),[7.3258]→[7.486:510](∅→∅),[7.510]→[7.3442:3443](∅→∅),[7.3442]→[7.3442:3443](∅→∅),[7.3443]→[7.2712:2784](∅→∅),[7.2784]→[7.724:733](∅→∅),[7.724]→[7.724:733](∅→∅),[7.733]→[7.313:478](∅→∅),[7.478]→[7.733:862](∅→∅),[7.733]→[7.733:862](∅→∅),[7.862]→[7.3753:3851](∅→∅),[7.3851]→[7.1440:1692](∅→∅),[7.1440]→[7.1440:1692](∅→∅),[7.1692]→[7.479:553](∅→∅),[7.553]→[7.1887:1937](∅→∅),[7.3970]→[7.1887:1937](∅→∅),[7.1887]→[7.1887:1937](∅→∅),[7.1937]→[7.554:659](∅→∅),[7.659]→[7.2016:2047](∅→∅),[7.2016]→[7.2016:2047](∅→∅),[7.2047]→[7.2135:2160](∅→∅),[7.3443]→[7.2135:2160](∅→∅),[7.2160]→[7.3443:3444](∅→∅),[7.3443]→[7.3443:3444](∅→∅),[7.3444]→[7.2048:2135](∅→∅),[7.112]→[7.1783:1784](∅→∅),[7.874]→[7.1783:1784](∅→∅),[7.1461]→[7.1783:1784](∅→∅),[7.2135]→[7.1783:1784](∅→∅),[7.2191]→[7.1783:1784](∅→∅),[7.1783]→[7.1783:1784](∅→∅),[7.1784]→[5.164:273](∅→∅),[5.273]→[7.660:920](∅→∅),[7.1784]→[7.660:920](∅→∅),[7.202]→[7.1825:1826](∅→∅),[7.615]→[7.1825:1826](∅→∅),[7.920]→[7.1825:1826](∅→∅),[7.2297]→[7.1825:1826](∅→∅),[7.1825]→[7.1825:1826](∅→∅),[7.1872]→[7.1600:1624](∅→∅),[7.1624]→[7.4825:4855](∅→∅),[7.4855]→[7.227:245](∅→∅),[7.1634]→[7.227:245](∅→∅),[7.245]→[7.4044:4053](∅→∅),[7.4044]→[7.4044:4053](∅→∅),[7.4053]→[7.246:399](∅→∅),[7.399]→[7.1643:1671](∅→∅),[7.1643]→[7.1643:1671](∅→∅),[7.1671]→[7.2324:2431](∅→∅),[7.2431]→[7.1711:1761](∅→∅),[7.4247]→[7.1711:1761](∅→∅),[7.1711]→[7.1711:1761](∅→∅),[7.1761]→[7.2432:2443](∅→∅),[7.2443]→[7.4302:4581](∅→∅),[7.4581]→[7.2672:2684](∅→∅),[7.2672]→[7.2672:2684](∅→∅),[7.2684]→[7.1854:1864](∅→∅),[7.4401]→[7.1854:1864](∅→∅),[7.1854]→[7.1854:1864](∅→∅),[7.1864]→[7.2122:2196](∅→∅),[7.2196]→[7.8247:8289](∅→∅),[7.8289]→[7.1506:1636](∅→∅),[7.1636]→[7.466:618](∅→∅),[7.466]→[7.466:618](∅→∅),[7.618]→[7.8365:8433](∅→∅),[7.8365]→[7.8365:8433](∅→∅),[7.5586]→[7.5586:5626](∅→∅),[7.5626]→[7.1864:1894](∅→∅),[7.1864]→[7.1864:1894](∅→∅),[7.1894]→[7.2036:2037](∅→∅),[7.2036]→[7.2036:2037](∅→∅),[7.697]→[7.2037:2079](∅→∅),[7.2037]→[7.2037:2079](∅→∅),[7.2079]→[7.921:984](∅→∅),[7.792]→[7.2142:2155](∅→∅),[7.984]→[7.2142:2155](∅→∅),[7.2142]→[7.2142:2155](∅→∅),[7.2155]→[7.2197:2224](∅→∅),[7.2224]→[7.2167:2217](∅→∅),[7.2167]→[7.2167:2217](∅→∅),[7.2217]→[7.2225:2317](∅→∅),[7.2317]→[7.985:1144](∅→∅),[7.1144]→[7.2620:2660](∅→∅),[7.2317]→[7.2620:2660](∅→∅),[7.2620]→[7.2620:2660](∅→∅),[7.2838]→[7.2838:2848](∅→∅),[7.2857]→[7.2857:2870](∅→∅)
[% 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>[% INCLUDE maybeEditString param=param value=alt.value %]<br />[% ELSE %][% INCLUDE maybeEditString param=param value=alt.value %][% END %][% END %][% BLOCK renderInput %]<tr class="input [% extraClass %]" [% IF id %]id="[% id %]"[% END %]><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" %]"><input type="hidden" [% HTML.attributes(name => "jobset-$baseName-oldName", value => jobset.name) %] /><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 class="layoutTable">[% 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>[% IF !edit %]<tr><th>Last checked:</th><td>[% IF jobset.lastcheckedtime %][% INCLUDE renderDateTime timestamp = jobset.lastcheckedtime -%][% IF jobset.errormsg -%]<em>, evaluation error</em>:<pre class="multiLineMsg error">[% HTML.escape(jobset.errormsg) %]</pre>[% ELSE %], <em>no errors</em>[% END %][% ELSE %]<em>never</em>[% END %]</td></tr>[% END %]</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 %] - replacement in src/root/project.tt at line 17
<h2>General information</h2><h2>Information[% IF !edit %] <a class="smallLink" href="[% c.uri_for('/project' project.name 'edit') %]">[Edit]</a>[% END %]</h2> - edit in src/root/project.tt at line 59
- edit in src/root/project.tt at line 64
<h2>Statistics</h2> - replacement in src/root/project.tt at line 65
[% INCLUDE showBuildStats %]<h2>Jobsets</h2> - replacement in src/root/project.tt at line 67
[% END %][% IF project.jobsets.size > 0 %] - edit in src/root/project.tt at line 69
<p>This project has the following jobsets:</p> - replacement in src/root/project.tt at line 71
<h2>Jobsets</h2><table class="tablesorter"><thead><tr><th>Id</th><th>Description</th><th>Last evaluated</th></tr></thead><tbody>[% FOREACH j IN project.jobsets %]<tr class="clickable [% IF odd %] odd [% END; odd = !odd %]"onclick="window.location = '[% c.uri_for('/jobset' project.name j.name) %]'"><td>[% INCLUDE renderJobsetName project = project.name jobset = j.name %]</td><td>[% HTML.escape(j.description) %]</td><td>[% INCLUDE renderDateTime timestamp = j.lastcheckedtime %]</td></tr>[% END %]</tbody></table> - edit in src/root/project.tt at line 91
[% IF project.jobsets && project.jobsets.size > 0 || edit %] - replacement in src/root/project.tt at line 92
[% IF edit %]<p><button type="button" id="add-jobset">Add a new jobset</button></p>[% ELSE %] - replacement in src/root/project.tt at line 94
<div id="jobset-template" class="template">[% INCLUDE renderJobset jobset="" baseName="template" %]</div><p>No jobsets have been defined yet.</p> - replacement in src/root/project.tt at line 96[7.1603]→[7.2318:2548](∅→∅),[7.2548]→[7.1221:1322](∅→∅),[7.1322]→[7.1788:1798](∅→∅),[7.1788]→[7.1788:1798](∅→∅)
<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>[% END %] - replacement in src/root/project.tt at line 98[7.1751]→[7.2785:2821](∅→∅),[7.2821]→[7.1799:1947](∅→∅),[7.3942]→[7.1799:1947](∅→∅),[7.1947]→[7.2549:3091](∅→∅)
<script type="text/javascript">$(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;});<a href="[% c.uri_for(c.controller('Project').action_for('create_jobset'), [project.name]) %]">[Create a new jobset]</a> - edit in src/root/project.tt at line 100[7.3092]→[7.3092:3279](∅→∅),[7.3279]→[7.1323:1433](∅→∅),[7.1433]→[7.3384:3577](∅→∅),[7.3384]→[7.3384:3577](∅→∅),[7.3577]→[7.2443:2479](∅→∅),[7.2443]→[7.2443:2479](∅→∅)
$(".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;}); - edit in src/root/project.tt at line 101[7.2480]→[7.3578:3809](∅→∅),[7.3809]→[7.2694:2706](∅→∅),[7.2694]→[7.2694:2706](∅→∅),[7.2706]→[7.4558:4594](∅→∅),[7.4558]→[7.4558:4594](∅→∅)
$(".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 %] - replacement in src/root/project.tt at line 102
[% n = 0; FOREACH jobset IN project.jobsets -%][% INCLUDE renderJobset jobset=jobset baseName="e$n"; n = n + 1 %][% END -%]<h2>Releases</h2>[% IF releaseSets.size > 0 %]<p>Project <tt>[% project.name %]</tt> has the following release sets:</p><ul>[% FOREACH releaseSet IN releaseSets %]<li><a href="[% c.uri_for('/releases' project.name releaseSet.name) %]"><tt>[% releaseSet.name %]</tt></a>[<a href="[% c.uri_for('/releases' project.name releaseSet.name "edit") %]">Edit</a>]</li>[% END %]</ul> - replacement in src/root/project.tt at line 119
<p>No jobsets have been defined yet.</p><p>Project <tt>[% project.name %]</tt> has no release sets.</p> - edit in src/root/project.tt at line 122
<p><a href="[% c.uri_for('/create_releaseset' project.name) %]">[Create a new release set]</a></p> - replacement in src/root/project.tt at line 126
[% IF edit %]<h2>Channels</h2> - replacement in src/root/project.tt at line 128
<hr /><p>This project provides the following Nix channels:</p><ul><li><a href="[% c.uri_for('/project' project.name 'channel' 'latest') %]"><tt>latest</tt></a> —contains the latest successful build of every job in this project.</li><li><a href="[% c.uri_for('/project' project.name 'channel' 'all') %]"><tt>all</tt></a> —contains every successful, non-garbage-collected build of everyjob in this project.</li></ul><h2>Statistics</h2>[% INCLUDE showBuildStats %][% END %][% IF edit %] - replacement in src/root/release.tt at line 17
[% FOREACH job IN release.jobs %][% FOREACH j IN release.jobs %] - replacement in src/root/release.tt at line 20
[% IF job.build %]<a href="[% c.uri_for('/build' job.build.id) %]">[% END %][% INCLUDE renderReleaseJobName job=job.job %][% IF job.build %]</a>[% END %][% IF j.build %]<a href="[% c.uri_for('/build' job.build.id) %]">[% END %][% INCLUDE renderReleaseJobName job=j.job %][% IF j.build %]</a>[% END %] - replacement in src/root/release.tt at line 25
[% IF job.build %][% IF j.build %] - replacement in src/root/release.tt at line 27
[% IF job.build.resultInfo.buildstatus == 0 %][% IF j.build.resultInfo.buildstatus == 0 %] - replacement in src/root/release.tt at line 29
[% INCLUDE renderProductList build=job.build %][% INCLUDE renderProductList build=j.build %] - replacement in src/root/releases.tt at line 19
[% FOREACH job IN jobs %]<th class="releaseSetJobName">[% INCLUDE renderReleaseJobName %]</th>[% FOREACH j IN jobs %]<th class="releaseSetJobName">[% INCLUDE renderReleaseJobName job=j %]</th> - replacement in src/root/releases.tt at line 47
[% FOREACH job IN release.jobs %][% FOREACH j IN release.jobs %] - replacement in src/root/releases.tt at line 49
[% IF job.build %]<a href="[% c.uri_for('/build' job.build.id) %]">[% IF job.build.get_column('buildstatus') == 0 %][% IF j.build %]<a href="[% c.uri_for('/build' j.build.id) %]">[% IF j.build.get_column('buildstatus') == 0 %] - edit in src/root/static/css/hydra.css at line 68
vertical-align: center; - edit in src/root/static/css/hydra.css at line 103
a.no-hover:hover { background: none; } - edit in src/root/static/css/hydra.css at line 137
}a.smallLink {font-size: 60%;vertical-align: top; - edit in src/root/static/css/hydra.css at line 202[7.483]→[7.428:431](∅→∅),[7.3711]→[7.428:431](∅→∅),[7.1951]→[7.466:508](∅→∅),[7.508]→[7.445:498](∅→∅),[7.498]→[7.508:555](∅→∅),[7.508]→[7.508:555](∅→∅),[7.580]→[7.580:625](∅→∅),[7.654]→[7.654:685](∅→∅),[7.756]→[7.3711:3713](∅→∅),[7.1987]→[7.3711:3713](∅→∅),[7.3711]→[7.3711:3713](∅→∅),[7.3713]→[7.1606:1607](∅→∅),[7.2037]→[7.1606:1607](∅→∅),[7.1607]→[7.757:816](∅→∅)
}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; - edit in src/root/static/css/hydra.css at line 305
color: black; - edit in src/root/static/css/hydra.css at line 311
background-image: url(/static/images/arrow-down.gif);background-repeat: no-repeat;background-position: 0.3em center;}#leftnavbar ul.menu > li > div.title > a {display: block;background: none;color: black; - edit in src/root/static/css/hydra.css at line 322
#leftnavbar ul.menu > li > div.title > a:focus {outline: none;} - edit in src/root/static/css/hydra.css at line 332
#leftnavbar ul.collapsed {display: none;} - edit in src/root/static/css/hydra.css at line 425
.hidden {display: none;}