250 lines
8.9 KiB
Perl
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package Hydra::Controller::Job;
use utf8;
use strict;
use warnings;
use base 'Hydra::Base::Controller::ListBuilds';
use Hydra::Helper::Nix;
use Hydra::Helper::CatalystUtils;
use JSON::MaybeXS;
use Net::Prometheus;
sub job : Chained('/') PathPart('job') CaptureArgs(3) {
my ($self, $c, $projectName, $jobsetName, $jobName) = @_;
$c->stash->{jobset} = $c->model('DB::Jobsets')->find({ project => $projectName, name => $jobsetName });
if (!$c->stash->{jobset}) {
my $rename = $c->model('DB::JobsetRenames')->find({ project => $projectName, from_ => $jobsetName });
notFound($c, "Jobset $jobsetName doesn't exist.") unless defined $rename;
# Return a permanent redirect to the new jobset name.
my @captures = @{$c->req->captures};
$captures[1] = $rename->to_;
$c->res->redirect($c->uri_for($c->action, \@captures, $c->req->params), 301);
$c->detach;
}
$c->stash->{job} = $jobName;
$c->stash->{project} = $c->stash->{jobset}->project;
}
sub shield :Chained('job') PathPart('shield') Args(0) {
my ($self, $c) = @_;
my $job = $c->stash->{job};
my $lastBuild = $c->stash->{jobset}->builds->find(
{ job => $job, finished => 1 },
{ order_by => 'id DESC', rows => 1, columns => [@buildListColumns] }
);
notFound($c, "No latest build for job $job.") unless defined $lastBuild;
my $color =
$lastBuild->buildstatus == 0 ? "green" :
$lastBuild->buildstatus == 4 ? "yellow" :
"red";
my $message =
$lastBuild->buildstatus == 0 ? "passing" :
$lastBuild->buildstatus == 4 ? "cancelled" :
"failing";
$c->response->content_type('application/json');
$c->stash->{'plain'} = {
data => scalar (encode_json(
{
schemaVersion => 1,
label => "hydra build",
color => $color,
message => $message,
}))
};
$c->forward('Hydra::View::Plain');
}
sub prometheus : Chained('job') PathPart('prometheus') Args(0) {
my ($self, $c) = @_;
my $prometheus = Net::Prometheus->new;
my $lastBuild = $c->stash->{jobset}->builds->find(
{ job => $c->stash->{job}, finished => 1 },
{ order_by => 'id DESC', rows => 1, columns => ["stoptime", "buildstatus", "closuresize", "size"] }
);
$prometheus->new_counter(
name => "hydra_job_completion_time",
help => "The most recent job's completion time",
labels => [ "project", "jobset", "job" ]
)->labels(
$c->stash->{project}->name,
$c->stash->{jobset}->name,
$c->stash->{job},
)->inc($lastBuild->stoptime);
$prometheus->new_gauge(
name => "hydra_job_failed",
help => "Record if the most recent version of this job failed (1 means failed)",
labels => [ "project", "jobset", "job" ]
)->labels(
$c->stash->{project}->name,
$c->stash->{jobset}->name,
$c->stash->{job},
)->inc($lastBuild->buildstatus > 0);
$prometheus->new_gauge(
name => "hydra_build_closure_size",
help => "Closure size of the last job's build in bytes",
labels => [ "project", "jobset", "job" ]
)->labels(
$c->stash->{project}->name,
$c->stash->{jobset}->name,
$c->stash->{job},
)->inc($lastBuild->closuresize);
$prometheus->new_gauge(
name => "hydra_build_output_size",
help => "Output size of the last job's build in bytes",
labels => [ "project", "jobset", "job" ]
)->labels(
$c->stash->{project}->name,
$c->stash->{jobset}->name,
$c->stash->{job},
)->inc($lastBuild->size);
$c->stash->{'plain'} = { data => $prometheus->render };
$c->forward('Hydra::View::Plain');
}
sub overview : Chained('job') PathPart('') Args(0) {
my ($self, $c) = @_;
$c->stash->{template} = 'job.tt';
$c->stash->{lastBuilds} =
[ $c->stash->{jobset}->builds->search({ job => $c->stash->{job}, finished => 1 },
{ order_by => 'id DESC', rows => 10, columns => [@buildListColumns] }) ];
$c->stash->{queuedBuilds} = [
$c->stash->{jobset}->builds->search(
{ job => $c->stash->{job}, finished => 0 },
{ order_by => ["priority DESC", "id"] }
) ];
# If this is an aggregate job, then get its constituents.
my @constituents = $c->model('DB::Builds')->search(
{ aggregate => { -in => $c->stash->{jobset}->builds->search({ job => $c->stash->{job} }, { columns => ["id"], order_by => "id desc", rows => 15 })->as_query } },
{ join => 'aggregateconstituents_constituents',
columns => ['id', 'job', 'finished', 'buildstatus'],
+select => ['aggregateconstituents_constituents.aggregate'],
+as => ['aggregate']
});
my $aggregates = {};
my %constituentJobs;
foreach my $build (@constituents) {
$aggregates->{$build->get_column('aggregate')}->{constituents}->{$build->job} =
{ id => $build->id, finished => $build->finished, buildstatus => $build->buildstatus };
$constituentJobs{$build->job} = 1;
}
foreach my $agg (keys %$aggregates) {
# FIXME: could be done in one query.
$aggregates->{$agg}->{build} =
$c->model('DB::Builds')->find({id => $agg}, {columns => [@buildListColumns]}) or die;
}
$c->stash->{aggregates} = $aggregates;
$c->stash->{constituentJobs} = [sort (keys %constituentJobs)];
$c->stash->{starred} = $c->user->starredjobs(
{ project => $c->stash->{project}->name
, jobset => $c->stash->{jobset}->name
, job => $c->stash->{job}
})->count == 1 if $c->user_exists;
}
sub metrics_tab : Chained('job') PathPart('metric-tab') Args(0) {
my ($self, $c) = @_;
$c->stash->{template} = 'job-metrics-tab.tt';
$c->stash->{metrics} = [ $c->stash->{jobset}->buildmetrics->search(
{ job => $c->stash->{job} }, { select => ["name"], distinct => 1, order_by => "name", }) ];
}
sub build_times : Chained('job') PathPart('build-times') Args(0) {
my ($self, $c) = @_;
my @res = $c->stash->{jobset}->builds->search(
{ job => $c->stash->{job}, finished => 1, buildstatus => 0, closuresize => { '!=', 0 } },
{ join => "actualBuildStep"
, "+select" => ["actualBuildStep.stoptime - actualBuildStep.starttime"]
, "+as" => ["actualBuildTime"],
, order_by => "id" });
$self->status_ok($c, entity => [ map { { id => $_->id, timestamp => $_ ->timestamp, value => $_->get_column('actualBuildTime') } } @res ]);
}
sub closure_sizes : Chained('job') PathPart('closure-sizes') Args(0) {
my ($self, $c) = @_;
my @res = $c->stash->{jobset}->builds->search(
{ job => $c->stash->{job}, finished => 1, buildstatus => 0, closuresize => { '!=', 0 } },
{ order_by => "id", columns => [ "id", "timestamp", "closuresize" ] });
$self->status_ok($c, entity => [ map { { id => $_->id, timestamp => $_ ->timestamp, value => $_->closuresize } } @res ]);
}
sub output_sizes : Chained('job') PathPart('output-sizes') Args(0) {
my ($self, $c) = @_;
my @res = $c->stash->{jobset}->builds->search(
{ job => $c->stash->{job}, finished => 1, buildstatus => 0, size => { '!=', 0 } },
{ order_by => "id", columns => [ "id", "timestamp", "size" ] });
$self->status_ok($c, entity => [ map { { id => $_->id, timestamp => $_ ->timestamp, value => $_->size } } @res ]);
}
sub metric : Chained('job') PathPart('metric') Args(1) {
my ($self, $c, $metricName) = @_;
$c->stash->{template} = 'metric.tt';
$c->stash->{metricName} = $metricName;
my @res = $c->stash->{jobset}->buildmetrics->search(
{ job => $c->stash->{job}, name => $metricName },
{ order_by => "timestamp", columns => [ "build", "name", "timestamp", "value", "unit" ] });
$self->status_ok($c, entity => [ map { { id => $_->get_column("build"), timestamp => $_ ->timestamp, value => $_->value, unit => $_->unit } } @res ]);
}
# Hydra::Base::Controller::ListBuilds needs this.
sub get_builds : Chained('job') PathPart('') CaptureArgs(0) {
my ($self, $c) = @_;
$c->stash->{allBuilds} = $c->stash->{jobset}->builds->search({ job => $c->stash->{job} });
$c->stash->{latestSucceeded} = $c->model('DB')->resultset('LatestSucceededForJob')
->search({}, {bind => [$c->stash->{jobset}->id, $c->stash->{job}]});
$c->stash->{channelBaseName} =
$c->stash->{project}->name . "-" . $c->stash->{jobset}->name . "-" . $c->stash->{job};
}
sub star : Chained('job') PathPart('star') Args(0) {
my ($self, $c) = @_;
requirePost($c);
requireUser($c);
my $args =
{ project => $c->stash->{project}->name
, jobset => $c->stash->{jobset}->name
, job => $c->stash->{job}
};
if ($c->request->params->{star} eq "1") {
$c->user->starredjobs->update_or_create($args);
} else {
$c->user->starredjobs->find($args)->delete;
}
$c->stash->{resource}->{success} = 1;
}
1;