diff --git a/doc/dev-notes.txt b/doc/dev-notes.txt index 5b1bed15..b1fef80d 100644 --- a/doc/dev-notes.txt +++ b/doc/dev-notes.txt @@ -129,3 +129,13 @@ $ nix-env -p /nix/var/nix/profiles/per-user/eelco/hydra-deps -f deps.nix -i \* --arg pkgs 'import /home/eelco/Dev/nixpkgs {}' + +* select x.project, x.jobset, x.job, x.system, x.id, x.timestamp, r.buildstatus, b.id, b.timestamp + from (select project, jobset, job, system, max(id) as id from Builds where finished = 1 group by project, jobset, job, system) as a_ + natural join Builds x + natural join BuildResultInfo r + left join Builds b on b.id = + (select max(id) from builds c + natural join buildresultinfo r2 + 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 != r2.buildstatus); diff --git a/src/lib/Hydra/Base/Controller/ListBuilds.pm b/src/lib/Hydra/Base/Controller/ListBuilds.pm index ec5abdf5..2390cffc 100644 --- a/src/lib/Hydra/Base/Controller/ListBuilds.pm +++ b/src/lib/Hydra/Base/Controller/ListBuilds.pm @@ -14,7 +14,7 @@ sub filterInactiveJobs { { join => 'job' , '+select' => ["job.active"] , '+as' => ["active"] - }) + }); } @@ -26,6 +26,13 @@ sub getJobStatus { $latest = filterInactiveJobs($latest) unless defined $c->stash->{showInactiveJobs}; + $latest = $latest->search( + {}, + { '+select' => ["me.statusChangeId", "me.statusChangeTime"] + , '+as' => ["statusChangeId", "statusChangeTime"] + , order_by => "statusChangeTime DESC" + }); + return $latest; } @@ -49,7 +56,7 @@ sub errors : Chained('get_builds') PathPart Args(0) { [$c->stash->{allJobs}->search({errormsg => {'!=' => ''}})] if defined $c->stash->{allJobs}; $c->stash->{brokenBuilds} = - [getJobStatus($self, $c)->search({buildstatus => {'!=' => 0}})]; + [getJobStatus($self, $c)->search({'me.buildstatus' => {'!=' => 0}})]; } diff --git a/src/lib/Hydra/Schema/Builds.pm b/src/lib/Hydra/Schema/Builds.pm index c78e649b..83c1b8e0 100644 --- a/src/lib/Hydra/Schema/Builds.pm +++ b/src/lib/Hydra/Schema/Builds.pm @@ -193,10 +193,10 @@ __PACKAGE__->belongs_to( ); sub addSequence { - my $hydradbi = getHydraDBPath ; - if ($hydradbi =~ m/^dbi:Pg/) { - __PACKAGE__->sequence('builds_id_seq'); - } + my $hydradbi = getHydraDBPath; + if ($hydradbi =~ m/^dbi:Pg/) { + __PACKAGE__->sequence('builds_id_seq'); + } } sub makeSource { @@ -210,8 +210,14 @@ sub makeSource { sub makeQueries { my ($name, $constraint) = @_; - makeSource('JobStatus' . $name, "select * from (select project, jobset, job, system, max(id) as id from Builds where finished = 1 $constraint group by project, jobset, job, system) as a natural join Builds"); - makeSource('LatestSucceeded' . $name, "select * from (select project, jobset, job, system, max(id) as id from Builds natural join BuildResultInfo where finished = 1 and buildStatus = 0 $constraint group by project, jobset, job, system) as a natural join Builds"); + my $joinWithStatusChange = + "natural join BuildResultInfo r " . + "left join Builds b on b.id = " . + "(select max(id) from builds c natural join buildresultinfo r2 " . + " 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 != r2.buildstatus)"; + makeSource('JobStatus' . $name, "select *, b.id statusChangeId, b.timestamp statusChangeTime from (select project, jobset, job, system, max(id) as id from Builds where finished = 1 $constraint group by project, jobset, job, system) as latest natural join Builds x $joinWithStatusChange"); + makeSource('LatestSucceeded' . $name, "select * from (select project, jobset, job, system, max(id) as id from Builds natural join BuildResultInfo where finished = 1 and buildStatus = 0 $constraint group by project, jobset, job, system) as latest natural join Builds x $joinWithStatusChange"); } addSequence; diff --git a/src/root/common.tt b/src/root/common.tt index 58fcad64..10fe1609 100644 --- a/src/root/common.tt +++ b/src/root/common.tt @@ -73,6 +73,9 @@ <th>Release Name</th> <th>System</th> <th>Timestamp</th> + [% IF showStatusChange %] + <th class="headerSortUp">Last status change</th> + [% END %] <th>Description</th> </tr> </thead> @@ -105,6 +108,17 @@ <td>[% !showSchedulingInfo and build.get_column('releasename') ? build.get_column('releasename') : build.nixname %]</td> <td><tt>[% build.system %]</tt></td> <td>[% date.format(build.timestamp, '%Y-%m-%d %H:%M:%S') %]</td> + [% IF showStatusChange %] + <td> + [% IF build.get_column('statusChangeTime') %] + <a href="[% c.uri_for('/build' build.get_column('statusChangeId')) %]"> + [% date.format(build.get_column('statusChangeTime'), '%Y-%m-%d %H:%M:%S') %] + </a> + [% ELSE %] + <em>never</em> + [% END %] + </td> + [% END %] <td>[% build.description %]</td> </tr> [% END -%] diff --git a/src/root/errors.tt b/src/root/errors.tt index 2dc6e00f..abf14a3f 100644 --- a/src/root/errors.tt +++ b/src/root/errors.tt @@ -67,7 +67,7 @@ that don’t build.</p> <h2>Broken builds</h2> -[% INCLUDE renderBuildList builds=brokenBuilds %] +[% INCLUDE renderBuildList builds=brokenBuilds showStatusChange=1 %] [% END %] diff --git a/src/root/jobstatus.tt b/src/root/jobstatus.tt index b6a6c060..ab10a36b 100644 --- a/src/root/jobstatus.tt +++ b/src/root/jobstatus.tt @@ -3,8 +3,11 @@ <h1>Job Status[% IF project %] of Project <tt>[% project.name %]</tt>[% END %]</h1> -<p>Below are the latest builds for each job.</p> +<p>Below are the latest builds for each job. It is ordered by the status +change time (the timestamp of the last build that had a different +build result status). That is, it shows the jobs that most recently +changed from failed to successful or vice versa first.</p> -[% INCLUDE renderBuildList builds=latestBuilds %] +[% INCLUDE renderBuildList builds=latestBuilds showStatusChange=1 %] [% END %] diff --git a/src/sql/hydra.sql b/src/sql/hydra.sql index 57a6ac70..8183770e 100644 --- a/src/sql/hydra.sql +++ b/src/sql/hydra.sql @@ -407,4 +407,5 @@ create table ReleaseSetJobs ( create index IndexBuildInputsByBuild on BuildInputs(build); create index IndexBuildInputsByDependency on BuildInputs(dependency); create index IndexBuildsByTimestamp on Builds(timestamp); ---create index IndexBuildsByJobAndSystem on Builds(project, jobset, job, system); +create index IndexBuildsByJobAndSystem on Builds(project, jobset, job, system); +create index IndexBuildResultInfo on BuildResultInfo(id); -- primary key index, not created automatically by PostgreSQL