From d350b935f2939fee7e6bda9e1f8ae3b4f281c07f Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 08:53:00 +0000
Subject: [PATCH 1/8] Add validation for project and jobset names
---
src/lib/Hydra/Controller/Jobset.pm | 16 ++++++++--------
src/lib/Hydra/Controller/JobsetEval.pm | 18 +++++++++++-------
src/lib/Hydra/Controller/Project.pm | 6 +++++-
src/lib/Hydra/Helper/CatalystUtils.pm | 16 +++++++++-------
4 files changed, 33 insertions(+), 23 deletions(-)
diff --git a/src/lib/Hydra/Controller/Jobset.pm b/src/lib/Hydra/Controller/Jobset.pm
index 4dc90094..fa968ef3 100644
--- a/src/lib/Hydra/Controller/Jobset.pm
+++ b/src/lib/Hydra/Controller/Jobset.pm
@@ -221,7 +221,7 @@ sub updateJobset {
my ($c, $jobset) = @_;
my $jobsetName = trim $c->request->params->{"name"};
- error($c, "Invalid jobset name: $jobsetName") unless $jobsetName =~ /^[[:alpha:]][\w\-]*$/;
+ error($c, "Invalid jobset name: ‘$jobsetName’") if $jobsetName !~ /^$jobsetNameRE$/;
my ($nixExprPath, $nixExprInput) = nixExprPathFromParams $c;
@@ -298,13 +298,13 @@ sub clone_submit : Chained('jobset') PathPart('clone/submit') Args(0) {
requireProjectOwner($c, $jobset->project);
requirePost($c);
- my $newjobsetName = trim $c->request->params->{"newjobset"};
- error($c, "Invalid jobset name: $newjobsetName") unless $newjobsetName =~ /^[[:alpha:]][\w\-]*$/;
+ my $newJobsetName = trim $c->request->params->{"newjobset"};
+ error($c, "Invalid jobset name: $newJobsetName") unless $newJobsetName =~ /^[[:alpha:]][\w\-]*$/;
- my $newjobset;
+ my $newJobset;
txn_do($c->model('DB')->schema, sub {
- $newjobset = $jobset->project->jobsets->create(
- { name => $newjobsetName
+ $newJobset = $jobset->project->jobsets->create(
+ { name => $newJobsetName
, description => $jobset->description
, nixexprpath => $jobset->nixexprpath
, nixexprinput => $jobset->nixexprinput
@@ -314,14 +314,14 @@ sub clone_submit : Chained('jobset') PathPart('clone/submit') Args(0) {
});
foreach my $input ($jobset->jobsetinputs) {
- my $newinput = $newjobset->jobsetinputs->create({name => $input->name, type => $input->type});
+ my $newinput = $newJobset->jobsetinputs->create({name => $input->name, type => $input->type});
foreach my $inputalt ($input->jobsetinputalts) {
$newinput->jobsetinputalts->create({altnr => $inputalt->altnr, value => $inputalt->value});
}
}
});
- $c->res->redirect($c->uri_for($c->controller('Jobset')->action_for("edit"), [$jobset->project->name, $newjobsetName]));
+ $c->res->redirect($c->uri_for($c->controller('Jobset')->action_for("edit"), [$jobset->project->name, $newJobsetName]));
}
diff --git a/src/lib/Hydra/Controller/JobsetEval.pm b/src/lib/Hydra/Controller/JobsetEval.pm
index 76c85feb..ebfc49be 100644
--- a/src/lib/Hydra/Controller/JobsetEval.pm
+++ b/src/lib/Hydra/Controller/JobsetEval.pm
@@ -32,13 +32,17 @@ sub view : Chained('eval') PathPart('') Args(0) {
# Allow comparing this evaluation against the previous evaluation
# (default), an arbitrary evaluation, or the latest completed
# evaluation of another jobset.
- if (defined $compare && $compare =~ /^\d+$/) {
- $eval2 = $c->model('DB::JobsetEvals')->find($compare)
- or notFound($c, "Evaluation $compare doesn't exist.");
- } elsif (defined $compare && $compare =~ /^($jobNameRE)$/) {
- my $j = $c->stash->{project}->jobsets->find({name => $compare})
- or notFound($c, "Jobset $compare doesn't exist.");
- $eval2 = getLatestFinishedEval($c, $j);
+ if (defined $compare) {
+ if ($compare =~ /^\d+$/) {
+ $eval2 = $c->model('DB::JobsetEvals')->find($compare)
+ or notFound($c, "Evaluation $compare doesn't exist.");
+ } elsif (defined $compare && $compare =~ /^($jobsetNameRE)$/) {
+ my $j = $c->stash->{project}->jobsets->find({name => $compare})
+ or notFound($c, "Jobset $compare doesn't exist.");
+ $eval2 = getLatestFinishedEval($c, $j);
+ } else {
+ notFound($c, "Unknown comparison source ‘$compare’.");
+ }
} else {
($eval2) = $eval->jobset->jobsetevals->search(
{ hasnewbuilds => 1, id => { '<', $eval->id } },
diff --git a/src/lib/Hydra/Controller/Project.pm b/src/lib/Hydra/Controller/Project.pm
index 0b600d41..18597942 100644
--- a/src/lib/Hydra/Controller/Project.pm
+++ b/src/lib/Hydra/Controller/Project.pm
@@ -119,6 +119,8 @@ sub create_submit : Path('/create-project/submit') {
my $projectName = trim $c->request->params->{name};
+ error($c, "Invalid project name: ‘$projectName’") if $projectName !~ /^$projectNameRE$/;
+
txn_do($c->model('DB')->schema, sub {
# Note: $projectName is validated in updateProject,
# which will abort the transaction if the name isn't
@@ -152,6 +154,8 @@ sub create_jobset_submit : Chained('project') PathPart('create-jobset/submit') A
my $jobsetName = trim $c->request->params->{name};
+ error($c, "Invalid jobset name: ‘$jobsetName’") if $jobsetName !~ /^$jobsetNameRE$/;
+
txn_do($c->model('DB')->schema, sub {
# Note: $jobsetName is validated in updateProject, which will
# abort the transaction if the name isn't valid.
@@ -168,7 +172,7 @@ sub create_jobset_submit : Chained('project') PathPart('create-jobset/submit') A
sub updateProject {
my ($c, $project) = @_;
my $projectName = trim $c->request->params->{name};
- error($c, "Invalid project name: " . ($projectName || "(empty)")) unless $projectName =~ /^[[:alpha:]][\w\-]*$/;
+ error($c, "Invalid project name: ‘$projectName’") if $projectName !~ /^$projectNameRE$/;
my $displayName = trim $c->request->params->{displayname};
error($c, "Invalid display name: $displayName") if $displayName eq "";
diff --git a/src/lib/Hydra/Helper/CatalystUtils.pm b/src/lib/Hydra/Helper/CatalystUtils.pm
index 80c391ab..a58c9c38 100644
--- a/src/lib/Hydra/Helper/CatalystUtils.pm
+++ b/src/lib/Hydra/Helper/CatalystUtils.pm
@@ -13,7 +13,7 @@ our @EXPORT = qw(
requireLogin requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner
trim
getLatestFinishedEval
- $pathCompRE $relPathRE $relNameRE $jobNameRE $systemRE
+ $pathCompRE $relPathRE $relNameRE $projectNameRE $jobsetNameRE $jobNameRE $systemRE
@buildListColumns
);
@@ -181,12 +181,14 @@ sub getLatestFinishedEval {
# Security checking of filenames.
-Readonly our $pathCompRE => "(?:[A-Za-z0-9-\+\._][A-Za-z0-9-\+\._]*)";
-Readonly our $relPathRE => "(?:$pathCompRE(?:/$pathCompRE)*)";
-Readonly our $relNameRE => "(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)";
-Readonly our $attrNameRE => "(?:[A-Za-z_][A-Za-z0-9_]*)";
-Readonly our $jobNameRE => "(?:$attrNameRE(?:\\.$attrNameRE)*)";
-Readonly our $systemRE => "(?:[a-z0-9_]+-[a-z0-9_]+)";
+Readonly our $pathCompRE => "(?:[A-Za-z0-9-\+\._][A-Za-z0-9-\+\._]*)";
+Readonly our $relPathRE => "(?:$pathCompRE(?:/$pathCompRE)*)";
+Readonly our $relNameRE => "(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)";
+Readonly our $attrNameRE => "(?:[A-Za-z_][A-Za-z0-9_]*)";
+Readonly our $projectNameRE => "(?:[A-Za-z_][A-Za-z0-9-_]*)";
+Readonly our $jobsetNameRE => "(?:[A-Za-z_][A-Za-z0-9-_]*)";
+Readonly our $jobNameRE => "(?:$attrNameRE(?:\\.$attrNameRE)*)";
+Readonly our $systemRE => "(?:[a-z0-9_]+-[a-z0-9_]+)";
1;
From 896a47d9502fe6bcb79694a13f1a908d6eccc76b Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 09:34:35 +0000
Subject: [PATCH 2/8] Clear nrSucceeded when restarting a build
---
src/lib/Hydra/Controller/Build.pm | 4 ++--
src/lib/Hydra/Helper/AddBuilds.pm | 6 ++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/lib/Hydra/Controller/Build.pm b/src/lib/Hydra/Controller/Build.pm
index f9f1825a..b3442f02 100644
--- a/src/lib/Hydra/Controller/Build.pm
+++ b/src/lib/Hydra/Controller/Build.pm
@@ -351,9 +351,9 @@ sub restart : Chained('build') PathPart Args(0) {
requireProjectOwner($c, $build->project);
- my $drvpath = $build->drvpath ;
+ my $drvpath = $build->drvpath;
error($c, "This build cannot be restarted.")
- unless $build->finished && -f $drvpath ;
+ unless $build->finished && -f $drvpath;
restartBuild($c->model('DB')->schema, $build);
diff --git a/src/lib/Hydra/Helper/AddBuilds.pm b/src/lib/Hydra/Helper/AddBuilds.pm
index c6c7703a..1e9bd0e7 100644
--- a/src/lib/Hydra/Helper/AddBuilds.pm
+++ b/src/lib/Hydra/Helper/AddBuilds.pm
@@ -968,5 +968,11 @@ sub restartBuild {
, busy => 0
, locker => ""
});
+
+ # Reset the stats for the evals to which this build belongs.
+ # !!! Should do this in a trigger.
+ foreach my $m ($build->jobsetevalmembers->all) {
+ $m->eval->update({nrsucceeded => undef});
+ }
});
}
From 634d8c092fb48113a4434a344a2a34d730cc94cb Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 09:35:37 +0000
Subject: [PATCH 3/8] Use for running/failed build steps
---
src/root/build.tt | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/root/build.tt b/src/root/build.tt
index 47d3d193..a6b51c8c 100644
--- a/src/root/build.tt
+++ b/src/root/build.tt
@@ -9,8 +9,6 @@
[% job = build.job %]
[% BLOCK renderBuildSteps %]
-
- [% type %] build steps
Nr What Duration Machine Status
@@ -67,7 +65,7 @@
[% IF flashMsg %]
-[% flashMsg %]
+[% flashMsg %]
[% END %]
@@ -160,12 +158,14 @@
[% END %]
- [% IF !build.finished && build.buildsteps.size > 0 %]
+ [% IF !build.finished %]
+ Running build steps
[% INCLUDE renderBuildSteps type="Running" %]
[% END %]
[% IF build.finished %]
[% IF build.buildsteps && build.buildstatus != 0 && build.buildstatus != 6 %]
+ Failed build steps
[% INCLUDE renderBuildSteps type="Failed" %]
[% END %]
@@ -416,9 +416,10 @@
[% END %]
[% IF build.buildsteps %]
-
- [% INCLUDE renderBuildSteps type="All" %]
-
+
+
All build steps
+ [% INCLUDE renderBuildSteps type="All" %]
+
[% END %]
From ea4aba83c317d5ecac72bbd93280b376f82d1217 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 09:36:10 +0000
Subject: [PATCH 4/8] Proper styling for flash message
---
src/root/queue.tt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/root/queue.tt b/src/root/queue.tt
index 58a3d00b..0ab13a0e 100644
--- a/src/root/queue.tt
+++ b/src/root/queue.tt
@@ -6,7 +6,7 @@
[ Running build steps ]
[% IF flashMsg %]
-[% flashMsg %]
+[% flashMsg %]
[% END %]
[% IF queue.size == 0 %]
From db09760e8cde3454372f572c168a67fb3d004515 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 11:39:08 +0200
Subject: [PATCH 5/8] Move the "Cancel build" button to the menu
---
src/root/common.tt | 5 -----
src/root/topbar.tt | 3 +++
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/root/common.tt b/src/root/common.tt
index bbf4ced3..1f900282 100644
--- a/src/root/common.tt
+++ b/src/root/common.tt
@@ -273,11 +273,6 @@
since [% INCLUDE renderDateTime timestamp = build.starttime %]
[% ELSE %]
Scheduled to be built
- [% IF c.user_exists %]
-
- [% END %]
[% END %]
[% END -%]
diff --git a/src/root/topbar.tt b/src/root/topbar.tt
index 6c822120..4f9e5124 100644
--- a/src/root/topbar.tt
+++ b/src/root/topbar.tt
@@ -145,6 +145,9 @@
[% INCLUDE makeLink
uri = c.uri_for('/build' build.id 'restart')
title = "Restart build" %]
+ [% INCLUDE makeLink
+ uri = c.uri_for('/build' build.id 'cancel')
+ title = "Cancel build" %]
[% END %]
[% END %]
From 8f31935ffaa9fddddbd0250756eaa6b6c981fcba Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 12:32:44 +0200
Subject: [PATCH 6/8] Handle the case where there are no builds and no previous
eval
---
src/script/hydra-evaluator | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/script/hydra-evaluator b/src/script/hydra-evaluator
index 7e3fac60..1fc0d260 100755
--- a/src/script/hydra-evaluator
+++ b/src/script/hydra-evaluator
@@ -194,7 +194,7 @@ sub checkJobset {
$ev->builds->update({iscurrent => 1});
} else {
print STDERR " created cached eval ", $ev->id, "\n";
- $prevEval->builds->update({iscurrent => 1});
+ $prevEval->builds->update({iscurrent => 1}) if defined $prevEval;
}
});
From 51b920c87509d2bfd221ca4b09d990ca2b22da5f Mon Sep 17 00:00:00 2001
From: Eelco Dolstra
Date: Tue, 17 Apr 2012 16:53:11 +0200
Subject: [PATCH 7/8] Bootstrapify the Hydra forms (except the project and
jobset edit pages)
Plus lots of other tweaks.
---
src/lib/Hydra/Controller/Admin.pm | 67 ++++++++++---
src/lib/Hydra/Controller/Project.pm | 30 +++---
src/lib/Hydra/Controller/Release.pm | 2 +
src/lib/Hydra/Controller/View.pm | 16 +--
src/root/admin.tt | 2 +-
src/root/all.tt | 6 +-
src/root/build.tt | 11 +-
src/root/channel-contents.tt | 2 +-
src/root/clone-build.tt | 2 +-
src/root/common.tt | 25 +++--
src/root/edit-release.tt | 84 ++++++++--------
src/root/edit-view.tt | 72 ++++++++------
src/root/error.tt | 2 +-
src/root/errors.tt | 2 +-
src/root/jobset-eval.tt | 2 +-
src/root/jobset-evals.tt | 4 +-
src/root/jobset.tt | 17 ++--
src/root/jobstatus.tt | 4 +-
src/root/layout.tt | 21 ++--
src/root/log.tt | 2 +-
src/root/login.tt | 45 +++++----
src/root/machine.tt | 149 +++++++++++++++-------------
src/root/machines.tt | 9 +-
src/root/news.tt | 32 +++---
src/root/plain.tt | 2 +-
src/root/project.tt | 44 ++++----
src/root/queue.tt | 4 +-
src/root/release.tt | 8 +-
src/root/releases.tt | 8 +-
src/root/status.tt | 2 +-
src/root/timeline.tt | 2 +-
src/root/topbar.tt | 12 ++-
src/root/user.tt | 99 +++++++++---------
src/root/users.tt | 10 +-
src/root/view-result.tt | 6 +-
src/root/view.tt | 10 +-
36 files changed, 456 insertions(+), 359 deletions(-)
diff --git a/src/lib/Hydra/Controller/Admin.pm b/src/lib/Hydra/Controller/Admin.pm
index e8898597..c09d6cf1 100644
--- a/src/lib/Hydra/Controller/Admin.pm
+++ b/src/lib/Hydra/Controller/Admin.pm
@@ -15,6 +15,7 @@ use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP;
use Config::General;
+
sub nixMachines {
my ($c) = @_;
my $result = "# GENERATED BY HYDRA\n";
@@ -32,6 +33,7 @@ sub nixMachines {
return $result;
}
+
sub saveNixMachines {
my ($c) = @_;
@@ -42,12 +44,14 @@ sub saveNixMachines {
close (NIXMACHINES);
}
+
sub admin : Chained('/') PathPart('admin') CaptureArgs(0) {
my ($self, $c) = @_;
requireAdmin($c);
$c->stash->{admin} = 1;
}
+
sub index : Chained('admin') PathPart('') Args(0) {
my ($self, $c) = @_;
$c->stash->{machines} = [$c->model('DB::BuildMachines')->search(
@@ -62,7 +66,8 @@ sub index : Chained('admin') PathPart('') Args(0) {
, order_by => [ 'machine', 'stepnr' ]
} ) ];
$c->stash->{template} = 'admin.tt';
- }
+}
+
sub updateUser {
my ($c, $user) = @_;
@@ -88,6 +93,16 @@ sub updateUser {
}
}
+
+sub create_user : Chained('admin') PathPart('create-user') Args(0) {
+ my ($self, $c) = @_;
+
+ requireAdmin($c);
+
+ error($c, "Not implemented yet!"); # FIXME
+}
+
+
sub user : Chained('admin') PathPart('user') CaptureArgs(1) {
my ($self, $c, $username) = @_;
@@ -99,6 +114,7 @@ sub user : Chained('admin') PathPart('user') CaptureArgs(1) {
$c->stash->{user} = $user;
}
+
sub users : Chained('admin') PathPart('users') Args(0) {
my ($self, $c) = @_;
$c->stash->{users} = [$c->model('DB::Users')->search({}, {order_by => "username"})];
@@ -106,6 +122,7 @@ sub users : Chained('admin') PathPart('users') Args(0) {
$c->stash->{template} = 'users.tt';
}
+
sub user_edit : Chained('user') PathPart('edit') Args(0) {
my ($self, $c) = @_;
@@ -113,16 +130,23 @@ sub user_edit : Chained('user') PathPart('edit') Args(0) {
$c->stash->{edit} = 1;
}
+
sub user_edit_submit : Chained('user') PathPart('submit') Args(0) {
my ($self, $c) = @_;
requirePost($c);
txn_do($c->model('DB')->schema, sub {
- updateUser($c, $c->stash->{user}) ;
+ if (($c->request->params->{submit} || "") eq "delete") {
+ $c->stash->{user}->delete;
+ } else {
+ updateUser($c, $c->stash->{user});
+ }
});
+
$c->res->redirect("/admin/users");
}
+
sub sendemail {
my ($to, $subject, $body) = @_;
@@ -141,6 +165,7 @@ sub sendemail {
sendmail($email);
}
+
sub reset_password : Chained('user') PathPart('reset-password') Args(0) {
my ($self, $c) = @_;
@@ -168,6 +193,7 @@ sub reset_password : Chained('user') PathPart('reset-password') Args(0) {
$c->res->redirect("/admin/users");
}
+
sub machines : Chained('admin') PathPart('machines') Args(0) {
my ($self, $c) = @_;
$c->stash->{machines} = [$c->model('DB::BuildMachines')->search({}, {order_by => "hostname"})];
@@ -176,7 +202,8 @@ sub machines : Chained('admin') PathPart('machines') Args(0) {
$c->stash->{nixMachinesWritable} = (-e "/etc/nix.machines" && -w "/etc/nix.machines");
$c->stash->{template} = 'machines.tt';
- }
+}
+
sub machine : Chained('admin') PathPart('machine') CaptureArgs(1) {
my ($self, $c, $machineName) = @_;
@@ -189,6 +216,7 @@ sub machine : Chained('admin') PathPart('machine') CaptureArgs(1) {
$c->stash->{machine} = $machine;
}
+
sub machine_edit : Chained('machine') PathPart('edit') Args(0) {
my ($self, $c) = @_;
$c->stash->{template} = 'machine.tt';
@@ -196,19 +224,27 @@ sub machine_edit : Chained('machine') PathPart('edit') Args(0) {
$c->stash->{edit} = 1;
}
+
sub machine_edit_submit : Chained('machine') PathPart('submit') Args(0) {
my ($self, $c) = @_;
requirePost($c);
txn_do($c->model('DB')->schema, sub {
- updateMachine($c, $c->stash->{machine}) ;
+ if (($c->request->params->{submit} || "") eq "delete") {
+ $c->stash->{machine}->delete;
+ } else {
+ updateMachine($c, $c->stash->{machine});
+ }
});
+
saveNixMachines($c);
+
$c->res->redirect("/admin/machines");
}
+
sub updateMachine {
- my ($c, $machine) = @_;
+ my ($c, $machine) = @_;
my $hostname = trim $c->request->params->{"hostname"};
my $username = trim $c->request->params->{"username"};
@@ -240,6 +276,7 @@ sub updateMachine {
}
}
+
sub create_machine : Chained('admin') PathPart('create-machine') Args(0) {
my ($self, $c) = @_;
@@ -269,16 +306,6 @@ sub create_machine_submit : Chained('admin') PathPart('create-machine/submit') A
$c->res->redirect("/admin/machines");
}
-sub machine_delete : Chained('machine') PathPart('delete') Args(0) {
- my ($self, $c) = @_;
- requirePost($c);
-
- txn_do($c->model('DB')->schema, sub {
- $c->stash->{machine}->delete;
- });
- saveNixMachines($c);
- $c->res->redirect("/admin/machines");
-}
sub machine_enable : Chained('machine') PathPart('enable') Args(0) {
my ($self, $c) = @_;
@@ -287,6 +314,7 @@ sub machine_enable : Chained('machine') PathPart('enable') Args(0) {
$c->res->redirect("/admin/machines");
}
+
sub machine_disable : Chained('machine') PathPart('disable') Args(0) {
my ($self, $c) = @_;
$c->stash->{machine}->update({ enabled => 0});
@@ -294,6 +322,7 @@ sub machine_disable : Chained('machine') PathPart('disable') Args(0) {
$c->res->redirect("/admin/machines");
}
+
sub clear_queue_non_current : Chained('admin') Path('clear-queue-non-current') Args(0) {
my ($self, $c) = @_;
# !!! Mark the builds as cancelled instead.
@@ -301,6 +330,7 @@ sub clear_queue_non_current : Chained('admin') Path('clear-queue-non-current') A
$c->res->redirect("/admin");
}
+
sub clear_queue : Chained('admin') Path('clear-queue') Args(0) {
my ($self, $c) = @_;
# !!! Mark the builds as cancelled instead.
@@ -308,6 +338,7 @@ sub clear_queue : Chained('admin') Path('clear-queue') Args(0) {
$c->res->redirect("/admin");
}
+
sub clearfailedcache : Chained('admin') Path('clear-failed-cache') Args(0) {
my ($self, $c) = @_;
@@ -316,6 +347,7 @@ sub clearfailedcache : Chained('admin') Path('clear-failed-cache') Args(0) {
$c->res->redirect("/admin");
}
+
sub clearvcscache : Chained('admin') Path('clear-vcs-cache') Args(0) {
my ($self, $c) = @_;
@@ -334,6 +366,7 @@ sub clearvcscache : Chained('admin') Path('clear-vcs-cache') Args(0) {
$c->res->redirect("/admin");
}
+
sub managenews : Chained('admin') Path('news') Args(0) {
my ($self, $c) = @_;
@@ -342,6 +375,7 @@ sub managenews : Chained('admin') Path('news') Args(0) {
$c->stash->{template} = 'news.tt';
}
+
sub news_submit : Chained('admin') Path('news/submit') Args(0) {
my ($self, $c) = @_;
@@ -359,6 +393,7 @@ sub news_submit : Chained('admin') Path('news/submit') Args(0) {
$c->res->redirect("/admin/news");
}
+
sub news_delete : Chained('admin') Path('news/delete') Args(1) {
my ($self, $c, $id) = @_;
@@ -371,6 +406,7 @@ sub news_delete : Chained('admin') Path('news/delete') Args(1) {
$c->res->redirect("/admin/news");
}
+
sub force_eval : Chained('admin') Path('eval') Args(2) {
my ($self, $c, $projectName, $jobsetName) = @_;
@@ -387,4 +423,5 @@ sub force_eval : Chained('admin') Path('eval') Args(2) {
$c->res->redirect("/project/$projectName");
}
+
1;
diff --git a/src/lib/Hydra/Controller/Project.pm b/src/lib/Hydra/Controller/Project.pm
index 18597942..050a7d40 100644
--- a/src/lib/Hydra/Controller/Project.pm
+++ b/src/lib/Hydra/Controller/Project.pm
@@ -45,6 +45,11 @@ sub submit : Chained('project') PathPart Args(0) {
requireProjectOwner($c, $c->stash->{project});
requirePost($c);
+ if (($c->request->params->{submit} || "") eq "delete") {
+ $c->stash->{project}->delete;
+ $c->res->redirect($c->uri_for("/"));
+ }
+
txn_do($c->model('DB')->schema, sub {
updateProject($c, $c->stash->{project});
});
@@ -65,6 +70,7 @@ sub hide : Chained('project') PathPart Args(0) {
$c->res->redirect($c->uri_for("/"));
}
+
sub unhide : Chained('project') PathPart Args(0) {
my ($self, $c) = @_;
@@ -77,19 +83,6 @@ sub unhide : Chained('project') PathPart Args(0) {
$c->res->redirect($c->uri_for("/"));
}
-sub delete : Chained('project') PathPart Args(0) {
- my ($self, $c) = @_;
-
- requireProjectOwner($c, $c->stash->{project});
- requirePost($c);
-
- txn_do($c->model('DB')->schema, sub {
- $c->stash->{project}->delete;
- });
-
- $c->res->redirect($c->uri_for("/"));
-}
-
sub requireMayCreateProjects {
my ($c) = @_;
@@ -171,12 +164,7 @@ sub create_jobset_submit : Chained('project') PathPart('create-jobset/submit') A
sub updateProject {
my ($c, $project) = @_;
- my $projectName = trim $c->request->params->{name};
- error($c, "Invalid project name: ‘$projectName’") if $projectName !~ /^$projectNameRE$/;
- my $displayName = trim $c->request->params->{displayname};
- error($c, "Invalid display name: $displayName") if $displayName eq "";
-
my $owner = $project->owner;
if ($c->check_user_roles('admin')) {
$owner = trim $c->request->params->{owner};
@@ -184,6 +172,12 @@ sub updateProject {
unless defined $c->model('DB::Users')->find({username => $owner});
}
+ my $projectName = trim $c->request->params->{name};
+ error($c, "Invalid project name: ‘$projectName’") if $projectName !~ /^$projectNameRE$/;
+
+ my $displayName = trim $c->request->params->{displayname};
+ error($c, "Invalid display name: $displayName") if $displayName eq "";
+
$project->update(
{ name => $projectName
, displayname => $displayName
diff --git a/src/lib/Hydra/Controller/Release.pm b/src/lib/Hydra/Controller/Release.pm
index da282a57..89cb2103 100644
--- a/src/lib/Hydra/Controller/Release.pm
+++ b/src/lib/Hydra/Controller/Release.pm
@@ -52,6 +52,8 @@ sub edit : Chained('release') PathPart('edit') Args(0) {
my ($self, $c) = @_;
requireProjectOwner($c, $c->stash->{project});
$c->stash->{template} = 'edit-release.tt';
+ $c->stash->{members} = [$c->stash->{release}->releasemembers->search({},
+ {order_by => ["description"]})];
}
diff --git a/src/lib/Hydra/Controller/View.pm b/src/lib/Hydra/Controller/View.pm
index a9cb1e05..aa3789cc 100644
--- a/src/lib/Hydra/Controller/View.pm
+++ b/src/lib/Hydra/Controller/View.pm
@@ -116,6 +116,11 @@ sub edit : Chained('view') PathPart('edit') Args(0) {
sub submit : Chained('view') PathPart('submit') Args(0) {
my ($self, $c) = @_;
requireProjectOwner($c, $c->stash->{project});
+ if (($c->request->params->{submit} || "") eq "delete") {
+ $c->stash->{view}->delete;
+ $c->res->redirect($c->uri_for($c->controller('Project')->action_for('view'),
+ [$c->stash->{project}->name]));
+ }
txn_do($c->model('DB')->schema, sub {
updateView($c, $c->stash->{view});
});
@@ -123,17 +128,6 @@ sub submit : Chained('view') PathPart('submit') Args(0) {
}
-sub delete : Chained('view') PathPart('delete') Args(0) {
- my ($self, $c) = @_;
- requireProjectOwner($c, $c->stash->{project});
- txn_do($c->model('DB')->schema, sub {
- $c->stash->{view}->delete;
- });
- $c->res->redirect($c->uri_for($c->controller('Project')->action_for('view'),
- [$c->stash->{project}->name]));
-}
-
-
sub latest : Chained('view') PathPart('latest') {
my ($self, $c, @args) = @_;
diff --git a/src/root/admin.tt b/src/root/admin.tt
index d2fab0fa..42c044b2 100644
--- a/src/root/admin.tt
+++ b/src/root/admin.tt
@@ -1,7 +1,7 @@
[% WRAPPER layout.tt title="Admin" %]
[% PROCESS common.tt %]
-Machine status
+
[% FOREACH m IN machines %]
diff --git a/src/root/all.tt b/src/root/all.tt
index ff146515..f0f0b9a6 100644
--- a/src/root/all.tt
+++ b/src/root/all.tt
@@ -1,10 +1,10 @@
-[% WRAPPER layout.tt title="All Builds" %]
+[% WRAPPER layout.tt title="All builds" %]
[% PROCESS common.tt %]
-All Builds
+
Showing builds [% (page - 1) * resultsPerPage + 1 %] - [% (page - 1) * resultsPerPage + builds.size %]
out of [% total %] in order of descending timestamp.
diff --git a/src/root/build.tt b/src/root/build.tt
index a6b51c8c..99de759b 100644
--- a/src/root/build.tt
+++ b/src/root/build.tt
@@ -140,9 +140,14 @@
[% IF c.user_exists && available %]
-
[% END %]
diff --git a/src/root/channel-contents.tt b/src/root/channel-contents.tt
index 911c4767..0f0387e2 100644
--- a/src/root/channel-contents.tt
+++ b/src/root/channel-contents.tt
@@ -2,7 +2,7 @@
[% PROCESS common.tt %]
[% USE HTML %]
-Channel [% channelName %]
+
This page provides a channel for the Nix package manager . If you have Nix
diff --git a/src/root/clone-build.tt b/src/root/clone-build.tt
index e44da753..44b6ccb7 100644
--- a/src/root/clone-build.tt
+++ b/src/root/clone-build.tt
@@ -3,7 +3,7 @@
[% USE HTML %]
[% edit=1 %]
-
Clone Build
+
Cloning allows you to perform a build with modified inputs.
diff --git a/src/root/common.tt b/src/root/common.tt
index 1f900282..c6b14a5e 100644
--- a/src/root/common.tt
+++ b/src/root/common.tt
@@ -189,7 +189,7 @@
[% BLOCK maybeLink -%]
- [% IF uri %] uri) %][% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>[% content %] [% ELSE; content; END -%]
+ [% IF uri %] uri, class => class) %][% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>[% content %] [% ELSE; content; END -%]
[% END -%]
[% BLOCK maybeButton -%]
@@ -198,11 +198,24 @@
[% BLOCK renderSelection %]
[% IF edit %]
- param, name => param) %]>
- [% FOREACH name IN options.keys.sort %]
- name) %] [% IF name == curValue; "selected='selected'"; END %]>[% options.$name %]
- [% END %]
-
+ [% IF radiobuttons %]
+
+ [% FOREACH name IN options.keys.sort %]
+
+ param, name => param, value => name) %]
+ [% IF name == curValue; "checked='1'"; END %]>
+ [% options.$name %]
+
+
+ [% END %]
+
+ [% ELSE %]
+ param, name => param) %]>
+ [% FOREACH name IN options.keys.sort %]
+ name) %] [% IF name == curValue; "selected='selected'"; END %]>[% options.$name %]
+ [% END %]
+
+ [% END %]
[% ELSE %]
[% options.$curValue %]
[% END %]
diff --git a/src/root/edit-release.tt b/src/root/edit-release.tt
index 63e29b51..7f8e86dc 100644
--- a/src/root/edit-release.tt
+++ b/src/root/edit-release.tt
@@ -1,57 +1,63 @@
-[% WRAPPER layout.tt title=(create ? "New Release" : "Edit Release") %]
+[% WRAPPER layout.tt title=(create ? "New release" : "Edit release") %]
[% PROCESS common.tt %]
[% USE HTML %]
-[% IF create %]New Release[% ELSE %]Release [% release.name %] [% END %]
+
-
[% END %]
-
-
- Add news item
-
-
-
-
- Post
-
-
+
+
+ Add news item
+
+
News text (HTML)
+
+
+
+
+
+
+
+
+ Post
+
+
-
-
[% END %]
diff --git a/src/root/plain.tt b/src/root/plain.tt
index 1975756a..110074e8 100644
--- a/src/root/plain.tt
+++ b/src/root/plain.tt
@@ -5,7 +5,7 @@
[% jobset = build.jobset %]
[% job = build.job %]
-[% title %]
+
[% contents -%]
diff --git a/src/root/project.tt b/src/root/project.tt
index da1e7b9f..c913697c 100644
--- a/src/root/project.tt
+++ b/src/root/project.tt
@@ -133,33 +133,35 @@
Enabled:
- [% INCLUDE renderSelection param="enabled" curValue=project.enabled options={"1" = "Yes", "0" = "No"} %]
+ [% INCLUDE renderSelection param="enabled" curValue=project.enabled radiobuttons=1 options={"1" = "Yes", "0" = "No"} %]
[% IF edit %]
-
[%IF create %]Create[% ELSE %]Apply changes[% END %]
+
+
+
+ [%IF create %]Create[% ELSE %]Apply changes[% END %]
+
+ [% IF !create %]
+
+
+ Delete this project
+
+
+ [% END %]
+
-
-
- [% IF !create %]
-
-
- Delete this project
-
-
-
-
- [% END %]
-
[% END %]
+
+
[% IF !edit %]
@@ -175,7 +177,7 @@
[% FOREACH view IN views %]
[% view.name %]
- [Edit ]
+ Edit
[% END %]
@@ -186,7 +188,9 @@
[% END %]
- [Create a new view]
+
+ Create a new view
+
[% END %]
diff --git a/src/root/queue.tt b/src/root/queue.tt
index 0ab13a0e..1c6d3425 100644
--- a/src/root/queue.tt
+++ b/src/root/queue.tt
@@ -1,9 +1,9 @@
[% WRAPPER layout.tt title="Queue" %]
[% PROCESS common.tt %]
-Hydra Queue
+
-[ Running build steps ]
+Running build steps
[% IF flashMsg %]
[% flashMsg %]
diff --git a/src/root/release.tt b/src/root/release.tt
index d8ca9d37..eb7fbaea 100644
--- a/src/root/release.tt
+++ b/src/root/release.tt
@@ -3,8 +3,8 @@
[% PROCESS "product-list.tt" %]
[% USE HTML %]
-Release [% release.name %] [Edit]
+
Released on [% INCLUDE renderDateTime timestamp =
release.timestamp %].
@@ -17,11 +17,11 @@ release.timestamp %].
[% FOREACH m IN members %]
-
+
[% INCLUDE renderProductList build=m.build %]
diff --git a/src/root/releases.tt b/src/root/releases.tt
index 9fe7061b..c0fc6a38 100644
--- a/src/root/releases.tt
+++ b/src/root/releases.tt
@@ -2,7 +2,7 @@
[% PROCESS common.tt %]
[% USE HTML %]
-Releases for Project [% project.name %]
+
[% IF releases.size == 0 %]
@@ -33,9 +33,9 @@
[% END %]
[% IF c.user_exists %]
-
-[Create a release ]
-
+
+ Create a release
+
[% END %]
[% END %]
diff --git a/src/root/status.tt b/src/root/status.tt
index 20677e4a..ee820c2e 100644
--- a/src/root/status.tt
+++ b/src/root/status.tt
@@ -1,7 +1,7 @@
[% WRAPPER layout.tt title="Hydra status" %]
[% PROCESS common.tt %]
-Hydra Status
+
[% INCLUDE hydraStatus %]
diff --git a/src/root/timeline.tt b/src/root/timeline.tt
index 96344590..6b35d09b 100644
--- a/src/root/timeline.tt
+++ b/src/root/timeline.tt
@@ -4,7 +4,7 @@
[% PROCESS common.tt %]
-Hydra timeline of last 24 hours
+
+ [% END %]
+
+
-[% IF !create %]
-
-
- Remove this user
-
-
-
-[% END %]
-
[% END %]
diff --git a/src/root/users.tt b/src/root/users.tt
index 01203245..7894155d 100644
--- a/src/root/users.tt
+++ b/src/root/users.tt
@@ -1,7 +1,7 @@
[% WRAPPER layout.tt title="Users" %]
[% PROCESS common.tt %]
-Users
+
@@ -17,18 +17,20 @@
[% FOREACH u IN users %]
- [% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('user_edit'), [u.username]) content = u.username %]
+ [% u.username %]
[% u.fullname %]
[% u.emailaddress %]
[% FOREACH r IN u.userroles %][% r.role %] [% END %]
[% IF u.emailonerror %]Yes[% ELSE %]No[% END %]
- [ [% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('reset_password'), [u.username]) content = "Reset password" confirmmsg = "Are you sure you want to reset the password for this user?" %] ]
+ [% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('reset_password'), [u.username]) content = "Reset password" confirmmsg = "Are you sure you want to reset the password for this user?" class = "btn btn-mini" %]
[% END %]
-[ Add a new user ]
+
+ Add a new user
+
[% END %]
diff --git a/src/root/view-result.tt b/src/root/view-result.tt
index 8ee2e958..96fb80ba 100644
--- a/src/root/view-result.tt
+++ b/src/root/view-result.tt
@@ -4,7 +4,7 @@
[% PROCESS "product-list.tt" %]
[% USE HTML %]
-View [% view.project.name %]:[% view.name %] result [% result.id %][% IF result.releasename %] ([% result.releasename %] )[% END %]
+
Finished building on [% INCLUDE renderDateTime timestamp = result.timestamp %].
@@ -46,11 +46,13 @@
[% END %]
+
+
[% END %]
[% IF c.user_exists %]
-[Release ]
+Release
[% END %]
diff --git a/src/root/view.tt b/src/root/view.tt
index cc314541..05eefd2b 100644
--- a/src/root/view.tt
+++ b/src/root/view.tt
@@ -2,11 +2,11 @@
[% PROCESS common.tt %]
[% USE HTML %]
-View [% view.project.name %]:[% view.name %]
+
-[Edit ]
-[Latest ]
+ Edit
+ Latest
Showing results [% (page - 1) * resultsPerPage + 1 %] - [% (page - 1) * resultsPerPage + results.size %] out of [% totalResults %].
@@ -65,8 +65,12 @@