Skip to content

Commit

Permalink
Merge pull request #5433 from perlpunk/latest-build
Browse files Browse the repository at this point in the history
Add /job_groups/id/build_results API route
  • Loading branch information
mergify[bot] committed Feb 7, 2024
2 parents 3dabfca + 2dd03be commit 0421525
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 53 deletions.
19 changes: 17 additions & 2 deletions lib/OpenQA/BuildResults.pm
Expand Up @@ -110,7 +110,7 @@ sub find_child_groups ($group, $subgroup_filter) {
return filter_subgroups($group, $subgroup_filter);
}

sub compute_build_results ($group, $limit, $time_limit_days, $tags, $subgroup_filter) {
sub compute_build_results ($group, $limit, $time_limit_days, $tags, $subgroup_filter, $show_tags) {

# find relevant child groups taking filter into account
my $child_groups = find_child_groups($group, $subgroup_filter);
Expand Down Expand Up @@ -233,8 +233,23 @@ sub compute_build_results ($group, $limit, $time_limit_days, $tags, $subgroup_fi
$max_jobs = $jr{total} if ($jr{total} > $max_jobs);
}
$result{max_jobs} = $max_jobs;
_map_tags_into_build($result{build_results}, $show_tags) if $show_tags;
return \%result;
}

1;
sub _map_tags_into_build ($results, $tags) {
for my $res (@$results) {
if (my $full_tag = $tags->{$res->{key}}) {
$res->{tag} = $full_tag;
}
elsif (my $build_only_tag = $tags->{$res->{build}}) {
# as fallback we are looking for build and not other criteria we can end
# up with multiple tags if the build appears more than once, e.g.
# for each version
$res->{tag} = $build_only_tag;
}
}
}


1;
2 changes: 2 additions & 0 deletions lib/OpenQA/WebAPI.pm
Expand Up @@ -330,6 +330,8 @@ sub startup ($self) {
$api_public_r->get('/job_groups')->name('apiv1_list_job_groups')->to('job_group#list');
$api_public_r->get('/job_groups/<group_id:num>')->name('apiv1_get_job_group')->to('job_group#list');
$api_public_r->get('/job_groups/<group_id:num>/jobs')->name('apiv1_get_job_group_jobs')->to('job_group#list_jobs');
$api_public_r->get('/job_groups/<group_id:num>/build_results')->name('apiv1_get_job_group_jobs')
->to('job_group#build_results');
$api_ra->post('/job_groups')->name('apiv1_post_job_group')->to('job_group#create');
$api_ra->put('/job_groups/<group_id:num>')->name('apiv1_put_job_group')->to('job_group#update');
$api_ra->delete('/job_groups/<group_id:num>')->name('apiv1_delete_job_group')->to('job_group#delete');
Expand Down
83 changes: 53 additions & 30 deletions lib/OpenQA/WebAPI/Controller/API/V1/JobGroup.pm
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later

package OpenQA::WebAPI::Controller::API::V1::JobGroup;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::Base 'Mojolicious::Controller', -signatures;

use OpenQA::Schema::Result::JobGroups;

Expand Down Expand Up @@ -36,8 +36,7 @@ Reports true if the job group given to the method is a parent group.
=cut

sub is_parent {
my ($self) = @_;
sub is_parent ($self) {
return $self->req->url->path =~ qr/.*\/parent_groups/;
}

Expand All @@ -51,8 +50,7 @@ Returns results for a set of groups.
=cut

sub resultset {
my ($self) = @_;
sub resultset ($self) {
return $self->schema->resultset($self->is_parent ? 'JobGroupParents' : 'JobGroups');
}

Expand All @@ -66,9 +64,7 @@ Returns information from a job group given its ID.
=cut

sub find_group {
my ($self) = @_;

sub find_group ($self) {
my $group_id = $self->param('group_id');
if (!defined $group_id) {
$self->render(json => {error => 'No group ID specified'}, status => 400);
Expand All @@ -95,8 +91,7 @@ create or update a job group via DBIx.
=cut

sub load_properties {
my ($self) = @_;
sub load_properties ($self) {

if (my $cached_properties = $self->{cached_properties}) {
return $cached_properties;
Expand Down Expand Up @@ -134,9 +129,7 @@ timestamps - is also returned as a list of indexed lists.
=cut

sub list {
my ($self) = @_;

sub list ($self) {
my $groups;
my $group_id = $self->param('group_id');
if ($group_id) {
Expand Down Expand Up @@ -170,18 +163,15 @@ Check existing job group on top level to prevent create/update duplicate.
=cut

sub check_top_level_group {
my ($self, $group_id) = @_;

sub check_top_level_group ($self, $group_id = undef) {
return 0 if $self->is_parent;
my $properties = $self->load_properties;
my $conditions = {name => $properties->{name}, parent_id => undef};
$conditions->{id} = {'!=', $group_id} if $group_id;
return $self->resultset->search($conditions);
}

sub _validate_common_properties {
my ($self) = @_;
sub _validate_common_properties ($self) {
my $validation = $self->validation;
$validation->optional('parent_id')->like(qr/^(none|[0-9]+)\z/);
$validation->optional('size_limit_gb')->like(qr/^(|[0-9]+)\z/);
Expand Down Expand Up @@ -215,9 +205,7 @@ Returns a 400 code on error or a 500 code if the group already exists.
=cut

sub create {
my ($self) = @_;

sub create ($self) {
my $validation = $self->validation;
$validation->required('name')->like(qr/^(?!\s*$).+/);
$validation->optional('default_keep_logs_in_days')->num(0);
Expand Down Expand Up @@ -257,9 +245,7 @@ Updates the properties of a job group.
=cut

sub update {
my ($self) = @_;

sub update ($self) {
my $group = $self->find_group;
return unless $group;

Expand Down Expand Up @@ -299,9 +285,7 @@ List jobs belonging to a job group.
=cut

sub list_jobs {
my ($self) = @_;

sub list_jobs ($self) {
my $group = $self->find_group;
return unless $group;

Expand All @@ -325,9 +309,7 @@ Deletes a job group. Verifies that it is not empty before attempting to remove.
=cut

sub delete {
my ($self) = @_;

sub delete ($self) {
my $group = $self->find_group();
return unless $group;

Expand All @@ -344,4 +326,45 @@ sub delete {
$self->render(json => $event_data);
}

=over 4
=item build_results()
Shows build results for a job group, similar to what the group_overview page
provides.
Currently it does not support parent job groups.
Use limit_builds=n to limit the number of returned builds. Default is 10.
Use time_limit_days=n to only go back n days.
Use only_tagged=1 to only return tagged builds.
Use show_tags=1 to show tags for each build. only_tagged implies show_tags.
=back
=cut

sub build_results ($self) {
my $group = $self->find_group() or return;
my $validation = $self->validation;
$validation->optional('limit_builds')->num;
$validation->optional('time_limit_days')->like(qr/^[0-9.]+$/);
$validation->optional('only_tagged');
$validation->optional('show_tags');
my $limit_builds = $validation->param('limit_builds') // 10;
my $time_limit_days = $validation->param('time_limit_days') // 0;
my $only_tagged = $validation->param('only_tagged') // 0;
my $show_tags = $validation->param('show_tags') // $only_tagged;

my $tags = $show_tags ? $group->tags : undef;
my $cbr
= OpenQA::BuildResults::compute_build_results($group, $limit_builds,
$time_limit_days, $only_tagged ? $tags : undef,
[], $tags);
$self->render(json => $cbr);
}

1;
26 changes: 5 additions & 21 deletions lib/OpenQA/WebAPI/Controller/Main.pm
Expand Up @@ -11,20 +11,6 @@ use OpenQA::BuildResults;
use OpenQA::Utils;
use Mojo::File qw(path);

sub _map_tags_into_build ($results, $tags) {
for my $res (@$results) {
if (my $full_tag = $tags->{$res->{key}}) {
$res->{tag} = $full_tag;
}
elsif (my $build_only_tag = $tags->{$res->{build}}) {
# as fallback we are looking for build and not other criteria we can end
# up with multiple tags if the build appears more than once, e.g.
# for each version
$res->{tag} = $build_only_tag;
}
}
}

sub dashboard_build_results ($self) {
my $validation = $self->validation;
$validation->optional('limit_builds')->num;
Expand Down Expand Up @@ -56,10 +42,9 @@ sub dashboard_build_results ($self) {
my $build_results
= OpenQA::BuildResults::compute_build_results($group, $limit_builds, $time_limit_days,
$only_tagged ? $tags : undef,
$group_params);
$group_params, $show_tags ? $tags : undef);

my $build_results_for_group = $build_results->{build_results};
_map_tags_into_build($build_results_for_group, $tags) if $show_tags;
push(@results, $build_results) if @{$build_results_for_group};
}
};
Expand Down Expand Up @@ -135,19 +120,18 @@ sub _group_overview ($self, $resultset, $template) {

my $tags = $group->tags;
my $cbr = eval {
OpenQA::BuildResults::compute_build_results($group, $limit_builds, $time_limit_days,
$only_tagged ? $tags : undef,
$group_params);
OpenQA::BuildResults::compute_build_results($group, $limit_builds,
$time_limit_days, $only_tagged ? $tags : undef,
$group_params, $tags);
};
if (my $error = $@) {
die $error unless $error =~ qr/^invalid regex: /;
return $self->_respond_error_for_group_overview($error);
}
my $build_results = $cbr->{build_results};
my $max_jobs = $cbr->{max_jobs};
$self->stash(children => $cbr->{children});

_map_tags_into_build($build_results, $tags);
$self->stash(children => $cbr->{children});
$self->stash(build_results => $build_results, max_jobs => $max_jobs);

my $is_parent_group = $group->can('children');
Expand Down
57 changes: 57 additions & 0 deletions t/api/10-jobgroups.t
Expand Up @@ -19,6 +19,63 @@ my $schema = $t->app->schema;
my $audit_events = $schema->resultset('AuditEvents');

my $opensuse_group = '1001';


subtest 'build results' => sub {
subtest 'default' => sub {
$t->get_ok("/api/v1/job_groups/$opensuse_group/build_results?time_limit_days=99999")->status_is(200);
$t->json_is('/build_results/4/all_passed' => '');
$t->json_is('/build_results/4/build' => '0091');
$t->json_is('/build_results/4/key' => '13.1-0091');
$t->json_is('/build_results/4/comments' => 0);
$t->json_is('/build_results/4/commented' => 1);
$t->json_is('/build_results/4/escaped_id' => '13_1-0091');
$t->json_is('/build_results/4/escaped_build' => '0091');
$t->json_is('/build_results/4/escaped_version' => '13_1');
$t->json_is('/build_results/4/failed' => 0);
$t->json_is('/build_results/4/labeled' => 0);
$t->json_is('/build_results/4/passed' => 2);
$t->json_is('/build_results/4/reviewed' => 1);
$t->json_is('/build_results/4/skipped' => 1);
$t->json_is('/build_results/4/softfailed' => 0);
$t->json_is('/build_results/4/total' => 5);
$t->json_is('/build_results/4/unfinished' => 2);
$t->json_is('/build_results/4/version' => '13.1');
$t->json_is('/build_results/3/build' => '0092');
$t->json_is('/build_results/2/build' => '0048');
$t->json_is('/build_results/1/build' => '0048@0815');
$t->json_is('/build_results/0/build' => '87.5011');
$t->json_is('/build_results/0/tag' => undef);
$t->json_is('/build_results/5' => undef);
$t->json_is('/max_jobs' => 5,);
$t->json_is('/group/id' => $opensuse_group);
$t->json_is('/group/name' => 'opensuse');
};

subtest 'tags' => sub {
$t->get_ok("/api/v1/job_groups/$opensuse_group/build_results?time_limit_days=99999&show_tags=1")
->status_is(200);
$t->json_is('/build_results/0/tag' => undef);

$t->get_ok("/api/v1/job_groups/$opensuse_group/build_results?time_limit_days=99999&only_tagged=1&show_tags=1")
->status_is(200);
$t->json_is('/build_results/0' => undef, 'no tagged build is shown');

my $comment = 'tag:0091:published:published';
$t->post_ok("/api/v1/groups/$opensuse_group/comments" => form => {text => $comment})
->status_is(200, 'comment can be created')->or(sub { diag 'error: ' . $t->tx->res->json->{error} });
my $cid = $t->tx->res->json->{id};
$t->get_ok("/api/v1/job_groups/$opensuse_group/build_results?time_limit_days=99999&only_tagged=1&show_tags=1")
->status_is(200);
my $json = $t->tx->res->json;
$t->json_is('/build_results/0/build' => '0091', 'one tagged build is shown');
$t->json_is('/build_results/0/tag/build' => '0091');
$t->json_is('/build_results/0/tag/description' => 'published');
$t->json_is('/build_results/0/tag/type' => 'published');
$t->json_is('/build_results/0/tag/version' => undef);
};
};

subtest 'list job groups' => sub() {
$t->get_ok('/api/v1/job_groups')->status_is(200);
is_deeply(
Expand Down

0 comments on commit 0421525

Please sign in to comment.