From f5d9a23d2352f954f394008b31301a07db751e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Wed, 17 Jan 2024 19:43:06 +0100 Subject: [PATCH] Add /job_groups/id/build_results API route Issue: https://progress.opensuse.org/issues/152939 I moved `_map_tags_into_build` into the `compute_build_results()` function. The command lime to get the last "published" build would look like this: openqa-cli api job_groups/1/build_results only_tagged=1 \ | jq -r '[.build_results[] | select(.tag.description=="published") | select(.version=="Tumbleweed") | .build ][0]' To only get the latest build: openqa-cli api job_groups/1/build_results | jq -r '[.build_results[] | .build ][0]' --- lib/OpenQA/BuildResults.pm | 19 ++++++- lib/OpenQA/WebAPI.pm | 1 + .../WebAPI/Controller/API/V1/JobGroup.pm | 40 ++++++++++++++ lib/OpenQA/WebAPI/Controller/Main.pm | 25 ++------- t/api/10-jobgroups.t | 54 +++++++++++++++++++ 5 files changed, 116 insertions(+), 23 deletions(-) diff --git a/lib/OpenQA/BuildResults.pm b/lib/OpenQA/BuildResults.pm index 224bc4ce38bf..173d83ca795c 100644 --- a/lib/OpenQA/BuildResults.pm +++ b/lib/OpenQA/BuildResults.pm @@ -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); @@ -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; diff --git a/lib/OpenQA/WebAPI.pm b/lib/OpenQA/WebAPI.pm index 02f0f7b8152e..2a16fd9a9c7b 100644 --- a/lib/OpenQA/WebAPI.pm +++ b/lib/OpenQA/WebAPI.pm @@ -330,6 +330,7 @@ sub startup ($self) { $api_public_r->get('/job_groups')->name('apiv1_list_job_groups')->to('job_group#list'); $api_public_r->get('/job_groups/')->name('apiv1_get_job_group')->to('job_group#list'); $api_public_r->get('/job_groups//jobs')->name('apiv1_get_job_group_jobs')->to('job_group#list_jobs'); + $api_public_r->get('/job_groups//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/')->name('apiv1_put_job_group')->to('job_group#update'); $api_ra->delete('/job_groups/')->name('apiv1_delete_job_group')->to('job_group#delete'); diff --git a/lib/OpenQA/WebAPI/Controller/API/V1/JobGroup.pm b/lib/OpenQA/WebAPI/Controller/API/V1/JobGroup.pm index 9d7b634255a5..aed265e04c76 100644 --- a/lib/OpenQA/WebAPI/Controller/API/V1/JobGroup.pm +++ b/lib/OpenQA/WebAPI/Controller/API/V1/JobGroup.pm @@ -326,4 +326,44 @@ sub delete ($self) { $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. + +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; diff --git a/lib/OpenQA/WebAPI/Controller/Main.pm b/lib/OpenQA/WebAPI/Controller/Main.pm index bbf488390743..5dcbd269a4b2 100644 --- a/lib/OpenQA/WebAPI/Controller/Main.pm +++ b/lib/OpenQA/WebAPI/Controller/Main.pm @@ -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; @@ -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}; } }; @@ -135,9 +120,8 @@ 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: /; @@ -145,9 +129,8 @@ sub _group_overview ($self, $resultset, $template) { } 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'); diff --git a/t/api/10-jobgroups.t b/t/api/10-jobgroups.t index a13ca40ce61b..e3335ca63ef7 100644 --- a/t/api/10-jobgroups.t +++ b/t/api/10-jobgroups.t @@ -19,6 +19,60 @@ 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(