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
