Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package openQA for openSUSE:Factory checked 
in at 2026-09-24 23:06:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openQA (Old)
 and      /work/SRC/openSUSE:Factory/.openQA.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openQA"

Thu Sep 24 23:06:12 2026 rev:882 rq:1380247 version:5.1790264833.381b79cd

Changes:
--------
--- /work/SRC/openSUSE:Factory/openQA/openQA.changes    2026-09-22 
20:30:31.766129023 +0200
+++ /work/SRC/openSUSE:Factory/.openQA.new.383539/openQA.changes        
2026-09-24 23:06:17.827442940 +0200
@@ -1,0 +2,23 @@
+Thu Sep 24 15:47:23 UTC 2026 - [email protected]
+
+- Update to version 5.1790264833.381b79cd:
+  * test(devel-fullstack): Fix waiting for `outstanding_images`
+  * chore(deps): Dependency cron 2026-09-24
+  * feat(cli): Add worker reservation subcommand
+  * feat(completion): Enhance openqa-cli shell completion
+  * fix(packaging): skip fixture test on SLE <= 1500
+  * feat(dev): introduce mock test environment
+
+-------------------------------------------------------------------
+Thu Sep 24 05:05:38 UTC 2026 - [email protected]
+
+- Update to version 5.1790226324.6b673da6:
+  * chore(deps): Dependency cron 2026-09-24
+  * feat(completion): Enhance openqa-cli shell completion
+  * chore(deps): Dependency cron 2026-09-22
+  * fix(packaging): skip fixture test on SLE <= 1500
+  * feat(dev): introduce mock test environment
+  * fix: Fix typo in NGINX config
+  * fix: Include missing `PATCH` in rate limiting config example
+
+-------------------------------------------------------------------

Old:
----
  openQA-5.1790071740.8a090f85.obscpio

New:
----
  openQA-5.1790264833.381b79cd.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ openQA-client-test.spec ++++++
--- /var/tmp/diff_new_pack.Vy1u6J/_old  2026-09-24 23:06:19.996533944 +0200
+++ /var/tmp/diff_new_pack.Vy1u6J/_new  2026-09-24 23:06:19.998534028 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-client
 Name:           %{short_name}-test
-Version:        5.1790071740.8a090f85
+Version:        5.1790264833.381b79cd
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-devel-test.spec ++++++
--- /var/tmp/diff_new_pack.Vy1u6J/_old  2026-09-24 23:06:20.026535203 +0200
+++ /var/tmp/diff_new_pack.Vy1u6J/_new  2026-09-24 23:06:20.027535245 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-devel
 Name:           %{short_name}-test
-Version:        5.1790071740.8a090f85
+Version:        5.1790264833.381b79cd
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-test.spec ++++++
--- /var/tmp/diff_new_pack.Vy1u6J/_old  2026-09-24 23:06:20.056536462 +0200
+++ /var/tmp/diff_new_pack.Vy1u6J/_new  2026-09-24 23:06:20.057536504 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA
 Name:           %{short_name}-test
-Version:        5.1790071740.8a090f85
+Version:        5.1790264833.381b79cd
 Release:        0
 Summary:        Test package for openQA
 License:        GPL-2.0-or-later

++++++ openQA-worker-test.spec ++++++
--- /var/tmp/diff_new_pack.Vy1u6J/_old  2026-09-24 23:06:20.081537511 +0200
+++ /var/tmp/diff_new_pack.Vy1u6J/_new  2026-09-24 23:06:20.083537595 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-worker
 Name:           %{short_name}-test
-Version:        5.1790071740.8a090f85
+Version:        5.1790264833.381b79cd
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA.spec ++++++
--- /var/tmp/diff_new_pack.Vy1u6J/_old  2026-09-24 23:06:20.109538685 +0200
+++ /var/tmp/diff_new_pack.Vy1u6J/_new  2026-09-24 23:06:20.111538769 +0200
@@ -104,7 +104,7 @@
 %define devel_requires %devel_no_selenium_requires chromedriver
 
 Name:           openQA
-Version:        5.1790071740.8a090f85
+Version:        5.1790264833.381b79cd
 Release:        0
 Summary:        Framework for automated system-level testing (web-frontend, 
scheduler and tools)
 Group:          Development/Tools/Other
@@ -346,6 +346,9 @@
 %package client-bash-completion
 Summary:        Bash Completion for %{name}
 Group:          Development/Tools/Other
+%if 0%{?suse_version} > 1500
+BuildRequires:  perl-App-AppSpec
+%endif
 Requires:       bash-completion
 Supplements:    (%{name}-client and bash-completion)
 
@@ -355,6 +358,9 @@
 %package client-zsh-completion
 Summary:        Zsh Completion for %{name}
 Group:          Development/Tools/Other
+%if 0%{?suse_version} > 1500
+BuildRequires:  perl-App-AppSpec
+%endif
 Supplements:    (%{name}-client and zsh)
 
 %description client-zsh-completion

++++++ openQA-5.1790071740.8a090f85.obscpio -> 
openQA-5.1790264833.381b79cd.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/Makefile 
new/openQA-5.1790264833.381b79cd/Makefile
--- old/openQA-5.1790071740.8a090f85/Makefile   2026-09-22 12:09:00.000000000 
+0200
+++ new/openQA-5.1790264833.381b79cd/Makefile   2026-09-24 17:47:13.000000000 
+0200
@@ -104,7 +104,8 @@
 .PHONY: generate-completions
 generate-completions: ## Regenerate shell completion scripts from 
public/openqa-cli.yaml
        mkdir -p contrib/completions
-       tools/generate-cli-completions
+       (appspec completion public/openqa-cli.yaml --bash 2>/dev/null || echo 
"# No completion available") > contrib/completions/openqa-cli-completion.bash
+       (appspec completion public/openqa-cli.yaml --zsh 2>/dev/null || echo "# 
No completion available") > contrib/completions/openqa-cli-completion.zsh
 
 .PHONY: generate-assets
 generate-assets: ## Generate packed assets and copy to DESTDIR
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/dist/rpm/openQA.spec 
new/openQA-5.1790264833.381b79cd/dist/rpm/openQA.spec
--- old/openQA-5.1790071740.8a090f85/dist/rpm/openQA.spec       2026-09-22 
12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/dist/rpm/openQA.spec       2026-09-24 
17:47:13.000000000 +0200
@@ -347,6 +347,9 @@
 %package client-bash-completion
 Summary:        Bash Completion for %{name}
 Group:          Development/Tools/Other
+%if 0%{?suse_version} > 1500
+BuildRequires:  perl-App-AppSpec
+%endif
 Requires:       bash-completion
 Supplements:    (%{name}-client and bash-completion)
 
@@ -356,6 +359,9 @@
 %package client-zsh-completion
 Summary:        Zsh Completion for %{name}
 Group:          Development/Tools/Other
+%if 0%{?suse_version} > 1500
+BuildRequires:  perl-App-AppSpec
+%endif
 Supplements:    (%{name}-client and zsh)
 
 %description client-zsh-completion
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/docs/UsersGuide.md 
new/openQA-5.1790264833.381b79cd/docs/UsersGuide.md
--- old/openQA-5.1790071740.8a090f85/docs/UsersGuide.md 2026-09-22 
12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/docs/UsersGuide.md 2026-09-24 
17:47:13.000000000 +0200
@@ -1094,8 +1094,16 @@
 jobs from being assigned. A reservation expires automatically after its
 duration, releasing the worker again.
 
-Reservations are managed in the workers table of the admin area or via the REST
-API:
+Reservations are managed in the workers table of the admin area or via the more
+convenient `reservation` subcommand of `openqa-cli`:
+
+```bash
+openqa-cli api --pretty -X GET workers  # get worker ID
+openqa-cli reservation --comment="Manual testing" --duration=5h <id>
+openqa-cli reservation --release <id>
+```
+
+Alternatively, reservations can be managed via the REST API directly:
 
 ```bash
 openqa-cli api -X POST workers/<id>/reservation comment="Manual testing" 
duration=5h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1790071740.8a090f85/lib/OpenQA/CLI/reservation.pm 
new/openQA-5.1790264833.381b79cd/lib/OpenQA/CLI/reservation.pm
--- old/openQA-5.1790071740.8a090f85/lib/OpenQA/CLI/reservation.pm      
1970-01-01 01:00:00.000000000 +0100
+++ new/openQA-5.1790264833.381b79cd/lib/OpenQA/CLI/reservation.pm      
2026-09-24 17:47:13.000000000 +0200
@@ -0,0 +1,30 @@
+# Copyright SUSE LLC
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+package OpenQA::CLI::reservation;
+use Mojo::Base 'OpenQA::Command', -signatures;
+
+has description => 'Manage worker reservations';
+has usage => sub { OpenQA::CLI->_help('reservation') };
+
+sub command ($self, @args) {
+    die $self->usage unless OpenQA::CLI::get_opt(reservation => \@args, [], 
\my %options);
+    @args = $self->decode_args(@args);
+    die $self->usage unless my $workerid = shift @args;
+    my $url = $self->url_for("workers/$workerid/reservation");
+    my $client = $self->client($url);
+    my $tx;
+    if ($options{release}) {
+        $tx = $client->build_tx(DELETE => $url);
+    }
+    else {
+        my %params;
+        $params{comment} = $options{comment} if defined $options{comment};
+        $params{duration} = $options{duration} if defined $options{duration};
+        $params{force} = 1 if $options{force};
+        $tx = $client->build_tx(POST => $url, form => \%params);
+    }
+    return $self->retry_tx($client, $tx);
+}
+
+1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/public/openqa-cli.yaml 
new/openQA-5.1790264833.381b79cd/public/openqa-cli.yaml
--- old/openQA-5.1790071740.8a090f85/public/openqa-cli.yaml     2026-09-22 
12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/public/openqa-cli.yaml     2026-09-24 
17:47:13.000000000 +0200
@@ -167,6 +167,16 @@
       - asset-size-limit|l=i   --Asset size limit in bytes
       - with-thumbnails|t      --Download thumbnails as well
 
+  reservation:
+    summary: Manage worker reservations
+    description: |
+      Usage: openqa-cli reservation [OPTIONS] WORKER_ID
+    options:
+      - comment|c=s            --Comment describing the reason for reservation
+      - duration|d=s           --Duration of the reservation (e.g. 5h, 30m, 
2d, 0 for indefinite)
+      - force|f                --Force reservation even if worker is already 
reserved
+      - release|r              --Release an existing reservation
+
   schedule:
     summary: Schedules a set of jobs (via "isos post" creating a schedule 
product)
     description: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/t/33-developer_mode.t 
new/openQA-5.1790264833.381b79cd/t/33-developer_mode.t
--- old/openQA-5.1790071740.8a090f85/t/33-developer_mode.t      2026-09-22 
12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/t/33-developer_mode.t      2026-09-24 
17:47:13.000000000 +0200
@@ -33,6 +33,7 @@
 use Fcntl ':mode';
 use DBI;
 use File::Path qw(make_path remove_tree);
+use Time::Seconds;
 use Module::Load::Conditional 'can_load';
 use OpenQA::Utils qw(service_port);
 use OpenQA::Test::Utils qw(
@@ -230,9 +231,17 @@
         'response to set_assert_screen_timeout'
     );
 
+    # wait until paused and the upload has finished
+    # note: The "match=on_prompt timed out" message might be sent before or 
after "outstanding_images" so we specify 0
+    #       as start offset when checking for "outstanding_images" to consider 
also log output before
+    #       "match=on_prompt timed out" and thus not asserting a specific 
order of messages.
     wait_for_developer_console_like($driver, qr/match=on_prompt timed out/, 
'paused on assert_screen timeout (again)');
-    wait_for_developer_console_like($driver, 
qr/\"(outstanding_images)\":[1-9]*/, 'progress of image upload received');
-    wait_for_developer_console_like($driver, qr/\"(outstanding_images)\":0/, 
'image upload has finished');
+    wait_for_developer_console_like(
+        $driver,
+        qr/\"outstanding_images\":[1-9]*/,
+        'progress of image upload received', ONE_MINUTE
+    );
+    wait_for_developer_console_like($driver, qr/\"outstanding_images\":0/, 
'image upload has finished', ONE_MINUTE);
 
     # open needle editor in 2nd tab
     my $needle_editor_url = '/tests/1/edit';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/t/43-cli-reservation.t 
new/openQA-5.1790264833.381b79cd/t/43-cli-reservation.t
--- old/openQA-5.1790071740.8a090f85/t/43-cli-reservation.t     1970-01-01 
01:00:00.000000000 +0100
+++ new/openQA-5.1790264833.381b79cd/t/43-cli-reservation.t     2026-09-24 
17:47:13.000000000 +0200
@@ -0,0 +1,79 @@
+# Copyright SUSE LLC
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+use Test::Most;
+use Test::Warnings qw(:report_warnings warning);
+
+use FindBin;
+use lib "$FindBin::Bin/lib", 
"$FindBin::Bin/../external/os-autoinst-common/lib";
+
+use Capture::Tiny qw(capture capture_stdout);
+use Mojo::Server::Daemon;
+use OpenQA::CLI;
+use OpenQA::CLI::reservation;
+use OpenQA::Test::Case;
+use OpenQA::Test::TimeLimit '15';
+
+OpenQA::Test::Case->new->init_data(fixtures_glob => '01-jobs.pl 02-workers.pl 
03-users.pl');
+
+# Mock WebAPI using the real application
+my $daemon = Mojo::Server::Daemon->new(listen => ['http://127.0.0.1']);
+my $app = $daemon->build_app('OpenQA::WebAPI');
+$app->log->level('error');
+my $port = $daemon->start->ports->[0];
+my $host = "http://127.0.0.1:$port";;
+
+my @host = ('--host', $host);
+my @auth_op = ('--apikey', 'PERCIVALKEY02', '--apisecret', 'PERCIVALSECRET02', 
@host);
+my @auth_admin = ('--apikey', 'ARTHURKEY01', '--apisecret', 'EXCALIBUR', 
@host);
+
+my $cli = OpenQA::CLI->new;
+my $reservation = OpenQA::CLI::reservation->new;
+
+subtest 'Help' => sub {
+    my ($stdout, $stderr, @result) = capture sub { $cli->run('help', 
'reservation') };
+    like $stdout, qr/Usage: openqa-cli reservation/, 'help';
+    like $stdout, qr/--comment/, 'help describes comment option';
+    like $stdout, qr/--duration/, 'help describes duration option';
+    like $stdout, qr/--force/, 'help describes force option';
+    like $stdout, qr/--release/, 'help describes release option';
+};
+
+subtest 'Unknown options' => sub {
+    like warning {
+        throws_ok { $reservation->run('--unknown') } qr/Usage: openqa-cli 
reservation/, 'unknown option';
+    }, qr/Unknown option: unknown/, 'warning about unknown option';
+};
+
+subtest 'Defaults' => sub {
+    is $reservation->apibase, '/api/v1', 'apibase';
+    is $reservation->apikey, undef, 'no apikey';
+    is $reservation->apisecret, undef, 'no apisecret';
+    is $reservation->host, 'http://localhost', 'host';
+};
+
+subtest 'Reserve and Release Worker via CLI' => sub {
+    my ($stdout, $stderr, @result) = capture sub { $cli->run('reservation', 
@auth_op, 2, '--duration=1h') };
+    is_deeply \@result, [1],
+      'A reservation attempt without comment fails with a non-zero exit code 
because comments are required';
+    like $stdout, qr/comment/, 'The error details on stdout describe the 
missing comment requirement';
+    like $stderr, qr/400 Bad Request/, 'The HTTP response on stderr is a 400 
Bad Request';
+
+    ($stdout, $stderr, @result)
+      = capture sub { $cli->run('reservation', @auth_op, 2, 
'--comment=Testing', '--duration=1h') };
+    is_deeply \@result, [0], 'A valid reservation with a comment and a 
duration succeeds with exit code 0';
+    like $stdout, qr/reserved successfully/, 'The response on stdout confirms 
the worker is reserved successfully';
+
+    ($stdout, $stderr, @result)
+      = capture sub { $cli->run('reservation', @auth_op, 2, 
'--comment=Double', '--duration=1h') };
+    is_deeply \@result, [1],
+      'A double reservation attempt on an already reserved worker fails with a 
non-zero exit code';
+    like $stdout, qr/already reserved/, 'The error details on stdout describe 
the reservation conflict';
+    like $stderr, qr/409 Conflict/, 'The HTTP response on stderr is a 409 
Conflict';
+
+    ($stdout, $stderr, @result) = capture sub { $cli->run('reservation', 
@auth_op, 2, '--release') };
+    is_deeply \@result, [0], 'Releasing the active reservation by the same 
operator succeeds with exit code 0';
+    like $stdout, qr/released successfully/, 'The response on stdout confirms 
the reservation is released successfully';
+};
+
+done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1790071740.8a090f85/t/lib/OpenQA/Test/FullstackUtils.pm 
new/openQA-5.1790264833.381b79cd/t/lib/OpenQA/Test/FullstackUtils.pm
--- old/openQA-5.1790071740.8a090f85/t/lib/OpenQA/Test/FullstackUtils.pm        
2026-09-22 12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/t/lib/OpenQA/Test/FullstackUtils.pm        
2026-09-24 17:47:13.000000000 +0200
@@ -117,12 +117,18 @@
 
 # waits until the developer console content matches the specified regex
 # note: only considers the console output since the last successful call
-sub wait_for_developer_console_like ($driver, $message_regex, $diag_info, 
$timeout_s = ONE_MINUTE * 2) {
+sub wait_for_developer_console_like (
+    $driver, $message_regex, $diag_info,
+    $timeout_s = ONE_MINUTE * 2,
+    $start_offset = undef
+  )
+{
     my $js_erro_check_suffix = ', waiting for ' . $diag_info;
     ok(javascript_console_has_no_warnings_or_errors($js_erro_check_suffix), 
'No unexpected js warnings');
 
     # get log
-    my $position_of_last_match = $driver->execute_script('return 
window.lastWaitForDevelConsoleMsgMatch;') // 0;
+    my $position_of_last_match = $start_offset
+      // $driver->execute_script('return 
window.lastWaitForDevelConsoleMsgMatch;') // 0;
     my $log_textarea = $driver->find_element('#log');
     my $log = $log_textarea->get_text();
     my $previous_log = '';
@@ -147,10 +153,12 @@
         $previous_log = $log;
         $log = $log_textarea->get_text();
     }
-
-    $position_of_last_match += $match_index;
-    $driver->execute_script("window.lastWaitForDevelConsoleMsgMatch = 
$position_of_last_match;");
-    pass("found $diag_info at $position_of_last_match");
+    if (!defined $start_offset) {
+        $position_of_last_match += $match_index;
+        $driver->execute_script("window.lastWaitForDevelConsoleMsgMatch = 
$position_of_last_match;");
+        pass "found $diag_info at $position_of_last_match";
+    }
+    return $position_of_last_match;
 }
 
 sub wait_for_developer_console_available ($driver) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1790071740.8a090f85/tools/ci/autoinst.sha 
new/openQA-5.1790264833.381b79cd/tools/ci/autoinst.sha
--- old/openQA-5.1790071740.8a090f85/tools/ci/autoinst.sha      2026-09-22 
12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/tools/ci/autoinst.sha      2026-09-24 
17:47:13.000000000 +0200
@@ -1 +1 @@
-5.044000-465c975b2356744070591e7333d2950f28b8f49f
\ No newline at end of file
+5.044000-282ca44441fdf0dfd37891bdf1d73c35bfc152de
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1790071740.8a090f85/tools/generate-cli-completions 
new/openQA-5.1790264833.381b79cd/tools/generate-cli-completions
--- old/openQA-5.1790071740.8a090f85/tools/generate-cli-completions     
2026-09-22 12:09:00.000000000 +0200
+++ new/openQA-5.1790264833.381b79cd/tools/generate-cli-completions     
1970-01-01 01:00:00.000000000 +0100
@@ -1,160 +0,0 @@
-#!/usr/bin/env perl
-# Copyright SUSE LLC
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Generate bash and zsh completion scripts for openqa-cli from openqa-cli.yaml.
-# Run this script after adding or changing options in public/openqa-cli.yaml.
-use strict;
-use warnings;
-use YAML::PP;
-use Mojo::File qw(path);
-use feature 'signatures';
-
-my $spec_file = 'public/openqa-cli.yaml';
-my $bash_out = 'contrib/completions/openqa-cli-completion.bash';
-my $zsh_out = 'contrib/completions/openqa-cli-completion.zsh';
-
-my $spec = YAML::PP->new->load_file($spec_file);
-
-sub parse_option ($entry) {
-    if (ref $entry eq 'HASH') {
-        my $name = $entry->{name};
-        my $desc = $entry->{summary} // '';
-        $desc =~ s/\n\s*/ /g;
-        $desc =~ s/\s+$//;
-        my $has_arg = defined $entry->{type} ? 1 : 0;
-        return ($name, $desc, $has_arg);
-    }
-    # String format: "name[|alias][=type][@]   --description"
-    my ($spec_part, $desc) = split /\s+--/, $entry, 2;
-    my ($name_part, $type) = split /=/, $spec_part;
-    my ($name) = split /\|/, $name_part;
-    $name =~ s/^\s+|\s+$//g;
-    $desc //= '';
-    $desc =~ s/\n\s*/ /g;
-    $desc =~ s/\s+$//;
-    return ($name, $desc, defined $type ? 1 : 0);
-}
-
-sub collect_options ($option_list) {
-    return map { [parse_option($_)] } @{$option_list // []};
-}
-
-my @global_opts = collect_options($spec->{options});
-my %subcommands = %{$spec->{subcommands} // {}};
-my @subcmds = sort keys %subcommands;
-
-# bash
-
-sub bash_option_list (@opts) {
-    join ' ', map { "--$_->[0]" } @opts;
-}
-
-my $bash_content = <<'HEADER';
-# Generated by tools/generate-cli-completions — do not edit manually.
-# Regenerate with: make generate-completions
-_openqa_cli_completions() {
-    local cur subcommands main_options api_options archive_options 
monitor_options schedule_options
-    cur="${COMP_WORDS[COMP_CWORD]}"
-HEADER
-
-$bash_content .= sprintf "    subcommands=\"%s\"\n", join ' ', @subcmds;
-$bash_content .= sprintf "    main_options=\"%s\"\n", 
bash_option_list(@global_opts);
-
-for my $cmd (@subcmds) {
-    my @opts = collect_options($subcommands{$cmd}{options});
-    $bash_content .= sprintf "    %s_options=\"%s\"\n", $cmd, 
bash_option_list(@opts);
-}
-
-$bash_content .= <<'BODY';
-
-    if [[ ${COMP_CWORD} -eq 1 ]]; then
-        COMPREPLY=($(compgen -W "$subcommands" -- "$cur"))
-        return 0
-    fi
-    case "${COMP_WORDS[1]}" in
-BODY
-
-for my $cmd (@subcmds) {
-    $bash_content .= sprintf "        %s)\n", $cmd;
-    $bash_content .= sprintf "            COMPREPLY=(\$(compgen -W 
\"\$main_options \$%s_options\" -- \"\$cur\"))\n",
-      $cmd;
-    $bash_content .= "            ;;\n";
-}
-
-$bash_content .= <<'FOOTER';
-        *)
-            COMPREPLY=($(compgen -W "$subcommands" -- "$cur"))
-            ;;
-    esac
-}
-
-complete -F _openqa_cli_completions openqa-cli
-FOOTER
-
-path($bash_out)->spew($bash_content);
-
-# zsh
-
-sub zsh_option_entry ($name, $desc, $has_arg = 0) {
-    $desc =~ s/\\/\\\\/g;    # backslash first
-    $desc =~ s/"/\\"/g;    # double quotes
-    $desc =~ s/\$/\\\$/g;    # dollar signs
-    $desc =~ s/:/\\:/g;    # colon (word:desc separator for _describe)
-    my $suffix = $has_arg ? '=' : '';
-    return sprintf '        "--%s%s:%s"', $name, $suffix, $desc;
-}
-
-my $zsh_content = <<'HEADER';
-#compdef openqa-cli
-# Generated by tools/generate-cli-completions — do not edit manually.
-# Regenerate with: make generate-completions
-
-_openqa_cli_completions() {
-    local curcontext="$curcontext"
-    local -a subcommands main_options
-HEADER
-
-for my $cmd (@subcmds) {
-    $zsh_content .= sprintf "    local -a %s_options\n", $cmd;
-}
-
-$zsh_content .= sprintf "    subcommands=(%s)\n", join ' ', map { "\"$_\"" } 
@subcmds;
-
-$zsh_content .= "    main_options=(\n";
-$zsh_content .= join("\n", map { zsh_option_entry(@$_) } @global_opts) . "\n";
-$zsh_content .= "    )\n";
-
-for my $cmd (@subcmds) {
-    my @opts = collect_options($subcommands{$cmd}{options});
-    $zsh_content .= sprintf "    %s_options=(\n", $cmd;
-    $zsh_content .= join("\n", map { zsh_option_entry(@$_) } @opts) . "\n";
-    $zsh_content .= "    )\n";
-}
-
-$zsh_content .= <<'BODY';
-    if (( CURRENT == 2 )); then
-        _describe 'subcommand' subcommands
-    else
-        case "$words[2]" in
-BODY
-
-for my $cmd (@subcmds) {
-    $zsh_content .= sprintf "            %s)\n", $cmd;
-    $zsh_content .= sprintf "                local -a _all\n";
-    $zsh_content .= sprintf "                _all=(\"\${main_options[@]}\" 
\"\${%s_options[@]}\")\n", $cmd;
-    $zsh_content .= sprintf "                _describe 'option' _all\n";
-    $zsh_content .= "                ;;\n";
-}
-
-$zsh_content .= <<'FOOTER';
-            *)
-                _values 'subcommand' api archive monitor schedule
-                ;;
-        esac
-    fi
-}
-FOOTER
-
-path($zsh_out)->spew($zsh_content);
-
-printf "Generated:\n  %s\n  %s\n", $bash_out, $zsh_out;

++++++ openQA.obsinfo ++++++
--- /var/tmp/diff_new_pack.Vy1u6J/_old  2026-09-24 23:06:27.329841613 +0200
+++ /var/tmp/diff_new_pack.Vy1u6J/_new  2026-09-24 23:06:27.334841823 +0200
@@ -1,5 +1,5 @@
 name: openQA
-version: 5.1790071740.8a090f85
-mtime: 1790071740
-commit: 8a090f85ada2a17a6c9a043e71f9d1fb3a20a268
+version: 5.1790264833.381b79cd
+mtime: 1790264833
+commit: 381b79cd3be82c79d4499f5b7b66242a550ef46d
 

Reply via email to