diff --git a/deps.nix b/deps.nix index 46d7783c..1613efc8 100644 --- a/deps.nix +++ b/deps.nix @@ -35,5 +35,6 @@ in perlPackages.NetTwitterLite perlPackages.PadWalker perlPackages.DataDump + perlPackages.JSONXS nixPerl ] diff --git a/src/lib/Hydra/Controller/API.pm b/src/lib/Hydra/Controller/API.pm new file mode 100644 index 00000000..2cfa1b04 --- /dev/null +++ b/src/lib/Hydra/Controller/API.pm @@ -0,0 +1,209 @@ +package Hydra::Controller::API; + +use strict; +use warnings; +use base 'Catalyst::Controller'; +use Hydra::Helper::Nix; +use Hydra::Helper::CatalystUtils; +use Hydra::Controller::Project; +use JSON::Any; +use DateTime; + +sub api : Chained('/') PathPart('api') CaptureArgs(0) { + my ($self, $c) = @_; + $c->response->content_type('application/json'); +} + +sub projectToHash { + my ($project) = @_; + return { + name => $project->name, + description => $project->description + }; +} + +sub projects : Chained('api') PathPart('projects') Args(0) { + my ($self, $c) = @_; + + my @projects = $c->model('DB::Projects')->search({hidden => 0}, {order_by => 'name'}) ; + + my @list ; + foreach my $p (@projects) { + push @list, projectToHash($p) ; + } + + $c->stash->{'plain'} = { + data => scalar (JSON::Any->objToJson(\@list)) + }; + $c->forward('Hydra::View::Plain'); +} + +sub buildToHash { + my ($build) = @_; + my $result = { + id => $build->id, + project => $build->get_column("project"), + jobset => $build->get_column("jobset"), + job => $build->get_column("job"), + system => $build->system, + nixname => $build->nixname, + finished => $build->finished, + timestamp => $build->timestamp + }; + + if($build->finished) { + $result->{'buildstatus'} = $build->get_column("buildstatus") ; + } else { + $result->{'busy'} = $build->get_column("busy"); + $result->{'priority'} = $build->get_column("priority"); + } + + return $result; +}; + +sub latestbuilds : Chained('api') PathPart('latestbuilds') Args(0) { + my ($self, $c) = @_; + my $nr = $c->request->params->{nr} ; + error($c, "Parameter not defined!") if !defined $nr; + + my $project = $c->request->params->{project} ; + my $jobset = $c->request->params->{jobset} ; + my $job = $c->request->params->{job} ; + my $system = $c->request->params->{system} ; + + my $filter = {finished => 1} ; + $filter->{project} = $project if ! $project eq ""; + $filter->{jobset} = $jobset if ! $jobset eq ""; + $filter->{job} = $job if !$job eq ""; + $filter->{system} = $system if !$system eq ""; + + my @latest = joinWithResultInfo($c, $c->model('DB::Builds'))->search($filter, {rows => $nr, order_by => ["timestamp DESC"] }); + + my @list ; + foreach my $b (@latest) { + push @list, buildToHash($b) ; + } + + $c->stash->{'plain'} = { + data => scalar (JSON::Any->objToJson(\@list)) + }; + $c->forward('Hydra::View::Plain'); +} + +sub jobsetToHash { + my ($jobset) = @_; + return { + project => $jobset->project->name, + name => $jobset->name, + nrscheduled => $jobset->get_column("nrscheduled"), + nrsucceeded => $jobset->get_column("nrsucceeded"), + nrfailed => $jobset->get_column("nrfailed"), + nrtotal => $jobset->get_column("nrtotal") + }; +} + +sub jobsets : Chained('api') PathPart('jobsets') Args(0) { + my ($self, $c) = @_; + + my $projectName = $c->request->params->{project} ; + error($c, "Parameter 'project' not defined!") if !defined $projectName; + + my $project = $c->model('DB::Projects')->find($projectName) + or notFound($c, "Project $projectName doesn't exist."); + + my @jobsets = jobsetOverview($c, $project); + + my @list ; + foreach my $j (@jobsets) { + push @list, jobsetToHash($j) ; + } + + $c->stash->{'plain'} = { + data => scalar (JSON::Any->objToJson(\@list)) + }; + $c->forward('Hydra::View::Plain'); +} + +sub queue : Chained('api') PathPart('queue') Args(0) { + my ($self, $c) = @_; + + my $nr = $c->request->params->{nr} ; + error($c, "Parameter not defined!") if !defined $nr; + + my @builds = $c->model('DB::Builds')->search({finished => 0}, {rows => $nr, join => ['schedulingInfo'] , order_by => ["busy DESC", "priority DESC", "timestamp"], '+select' => ['schedulingInfo.priority', 'schedulingInfo.busy'], '+as' => ['priority', 'busy'] }); + + my @list ; + foreach my $b (@builds) { + push @list, buildToHash($b) ; + } + + $c->stash->{'plain'} = { + data => scalar (JSON::Any->objToJson(\@list)) + }; + $c->forward('Hydra::View::Plain'); +} + +sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) { + my ($self, $c) = @_; + my $nrQueuedBuilds = $c->model('DB::BuildSchedulingInfo')->count(); + $c->stash->{'plain'} = { + data => $nrQueuedBuilds + }; + $c->forward('Hydra::View::Plain'); +} + +sub nrrunning : Chained('api') PathPart('nrrunning') Args(0) { + my ($self, $c) = @_; + my $nrRunningBuilds = $c->model('DB::BuildSchedulingInfo')->search({ busy => 1 }, {})->count(); + $c->stash->{'plain'} = { + data => $nrRunningBuilds + }; + $c->forward('Hydra::View::Plain'); +} + +sub ts { + my ($nr, $period) = @_; + my @arr ; + + + + + return @arr; +} + +sub nrbuilds : Chained('api') PathPart('nrbuilds') Args(0) { + my ($self, $c) = @_; + my $nr = $c->request->params->{nr} ; + my $period = $c->request->params->{period} ; + + error($c, "Parameter not defined!") if !defined $nr || !defined $period; + my $base; + + my $project = $c->request->params->{project} ; + my $jobset = $c->request->params->{jobset} ; + my $job = $c->request->params->{job} ; + my $system = $c->request->params->{system} ; + + my $filter = {finished => 1} ; + $filter->{project} = $project if ! $project eq ""; + $filter->{jobset} = $jobset if ! $jobset eq ""; + $filter->{job} = $job if !$job eq ""; + $filter->{system} = $system if !$system eq ""; + + $base = 60*60 if($period eq "hour"); + $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 @arr ; + foreach my $d (@stats) { + push @arr, int($d->get_column("nr")); + } + @arr = reverse(@arr); + + $c->stash->{'plain'} = { + data => scalar (JSON::Any->objToJson(\@arr)) + }; + $c->forward('Hydra::View::Plain'); +} + +1; diff --git a/src/lib/Hydra/Controller/Project.pm b/src/lib/Hydra/Controller/Project.pm index e8d6fed6..3a58911f 100644 --- a/src/lib/Hydra/Controller/Project.pm +++ b/src/lib/Hydra/Controller/Project.pm @@ -6,6 +6,8 @@ use base 'Hydra::Base::Controller::ListBuilds'; use Hydra::Helper::Nix; use Hydra::Helper::CatalystUtils; +our @ISA = qw(Exporter); +our @EXPORT = qw(jobsetOverview); sub project : Chained('/') PathPart('project') CaptureArgs(1) { my ($self, $c, $projectName) = @_; @@ -17,6 +19,19 @@ sub project : Chained('/') PathPart('project') CaptureArgs(1) { } +sub jobsetOverview { + my ($c, $project) = @_; + return $project->jobsets->search( isProjectOwner($c, $project->name) ? {} : { hidden => 0 }, + { order_by => "name" + , "+select" => [ + "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildSchedulingInfo WHERE me.project = a.project AND me.name = a.jobset AND a.isCurrent = 1 )" + , "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildResultInfo WHERE me.project = a.project AND me.name = a.jobset AND buildstatus <> 0 AND a.isCurrent = 1 )" + , "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildResultInfo WHERE 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 )" + ] + , "+as" => ["nrscheduled", "nrfailed", "nrsucceeded", "nrtotal"] + }); +} sub view : Chained('project') PathPart('') Args(0) { my ($self, $c) = @_; @@ -26,16 +41,7 @@ sub view : Chained('project') PathPart('') Args(0) { #getBuildStats($c, scalar $c->stash->{project}->builds); $c->stash->{views} = [$c->stash->{project}->views->all]; - $c->stash->{jobsets} = [$c->stash->{project}->jobsets->search( isProjectOwner($c, $c->stash->{project}->name) ? {} : { hidden => 0 }, - { order_by => "name" - , "+select" => [ - "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildSchedulingInfo WHERE me.project = a.project AND me.name = a.jobset AND a.isCurrent = 1 )" - , "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildResultInfo WHERE me.project = a.project AND me.name = a.jobset AND buildstatus <> 0 AND a.isCurrent = 1 )" - , "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildResultInfo WHERE 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 )" - ] - , "+as" => ["nrscheduled", "nrfailed", "nrsucceeded", "nrtotal"] - })]; + $c->stash->{jobsets} = [jobsetOverview($c, $c->stash->{project})]; }