2012-04-02 16:11:22 +02:00
|
|
|
|
package Hydra::Controller::JobsetEval;
|
|
|
|
|
|
2016-10-24 16:08:19 +02:00
|
|
|
|
use utf8;
|
2012-04-02 16:11:22 +02:00
|
|
|
|
use strict;
|
|
|
|
|
use warnings;
|
2012-04-02 23:25:07 +02:00
|
|
|
|
use base 'Hydra::Base::Controller::NixChannel';
|
2012-04-02 16:11:22 +02:00
|
|
|
|
use Hydra::Helper::Nix;
|
|
|
|
|
use Hydra::Helper::CatalystUtils;
|
2022-01-10 11:40:23 -08:00
|
|
|
|
use Hydra::Helper::BuildDiff;
|
2021-12-14 10:08:30 -05:00
|
|
|
|
use List::SomeUtils qw(uniq);
|
2012-04-02 16:11:22 +02:00
|
|
|
|
|
|
|
|
|
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub evalChain : Chained('/') PathPart('eval') CaptureArgs(1) {
|
2012-04-02 16:11:22 +02:00
|
|
|
|
my ($self, $c, $evalId) = @_;
|
2013-01-22 14:41:02 +01:00
|
|
|
|
|
2012-04-02 16:11:22 +02:00
|
|
|
|
my $eval = $c->model('DB::JobsetEvals')->find($evalId)
|
2013-01-22 14:09:37 +01:00
|
|
|
|
or notFound($c, "Evaluation $evalId doesn't exist.");
|
2012-04-02 16:11:22 +02:00
|
|
|
|
|
|
|
|
|
$c->stash->{eval} = $eval;
|
|
|
|
|
$c->stash->{jobset} = $eval->jobset;
|
2021-01-26 09:50:59 -05:00
|
|
|
|
$c->stash->{project} = $eval->jobset->project;
|
2012-04-02 16:11:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub view :Chained('evalChain') :PathPart('') :Args(0) :ActionClass('REST') { }
|
|
|
|
|
|
|
|
|
|
sub view_GET {
|
2012-04-02 16:11:22 +02:00
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
|
|
|
|
|
$c->stash->{template} = 'jobset-eval.tt';
|
|
|
|
|
|
|
|
|
|
my $eval = $c->stash->{eval};
|
|
|
|
|
|
2013-08-28 16:07:24 +02:00
|
|
|
|
$c->stash->{filter} = $c->request->params->{filter} // "";
|
|
|
|
|
my $filter = $c->stash->{filter} eq "" ? {} : { job => { ilike => "%" . $c->stash->{filter} . "%" } };
|
|
|
|
|
|
2012-04-02 20:40:59 +02:00
|
|
|
|
my $compare = $c->req->params->{compare};
|
|
|
|
|
my $eval2;
|
2012-04-02 16:11:22 +02:00
|
|
|
|
|
2012-04-02 20:40:59 +02:00
|
|
|
|
# Allow comparing this evaluation against the previous evaluation
|
|
|
|
|
# (default), an arbitrary evaluation, or the latest completed
|
|
|
|
|
# evaluation of another jobset.
|
2012-04-17 08:53:00 +00:00
|
|
|
|
if (defined $compare) {
|
|
|
|
|
if ($compare =~ /^\d+$/) {
|
|
|
|
|
$eval2 = $c->model('DB::JobsetEvals')->find($compare)
|
|
|
|
|
or notFound($c, "Evaluation $compare doesn't exist.");
|
2013-10-03 01:54:42 +02:00
|
|
|
|
} elsif ($compare =~ /^-(\d+)$/) {
|
|
|
|
|
my $t = int($1);
|
2013-08-28 15:46:08 +02:00
|
|
|
|
$eval2 = $c->stash->{jobset}->jobsetevals->find(
|
2013-10-03 01:54:42 +02:00
|
|
|
|
{ hasnewbuilds => 1, timestamp => {'<=', $eval->timestamp - $t} },
|
|
|
|
|
{ order_by => "timestamp desc", rows => 1});
|
2012-04-17 08:53:00 +00:00
|
|
|
|
} elsif (defined $compare && $compare =~ /^($jobsetNameRE)$/) {
|
|
|
|
|
my $j = $c->stash->{project}->jobsets->find({name => $compare})
|
|
|
|
|
or notFound($c, "Jobset $compare doesn't exist.");
|
2013-11-11 21:17:22 +00:00
|
|
|
|
$eval2 = getLatestFinishedEval($j);
|
2012-04-17 08:53:00 +00:00
|
|
|
|
} else {
|
|
|
|
|
notFound($c, "Unknown comparison source ‘$compare’.");
|
|
|
|
|
}
|
2012-04-02 20:40:59 +02:00
|
|
|
|
} else {
|
|
|
|
|
($eval2) = $eval->jobset->jobsetevals->search(
|
|
|
|
|
{ hasnewbuilds => 1, id => { '<', $eval->id } },
|
|
|
|
|
{ order_by => "id DESC", rows => 1 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$c->stash->{otherEval} = $eval2 if defined $eval2;
|
2013-01-22 14:41:02 +01:00
|
|
|
|
|
2013-08-28 16:07:24 +02:00
|
|
|
|
my @builds = $eval->builds->search($filter, { columns => [@buildListColumns] });
|
|
|
|
|
my @builds2 = defined $eval2 ? $eval2->builds->search($filter, { columns => [@buildListColumns] }) : ();
|
2013-08-28 13:04:14 +00:00
|
|
|
|
|
2022-01-10 10:54:54 -08:00
|
|
|
|
my $diff = buildDiff([@builds], [@builds2]);
|
|
|
|
|
$c->stash->{stillSucceed} = $diff->{stillSucceed};
|
|
|
|
|
$c->stash->{stillFail} = $diff->{stillFail};
|
|
|
|
|
$c->stash->{nowSucceed} = $diff->{nowSucceed};
|
|
|
|
|
$c->stash->{nowFail} = $diff->{nowFail};
|
|
|
|
|
$c->stash->{new} = $diff->{new};
|
|
|
|
|
$c->stash->{removed} = $diff->{removed};
|
|
|
|
|
$c->stash->{unfinished} = $diff->{unfinished};
|
|
|
|
|
$c->stash->{aborted} = $diff->{aborted};
|
|
|
|
|
$c->stash->{failed} = $diff->{failed};
|
2013-01-22 14:41:02 +01:00
|
|
|
|
|
2012-04-02 16:11:22 +02:00
|
|
|
|
$c->stash->{full} = ($c->req->params->{full} || "0") eq "1";
|
2015-09-02 13:13:55 +02:00
|
|
|
|
|
|
|
|
|
$self->status_ok(
|
|
|
|
|
$c,
|
|
|
|
|
entity => $eval
|
|
|
|
|
);
|
2012-04-02 16:11:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub create_jobset : Chained('evalChain') PathPart('create-jobset') Args(0) {
|
2015-07-06 15:17:35 +02:00
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
my $eval = $c->stash->{eval};
|
|
|
|
|
|
|
|
|
|
requireProjectOwner($c, $c->stash->{project});
|
|
|
|
|
|
|
|
|
|
$c->stash->{template} = 'edit-jobset.tt';
|
|
|
|
|
$c->stash->{createFromEval} = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub cancel : Chained('evalChain') PathPart('cancel') Args(0) {
|
2013-10-04 15:40:43 +02:00
|
|
|
|
my ($self, $c) = @_;
|
2021-02-01 10:21:10 -05:00
|
|
|
|
requireCancelBuildPrivileges($c, $c->stash->{project});
|
2021-10-27 11:05:00 -04:00
|
|
|
|
my $n = cancelBuilds($c->model('DB')->schema, $c->stash->{eval}->builds->search_rs({}));
|
2013-10-04 15:40:43 +02:00
|
|
|
|
$c->flash->{successMsg} = "$n builds have been cancelled.";
|
|
|
|
|
$c->res->redirect($c->uri_for($c->controller('JobsetEval')->action_for('view'), $c->req->captures));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-10-28 15:04:12 +01:00
|
|
|
|
sub restart {
|
|
|
|
|
my ($self, $c, $condition) = @_;
|
2021-02-01 10:21:10 -05:00
|
|
|
|
requireRestartPrivileges($c, $c->stash->{project});
|
2021-10-21 09:34:06 -04:00
|
|
|
|
my $builds = $c->stash->{eval}->builds->search_rs({ finished => 1, buildstatus => $condition });
|
2013-10-04 17:01:47 +02:00
|
|
|
|
my $n = restartBuilds($c->model('DB')->schema, $builds);
|
|
|
|
|
$c->flash->{successMsg} = "$n builds have been restarted.";
|
|
|
|
|
$c->res->redirect($c->uri_for($c->controller('JobsetEval')->action_for('view'), $c->req->captures));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-10-28 15:04:12 +01:00
|
|
|
|
sub restart_aborted : Chained('evalChain') PathPart('restart-aborted') Args(0) {
|
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
restart($self, $c, { -in => [3, 4, 9] });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sub restart_failed : Chained('evalChain') PathPart('restart-failed') Args(0) {
|
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
restart($self, $c, { 'not in' => [0] });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub bump : Chained('evalChain') PathPart('bump') Args(0) {
|
2015-08-10 18:56:19 +02:00
|
|
|
|
my ($self, $c) = @_;
|
2021-02-01 10:21:10 -05:00
|
|
|
|
requireBumpPrivileges($c, $c->stash->{project}); # FIXME: require admin?
|
2015-08-10 18:56:19 +02:00
|
|
|
|
my $builds = $c->stash->{eval}->builds->search({ finished => 0 });
|
|
|
|
|
my $n = $builds->count();
|
|
|
|
|
$c->model('DB')->schema->txn_do(sub {
|
|
|
|
|
$builds->update({globalpriority => time()});
|
|
|
|
|
});
|
|
|
|
|
$c->flash->{successMsg} = "$n builds have been bumped to the front of the queue.";
|
|
|
|
|
$c->res->redirect($c->uri_for($c->controller('JobsetEval')->action_for('view'), $c->req->captures));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-04-02 23:25:07 +02:00
|
|
|
|
# Hydra::Base::Controller::NixChannel needs this.
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub nix : Chained('evalChain') PathPart('channel') CaptureArgs(0) {
|
2012-04-02 23:25:07 +02:00
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
$c->stash->{channelName} = $c->stash->{project}->name . "-" . $c->stash->{jobset}->name . "-latest";
|
|
|
|
|
$c->stash->{channelBuilds} = $c->stash->{eval}->builds
|
|
|
|
|
->search_literal("exists (select 1 from buildproducts where build = build.id and type = 'nix-build')")
|
2013-02-13 16:49:28 +00:00
|
|
|
|
->search({ finished => 1, buildstatus => 0 },
|
|
|
|
|
{ columns => [@buildListColumns, 'drvpath', 'description', 'homepage']
|
|
|
|
|
, join => ["buildoutputs"]
|
2013-10-07 17:06:17 +02:00
|
|
|
|
, order_by => ["build.id", "buildoutputs.name"]
|
2013-02-13 16:49:28 +00:00
|
|
|
|
, '+select' => ['buildoutputs.path', 'buildoutputs.name'], '+as' => ['outpath', 'outname'] });
|
2012-04-02 23:25:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-09-02 13:13:55 +02:00
|
|
|
|
sub job : Chained('evalChain') PathPart('job') {
|
2013-08-13 01:56:45 +02:00
|
|
|
|
my ($self, $c, $job, @rest) = @_;
|
|
|
|
|
|
|
|
|
|
my $build = $c->stash->{eval}->builds->find({job => $job});
|
|
|
|
|
|
|
|
|
|
notFound($c, "This evaluation has no job with the specified name.") unless defined $build;
|
|
|
|
|
|
|
|
|
|
$c->res->redirect($c->uri_for($c->controller('Build')->action_for("build"), [$build->id], @rest));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-03-02 15:17:22 +01:00
|
|
|
|
# Return the store paths of all succeeded builds of type 'nix-build'
|
|
|
|
|
# (i.e. regular packages). Used by the NixOS channel scripts.
|
|
|
|
|
sub store_paths : Chained('evalChain') PathPart('store-paths') Args(0) {
|
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
|
|
|
|
|
my @builds = $c->stash->{eval}->builds
|
|
|
|
|
->search_literal("exists (select 1 from buildproducts where build = build.id and type = 'nix-build')")
|
|
|
|
|
->search({ finished => 1, buildstatus => 0 },
|
|
|
|
|
{ columns => [], join => ["buildoutputs"]
|
|
|
|
|
, '+select' => ['buildoutputs.path'], '+as' => ['outpath'] });
|
|
|
|
|
|
|
|
|
|
$self->status_ok(
|
|
|
|
|
$c,
|
2016-03-03 11:32:30 +01:00
|
|
|
|
entity => [uniq(sort map {$_->get_column('outpath')} @builds)]
|
2016-03-02 15:17:22 +01:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-01-14 01:26:31 +01:00
|
|
|
|
# Return full info about all the builds in this evaluation.
|
|
|
|
|
sub all_builds : Chained('evalChain') PathPart('builds') Args(0) {
|
|
|
|
|
my ($self, $c) = @_;
|
|
|
|
|
my @builds = $c->stash->{eval}->builds;
|
|
|
|
|
$self->status_ok(
|
|
|
|
|
$c,
|
|
|
|
|
entity => [@builds],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-04-02 16:11:22 +02:00
|
|
|
|
1;
|