Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package openQA for openSUSE:Factory checked in at 2025-10-03 15:44:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.11973 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Fri Oct 3 15:44:03 2025 rev:762 rq:1308695 version:5.1759402042.49e912c3 Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2025-10-02 19:21:11.464945907 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new.11973/openQA.changes 2025-10-03 15:45:06.416708572 +0200 @@ -1,0 +2,7 @@ +Thu Oct 02 18:13:03 UTC 2025 - [email protected] + +- Update to version 5.1759402042.49e912c3: + * Introduce array job settings + * Retry `obs_rsync_update_*` tasks if Gru service terminates + +------------------------------------------------------------------- Old: ---- openQA-5.1759329378.3b8e8685.obscpio New: ---- openQA-5.1759402042.49e912c3.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.Epzppj/_old 2025-10-03 15:45:07.808766047 +0200 +++ /var/tmp/diff_new_pack.Epzppj/_new 2025-10-03 15:45:07.812766212 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1759329378.3b8e8685 +Version: 5.1759402042.49e912c3 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.Epzppj/_old 2025-10-03 15:45:07.844767533 +0200 +++ /var/tmp/diff_new_pack.Epzppj/_new 2025-10-03 15:45:07.844767533 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1759329378.3b8e8685 +Version: 5.1759402042.49e912c3 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.Epzppj/_old 2025-10-03 15:45:07.872768690 +0200 +++ /var/tmp/diff_new_pack.Epzppj/_new 2025-10-03 15:45:07.876768854 +0200 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1759329378.3b8e8685 +Version: 5.1759402042.49e912c3 Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.Epzppj/_old 2025-10-03 15:45:07.904770011 +0200 +++ /var/tmp/diff_new_pack.Epzppj/_new 2025-10-03 15:45:07.908770176 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1759329378.3b8e8685 +Version: 5.1759402042.49e912c3 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.Epzppj/_old 2025-10-03 15:45:07.940771497 +0200 +++ /var/tmp/diff_new_pack.Epzppj/_new 2025-10-03 15:45:07.944771662 +0200 @@ -99,7 +99,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1759329378.3b8e8685 +Version: 5.1759402042.49e912c3 Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0-or-later ++++++ openQA-5.1759329378.3b8e8685.obscpio -> openQA-5.1759402042.49e912c3.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Schema/Result/Jobs.pm new/openQA-5.1759402042.49e912c3/lib/OpenQA/Schema/Result/Jobs.pm --- old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Schema/Result/Jobs.pm 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/lib/OpenQA/Schema/Result/Jobs.pm 2025-10-02 12:47:22.000000000 +0200 @@ -410,7 +410,7 @@ my $settings = $self->{_settings} = {}; my $all = $prefetched || [$self->settings->all]; for (@$all) { - # handle multi-value WORKER_CLASS + # handle multi-value WORKER_CLASS and array settings (like ISSUES[]) if (defined $settings->{$_->key}) { $settings->{$_->key} .= ',' . $_->value; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Schema/ResultSet/JobSettings.pm new/openQA-5.1759402042.49e912c3/lib/OpenQA/Schema/ResultSet/JobSettings.pm --- old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Schema/ResultSet/JobSettings.pm 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/lib/OpenQA/Schema/ResultSet/JobSettings.pm 2025-10-02 12:47:22.000000000 +0200 @@ -5,15 +5,29 @@ use Mojo::Base 'DBIx::Class::ResultSet', -signatures; use OpenQA::App; +use List::Util qw(min); sub all_values_sorted ($self, $job_id, $key) { state $options = {distinct => 1, columns => 'value', order_by => 'value'}; [map { $_->value } $self->search({job_id => $job_id, key => $key}, $options)]; } +sub jobs_for_setting_by_exact_key_and_value ($self, $key, $value, $limit) { + my $limits = OpenQA::App->singleton->config->{misc_limits}; + $limit = min($limits->{generic_max_limit}, $limit // $limits->{generic_default_limit}); + my $options = {columns => ['job_id'], rows => $limit, order_by => {-desc => 'id'}}; + return [map { $_->job_id } $self->search({key => $key, value => $value}, $options)]; +} + sub jobs_for_setting ($self, $options) { - my $limit = OpenQA::App->singleton->config->{misc_limits}{job_settings_max_recent_jobs}; + # Return jobs for settings specified by a concrete key/value pair + my $value = $options->{value}; + my $limit = $options->{limit}; + return $self->jobs_for_setting_by_exact_key_and_value($options->{key}, $value, $limit) if defined $value; + # Return jobs for settings specified by a key with globbing and a value that can be part of a comma-separated list + my $server_side_limit = OpenQA::App->singleton->config->{misc_limits}{job_settings_max_recent_jobs}; + $limit = min($server_side_limit, defined($limit) ? ($limit) : ()); my $key_like = $options->{key}; $key_like =~ s/\*/\%/g; my $list_value = $options->{list_value}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Schema/ResultSet/Jobs.pm new/openQA-5.1759402042.49e912c3/lib/OpenQA/Schema/ResultSet/Jobs.pm --- old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Schema/ResultSet/Jobs.pm 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/lib/OpenQA/Schema/ResultSet/Jobs.pm 2025-10-02 12:47:22.000000000 +0200 @@ -196,8 +196,8 @@ my @job_settings; my $now = now; for my $key (keys %settings) { - my @values = $key eq 'WORKER_CLASS' ? split(m/,/, $settings{$key}) : ($settings{$key}); - push(@job_settings, {t_created => $now, t_updated => $now, key => $key, value => $_}) for (@values); + my @values = $key =~ qr/(^WORKER_CLASS|\[\])$/ ? split(m/,/, $settings{$key}) : ($settings{$key}); + push(@job_settings, {t_created => $now, t_updated => $now, key => $key, value => $_}) for @values; } $job->settings->populate(\@job_settings); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Script/CloneJob.pm new/openQA-5.1759402042.49e912c3/lib/OpenQA/Script/CloneJob.pm --- old/openQA-5.1759329378.3b8e8685/lib/OpenQA/Script/CloneJob.pm 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/lib/OpenQA/Script/CloneJob.pm 2025-10-02 12:47:22.000000000 +0200 @@ -15,6 +15,7 @@ use Mojo::URL; use Mojo::JSON; # booleans use OpenQA::Script::CloneJobSUSE; +use List::Util 'any'; our @EXPORT = qw( clone_jobs @@ -35,9 +36,11 @@ my $TEST_NAME = TEST_NAME_ALLOWED_CHARS; my $TEST_NAME_PLUS_MINUS = TEST_NAME_ALLOWED_CHARS_PLUS_MINUS; -my $SETTINGS_REGEX = qr|([A-Z0-9_]+)(:([$TEST_NAME]+(?:[$TEST_NAME_PLUS_MINUS]+[$TEST_NAME])?))?(\+)?=(.*)|; +my $SETTINGS_REGEX = qr|([A-Z0-9_]+(\[\])?)(:([$TEST_NAME]+(?:[$TEST_NAME_PLUS_MINUS]+[$TEST_NAME])?))?(\+)?=(.*)|; -sub is_global_setting ($key) { grep /^$key$/, GLOBAL_SETTINGS } +sub is_global_setting ($key) { + any { $key eq $_ } GLOBAL_SETTINGS; +} sub clone_job_apply_settings ($argv, $depth, $settings, $options) { delete $settings->{NAME}; # usually autocreated @@ -48,7 +51,7 @@ warn "command-line argument '$arg' is no valid setting and will be ignored\n"; next; } - my ($key, $scope, $plus, $value) = ($1, $3, $4, $5); + my ($key, $scope, $plus, $value) = ($1, $4, $5, $6); next if defined $scope && ($settings->{TEST} // '') ne $scope; next if !defined $scope && !is_global_setting($key) && $depth > 1 && !$options->{'parental-inheritance'}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/lib/OpenQA/WebAPI/Controller/API/V1/JobSettings.pm new/openQA-5.1759402042.49e912c3/lib/OpenQA/WebAPI/Controller/API/V1/JobSettings.pm --- old/openQA-5.1759329378.3b8e8685/lib/OpenQA/WebAPI/Controller/API/V1/JobSettings.pm 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/lib/OpenQA/WebAPI/Controller/API/V1/JobSettings.pm 2025-10-02 12:47:22.000000000 +0200 @@ -10,22 +10,36 @@ Filters jobs based on a single setting key/value pair. + openqa-cli api job_settings/jobs key="ISSUES[]" value=39911 openqa-cli api job_settings/jobs key="*_TEST_ISSUES" list_value=39911 openqa-cli api job_settings/jobs key="*" list_value=39911 =item C<key> -The setting key to filter by. It accepts a string or a glob of a job variable. -Some variables are not stored and they can not be used. +The setting key to filter by. Some variables are not stored and they can not be +used. + +=item C<value> + +Returns all jobs where the value of the setting specified by C<key> is C<value>. + +As this query might find many jobs the results are limited by the server-side +setting C<{misc_limits}{generic_default_limit}>. This limit can be increased +using the C<limit> paremter (up to C<{misc_limits}{generic_max_limit}>). =item C<list_value> -The value to match for the given key. This can be a string without special characters. +Returns all jobs where the value of the setting specified by C<key> contains a +comma-separated list that in turn contains C<list_value>. This can be a string +without special characters. When C<list_value> is used, C<key> might contain an +asterisks for globbing. + +Use of C<list_value> is expensive so the search is limited via the server-side +setting C<{misc_limits}{job_settings_max_recent_jobs}>. =item Returns -On success, returns an array of the matched job ids. The results rely on -C<{misc_limits}{job_settings_max_recent_jobs}>. +On success, returns an array of the matched job IDs. =back @@ -33,14 +47,22 @@ sub jobs ($self) { my $validation = $self->validation; - $validation->required('key')->like(qr/^[\w\*]+$/); - $validation->required('list_value')->like(qr/^\w+$/); + $validation->required('key')->like(qr/^[\w\*\[\]]+$/); + $validation->optional('value'); + $validation->optional('list_value')->like(qr/^\w+$/); + $validation->optional('limit')->num(0); return $self->reply->validation_error({format => 'json'}) if $validation->has_error; my $key = $validation->param('key'); + my $value = $validation->param('value'); my $list_value = $validation->param('list_value'); - my $jobs = $self->schema->resultset('JobSettings')->jobs_for_setting({key => $key, list_value => $list_value}); - $self->render(json => {jobs => $jobs}); + my $limit = $validation->param('limit'); + return $self->render(json => {error => 'either "value" or "list_value" needs to be specified'}, status => 400) + unless defined($value) + xor defined($list_value); + my $job_settings = $self->schema->resultset('JobSettings'); + my $options = {key => $key, value => $value, list_value => $list_value, limit => $limit}; + $self->render(json => {jobs => $job_settings->jobs_for_setting($options)}); } 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm new/openQA-5.1759402042.49e912c3/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm --- old/openQA-5.1759329378.3b8e8685/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm 2025-10-02 12:47:22.000000000 +0200 @@ -5,6 +5,7 @@ use Mojo::Base 'Mojolicious::Plugin', -signatures; use Mojo::File; use IPC::Run; +use OpenQA::Task::SignalGuard; use Feature::Compat::Try; sub register ($self, $app, $conf) { @@ -76,6 +77,7 @@ } sub update_dirty_status ($job, $args) { + my $ensure_task_retry_on_termination_signal_guard = OpenQA::Task::SignalGuard->new($job); my $app = $job->app; my $project = $args->{project}; my $helper = $app->obs_rsync; @@ -84,6 +86,7 @@ } sub update_obs_builds_text ($job, $args) { + my $ensure_task_retry_on_termination_signal_guard = OpenQA::Task::SignalGuard->new($job); my $app = $job->app; my $alias = $args->{alias}; my $helper = $app->obs_rsync; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1759329378.3b8e8685/t/api/04-jobs.t new/openQA-5.1759402042.49e912c3/t/api/04-jobs.t --- old/openQA-5.1759329378.3b8e8685/t/api/04-jobs.t 2025-10-01 16:36:18.000000000 +0200 +++ new/openQA-5.1759402042.49e912c3/t/api/04-jobs.t 2025-10-02 12:47:22.000000000 +0200 @@ -292,6 +292,11 @@ ->json_is({jobs => []}); $t->get_ok('/api/v1/job_settings/jobs' => form => {key => '%test%', list_value => '%test%'})->status_is(400) ->json_is({error_status => 400, error => 'Erroneous parameters (key invalid, list_value invalid)'}); + my $value_error = 'either "value" or "list_value" needs to be specified'; + $t->get_ok('/api/v1/job_settings/jobs' => form => {key => 'KEY'}); + $t->status_is(400)->json_is('/error', $value_error, 'error if no value or list_value specified'); + $t->get_ok('/api/v1/job_settings/jobs' => form => {key => 'KEY', value => 'foo', list_value => 'bar'}); + $t->status_is(400)->json_is('/error', $value_error, 'error if value and list_value are both specified'); $t->get_ok('/api/v1/job_settings/jobs' => form => {key => '*_TEST_ISSUES', list_value => 26103})->status_is(200) ->json_is({jobs => [99926]}); @@ -970,6 +975,26 @@ is $jobs->find($id)->settings_hash->{WORKER_CLASS}, 'svirt', 'specified WORKER_CLASS assigned'; }; +subtest 'array settings correctly assigned when posting job' => sub { + my @test_values = qw(foo bar baz); + my $test_values_joined = join ',', @test_values; + my %array_params = (%jobs_post_params, 'ISSUES[]' => $test_values_joined); + my @expected_issues = map { {key => 'ISSUES[]', value => $_} } @test_values; + $t->post_ok('/api/v1/jobs', form => \%array_params)->status_is(200); + ok my $id = $t->tx->res->json->{id}, 'id returned (0)' or always_explain $t->tx->res->json; + my $job = $jobs->find($id); + my $issue_rows = $job->settings->search({key => 'ISSUES[]'}, {order_by => {-asc => 'id'}}); + my @issues = map { {key => $_->key, value => $_->value} } $issue_rows->all; + is_deeply \@issues, \@expected_issues, 'issues stored as distinct rows'; + is $job->settings_hash->{'ISSUES[]'}, $test_values_joined, 'ISSUES joined again when accessing hash'; + $t->get_ok('/api/v1/jobs/' . $id)->status_is(200); + $t->json_is('/job/settings/ISSUES[]' => $test_values_joined, 'ISSUES joined again when queried via API'); + for my $value (@test_values) { + $t->get_ok('/api/v1/job_settings/jobs' => form => {key => 'ISSUES[]', value => $value})->status_is(200); + $t->json_is('/jobs', [$id], "job can be retrieved using single value $value"); + } +}; + subtest 'priority correctly assigned when posting job' => sub { # post new job and check default priority $t->post_ok('/api/v1/jobs', form => \%jobs_post_params)->status_is(200); ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.Epzppj/_old 2025-10-03 15:45:25.597500508 +0200 +++ /var/tmp/diff_new_pack.Epzppj/_new 2025-10-03 15:45:25.609501003 +0200 @@ -1,5 +1,5 @@ name: openQA -version: 5.1759329378.3b8e8685 -mtime: 1759329378 -commit: 3b8e86855acd7c896b2bf14e212b157c3035f02a +version: 5.1759402042.49e912c3 +mtime: 1759402042 +commit: 49e912c3ae9327420f34bb58f5edf168bc52dbcb
