forked from lix-project/hydra
* Allow builds to be restarted (if they failed with a transient error,
e.g. interrupted or network problems).
This commit is contained in:
parent
c7736f0643
commit
f75924db95
|
@ -30,6 +30,7 @@ sub view_build : Chained('build') PathPart('') Args(0) {
|
||||||
$c->stash->{curTime} = time;
|
$c->stash->{curTime} = time;
|
||||||
$c->stash->{available} = isValidPath $build->outpath;
|
$c->stash->{available} = isValidPath $build->outpath;
|
||||||
$c->stash->{drvAvailable} = isValidPath $build->drvpath;
|
$c->stash->{drvAvailable} = isValidPath $build->drvpath;
|
||||||
|
$c->stash->{flashMsg} = $c->flash->{afterRestart};
|
||||||
|
|
||||||
if (!$build->finished && $build->schedulingInfo->busy) {
|
if (!$build->finished && $build->schedulingInfo->busy) {
|
||||||
my $logfile = $build->schedulingInfo->logfile;
|
my $logfile = $build->schedulingInfo->logfile;
|
||||||
|
@ -155,4 +156,35 @@ sub nix : Chained('build') PathPart('nix') CaptureArgs(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub restart : Chained('build') PathPart('restart') Args(0) {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
my $build = $c->stash->{build};
|
||||||
|
|
||||||
|
requireProjectOwner($c, $build->project);
|
||||||
|
|
||||||
|
error($c, "This build cannot be restarted.")
|
||||||
|
unless $build->finished && $build->resultInfo->buildstatus == 3;
|
||||||
|
|
||||||
|
$c->model('DB')->schema->txn_do(sub {
|
||||||
|
$build->finished(0);
|
||||||
|
$build->timestamp(time());
|
||||||
|
$build->update;
|
||||||
|
|
||||||
|
$build->resultInfo->delete;
|
||||||
|
|
||||||
|
$c->model('DB::BuildSchedulingInfo')->create(
|
||||||
|
{ id => $build->id
|
||||||
|
, priority => 0 # don't know the original priority anymore...
|
||||||
|
, busy => 0
|
||||||
|
, locker => ""
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$c->flash->{afterRestart} = "Build has been restarted.";
|
||||||
|
|
||||||
|
$c->response->redirect($c->uri_for($self->action_for("view_build"), $c->req->captures));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -82,13 +82,6 @@ sub logout :Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub requireLogin {
|
|
||||||
my ($c) = @_;
|
|
||||||
$c->flash->{afterLogin} = $c->request->uri;
|
|
||||||
$c->response->redirect($c->uri_for('/login'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub queue :Local {
|
sub queue :Local {
|
||||||
my ($self, $c) = @_;
|
my ($self, $c) = @_;
|
||||||
$c->stash->{template} = 'queue.tt';
|
$c->stash->{template} = 'queue.tt';
|
||||||
|
@ -230,10 +223,7 @@ sub releases :Local {
|
||||||
|
|
||||||
if (defined $subcommand && $subcommand ne "") {
|
if (defined $subcommand && $subcommand ne "") {
|
||||||
|
|
||||||
return requireLogin($c) if !$c->user_exists;
|
requireProjectOwner($c, $project);
|
||||||
|
|
||||||
error($c, "Only the project owner or the administrator can perform this operation.")
|
|
||||||
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
|
||||||
|
|
||||||
if ($subcommand eq "edit") {
|
if ($subcommand eq "edit") {
|
||||||
$c->stash->{template} = 'edit-releaseset.tt';
|
$c->stash->{template} = 'edit-releaseset.tt';
|
||||||
|
@ -272,10 +262,7 @@ sub create_releaseset :Local {
|
||||||
die "Project $projectName doesn't exist." if !defined $project;
|
die "Project $projectName doesn't exist." if !defined $project;
|
||||||
$c->stash->{curProject} = $project;
|
$c->stash->{curProject} = $project;
|
||||||
|
|
||||||
return requireLogin($c) if !$c->user_exists;
|
requireProjectOwner($c, $project);
|
||||||
|
|
||||||
error($c, "Only the project owner or the administrator can perform this operation.")
|
|
||||||
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
|
||||||
|
|
||||||
if (defined $subcommand && $subcommand eq "submit") {
|
if (defined $subcommand && $subcommand eq "submit") {
|
||||||
my $releaseSetName = $c->request->params->{name};
|
my $releaseSetName = $c->request->params->{name};
|
||||||
|
@ -468,10 +455,7 @@ sub project :Local {
|
||||||
|
|
||||||
elsif ($subcommand ne "") {
|
elsif ($subcommand ne "") {
|
||||||
|
|
||||||
return requireLogin($c) if !$c->user_exists;
|
requireProjectOwner($c, $project);
|
||||||
|
|
||||||
error($c, "Only the project owner or the administrator can perform this operation.")
|
|
||||||
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
|
||||||
|
|
||||||
if ($subcommand eq "edit") {
|
if ($subcommand eq "edit") {
|
||||||
$c->stash->{edit} = 1;
|
$c->stash->{edit} = 1;
|
||||||
|
@ -506,7 +490,7 @@ sub project :Local {
|
||||||
sub createproject :Local {
|
sub createproject :Local {
|
||||||
my ($self, $c, $subcommand) = @_;
|
my ($self, $c, $subcommand) = @_;
|
||||||
|
|
||||||
return requireLogin($c) if !$c->user_exists;
|
requireLogin($c) if !$c->user_exists;
|
||||||
|
|
||||||
error($c, "Only administrators can create projects.")
|
error($c, "Only administrators can create projects.")
|
||||||
unless $c->check_user_roles('admin');
|
unless $c->check_user_roles('admin');
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Readonly;
|
||||||
our @ISA = qw(Exporter);
|
our @ISA = qw(Exporter);
|
||||||
our @EXPORT = qw(
|
our @EXPORT = qw(
|
||||||
getBuild error notFound
|
getBuild error notFound
|
||||||
|
requireLogin requireProjectOwner
|
||||||
$pathCompRE $relPathRE
|
$pathCompRE $relPathRE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ sub getBuild {
|
||||||
sub error {
|
sub error {
|
||||||
my ($c, $msg) = @_;
|
my ($c, $msg) = @_;
|
||||||
$c->error($msg);
|
$c->error($msg);
|
||||||
$c->detach;
|
$c->detach; # doesn't return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +33,24 @@ sub notFound {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub requireLogin {
|
||||||
|
my ($c) = @_;
|
||||||
|
$c->flash->{afterLogin} = $c->request->uri;
|
||||||
|
$c->response->redirect($c->uri_for('/login'));
|
||||||
|
$c->detach; # doesn't return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub requireProjectOwner {
|
||||||
|
my ($c, $project) = @_;
|
||||||
|
|
||||||
|
requireLogin($c) if !$c->user_exists;
|
||||||
|
|
||||||
|
error($c, "Only the project owner or the administrator can perform this operation.")
|
||||||
|
unless $c->check_user_roles('admin') || $c->user->username eq $project->owner->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Security checking of filenames.
|
# Security checking of filenames.
|
||||||
Readonly::Scalar our $pathCompRE => "(?:[A-Za-z0-9-\+][A-Za-z0-9-\+\._]*)";
|
Readonly::Scalar our $pathCompRE => "(?:[A-Za-z0-9-\+][A-Za-z0-9-\+\._]*)";
|
||||||
Readonly::Scalar our $relPathRE => "(?:$pathCompRE(?:\/$pathCompRE)*)";
|
Readonly::Scalar our $relPathRE => "(?:$pathCompRE(?:\/$pathCompRE)*)";
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
|
||||||
|
[% IF flashMsg %]
|
||||||
|
<p class="error">[% flashMsg %]</p>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
|
||||||
<h2>Information</h2>
|
<h2>Information</h2>
|
||||||
|
|
||||||
<table class="layoutTable">
|
<table class="layoutTable">
|
||||||
|
@ -39,6 +44,9 @@
|
||||||
<img src="/static/images/failure.gif" />
|
<img src="/static/images/failure.gif" />
|
||||||
<span class="error">Build failed</span>
|
<span class="error">Build failed</span>
|
||||||
(see <a href="#nix-error">below</a>)
|
(see <a href="#nix-error">below</a>)
|
||||||
|
<form action="[% c.uri_for('/build' build.id 'restart') %]" method="post" class="inline">
|
||||||
|
<button id="delete-project" type="submit">Restart</button>
|
||||||
|
</form>
|
||||||
[% END %]
|
[% END %]
|
||||||
[% ELSIF build.schedulingInfo.busy %]
|
[% ELSIF build.schedulingInfo.busy %]
|
||||||
<strong>Build in progress</strong>
|
<strong>Build in progress</strong>
|
||||||
|
|
|
@ -437,3 +437,7 @@ select {
|
||||||
button {
|
button {
|
||||||
background-color: #f0f0e0;
|
background-color: #f0f0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue