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-12-18 18:31:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.1928 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Thu Dec 18 18:31:53 2025 rev:787 rq:1323427 version:5.1766014013.377e64fe Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2025-12-17 17:38:40.345458661 +0100 +++ /work/SRC/openSUSE:Factory/.openQA.new.1928/openQA.changes 2025-12-18 18:32:41.828751405 +0100 @@ -1,0 +2,7 @@ +Thu Dec 18 03:54:10 UTC 2025 - [email protected] + +- Update to version 5.1766014013.377e64fe: + * feat(Needle::Save): Adapt to new error handling + * feat(OpenQA::Git): Make error handling more flexible with exceptions + +------------------------------------------------------------------- Old: ---- openQA-5.1765887110.8fc02990.obscpio New: ---- openQA-5.1766014013.377e64fe.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.ZKLqPw/_old 2025-12-18 18:32:43.024801650 +0100 +++ /var/tmp/diff_new_pack.ZKLqPw/_new 2025-12-18 18:32:43.024801650 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1765887110.8fc02990 +Version: 5.1766014013.377e64fe Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.ZKLqPw/_old 2025-12-18 18:32:43.064803330 +0100 +++ /var/tmp/diff_new_pack.ZKLqPw/_new 2025-12-18 18:32:43.068803498 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1765887110.8fc02990 +Version: 5.1766014013.377e64fe Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.ZKLqPw/_old 2025-12-18 18:32:43.096804675 +0100 +++ /var/tmp/diff_new_pack.ZKLqPw/_new 2025-12-18 18:32:43.100804842 +0100 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1765887110.8fc02990 +Version: 5.1766014013.377e64fe Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.ZKLqPw/_old 2025-12-18 18:32:43.136806355 +0100 +++ /var/tmp/diff_new_pack.ZKLqPw/_new 2025-12-18 18:32:43.140806523 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1765887110.8fc02990 +Version: 5.1766014013.377e64fe Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.ZKLqPw/_old 2025-12-18 18:32:43.176808035 +0100 +++ /var/tmp/diff_new_pack.ZKLqPw/_new 2025-12-18 18:32:43.176808035 +0100 @@ -99,7 +99,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1765887110.8fc02990 +Version: 5.1766014013.377e64fe Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0-or-later ++++++ openQA-5.1765887110.8fc02990.obscpio -> openQA-5.1766014013.377e64fe.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/lib/OpenQA/Error/Cmd.pm new/openQA-5.1766014013.377e64fe/lib/OpenQA/Error/Cmd.pm --- old/openQA-5.1765887110.8fc02990/lib/OpenQA/Error/Cmd.pm 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/lib/OpenQA/Error/Cmd.pm 2025-12-18 00:26:53.000000000 +0100 @@ -0,0 +1,16 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package OpenQA::Error::Cmd; + +use Mojo::Base -base, -signatures; + +has [qw(status return_code stdout stderr signal msg)]; + +# Perl::Critic::Policy::Community::OverloadOptions +# Automatically render error message in string context +use overload '""' => \&to_string, bool => sub { 1 }, fallback => 1; + +sub to_string ($self, @) { (ref $self) . ': ' . $self->msg } + +1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/lib/OpenQA/Git.pm new/openQA-5.1766014013.377e64fe/lib/OpenQA/Git.pm --- old/openQA-5.1765887110.8fc02990/lib/OpenQA/Git.pm 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/lib/OpenQA/Git.pm 2025-12-18 00:26:53.000000000 +0100 @@ -10,6 +10,8 @@ use OpenQA::Utils qw(run_cmd_with_log_return_error run_cmd_with_log config_autocommit_enabled); use OpenQA::App; use Feature::Compat::Try; +use OpenQA::Error::Cmd; +use Carp qw(croak); has 'app'; has 'dir'; @@ -45,9 +47,14 @@ expected_return_codes => $options->{expected_return_codes}, output_file => $options->{output_file}); $self->app->log->error("Git command failed: @cmd - Error: $result->{stderr}") unless $result->{status}; + $self->error($result, $options->{croak}) if $options->{croak} && !$result->{status}; return $result; } +sub error ($self, $result, $msg) { + croak(OpenQA::Error::Cmd->new(%$result, msg => $self->_format_git_error($result, $msg))); +} + sub _prepare_git_command ($self, $include_git_path) { return 'git' unless $include_git_path; my $dir = $self->dir; @@ -93,29 +100,31 @@ for my $cmd (qw(add rm)) { next unless $args->{$cmd}; push(@files, @{$args->{$cmd}}); - my $res = $self->_run_cmd([$cmd, @{$args->{$cmd}}]); - return $self->_format_git_error($res, "Unable to $cmd via Git") unless $res->{status}; + $self->_run_cmd([$cmd, @{$args->{$cmd}}], {croak => "Unable to $cmd via Git"}); } # commit changes my $message = $args->{message}; my $author = sprintf('--author=%s <%s>', $self->user->fullname, $self->user->email); - my $res = $self->_run_cmd(['commit', '-q', '-m', $message, $author, @files]); - return $self->_format_git_error($res, 'Unable to commit via Git') unless $res->{status}; + $self->_run_cmd(['commit', '-q', '-m', $message, $author, @files], {croak => 'Unable to commit via Git'}); # push changes if (($self->config->{do_push} || '') eq 'yes') { - $res = $self->_run_cmd(['push'], {batchmode => 1}); - return undef if $res->{status}; - my $msg = 'Unable to push Git commit'; - if ($res->{return_code} == 128 and $res->{stderr} =~ m/Authentication failed for .http/) { - $msg - .= '. See https://open.qa/docs/#_setting_up_git_support on how to setup git support and possibly push via ssh.'; + try { + $self->_run_cmd(['push'], {batchmode => 1, croak => $msg}); + return undef; + } + catch ($e) { + if ($e->return_code == 128 and $e->stderr =~ m/Authentication failed for .http/) { + $msg + .= '. See https://open.qa/docs/#_setting_up_git_support on how to setup git support and possibly push via ssh.'; + $e->msg($msg); + } + croak $e; } - return $self->_format_git_error($res, $msg); - } + } return undef; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/lib/OpenQA/Schema/Result/Needles.pm new/openQA-5.1766014013.377e64fe/lib/OpenQA/Schema/Result/Needles.pm --- old/openQA-5.1765887110.8fc02990/lib/OpenQA/Schema/Result/Needles.pm 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/lib/OpenQA/Schema/Result/Needles.pm 2025-12-18 00:26:53.000000000 +0100 @@ -17,6 +17,8 @@ use OpenQA::Jobs::Constants; use OpenQA::Schema::Result::Jobs; use OpenQA::Needles qw(locate_needle); +use Feature::Compat::Try; +use Carp qw(croak); __PACKAGE__->table('needles'); __PACKAGE__->load_components(qw(InflateColumn::DateTime Timestamps)); @@ -178,12 +180,11 @@ my $git = OpenQA::Git->new({app => $app, dir => $self->directory->path, user => $user}); if ($git->autocommit_enabled) { my $directory = $self->directory; - my $error = $git->commit( + $git->commit( { rm => [$fname, $screenshot], message => sprintf('Remove %s/%s', $directory->name, $self->filename), }); - return $error if $error; } else { my @error_files; @@ -192,7 +193,7 @@ if (@error_files) { my $error = 'Unable to delete ' . join(' and ', @error_files); $app->log->debug($error); - return $error; + croak $error; } } $self->check_file; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/lib/OpenQA/Task/Needle/Delete.pm new/openQA-5.1766014013.377e64fe/lib/OpenQA/Task/Needle/Delete.pm --- old/openQA-5.1765887110.8fc02990/lib/OpenQA/Task/Needle/Delete.pm 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/lib/OpenQA/Task/Needle/Delete.pm 2025-12-18 00:26:53.000000000 +0100 @@ -8,6 +8,7 @@ use Scalar::Util 'looks_like_number'; use Time::Seconds 'ONE_HOUR'; use OpenQA::Task::SignalGuard; +use Feature::Compat::Try; sub register { my ($self, $app) = @_; @@ -57,12 +58,15 @@ } for my $needle (@$needles) { my $needle_id = $needle->id; - if (my $error = $needle->remove($user)) { + try { + $needle->remove($user); + } + catch ($e) { push @errors, { id => $needle_id, display_name => $needle->filename, - message => $error, + message => ref $e ? $e->msg : $e, }; next; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/lib/OpenQA/Task/Needle/Save.pm new/openQA-5.1766014013.377e64fe/lib/OpenQA/Task/Needle/Save.pm --- old/openQA-5.1765887110.8fc02990/lib/OpenQA/Task/Needle/Save.pm 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/lib/OpenQA/Task/Needle/Save.pm 2025-12-18 00:26:53.000000000 +0100 @@ -140,17 +140,12 @@ } return $minion_job->fail({error => "<strong>Error creating/updating needle:</strong><br>$!."}) unless $success; - # commit needle in Git repository - if ($git->autocommit_enabled) { - my $error = $git->commit( - { - add => ["$needlename.json", "$needlename.png"], - message => ($commit_message || sprintf('%s for %s', $needlename, $openqa_job->name)), - }); - if ($error) { - $app->log->error($error); - return $minion_job->fail({error => _format_git_error($needlename, $error)}); - } + try { + _commit_needle_in_git_repo($app, $git, $needlename, $openqa_job, $commit_message); + } + catch ($e) { + $app->log->error("$e"); + return $minion_job->fail({error => _format_git_error($needlename, "$e")}); } # create/update needle in database @@ -170,4 +165,12 @@ return $minion_job->finish($info); } +sub _commit_needle_in_git_repo ($app, $git, $needlename, $openqa_job, $commit_message) { + $git->commit( + { + add => ["$needlename.json", "$needlename.png"], + message => ($commit_message || sprintf('%s for %s', $needlename, $openqa_job->name)), + }) if $git->autocommit_enabled; +} + 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/t/14-grutasks-git.t new/openQA-5.1766014013.377e64fe/t/14-grutasks-git.t --- old/openQA-5.1765887110.8fc02990/t/14-grutasks-git.t 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/t/14-grutasks-git.t 2025-12-18 00:26:53.000000000 +0100 @@ -464,7 +464,9 @@ $openqa_git->redefine( run_cmd_with_log_return_error => sub ($cmd, %args) { push @cmds, "@$cmd"; - return {status => 0, stderr => 'lala', stdout => ''}; + my $res = {status => 0, stderr => 'lala', stdout => ''}; + OpenQA::Git->error($res, $args{croak}) if !$res->{status} && $args{croak}; + return $res; }); $args{needle_ids} = [5]; stderr_like { $res = run_gru_job(@gru_args) } qr{Git command failed.*git.*rm}, 'expected stderr'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/t/16-utils-runcmd.t new/openQA-5.1766014013.377e64fe/t/16-utils-runcmd.t --- old/openQA-5.1765887110.8fc02990/t/16-utils-runcmd.t 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/t/16-utils-runcmd.t 2025-12-18 00:26:53.000000000 +0100 @@ -75,9 +75,10 @@ my $res; subtest 'invoking Git command outside of a Git repo' => sub { - stdout_like { $res = $git->commit({cmd => 'status', message => 'test'}) } - qr/.*\[warn\].*fatal: Not a git repository/i, 'Git error logged'; - like $res, qr"^Unable to commit via Git \($empty_tmp_dir\): fatal: Not a git repository"i, 'Git error returned'; + throws_ok { + stdout_like { $res = $git->commit({cmd => 'status', message => 'test'}) } + qr/.*\[warn\].*fatal: Not a git repository/i, 'Git error logged' + } qr/OpenQA::Error::Cmd: Unable to commit via Git.*\Q$empty_tmp_dir\E.*fatal: Not a git repository/i; combined_like { throws_ok { $git->check_sha('this-sha-does-not-exist') } qr/internal Git error/i, 'check throws an exception' @@ -259,10 +260,14 @@ } return \%mock_return_value; }); - combined_like { - like $git->commit({message => 'failed push test'}), qr/Unable to push Git commit/, 'error handled during push'; - } - qr/Error: mocked push error/, 'push error logged'; + throws_ok { + combined_like { + like $git->commit({message => 'failed push test'}), qr/Unable to push Git commit/, + 'error handled during push'; + } + qr/Error: mocked push error/, + 'push error logged' + } qr{OpenQA::Error::Cmd: Unable to push Git commit.*mocked push error}; $git->config->{do_push} = ''; }; @@ -335,16 +340,16 @@ sub fail ($self, $args) { $self->{fail_message} = $args } } # uncoverable statement - sub _run_save_needle_test ($git_mock) { + sub _run_save_needle_test ($git_mock, $log_error = undef, $fail_message = undef) { my @log_errors; my $log_mock = Test::MockModule->new(ref $t->app->log); $log_mock->redefine(error => sub ($self, $message) { push @log_errors, $message; }); my $job = bless({} => 'Test::FailingMinionJob'); OpenQA::Task::Needle::Save::_save_needle($t->app, $job, $fake_needle); - like $log_errors[0], qr/Unable to fetch.*mocked/, 'error logged on fail'; + like $log_errors[0], $log_error // qr/Unable to fetch.*mocked/, 'error logged on fail'; like $job->{fail_message}->{error}, - qr{<strong>Failed to save.*</strong>.*<pre>Unable to fetch.*mocked.*</pre>}, + $fail_message // qr{<strong>Failed to save.*</strong>.*<pre>Unable to fetch.*mocked.*</pre>}, 'error message in fail'; } @@ -361,6 +366,13 @@ $t->app->config->{'scm git'}->{do_cleanup} = 'no'; _run_save_needle_test($git_mock); }; + + subtest 'fails when commit fails ' => sub { + $git_mock->redefine(set_to_latest_master => ''); + $git_mock->redefine(commit => sub ($self, @) { $self->error({status => 0}, 'Commit error') }); + local $fake_needle->{overwrite} = 1; + _run_save_needle_test($git_mock, (qr/OpenQA::Error::Cmd: Commit error/) x 2); + }; }; done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1765887110.8fc02990/t/ui/21-admin-needles.t new/openQA-5.1766014013.377e64fe/t/ui/21-admin-needles.t --- old/openQA-5.1765887110.8fc02990/t/ui/21-admin-needles.t 2025-12-16 13:11:50.000000000 +0100 +++ new/openQA-5.1766014013.377e64fe/t/ui/21-admin-needles.t 2025-12-18 00:26:53.000000000 +0100 @@ -118,9 +118,9 @@ wait_for_ajax(with_minion => $minion); is(scalar @{$driver->find_elements('#outstanding-needles li', 'css')}, 0, 'no outstanding needles'); is(scalar @{$driver->find_elements('#failed-needles li', 'css')}, 1, 'but failed needle'); - is( + like( $driver->find_element('#failed-needles li')->get_text(), -"inst-timezone-text.json\nUnable to delete t/data/openqa/share/tests/opensuse/needles/inst-timezone-text.json and t/data/openqa/share/tests/opensuse/needles/inst-timezone-text.png", +qr{inst-timezone-text.json\nUnable to delete t/data/openqa/share/tests/opensuse/needles/inst-timezone-text.json and t/data/openqa/share/tests/opensuse/needles/inst-timezone-text.png}, 'right needle name and error message displayed' ); $driver->find_element_by_id('close_delete')->click(); ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.ZKLqPw/_old 2025-12-18 18:33:09.469912566 +0100 +++ /var/tmp/diff_new_pack.ZKLqPw/_new 2025-12-18 18:33:09.485913238 +0100 @@ -1,5 +1,5 @@ name: openQA -version: 5.1765887110.8fc02990 -mtime: 1765887110 -commit: 8fc02990d191051d7fd201ea553ee3112c911efd +version: 5.1766014013.377e64fe +mtime: 1766014013 +commit: 377e64fe96888612ae1cc9a2b39306d811eae7c3
