Merge the BuildResultInfo table into the Builds table

This commit is contained in:
Eelco Dolstra 2012-03-05 21:52:47 +01:00
parent 25334715f8
commit 68a867da67
20 changed files with 270 additions and 449 deletions

View file

@ -10,14 +10,12 @@ use Hydra::Helper::CatalystUtils;
sub getJobStatus { sub getJobStatus {
my ($self, $c) = @_; my ($self, $c) = @_;
my $latest = joinWithResultInfo($c, $c->stash->{jobStatus});
my $maintainer = $c->request->params->{"maintainer"}; my $maintainer = $c->request->params->{"maintainer"};
$latest = $latest->search( my $latest = $c->stash->{jobStatus}->search(
defined $maintainer ? { maintainers => { like => "%$maintainer%" } } : {}, defined $maintainer ? { maintainers => { like => "%$maintainer%" } } : {},
{ '+select' => ["me.statusChangeId", "me.statusChangeTime", "resultInfo.buildStatus"] { '+select' => ["me.statusChangeId", "me.statusChangeTime"]
, '+as' => ["statusChangeId", "statusChangeTime", "buildStatus"] , '+as' => ["statusChangeId", "statusChangeTime"]
, order_by => "coalesce(statusChangeTime, 0) desc" , order_by => "coalesce(statusChangeTime, 0) desc"
}); });
@ -43,7 +41,7 @@ sub errors : Chained('get_builds') PathPart Args(0) {
[$c->stash->{allJobs}->search({errormsg => {'!=' => ''}})] [$c->stash->{allJobs}->search({errormsg => {'!=' => ''}})]
if defined $c->stash->{allJobs}; if defined $c->stash->{allJobs};
$c->stash->{brokenBuilds} = $c->stash->{brokenBuilds} =
[getJobStatus($self, $c)->search({'resultInfo.buildstatus' => {'!=' => 0}})]; [getJobStatus($self, $c)->search({buildStatus => {'!=' => 0}})];
} }
@ -64,11 +62,9 @@ sub all : Chained('get_builds') PathPart {
$c->stash->{resultsPerPage} = $resultsPerPage; $c->stash->{resultsPerPage} = $resultsPerPage;
$c->stash->{totalBuilds} = $nrBuilds; $c->stash->{totalBuilds} = $nrBuilds;
$c->stash->{builds} = [ joinWithResultInfo($c, $c->stash->{allBuilds})->search( $c->stash->{builds} = [ $c->stash->{allBuilds}->search(
{ finished => 1 }, { finished => 1 },
{ '+select' => ["resultInfo.buildStatus"] { order_by => "timestamp DESC"
, '+as' => ["buildStatus"]
, order_by => "timestamp DESC"
, rows => $resultsPerPage , rows => $resultsPerPage
, page => $page }) ]; , page => $page }) ];
} }
@ -97,8 +93,8 @@ sub nix : Chained('get_builds') PathPart('channel') CaptureArgs(1) {
sub latest : Chained('get_builds') PathPart('latest') { sub latest : Chained('get_builds') PathPart('latest') {
my ($self, $c, @rest) = @_; my ($self, $c, @rest) = @_;
my ($latest) = joinWithResultInfo($c, $c->stash->{allBuilds}) my ($latest) = $c->stash->{allBuilds}->search(
->search({finished => 1, buildstatus => 0}, {order_by => ["isCurrent DESC", "timestamp DESC"]}); {finished => 1, buildstatus => 0}, {order_by => ["isCurrent DESC", "timestamp DESC"]});
notFound($c, "There is no successful build to redirect to.") unless defined $latest; notFound($c, "There is no successful build to redirect to.") unless defined $latest;
@ -112,8 +108,8 @@ sub latest_for : Chained('get_builds') PathPart('latest-for') {
notFound($c, "You need to specify a platform type in the URL.") unless defined $system; notFound($c, "You need to specify a platform type in the URL.") unless defined $system;
my ($latest) = joinWithResultInfo($c, $c->stash->{allBuilds}) my ($latest) = $c->stash->{allBuilds}->search(
->search({finished => 1, buildstatus => 0, system => $system}, {order_by => ["isCurrent DESC", "timestamp DESC"]}); {finished => 1, buildstatus => 0, system => $system}, {order_by => ["isCurrent DESC", "timestamp DESC"]});
notFound($c, "There is no successful build for platform `$system' to redirect to.") unless defined $latest; notFound($c, "There is no successful build for platform `$system' to redirect to.") unless defined $latest;

View file

@ -15,11 +15,13 @@ use File::Slurp;
# !!! Rewrite this to use View::JSON. # !!! Rewrite this to use View::JSON.
sub api : Chained('/') PathPart('api') CaptureArgs(0) { sub api : Chained('/') PathPart('api') CaptureArgs(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
$c->response->content_type('application/json'); $c->response->content_type('application/json');
} }
sub projectToHash { sub projectToHash {
my ($project) = @_; my ($project) = @_;
return { return {
@ -28,14 +30,15 @@ sub projectToHash {
}; };
} }
sub projects : Chained('api') PathPart('projects') Args(0) { sub projects : Chained('api') PathPart('projects') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my @projects = $c->model('DB::Projects')->search({hidden => 0}, {order_by => 'name'}) ; my @projects = $c->model('DB::Projects')->search({hidden => 0}, {order_by => 'name'});
my @list ; my @list;
foreach my $p (@projects) { foreach my $p (@projects) {
push @list, projectToHash($p) ; push @list, projectToHash($p);
} }
$c->stash->{'plain'} = { $c->stash->{'plain'} = {
@ -44,6 +47,7 @@ sub projects : Chained('api') PathPart('projects') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub buildToHash { sub buildToHash {
my ($build) = @_; my ($build) = @_;
my $result = { my $result = {
@ -58,7 +62,7 @@ sub buildToHash {
}; };
if($build->finished) { if($build->finished) {
$result->{'buildstatus'} = $build->get_column("buildstatus") ; $result->{'buildstatus'} = $build->get_column("buildstatus");
} else { } else {
$result->{'busy'} = $build->get_column("busy"); $result->{'busy'} = $build->get_column("busy");
$result->{'priority'} = $build->get_column("priority"); $result->{'priority'} = $build->get_column("priority");
@ -67,28 +71,27 @@ sub buildToHash {
return $result; return $result;
}; };
sub latestbuilds : Chained('api') PathPart('latestbuilds') Args(0) { sub latestbuilds : Chained('api') PathPart('latestbuilds') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $nr = $c->request->params->{nr} ; my $nr = $c->request->params->{nr};
error($c, "Parameter not defined!") if !defined $nr; error($c, "Parameter not defined!") if !defined $nr;
my $project = $c->request->params->{project} ; my $project = $c->request->params->{project};
my $jobset = $c->request->params->{jobset} ; my $jobset = $c->request->params->{jobset};
my $job = $c->request->params->{job} ; my $job = $c->request->params->{job};
my $system = $c->request->params->{system} ; my $system = $c->request->params->{system};
my $filter = {finished => 1} ; my $filter = {finished => 1};
$filter->{project} = $project if ! $project eq ""; $filter->{project} = $project if ! $project eq "";
$filter->{jobset} = $jobset if ! $jobset eq ""; $filter->{jobset} = $jobset if ! $jobset eq "";
$filter->{job} = $job if !$job eq ""; $filter->{job} = $job if !$job eq "";
$filter->{system} = $system if !$system eq ""; $filter->{system} = $system if !$system eq "";
my @latest = joinWithResultInfo($c, $c->model('DB::Builds'))->search($filter, {rows => $nr, order_by => ["timestamp DESC"] }); my @latest = $c->model('DB::Builds')->search($filter, {rows => $nr, order_by => ["timestamp DESC"] });
my @list ; my @list;
foreach my $b (@latest) { push @list, buildToHash($_) foreach @latest;
push @list, buildToHash($b) ;
}
$c->stash->{'plain'} = { $c->stash->{'plain'} = {
data => scalar (JSON::Any->objToJson(\@list)) data => scalar (JSON::Any->objToJson(\@list))
@ -96,6 +99,7 @@ sub latestbuilds : Chained('api') PathPart('latestbuilds') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub jobsetToHash { sub jobsetToHash {
my ($jobset) = @_; my ($jobset) = @_;
return { return {
@ -108,10 +112,11 @@ sub jobsetToHash {
}; };
} }
sub jobsets : Chained('api') PathPart('jobsets') Args(0) { sub jobsets : Chained('api') PathPart('jobsets') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $projectName = $c->request->params->{project} ; my $projectName = $c->request->params->{project};
error($c, "Parameter 'project' not defined!") if !defined $projectName; error($c, "Parameter 'project' not defined!") if !defined $projectName;
my $project = $c->model('DB::Projects')->find($projectName) my $project = $c->model('DB::Projects')->find($projectName)
@ -119,10 +124,8 @@ sub jobsets : Chained('api') PathPart('jobsets') Args(0) {
my @jobsets = jobsetOverview($c, $project); my @jobsets = jobsetOverview($c, $project);
my @list ; my @list;
foreach my $j (@jobsets) { push @list, jobsetToHash($_) foreach @jobsets;
push @list, jobsetToHash($j) ;
}
$c->stash->{'plain'} = { $c->stash->{'plain'} = {
data => scalar (JSON::Any->objToJson(\@list)) data => scalar (JSON::Any->objToJson(\@list))
@ -130,10 +133,11 @@ sub jobsets : Chained('api') PathPart('jobsets') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub queue : Chained('api') PathPart('queue') Args(0) { sub queue : Chained('api') PathPart('queue') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $nr = $c->request->params->{nr} ; my $nr = $c->request->params->{nr};
error($c, "Parameter not defined!") if !defined $nr; error($c, "Parameter not defined!") if !defined $nr;
my @builds = $c->model('DB::Builds')->search({finished => 0}, {rows => $nr, order_by => ["busy DESC", "priority DESC", "timestamp"]}); my @builds = $c->model('DB::Builds')->search({finished => 0}, {rows => $nr, order_by => ["busy DESC", "priority DESC", "timestamp"]});
@ -147,6 +151,7 @@ sub queue : Chained('api') PathPart('queue') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) { sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $nrQueuedBuilds = $c->model('DB::Builds')->search({finished => 0})->count(); my $nrQueuedBuilds = $c->model('DB::Builds')->search({finished => 0})->count();
@ -156,6 +161,7 @@ sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub nrrunning : Chained('api') PathPart('nrrunning') Args(0) { sub nrrunning : Chained('api') PathPart('nrrunning') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $nrRunningBuilds = $c->model('DB::Builds')->search({finished => 0, busy => 1 })->count(); my $nrRunningBuilds = $c->model('DB::Builds')->search({finished => 0, busy => 1 })->count();
@ -165,20 +171,21 @@ sub nrrunning : Chained('api') PathPart('nrrunning') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub nrbuilds : Chained('api') PathPart('nrbuilds') Args(0) { sub nrbuilds : Chained('api') PathPart('nrbuilds') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $nr = $c->request->params->{nr} ; my $nr = $c->request->params->{nr};
my $period = $c->request->params->{period} ; my $period = $c->request->params->{period};
error($c, "Parameter not defined!") if !defined $nr || !defined $period; error($c, "Parameter not defined!") if !defined $nr || !defined $period;
my $base; my $base;
my $project = $c->request->params->{project} ; my $project = $c->request->params->{project};
my $jobset = $c->request->params->{jobset} ; my $jobset = $c->request->params->{jobset};
my $job = $c->request->params->{job} ; my $job = $c->request->params->{job};
my $system = $c->request->params->{system} ; my $system = $c->request->params->{system};
my $filter = {finished => 1} ; my $filter = {finished => 1};
$filter->{project} = $project if ! $project eq ""; $filter->{project} = $project if ! $project eq "";
$filter->{jobset} = $jobset if ! $jobset eq ""; $filter->{jobset} = $jobset if ! $jobset eq "";
$filter->{job} = $job if !$job eq ""; $filter->{job} = $job if !$job eq "";
@ -187,11 +194,9 @@ sub nrbuilds : Chained('api') PathPart('nrbuilds') Args(0) {
$base = 60*60 if($period eq "hour"); $base = 60*60 if($period eq "hour");
$base = 24*60*60 if($period eq "day"); $base = 24*60*60 if($period eq "day");
my @stats = $c->model('DB::Builds')->search($filter, {select => [{ count => "*" }], as => ["nr"], group_by => ["timestamp - timestamp % $base"], order_by => "timestamp - timestamp % $base DESC", rows => $nr}) ; my @stats = $c->model('DB::Builds')->search($filter, {select => [{ count => "*" }], as => ["nr"], group_by => ["timestamp - timestamp % $base"], order_by => "timestamp - timestamp % $base DESC", rows => $nr});
my @arr ; my @arr;
foreach my $d (@stats) { push @arr, int($_->get_column("nr")) foreach @stats;
push @arr, int($d->get_column("nr"));
}
@arr = reverse(@arr); @arr = reverse(@arr);
$c->stash->{'plain'} = { $c->stash->{'plain'} = {
@ -200,38 +205,40 @@ sub nrbuilds : Chained('api') PathPart('nrbuilds') Args(0) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub scmdiff : Chained('api') PathPart('scmdiff') Args(0) { sub scmdiff : Chained('api') PathPart('scmdiff') Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $uri = $c->request->params->{uri} ; my $uri = $c->request->params->{uri};
my $type = $c->request->params->{type} ; my $type = $c->request->params->{type};
my $rev1 = $c->request->params->{rev1} ; my $rev1 = $c->request->params->{rev1};
my $rev2 = $c->request->params->{rev2} ; my $rev2 = $c->request->params->{rev2};
my $branch; my $branch;
die("invalid revisions: [$rev1] [$rev2]") if $rev1 !~ m/^[a-zA-Z0-9_.]+$/ || $rev2 !~ m/^[a-zA-Z0-9_.]+$/ ; die("invalid revisions: [$rev1] [$rev2]") if $rev1 !~ m/^[a-zA-Z0-9_.]+$/ || $rev2 !~ m/^[a-zA-Z0-9_.]+$/;
my $diff = ""; my $diff = "";
if($type eq "hg") { if ($type eq "hg") {
my $clonePath = scmPath . "/" . sha256_hex($uri); my $clonePath = scmPath . "/" . sha256_hex($uri);
die if ! -d $clonePath; die if ! -d $clonePath;
$branch = `(cd $clonePath ; hg log --template '{branch}' -r $rev2)`; $branch = `(cd $clonePath; hg log --template '{branch}' -r $rev2)`;
$diff .= `(cd $clonePath ; hg log -r $rev1 -r $rev2 -b $branch)`; $diff .= `(cd $clonePath; hg log -r $rev1 -r $rev2 -b $branch)`;
$diff .= `(cd $clonePath ; hg diff -r $rev1:$rev2)`; $diff .= `(cd $clonePath; hg diff -r $rev1:$rev2)`;
} elsif ($type eq "git") { } elsif ($type eq "git") {
my $clonePath = scmPath . "/" . sha256_hex($uri); my $clonePath = scmPath . "/" . sha256_hex($uri);
die if ! -d $clonePath; die if ! -d $clonePath;
$diff .= `(cd $clonePath ; git log $rev1..$rev2)`; $diff .= `(cd $clonePath; git log $rev1..$rev2)`;
$diff .= `(cd $clonePath ; git diff $rev1..$rev2)`; $diff .= `(cd $clonePath; git diff $rev1..$rev2)`;
} }
$c->stash->{'plain'} = { data => (scalar $diff) || " " }; $c->stash->{'plain'} = { data => (scalar $diff) || " " };
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
sub readNormalizedLog { sub readNormalizedLog {
my ($file) = @_; my ($file) = @_;
my $pipe = (-f "$file.bz2" ? "cat $file.bz2 | bzip2 -d" : "cat $file") ; my $pipe = (-f "$file.bz2" ? "cat $file.bz2 | bzip2 -d" : "cat $file");
my $res = `$pipe`; my $res = `$pipe`;
$res =~ s/\/nix\/store\/[a-z0-9]*-/\/nix\/store\/...-/g; $res =~ s/\/nix\/store\/[a-z0-9]*-/\/nix\/store\/...-/g;
@ -240,6 +247,7 @@ sub readNormalizedLog {
return $res; return $res;
} }
sub logdiff : Chained('api') PathPart('logdiff') Args(2) { sub logdiff : Chained('api') PathPart('logdiff') Args(2) {
my ($self, $c, $buildid1, $buildid2) = @_; my ($self, $c, $buildid1, $buildid2) = @_;
@ -252,9 +260,9 @@ sub logdiff : Chained('api') PathPart('logdiff') Args(2) {
notFound($c, "Build with ID $buildid2 doesn't exist.") notFound($c, "Build with ID $buildid2 doesn't exist.")
if !defined $build2; if !defined $build2;
if (-f $build1->resultInfo->logfile && -f $build2->resultInfo->logfile) { if (-f $build1->logfile && -f $build2->logfile) {
my $logtext1 = readNormalizedLog($build1->resultInfo->logfile); my $logtext1 = readNormalizedLog($build1->logfile);
my $logtext2 = readNormalizedLog($build2->resultInfo->logfile); my $logtext2 = readNormalizedLog($build2->logfile);
$diff = diff \$logtext1, \$logtext2; $diff = diff \$logtext1, \$logtext2;
} else { } else {
$c->response->status(404); $c->response->status(404);
@ -265,4 +273,5 @@ sub logdiff : Chained('api') PathPart('logdiff') Args(2) {
$c->forward('Hydra::View::Plain'); $c->forward('Hydra::View::Plain');
} }
1; 1;

View file

@ -48,20 +48,20 @@ sub view_build : Chained('build') PathPart('') Args(0) {
$c->stash->{logtext} = `cat $logfile` if defined $logfile && -e $logfile; $c->stash->{logtext} = `cat $logfile` if defined $logfile && -e $logfile;
} }
if (defined $build->resultInfo && $build->resultInfo->iscachedbuild) { if ($build->finished && $build->iscachedbuild) {
(my $cachedBuildStep) = $c->model('DB::BuildSteps')->search({ outpath => $build->outpath }, {}) ; (my $cachedBuildStep) = $c->model('DB::BuildSteps')->search({ outpath => $build->outpath }, {}) ;
$c->stash->{cachedBuild} = $cachedBuildStep->build if defined $cachedBuildStep; $c->stash->{cachedBuild} = $cachedBuildStep->build if defined $cachedBuildStep;
} }
(my $lastBuildStep) = $build->buildsteps->search({},{order_by => "stepnr DESC", rows => 1}); (my $lastBuildStep) = $build->buildsteps->search({},{order_by => "stepnr DESC", rows => 1});
my $path = defined $lastBuildStep ? $lastBuildStep->logfile : "" ; my $path = defined $lastBuildStep ? $lastBuildStep->logfile : "" ;
if (defined $build->resultInfo && ($build->resultInfo->buildstatus == 1 || $build->resultInfo->buildstatus == 6) && !($path eq "") && -f $lastBuildStep->logfile) { if ($build->finished && ($build->buildstatus == 1 || $build->buildstatus == 6) && !($path eq "") && -f $lastBuildStep->logfile) {
my $logtext = `tail -n 50 $path`; my $logtext = `tail -n 50 $path`;
$c->stash->{logtext} = removeAsciiEscapes($logtext); $c->stash->{logtext} = removeAsciiEscapes($logtext);
} }
if($build->finished) { if ($build->finished) {
$c->stash->{prevBuilds} = [joinWithResultInfo($c, $c->model('DB::Builds'))->search( $c->stash->{prevBuilds} = [$c->model('DB::Builds')->search(
{ project => $c->stash->{project}->name { project => $c->stash->{project}->name
, jobset => $c->stash->{build}->jobset->name , jobset => $c->stash->{build}->jobset->name
, job => $c->stash->{build}->job->name , job => $c->stash->{build}->job->name
@ -105,9 +105,9 @@ sub view_nixlog : Chained('build') PathPart('nixlog') {
sub view_log : Chained('build') PathPart('log') { sub view_log : Chained('build') PathPart('log') {
my ($self, $c, $mode) = @_; my ($self, $c, $mode) = @_;
error($c, "Build didn't produce a log.") if !defined $c->stash->{build}->resultInfo->logfile; error($c, "Build didn't produce a log.") if !defined $c->stash->{build}->logfile;
showLog($c, $c->stash->{build}->resultInfo->logfile, $mode); showLog($c, $c->stash->{build}->logfile, $mode);
} }
@ -438,7 +438,7 @@ sub keep : Chained('build') PathPart Args(1) {
registerRoot $build->outpath if $newStatus == 1; registerRoot $build->outpath if $newStatus == 1;
txn_do($c->model('DB')->schema, sub { txn_do($c->model('DB')->schema, sub {
$build->resultInfo->update({keep => int $newStatus}); $build->update({keep => int $newStatus});
}); });
$c->flash->{buildMsg} = $c->flash->{buildMsg} =

View file

@ -25,16 +25,11 @@ sub overview : Chained('job') PathPart('') Args(0) {
#getBuildStats($c, scalar $c->stash->{job}->builds); #getBuildStats($c, scalar $c->stash->{job}->builds);
$c->stash->{currentBuilds} = [$c->stash->{job}->builds->search({iscurrent => 1}, { join => 'resultInfo', '+select' => ["resultInfo.releasename", "resultInfo.buildStatus"] $c->stash->{currentBuilds} = [$c->stash->{job}->builds->search({finished => 1, iscurrent => 1}, { order_by => 'system' })];
, '+as' => ["releasename", "buildStatus"], order_by => 'system' })];
$c->stash->{lastBuilds} = $c->stash->{lastBuilds} =
[ $c->stash->{job}->builds->search({ finished => 1 }, [ $c->stash->{job}->builds->search({ finished => 1 },
{ join => 'resultInfo', { order_by => 'timestamp DESC', rows => 10 }) ];
, '+select' => ["resultInfo.releasename", "resultInfo.buildStatus"]
, '+as' => ["releasename", "buildStatus"]
, order_by => 'timestamp DESC', rows => 10
}) ];
$c->stash->{runningBuilds} = [ $c->stash->{runningBuilds} = [
$c->stash->{job}->builds->search( $c->stash->{job}->builds->search(

View file

@ -65,9 +65,9 @@ sub jobsetIndex {
my @as = (); my @as = ();
push(@select, "job"); push(@as, "job"); push(@select, "job"); push(@as, "job");
foreach my $system (@systems) { foreach my $system (@systems) {
push(@select, "(select buildstatus from BuildResultInfo bri join Builds b using (id) where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))"); push(@select, "(select buildstatus from Builds b where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))");
push(@as, $system); push(@as, $system);
push(@select, "(select b.id from BuildResultInfo bri join Builds b using (id) where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))"); push(@select, "(select b.id from Builds b where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))");
push(@as, "$system-build"); push(@as, "$system-build");
} }
$c->stash->{activeJobsStatus} = $c->stash->{activeJobsStatus} =
@ -81,13 +81,9 @@ sub jobsetIndex {
} }
# Last builds for jobset. # Last builds for jobset.
my $tmp = $c->stash->{jobset}->builds;
$c->stash->{lastBuilds} = $c->stash->{lastBuilds} =
[ joinWithResultInfo($c, $tmp)->search({ finished => 1 }, [ $c->stash->{jobset}->builds->search({ finished => 1 },
{ order_by => "timestamp DESC", rows => 5 { order_by => "timestamp DESC", rows => 5 }) ];
, '+select' => ["resultInfo.buildStatus"]
, '+as' => ["buildStatus"]
}) ];
} }

View file

@ -86,13 +86,10 @@ sub timeline :Local {
$pit = $pit-(24*60*60)-1; $pit = $pit-(24*60*60)-1;
$c->stash->{template} = 'timeline.tt'; $c->stash->{template} = 'timeline.tt';
$c->stash->{builds} = [$c->model('DB::Builds')->search( $c->stash->{builds} = [ $c->model('DB::Builds')->search
{finished => 1, stoptime => { '>' => $pit } } ( { finished => 1, stoptime => { '>' => $pit } }
, { join => 'resultInfo' , { order_by => ["starttime"] }
, order_by => ["starttime"] ) ];
, '+select' => [ 'resultInfo.starttime', 'resultInfo.stoptime', 'resultInfo.buildstatus' ]
, '+as' => [ 'starttime', 'stoptime', 'buildstatus' ]
})];
} }

View file

@ -153,10 +153,7 @@ sub result : Chained('view') PathPart('') {
# Note: we don't actually check whether $id is a primary build, # Note: we don't actually check whether $id is a primary build,
# but who cares? # but who cares?
my $primaryBuild = $c->stash->{project}->builds->find($id, my $primaryBuild = $c->stash->{project}->builds->find($id)
{ join => 'resultInfo',
, '+select' => ["resultInfo.releasename", "resultInfo.buildstatus"]
, '+as' => ["releasename", "buildstatus"] })
or error($c, "Build $id doesn't exist."); or error($c, "Build $id doesn't exist.");
my $result = getViewResult($primaryBuild, $c->stash->{jobs}); my $result = getViewResult($primaryBuild, $c->stash->{jobs});

View file

@ -244,7 +244,7 @@ sub fetchInputBuild {
(my $prevBuild) = $db->resultset('Builds')->search( (my $prevBuild) = $db->resultset('Builds')->search(
{ finished => 1, project => $projectName, jobset => $jobsetName { finished => 1, project => $projectName, jobset => $jobsetName
, job => $jobName, buildStatus => 0 }, , job => $jobName, buildStatus => 0 },
{ join => 'resultInfo', order_by => "me.id DESC", rows => 1 { order_by => "me.id DESC", rows => 1
, where => \ attrsToSQL($attrs, "me.id") }); , where => \ attrsToSQL($attrs, "me.id") });
if (!defined $prevBuild || !isValidPath($prevBuild->outpath)) { if (!defined $prevBuild || !isValidPath($prevBuild->outpath)) {
@ -257,7 +257,7 @@ sub fetchInputBuild {
my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)"; my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)";
my $versionRE = "(?:[A-Za-z0-9\.\-]+)"; my $versionRE = "(?:[A-Za-z0-9\.\-]+)";
my $relName = ($prevBuild->resultInfo->releasename or $prevBuild->nixname); my $relName = ($prevBuild->releasename or $prevBuild->nixname);
my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/; my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/;
return return
@ -294,7 +294,7 @@ sub fetchInputSystemBuild {
my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)"; my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)";
my $versionRE = "(?:[A-Za-z0-9\.\-]+)"; my $versionRE = "(?:[A-Za-z0-9\.\-]+)";
my $relName = ($prevBuild->resultInfo->releasename or $prevBuild->nixname); my $relName = ($prevBuild->releasename or $prevBuild->nixname);
my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/; my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/;
my $input = my $input =
@ -855,9 +855,9 @@ sub checkBuild {
if (isValidPath($outPath)) { if (isValidPath($outPath)) {
print STDERR "marked as cached build ", $build->id, "\n"; print STDERR "marked as cached build ", $build->id, "\n";
$build->update({ finished => 1 }); $build->update(
$build->create_related('buildresultinfo', { finished => 1
{ iscachedbuild => 1 , iscachedbuild => 1
, buildstatus => 0 , buildstatus => 0
, starttime => $time , starttime => $time
, stoptime => $time , stoptime => $time
@ -921,7 +921,5 @@ sub restartBuild {
, busy => 0 , busy => 0
, locker => "" , locker => ""
}); });
$build->resultInfo->delete;
}); });
} }

View file

@ -8,7 +8,7 @@ use Hydra::Helper::Nix;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw( our @EXPORT = qw(
getBuild getPreviousBuild getNextBuild getPreviousSuccessfulBuild getBuildStats joinWithResultInfo getChannelData getBuild getPreviousBuild getNextBuild getPreviousSuccessfulBuild getBuildStats getChannelData
error notFound error notFound
requireLogin requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner requireLogin requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner
trim trim
@ -58,7 +58,7 @@ sub getPreviousSuccessfulBuild {
my ($c, $build) = @_; my ($c, $build) = @_;
return undef if !defined $build; return undef if !defined $build;
(my $prevBuild) = joinWithResultInfo($c, $c->model('DB::Builds'))->search( (my $prevBuild) = $c->model('DB::Builds')->search(
{ finished => 1 { finished => 1
, system => $build->system , system => $build->system
, project => $build->project->name , project => $build->project->name
@ -76,43 +76,24 @@ sub getBuildStats {
$c->stash->{finishedBuilds} = $builds->search({finished => 1}) || 0; $c->stash->{finishedBuilds} = $builds->search({finished => 1}) || 0;
$c->stash->{succeededBuilds} = $builds->search( $c->stash->{succeededBuilds} = $builds->search({finished => 1, buildStatus => 0}) || 0;
{finished => 1, buildStatus => 0},
{join => 'resultInfo'}) || 0;
$c->stash->{scheduledBuilds} = $builds->search({finished => 0}) || 0; $c->stash->{scheduledBuilds} = $builds->search({finished => 0}) || 0;
$c->stash->{busyBuilds} = $builds->search({finished => 0, busy => 1}) || 0; $c->stash->{busyBuilds} = $builds->search({finished => 0, busy => 1}) || 0;
my $res; my $res;
$res = $builds->search({}, $res = $builds->search({}, {select => {sum => 'stoptime - starttime'}, as => ['sum']})->first;
{join => 'resultInfo', select => {sum => 'stoptime - starttime'}, as => ['sum']})
->first ;
$c->stash->{totalBuildTime} = defined ($res) ? $res->get_column('sum') : 0 ; $c->stash->{totalBuildTime} = defined ($res) ? $res->get_column('sum') : 0 ;
} }
# Add the releaseName and buildStatus attributes from the
# BuildResultInfo table for each build.
sub joinWithResultInfo {
my ($c, $source) = @_;
return $source->search(
{ },
{ join => 'resultInfo'
, '+select' => ["resultInfo.releasename", "resultInfo.buildstatus"]
, '+as' => ["releasename", "buildStatus"]
});
}
sub getChannelData { sub getChannelData {
my ($c, $builds) = @_; my ($c, $builds) = @_;
my @builds2 = joinWithResultInfo($c, $builds) my @builds2 = $builds->search_literal("exists (select 1 from buildproducts where build = me.id and type = 'nix-build')");
->search_literal("exists (select 1 from buildproducts where build = resultInfo.id and type = 'nix-build')");
my @storePaths = (); my @storePaths = ();
foreach my $build (@builds2) { foreach my $build (@builds2) {

View file

@ -121,9 +121,7 @@ sub allPrimaryBuilds {
my ($project, $primaryJob) = @_; my ($project, $primaryJob) = @_;
my $allPrimaryBuilds = $project->builds->search( my $allPrimaryBuilds = $project->builds->search(
{ jobset => $primaryJob->get_column('jobset'), job => $primaryJob->get_column('job'), finished => 1 }, { jobset => $primaryJob->get_column('jobset'), job => $primaryJob->get_column('job'), finished => 1 },
{ join => 'resultInfo', order_by => "timestamp DESC" { order_by => "timestamp DESC"
, '+select' => ["resultInfo.releasename", "resultInfo.buildstatus"]
, '+as' => ["releasename", "buildstatus"]
, where => \ attrsToSQL($primaryJob->attrs, "me.id") , where => \ attrsToSQL($primaryJob->attrs, "me.id")
}); });
return $allPrimaryBuilds; return $allPrimaryBuilds;
@ -165,10 +163,9 @@ sub findLastJobForBuilds {
{ {
$thisBuild = $ev->builds->find( $thisBuild = $ev->builds->find(
{ job => $job->get_column('job'), finished => 1 }, { job => $job->get_column('job'), finished => 1 },
{ join => 'resultInfo', rows => 1 { rows => 1
, order_by => ["build.id"] , order_by => ["build.id"]
, where => \ attrsToSQL($job->attrs, "build.id") , where => \ attrsToSQL($job->attrs, "build.id")
, '+select' => ["resultInfo.buildstatus"], '+as' => ["buildstatus"]
}); });
} }
@ -180,30 +177,31 @@ sub findLastJobForBuilds {
{ project => $project, jobset => $jobset { project => $project, jobset => $jobset
, job => $job->get_column('job'), finished => 1 , job => $job->get_column('job'), finished => 1
}, },
{ join => 'resultInfo', rows => 1 { rows => 1
, order_by => ["buildstatus", "timestamp"] , order_by => ["buildstatus", "timestamp"]
, where => \ attrsToSQL($job->attrs, "build.id") , where => \ attrsToSQL($job->attrs, "build.id")
, '+select' => ["resultInfo.buildstatus"], '+as' => ["buildstatus"]
}) })
unless defined $thisBuild; unless defined $thisBuild;
return $thisBuild; return $thisBuild;
} }
sub jobsetOverview { sub jobsetOverview {
my ($c, $project) = @_; my ($c, $project) = @_;
return $project->jobsets->search( isProjectOwner($c, $project) ? {} : { hidden => 0 }, return $project->jobsets->search( isProjectOwner($c, $project) ? {} : { hidden => 0 },
{ order_by => "name" { order_by => "name"
, "+select" => , "+select" =>
[ "(select count(*) from Builds as a where a.finished = 0 and me.project = a.project and me.name = a.jobset and a.isCurrent = 1)" [ "(select count(*) from Builds as a where a.finished = 0 and me.project = a.project and me.name = a.jobset and a.isCurrent = 1)"
, "(select count(*) from Builds as a join BuildResultInfo r using (id) where me.project = a.project and me.name = a.jobset and buildstatus <> 0 and a.isCurrent = 1)" , "(select count(*) from Builds as a where a.finished = 1 and me.project = a.project and me.name = a.jobset and buildstatus <> 0 and a.isCurrent = 1)"
, "(select count(*) from Builds as a join BuildResultInfo r using (id) where me.project = a.project and me.name = a.jobset and buildstatus = 0 and a.isCurrent = 1)" , "(select count(*) from Builds as a where a.finished = 1 and me.project = a.project and me.name = a.jobset and buildstatus = 0 and a.isCurrent = 1)"
, "(select count(*) from Builds as a where me.project = a.project and me.name = a.jobset and a.isCurrent = 1)" , "(select count(*) from Builds as a where me.project = a.project and me.name = a.jobset and a.isCurrent = 1)"
] ]
, "+as" => ["nrscheduled", "nrfailed", "nrsucceeded", "nrtotal"] , "+as" => ["nrscheduled", "nrfailed", "nrsucceeded", "nrtotal"]
}); });
} }
sub getViewResult { sub getViewResult {
my ($primaryBuild, $jobs) = @_; my ($primaryBuild, $jobs) = @_;
@ -258,10 +256,12 @@ sub getLatestSuccessfulViewResult {
return undef; return undef;
} }
sub removeAsciiEscapes { sub removeAsciiEscapes {
my ($logtext) = @_; my ($logtext) = @_;
$logtext =~ s/\e\[[0-9]*[A-Za-z]//g; $logtext =~ s/\e\[[0-9]*[A-Za-z]//g;
return $logtext; return $logtext;
} }
1; 1;

View file

@ -1,174 +0,0 @@
use utf8;
package Hydra::Schema::BuildResultInfo;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
Hydra::Schema::BuildResultInfo
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<BuildResultInfo>
=cut
__PACKAGE__->table("BuildResultInfo");
=head1 ACCESSORS
=head2 id
data_type: 'integer'
is_auto_increment: 1
is_foreign_key: 1
is_nullable: 0
=head2 iscachedbuild
data_type: 'integer'
is_nullable: 0
=head2 buildstatus
data_type: 'integer'
is_nullable: 1
=head2 errormsg
data_type: 'text'
is_nullable: 1
=head2 starttime
data_type: 'integer'
is_nullable: 1
=head2 stoptime
data_type: 'integer'
is_nullable: 1
=head2 logfile
data_type: 'text'
is_nullable: 1
=head2 logsize
data_type: 'bigint'
default_value: 0
is_nullable: 0
=head2 size
data_type: 'bigint'
default_value: 0
is_nullable: 0
=head2 closuresize
data_type: 'bigint'
default_value: 0
is_nullable: 0
=head2 releasename
data_type: 'text'
is_nullable: 1
=head2 keep
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 faileddepbuild
data_type: 'integer'
is_nullable: 1
=head2 faileddepstepnr
data_type: 'integer'
is_nullable: 1
=cut
__PACKAGE__->add_columns(
"id",
{
data_type => "integer",
is_auto_increment => 1,
is_foreign_key => 1,
is_nullable => 0,
},
"iscachedbuild",
{ data_type => "integer", is_nullable => 0 },
"buildstatus",
{ data_type => "integer", is_nullable => 1 },
"errormsg",
{ data_type => "text", is_nullable => 1 },
"starttime",
{ data_type => "integer", is_nullable => 1 },
"stoptime",
{ data_type => "integer", is_nullable => 1 },
"logfile",
{ data_type => "text", is_nullable => 1 },
"logsize",
{ data_type => "bigint", default_value => 0, is_nullable => 0 },
"size",
{ data_type => "bigint", default_value => 0, is_nullable => 0 },
"closuresize",
{ data_type => "bigint", default_value => 0, is_nullable => 0 },
"releasename",
{ data_type => "text", is_nullable => 1 },
"keep",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"faileddepbuild",
{ data_type => "integer", is_nullable => 1 },
"faileddepstepnr",
{ data_type => "integer", is_nullable => 1 },
);
=head1 PRIMARY KEY
=over 4
=item * L</id>
=back
=cut
__PACKAGE__->set_primary_key("id");
=head1 RELATIONS
=head2 id
Type: belongs_to
Related object: L<Hydra::Schema::Builds>
=cut
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" }, {});
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2011-12-05 14:15:43
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hX3+iQYrGslQqY9vKvyw3g
__PACKAGE__->belongs_to(
"failedDep",
"Hydra::Schema::BuildSteps",
{ build => "faileddepbuild", stepnr => "faileddepstepnr" },
);
1;

View file

@ -163,6 +163,52 @@ __PACKAGE__->table("Builds");
data_type: 'integer' data_type: 'integer'
is_nullable: 1 is_nullable: 1
=head2 stoptime
data_type: 'integer'
is_nullable: 1
=head2 iscachedbuild
data_type: 'integer'
is_nullable: 1
=head2 buildstatus
data_type: 'integer'
is_nullable: 1
=head2 errormsg
data_type: 'text'
is_nullable: 1
=head2 logsize
data_type: 'bigint'
is_nullable: 1
=head2 size
data_type: 'bigint'
is_nullable: 1
=head2 closuresize
data_type: 'bigint'
is_nullable: 1
=head2 releasename
data_type: 'text'
is_nullable: 1
=head2 keep
data_type: 'integer'
default_value: 0
is_nullable: 0
=cut =cut
__PACKAGE__->add_columns( __PACKAGE__->add_columns(
@ -218,6 +264,24 @@ __PACKAGE__->add_columns(
{ data_type => "integer", default_value => 0, is_nullable => 0 }, { data_type => "integer", default_value => 0, is_nullable => 0 },
"starttime", "starttime",
{ data_type => "integer", is_nullable => 1 }, { data_type => "integer", is_nullable => 1 },
"stoptime",
{ data_type => "integer", is_nullable => 1 },
"iscachedbuild",
{ data_type => "integer", is_nullable => 1 },
"buildstatus",
{ data_type => "integer", is_nullable => 1 },
"errormsg",
{ data_type => "text", is_nullable => 1 },
"logsize",
{ data_type => "bigint", is_nullable => 1 },
"size",
{ data_type => "bigint", is_nullable => 1 },
"closuresize",
{ data_type => "bigint", is_nullable => 1 },
"releasename",
{ data_type => "text", is_nullable => 1 },
"keep",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
); );
=head1 PRIMARY KEY =head1 PRIMARY KEY
@ -279,21 +343,6 @@ __PACKAGE__->has_many(
{}, {},
); );
=head2 buildresultinfo
Type: might_have
Related object: L<Hydra::Schema::BuildResultInfo>
=cut
__PACKAGE__->might_have(
"buildresultinfo",
"Hydra::Schema::BuildResultInfo",
{ "foreign.id" => "self.id" },
{},
);
=head2 buildsteps =head2 buildsteps
Type: has_many Type: has_many
@ -380,8 +429,8 @@ __PACKAGE__->has_many(
); );
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2012-02-29 00:47:54 # Created by DBIx::Class::Schema::Loader v0.07014 @ 2012-02-29 18:56:22
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VnnyFTwnLncGb2Dj2/giiA # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:w16c86FRReLPdA8H0yTIRg
use Hydra::Helper::Nix; use Hydra::Helper::Nix;
@ -399,12 +448,6 @@ __PACKAGE__->has_many(
{ "foreign.build" => "self.id" }, { "foreign.build" => "self.id" },
); );
__PACKAGE__->belongs_to(
"resultInfo",
"Hydra::Schema::BuildResultInfo",
{ id => "id" },
);
__PACKAGE__->has_one( __PACKAGE__->has_one(
"actualBuildStep", "actualBuildStep",
"Hydra::Schema::BuildSteps", "Hydra::Schema::BuildSteps",
@ -432,36 +475,16 @@ sub makeSource {
sub makeQueries { sub makeQueries {
my ($name, $constraint) = @_; my ($name, $constraint) = @_;
my $joinWithStatusChange =
<<QUERY;
join BuildResultInfo r using (id)
left join Builds b on
b.id =
(select max(c.id)
from builds c join buildresultinfo r2 on c.id = r2.id
where
x.project = c.project and x.jobset = c.jobset and x.job = c.job and x.system = c.system and
x.id > c.id and
((r.buildstatus = 0 and r2.buildstatus != 0) or
(r.buildstatus != 0 and r2.buildstatus = 0)))
QUERY
my $activeJobs = "(select distinct project, jobset, job, system from Builds where isCurrent = 1 $constraint)"; my $activeJobs = "(select distinct project, jobset, job, system from Builds where isCurrent = 1 $constraint)";
makeSource( makeSource(
"JobStatus$name", "JobStatus$name",
# Urgh, can't use "*" in the "select" here because of the status change join. # Urgh, can't use "*" in the "select" here because of the status change join.
<<QUERY <<QUERY
select select x.*, b.id as statusChangeId, b.timestamp as statusChangeTime
x.id, x.finished, x.timestamp, x.project, x.jobset, x.job, x.nixname,
x.description, x.drvpath, x.outpath, x.system, x.longdescription,
x.license, x.homepage, x.maintainers, x.isCurrent, x.nixExprInput,
x.nixExprPath, x.maxsilent, x.timeout, x.priority, x.busy, x.locker,
x.logfile, x.disabled, x.startTime,
b.id as statusChangeId, b.timestamp as statusChangeTime
from from
(select (select
(select max(b.id) from builds b (select max(b.id) from Builds b
where where
project = activeJobs.project and jobset = activeJobs.jobset project = activeJobs.project and jobset = activeJobs.jobset
and job = activeJobs.job and system = activeJobs.system and job = activeJobs.job and system = activeJobs.system
@ -470,7 +493,15 @@ QUERY
from $activeJobs as activeJobs from $activeJobs as activeJobs
) as latest ) as latest
join Builds x using (id) join Builds x using (id)
$joinWithStatusChange left join Builds b on
b.id =
(select max(c.id) from Builds c
where
c.finished = 1 and
x.project = c.project and x.jobset = c.jobset and x.job = c.job and x.system = c.system and
x.id > c.id and
((x.buildStatus = 0 and c.buildStatus != 0) or
(x.buildStatus != 0 and c.buildStatus = 0)))
QUERY QUERY
); );
@ -486,8 +517,7 @@ QUERY
where where
project = activeJobs.project and jobset = activeJobs.jobset project = activeJobs.project and jobset = activeJobs.jobset
and job = activeJobs.job and system = activeJobs.system and job = activeJobs.job and system = activeJobs.system
and finished = 1 and finished = 1 and buildstatus = 0
and exists (select 1 from buildresultinfo where id = b.id and buildstatus = 0)
) as id ) as id
from $activeJobs as activeJobs from $activeJobs as activeJobs
) as latest ) as latest

View file

@ -7,7 +7,6 @@
[% project = build.project %] [% project = build.project %]
[% jobset = build.jobset %] [% jobset = build.jobset %]
[% job = build.job %] [% job = build.job %]
[% resultInfo = build.resultInfo %]
[% BLOCK renderBuildSteps %] [% BLOCK renderBuildSteps %]
@ -35,7 +34,7 @@
[% INCLUDE renderDuration duration = step.stoptime - step.starttime %] [% INCLUDE renderDuration duration = step.stoptime - step.starttime %]
[% ELSE %] [% ELSE %]
[% IF build.finished %] [% IF build.finished %]
[% INCLUDE renderDuration duration = resultInfo.stoptime - step.starttime %] [% INCLUDE renderDuration duration = build.stoptime - step.starttime %]
[% ELSE %] [% ELSE %]
[% INCLUDE renderDuration duration = curTime - step.starttime %] [% INCLUDE renderDuration duration = curTime - step.starttime %]
[% END %] [% END %]
@ -106,10 +105,10 @@
<th>Build ID:</th> <th>Build ID:</th>
<td>[% build.id %]</td> <td>[% build.id %]</td>
</tr> </tr>
[% IF resultInfo.releasename %] [% IF build.releasename %]
<tr> <tr>
<th>Release name:</th> <th>Release name:</th>
<td><tt>[% HTML.escape(resultInfo.releasename) %]</tt></td> <td><tt>[% HTML.escape(build.releasename) %]</tt></td>
</tr> </tr>
[% ELSE %] [% ELSE %]
<tr> <tr>
@ -131,15 +130,15 @@
<tr> <tr>
<th>Duration:</th> <th>Duration:</th>
<td> <td>
[% IF resultInfo.iscachedbuild %] [% IF build.iscachedbuild %]
(cached[% IF cachedBuild %] from [% INCLUDE renderFullBuildLink build=cachedBuild %][% END %]) (cached[% IF cachedBuild %] from [% INCLUDE renderFullBuildLink build=cachedBuild %][% END %])
[% ELSE %] [% ELSE %]
[% INCLUDE renderDuration duration = resultInfo.stoptime - resultInfo.starttime %] <tt>finished at [% INCLUDE renderDateTime timestamp = resultInfo.stoptime %]</tt> [% INCLUDE renderDuration duration = build.stoptime - build.starttime %] <tt>finished at [% INCLUDE renderDateTime timestamp = build.stoptime %]</tt>
[% END %] [% END %]
</td> </td>
</tr> </tr>
[% END %] [% END %]
[% IF resultInfo.logfile %] [% IF build.logfile %]
<tr> <tr>
<th>Logfile:</th> <th>Logfile:</th>
<td> <td>
@ -182,7 +181,7 @@
[% END %] [% END %]
[% IF build.finished %] [% IF build.finished %]
[% IF build.buildsteps && resultInfo.buildstatus != 0 && resultInfo.buildstatus != 6 %] [% IF build.buildsteps && build.buildstatus != 0 && build.buildstatus != 6 %]
[% INCLUDE renderBuildSteps type="Failed" %] [% INCLUDE renderBuildSteps type="Failed" %]
[% END %] [% END %]
@ -214,11 +213,11 @@
</table> </table>
[% END %] [% END %]
[% IF resultInfo.errormsg && resultInfo.buildstatus != 5 %] [% IF build.errormsg && build.buildstatus != 5 %]
<h2 id="nix-error">Nix error output</h2> <h2 id="nix-error">Nix error output</h2>
<pre class="buildlog">[% HTML.escape(resultInfo.errormsg) -%]</pre> <pre class="buildlog">[% HTML.escape(build.errormsg) -%]</pre>
[% END %] [% END %]
[% END %] [% END %]
[% IF logtext %] [% IF logtext %]
@ -264,10 +263,10 @@
<th>Nix name:</th> <th>Nix name:</th>
<td><tt>[% build.nixname %]</tt></td> <td><tt>[% build.nixname %]</tt></td>
</tr> </tr>
[% IF resultInfo.releasename %] [% IF build.releasename %]
<tr> <tr>
<th>Release name:</th> <th>Release name:</th>
<td><tt>[% HTML.escape(resultInfo.releasename) %]</tt></td> <td><tt>[% HTML.escape(build.releasename) %]</tt></td>
</tr> </tr>
[% END %] [% END %]
<tr> <tr>
@ -328,8 +327,8 @@
<th>Time added:</th> <th>Time added:</th>
<td>[% INCLUDE renderDateTime timestamp = build.timestamp %]</td> <td>[% INCLUDE renderDateTime timestamp = build.timestamp %]</td>
</tr> </tr>
[% IF build.finished && resultInfo.buildstatus != 4 %] [% IF build.finished && build.buildstatus != 4 %]
[% IF resultInfo.iscachedbuild && cachedBuild %] [% IF build.iscachedbuild && cachedBuild %]
<tr> <tr>
<th>Cached build:</th> <th>Cached build:</th>
<td>[% INCLUDE renderFullBuildLink build=cachedBuild %]</td> <td>[% INCLUDE renderFullBuildLink build=cachedBuild %]</td>
@ -338,23 +337,23 @@
<tr> <tr>
<th>Build started:</th> <th>Build started:</th>
<td>[% IF resultInfo.starttime %][% INCLUDE renderDateTime timestamp = resultInfo.starttime %][% ELSE %]<em>(cached build)</em>[% END %]</td> <td>[% IF build.starttime %][% INCLUDE renderDateTime timestamp = build.starttime %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr> </tr>
<tr> <tr>
<th>Build finished:</th> <th>Build finished:</th>
<td>[% IF resultInfo.stoptime %][% INCLUDE renderDateTime timestamp = resultInfo.stoptime %][% ELSE %]<em>(cached build)</em>[% END %]</td> <td>[% IF build.stoptime %][% INCLUDE renderDateTime timestamp = build.stoptime %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr> </tr>
<tr> <tr>
<th>Duration:</th> <th>Duration:</th>
<td> <td>
[% IF resultInfo.iscachedbuild %] [% IF build.iscachedbuild %]
<em>(cached build)</em> <em>(cached build)</em>
[% ELSE %] [% ELSE %]
[% INCLUDE renderDuration duration = resultInfo.stoptime - resultInfo.starttime %] [% INCLUDE renderDuration duration = build.stoptime - build.starttime %]
[% END %] [% END %]
</td> </td>
</tr> </tr>
[% IF resultInfo.logfile %] [% IF build.logfile %]
<tr> <tr>
<th>Logfile:</th> <th>Logfile:</th>
<td> <td>
@ -377,7 +376,7 @@
<td> <td>
[% IF !available %] [% IF !available %]
<em>Build output is no longer available</em> <em>Build output is no longer available</em>
[% ELSIF resultInfo.keep %] [% ELSIF build.keep %]
<em>Build output will be kept permanently</em> <em>Build output will be kept permanently</em>
[% IF c.user_exists %] [% IF c.user_exists %]
<form action="[% c.uri_for('/build' build.id 'keep' 0) %]" method="post" class="inline"> <form action="[% c.uri_for('/build' build.id 'keep' 0) %]" method="post" class="inline">
@ -487,10 +486,9 @@
$(function() { $(function() {
var d = []; var d = [];
var ids = []; var ids = [];
[% FOREACH prevbuild IN prevBuilds %][% IF prevbuild.resultInfo.starttime != 0 %] [% FOREACH prevbuild IN prevBuilds %][% IF prevbuild.build.starttime != 0 %]
[% pbResultInfo = prevbuild.resultInfo %] d.push([[% prevbuild.starttime * 1000 %],[% prevbuild.get_column('actualBuildTime') %]]);
d.push([[% pbResultInfo.starttime * 1000 %],[% prevbuild.get_column('actualBuildTime') %]]); ids[[% prevbuild.starttime * 1000 %]] = [% prevbuild.id %] ;
ids[[% pbResultInfo.starttime * 1000 %]] = [% prevbuild.id %] ;
[% END %][% END %] [% END %][% END %]
var options = { var options = {
@ -560,9 +558,9 @@
$(function() { $(function() {
var d = []; var d = [];
var ids = []; var ids = [];
[% FOREACH prevbuild IN prevBuilds %][% IF prevbuild.resultInfo.size != 0 %] [% FOREACH prevbuild IN prevBuilds %][% IF prevbuild.size != 0 %]
d.push([[% prevbuild.resultInfo.starttime * 1000 %],[% prevbuild.resultInfo.size / (1024*1024.0) %]]); d.push([[% prevbuild.starttime * 1000 %],[% prevbuild.size / (1024*1024.0) %]]);
ids[[% prevbuild.resultInfo.starttime * 1000 %]] = [% prevbuild.id %] ; ids[[% prevbuild.starttime * 1000 %]] = [% prevbuild.id %] ;
[% END %][% END %] [% END %][% END %]
var options = { var options = {

View file

@ -100,7 +100,7 @@
onclick="if(event.which == 2) return true; window.location = '[% c.uri_for('/build' build.id) %]'"> onclick="if(event.which == 2) return true; window.location = '[% c.uri_for('/build' build.id) %]'">
[%- IF !hideResultInfo -%] [%- IF !hideResultInfo -%]
<td> <td>
[%- INCLUDE renderBuildStatusIcon size=16 busy=(showSchedulingInfo ? 1 : 0) buildstatus=build.get_column('buildStatus') -%] [%- INCLUDE renderBuildStatusIcon size=16 busy=(showSchedulingInfo ? 1 : 0) buildstatus=build.buildstatus -%]
</td> </td>
[%- END -%] [%- END -%]
<td><a href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td> <td><a href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td>
@ -204,7 +204,7 @@
[%- BLOCK renderBuildStatusIcon -%] [%- BLOCK renderBuildStatusIcon -%]
[%- finished = build != undef ? build.finished : 1 -%] [%- finished = build != undef ? build.finished : 1 -%]
[%- busy = busy != undef ? busy : build.busy -%] [%- busy = busy != undef ? busy : build.busy -%]
[%- buildstatus = buildstatus != undef ? buildstatus : build.resultInfo.buildstatus -%] [%- buildstatus = buildstatus != undef ? buildstatus : build.buildstatus -%]
[%- IF finished -%] [%- IF finished -%]
[%- IF buildstatus == 0 -%] [%- IF buildstatus == 0 -%]
<img src="/static/images/checkmark_[% size %].png" alt="Succeeded" /> <img src="/static/images/checkmark_[% size %].png" alt="Succeeded" />
@ -230,7 +230,7 @@
[% BLOCK renderStatus %] [% BLOCK renderStatus %]
[% IF build.finished %] [% IF build.finished %]
[% buildstatus = build.resultInfo.buildstatus %] [% buildstatus = build.buildstatus %]
[% INCLUDE renderBuildStatusIcon size=16 %] [% INCLUDE renderBuildStatusIcon size=16 %]
[% IF buildstatus == 0 %] [% IF buildstatus == 0 %]
<strong>Success</strong> <strong>Success</strong>
@ -242,8 +242,6 @@
<span class="error">Cancelled by user</span> <span class="error">Cancelled by user</span>
[% ELSIF buildstatus == 5 %] [% ELSIF buildstatus == 5 %]
<span class="error">Build inhibited because a dependency previously failed to build</span> <span class="error">Build inhibited because a dependency previously failed to build</span>
[% failedDep = build.resultInfo.failedDep %]
(namely, <a href="[% c.uri_for('/build' failedDep.build.id 'nixlog' failedDep.stepnr) %]"><tt>[% failedDep.outpath %]</tt></a>)
[% ELSIF buildstatus == 6 %] [% ELSIF buildstatus == 6 %]
<span class="error">Build failed (with result)</span> <span class="error">Build failed (with result)</span>
[% ELSE %] [% ELSE %]

View file

@ -19,7 +19,7 @@
[% SWITCH product.type %] [% SWITCH product.type %]
[% CASE "nix-build" %] [% CASE "nix-build" %]
[% IF build.resultInfo.buildstatus == 6 %] [% IF build.buildstatus == 6 %]
[% filename = "${build.nixname}.closure.gz" %] [% filename = "${build.nixname}.closure.gz" %]
[% uri = c.uri_for('/build' build.id 'nix' 'closure' filename ) %] [% uri = c.uri_for('/build' build.id 'nix' 'closure' filename ) %]
<tr class="product"> <tr class="product">

View file

@ -24,7 +24,7 @@
[% IF j.build %] [% IF j.build %]
[% IF j.build.resultInfo.buildstatus == 0 %] [% IF j.build.buildstatus == 0 %]
[% IF j.build.buildproducts %] [% IF j.build.buildproducts %]
[% p = jobNames.${j.job.job} > 1 ? "-${j.build.system}" : ""; [% p = jobNames.${j.job.job} > 1 ? "-${j.build.system}" : "";

View file

@ -34,9 +34,9 @@ sub sendTwitterNotification {
my $addURL = defined $config{'base_uri'}; my $addURL = defined $config{'base_uri'};
my $jobName = $build->project->name . ":" . $build->jobset->name . ":" . $build->job->name; my $jobName = $build->project->name . ":" . $build->jobset->name . ":" . $build->job->name;
my $status = $build->resultInfo->buildstatus == 0 ? "SUCCEEDED" : "FAILED"; my $status = $build->buildstatus == 0 ? "SUCCEEDED" : "FAILED";
my $system = $build->system; my $system = $build->system;
my $duration = ($build->resultInfo->stoptime - $build->resultInfo->starttime) . " seconds"; my $duration = ($build->stoptime - $build->starttime) . " seconds";
my $url = $config{'base_uri'}."/build/".$build->id ; my $url = $config{'base_uri'}."/build/".$build->id ;
my $nt = Net::Twitter::Lite->new( my $nt = Net::Twitter::Lite->new(
@ -74,7 +74,7 @@ sub statusDescription {
sub sendEmailNotification { sub sendEmailNotification {
my ($build) = @_; my ($build) = @_;
die unless defined $build->resultInfo; die unless $build->finished;
return if ! ( $build->jobset->enableemail && ($build->maintainers ne "" || $build->jobset->emailoverride ne "") ); return if ! ( $build->jobset->enableemail && ($build->maintainers ne "" || $build->jobset->emailoverride ne "") );
@ -93,13 +93,13 @@ sub sendEmailNotification {
); );
# if there is a previous build with same buildstatus, do not send email # if there is a previous build with same buildstatus, do not send email
if (defined $prevBuild && ($build->resultInfo->buildstatus == $prevBuild->resultInfo->buildstatus)) { if (defined $prevBuild && ($build->buildstatus == $prevBuild->buildstatus)) {
return; return;
} }
# if buildstatus of this build or the previous one is aborted, do # if buildstatus of this build or the previous one is aborted, do
# not send email # not send email
if ($build->resultInfo->buildstatus == 3 || (defined $prevBuild && ($prevBuild->resultInfo->buildstatus == 3))) { if ($build->buildstatus == 3 || (defined $prevBuild && ($prevBuild->buildstatus == 3))) {
return; return;
} }
@ -110,7 +110,7 @@ sub sendEmailNotification {
my $jobName = $build->project->name . ":" . $build->jobset->name . ":" . $build->job->name; my $jobName = $build->project->name . ":" . $build->jobset->name . ":" . $build->job->name;
my $status = statusDescription($build->resultInfo->buildstatus); my $status = statusDescription($build->buildstatus);
my $baseurl = hostname_long ; my $baseurl = hostname_long ;
my $sender = $config{'notification_sender'} || my $sender = $config{'notification_sender'} ||
@ -132,10 +132,10 @@ sub sendEmailNotification {
[ "Time added:", showTime $build->timestamp ], [ "Time added:", showTime $build->timestamp ],
); );
push @lines, ( push @lines, (
[ "Build started:", showTime $build->resultInfo->starttime ], [ "Build started:", showTime $build->starttime ],
[ "Build finished:", showTime $build->resultInfo->stoptime ], [ "Build finished:", showTime $build->stoptime ],
[ "Duration:", $build->resultInfo->stoptime - $build->resultInfo->starttime . "s" ], [ "Duration:", $build->stoptime - $build->starttime . "s" ],
) if $build->resultInfo->starttime; ) if $build->starttime;
$infoTable->load(@lines); $infoTable->load(@lines);
my $inputsTable = Text::Table->new( my $inputsTable = Text::Table->new(
@ -157,18 +157,18 @@ sub sendEmailNotification {
$inputsTable->load(@lines); $inputsTable->load(@lines);
my $loglines = 50; my $loglines = 50;
my $logfile = $build->resultInfo->logfile; my $logfile = $build->logfile;
my $logtext = defined $logfile && -e $logfile ? `tail -$loglines $logfile` : "No logfile available.\n"; my $logtext = defined $logfile && -e $logfile ? `tail -$loglines $logfile` : "No logfile available.\n";
$logtext = removeAsciiEscapes($logtext); $logtext = removeAsciiEscapes($logtext);
my $body = "Hi,\n" my $body = "Hi,\n"
. "\n" . "\n"
. "This is to let you know that Hydra build " . $build->id . "This is to let you know that Hydra build " . $build->id
. " of job " . $jobName . " " . (defined $prevBuild ? "has changed from '" . statusDescription($prevBuild->resultInfo->buildstatus) . "' to '$status'" : "is '$status'" ) .".\n" . " of job " . $jobName . " " . (defined $prevBuild ? "has changed from '" . statusDescription($prevBuild->buildstatus) . "' to '$status'" : "is '$status'" ) .".\n"
. "\n" . "\n"
. "Complete build information can be found on this page: " . "Complete build information can be found on this page: "
. "$selfURI/build/" . $build->id . "\n" . "$selfURI/build/" . $build->id . "\n"
. ($build->resultInfo->buildstatus != 0 ? "\nThe last $loglines lines of the build log are shown at the bottom of this email.\n" : "") . ($build->buildstatus != 0 ? "\nThe last $loglines lines of the build log are shown at the bottom of this email.\n" : "")
. "\n" . "\n"
. "A summary of the build information follows:\n" . "A summary of the build information follows:\n"
. "\n" . "\n"
@ -181,7 +181,7 @@ sub sendEmailNotification {
. $inputsTable->body . $inputsTable->body
. "\n" . "\n"
. "Regards,\n\nThe Hydra build daemon.\n" . "Regards,\n\nThe Hydra build daemon.\n"
. ($build->resultInfo->buildstatus != 0 ? "\n---\n$logtext" : ""); . ($build->buildstatus != 0 ? "\n---\n$logtext" : "");
# stripping trailing spaces from lines # stripping trailing spaces from lines
$body =~ s/[\ ]+$//gm; $body =~ s/[\ ]+$//gm;
@ -398,16 +398,16 @@ sub doBuild {
} }
txn_do($db, sub { txn_do($db, sub {
$build->update({finished => 1, busy => 0, locker => '', logfile => '', timestamp => time});
my $releaseName = getReleaseName($outPath); my $releaseName = getReleaseName($outPath);
if ($buildStatus == 0 && -f "$outPath/nix-support/failed") { $buildStatus = 6 if $buildStatus == 0 && -f "$outPath/nix-support/failed";
$buildStatus = 6;
}
$db->resultset('BuildResultInfo')->create( $build->update(
{ id => $build->id { finished => 1
, busy => 0
, locker => ''
, logfile => ''
, timestamp => time # !!! Why change the timestamp?
, iscachedbuild => $isCachedBuild , iscachedbuild => $isCachedBuild
, buildstatus => $buildStatus , buildstatus => $buildStatus
, starttime => $startTime , starttime => $startTime
@ -450,7 +450,7 @@ my $build;
txn_do($db, sub { txn_do($db, sub {
$build = $db->resultset('Builds')->find($buildId); $build = $db->resultset('Builds')->find($buildId);
die "build $buildId doesn't exist" unless defined $build; die "build $buildId doesn't exist" unless defined $build;
die "build $buildId already done" if defined $build->resultInfo; die "build $buildId already done" if $build->finished;
if ($build->busy != 0 && $build->locker != getppid) { if ($build->busy != 0 && $build->locker != getppid) {
die "build $buildId is already being built"; die "build $buildId is already being built";
} }

View file

@ -69,8 +69,7 @@ foreach my $project ($db->resultset('Projects')->all) {
, buildStatus => 0 # == success , buildStatus => 0 # == success
, system => $system->system , system => $system->system
}, },
{ join => 'resultInfo' { order_by => 'me.id DESC'
, order_by => 'me.id DESC'
, rows => $keepnr , rows => $keepnr
}); });
keepBuild $_ foreach @recentBuilds; keepBuild $_ foreach @recentBuilds;
@ -106,7 +105,7 @@ foreach my $project ($db->resultset('Projects')->all) {
# Keep all builds that have been marked as "keep". # Keep all builds that have been marked as "keep".
print STDERR "*** looking for kept builds\n"; print STDERR "*** looking for kept builds\n";
my @buildsToKeep = $db->resultset('Builds')->search({finished => 1, keep => 1}, {join => 'resultInfo'}); my @buildsToKeep = $db->resultset('Builds')->search({finished => 1, keep => 1});
keepBuild $_ foreach @buildsToKeep; keepBuild $_ foreach @buildsToKeep;

View file

@ -163,18 +163,10 @@ create table Builds (
disabled integer not null default 0, -- !!! boolean disabled integer not null default 0, -- !!! boolean
startTime integer, -- if busy, time we started startTime integer, -- if busy, time we started
stopTime integer,
foreign key (project) references Projects(name) on update cascade, -- Information about finished builds.
foreign key (project, jobset) references Jobsets(project, name) on update cascade, isCachedBuild integer, -- boolean
foreign key (project, jobset, job) references Jobs(project, jobset, name) on update cascade
);
-- Info for a finished build.
create table BuildResultInfo (
id integer primary key not null,
isCachedBuild integer not null, -- boolean
-- Status codes: -- Status codes:
-- 0 = succeeded -- 0 = succeeded
@ -187,23 +179,17 @@ create table BuildResultInfo (
errorMsg text, -- error message in case of a Nix failure errorMsg text, -- error message in case of a Nix failure
startTime integer, -- in Unix time, 0 = used cached build result logSize bigint,
stopTime integer, size bigint,
closureSize bigint,
logfile text, -- the path of the logfile
logsize bigint not null default 0,
size bigint not null default 0,
closuresize bigint not null default 0,
releaseName text, -- e.g. "patchelf-0.5pre1234" releaseName text, -- e.g. "patchelf-0.5pre1234"
keep integer not null default 0, -- true means never garbage-collect the build output keep integer not null default 0, -- true means never garbage-collect the build output
failedDepBuild integer, -- obsolete foreign key (project) references Projects(name) on update cascade,
failedDepStepNr integer, -- obsolete foreign key (project, jobset) references Jobsets(project, name) on update cascade,
foreign key (project, jobset, job) references Jobs(project, jobset, name) on update cascade
foreign key (id) references Builds(id) on delete cascade
); );

View file

@ -4,12 +4,16 @@ alter table Builds
add column locker text, add column locker text,
add column logfile text, add column logfile text,
add column disabled integer not null default 0, add column disabled integer not null default 0,
add column startTime integer; add column startTime integer,
add column stopTime integer,
--alter table Builds add column isCachedBuild integer,
-- add column isCachedBuild integer, add column buildStatus integer,
-- add column buildStatus integer, add column errorMsg text,
-- add column errorMsg text; add column logSize bigint,
add column size bigint,
add column closureSize bigint,
add column releaseName text,
add column keep integer not null default 0;
update Builds b set update Builds b set
priority = (select priority from BuildSchedulingInfo s where s.id = b.id), priority = (select priority from BuildSchedulingInfo s where s.id = b.id),
@ -21,6 +25,17 @@ update Builds b set
update Builds b set update Builds b set
startTime = ((select startTime from BuildSchedulingInfo s where s.id = b.id) union (select startTime from BuildResultInfo r where r.id = b.id)); startTime = ((select startTime from BuildSchedulingInfo s where s.id = b.id) union (select startTime from BuildResultInfo r where r.id = b.id));
-- isCachedBuild = (select isCachedBuild from BuildResultInfo r where r.id = b.id),
-- buildStatus = (select buildStatus from BuildResultInfo r where r.id = b.id), update Builds b set
-- errorMsg = (select errorMsg from BuildResultInfo r where r.id = b.id); isCachedBuild = (select isCachedBuild from BuildResultInfo r where r.id = b.id),
buildStatus = (select buildStatus from BuildResultInfo r where r.id = b.id),
errorMsg = (select errorMsg from BuildResultInfo r where r.id = b.id),
startTime = (select startTime from BuildResultInfo r where r.id = b.id),
stopTime = (select stopTime from BuildResultInfo r where r.id = b.id),
logfile = (select logfile from BuildResultInfo r where r.id = b.id),
logSize = (select logsize from BuildResultInfo r where r.id = b.id),
size = (select size from BuildResultInfo r where r.id = b.id),
closureSize = (select closuresize from BuildResultInfo r where r.id = b.id),
releaseName = (select releaseName from BuildResultInfo r where r.id = b.id),
keep = (select keep from BuildResultInfo r where r.id = b.id)
where exists (select 1 from BuildResultInfo r where r.id = b.id);