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-03-24 18:48:34 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Tue Mar 24 18:48:34 2026 rev:826 rq:1342076 version:5.1774278862.ea002efa Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2026-03-23 17:14:54.985537891 +0100 +++ /work/SRC/openSUSE:Factory/.openQA.new.8177/openQA.changes 2026-03-24 18:49:02.318876293 +0100 @@ -1,0 +2,14 @@ +Mon Mar 23 16:26:14 UTC 2026 - [email protected] + +- Update to version 5.1774278862.ea002efa: + * refactor: slightly simplify BuildResults + * chore(AGENTS.md): add customized file + * refactor: deduplicate configuration defaults and verify openqa.ini + * fix(ci): fix referencing commit-message-checker + * style: Add Test::Perl::Critic dependency + * docs: document "always_run" test flag + * feat(Makefile): add help text for missing targets + * fix: prevent intermittent failure in t/ui/13-admin.t + * fix: remove fixed container sizing in needlediff view + +------------------------------------------------------------------- Old: ---- openQA-5.1774104919.9788babf.obscpio New: ---- openQA-5.1774278862.ea002efa.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.5K1o7y/_old 2026-03-24 18:49:04.482965585 +0100 +++ /var/tmp/diff_new_pack.5K1o7y/_new 2026-03-24 18:49:04.486965750 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1774104919.9788babf +Version: 5.1774278862.ea002efa Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.5K1o7y/_old 2026-03-24 18:49:04.650972517 +0100 +++ /var/tmp/diff_new_pack.5K1o7y/_new 2026-03-24 18:49:04.658972847 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1774104919.9788babf +Version: 5.1774278862.ea002efa Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.5K1o7y/_old 2026-03-24 18:49:04.846980604 +0100 +++ /var/tmp/diff_new_pack.5K1o7y/_new 2026-03-24 18:49:04.858981100 +0100 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1774104919.9788babf +Version: 5.1774278862.ea002efa Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.5K1o7y/_old 2026-03-24 18:49:04.958985226 +0100 +++ /var/tmp/diff_new_pack.5K1o7y/_new 2026-03-24 18:49:04.962985391 +0100 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1774104919.9788babf +Version: 5.1774278862.ea002efa Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.5K1o7y/_old 2026-03-24 18:49:05.010987372 +0100 +++ /var/tmp/diff_new_pack.5K1o7y/_new 2026-03-24 18:49:05.014987536 +0100 @@ -90,7 +90,7 @@ %define qemu qemu %endif # The following line is generated from dependencies.yaml -%define style_check_requires ShellCheck perl(Code::TidyAll) perl(Perl::Critic) perl(Perl::Critic::Community) python3-gitlint python3-yamllint shfmt +%define style_check_requires ShellCheck perl(Code::TidyAll) perl(Perl::Critic) perl(Perl::Critic::Community) perl(Test::Perl::Critic) python3-gitlint python3-yamllint shfmt # The following line is generated from dependencies.yaml %define cover_requires perl(Devel::Cover) perl(Devel::Cover::Report::Codecovbash) # The following line is generated from dependencies.yaml @@ -99,7 +99,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1774104919.9788babf +Version: 5.1774278862.ea002efa Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0-or-later ++++++ openQA-5.1774104919.9788babf.obscpio -> openQA-5.1774278862.ea002efa.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/.github/workflows/commit-message-checker.yml new/openQA-5.1774278862.ea002efa/.github/workflows/commit-message-checker.yml --- old/openQA-5.1774104919.9788babf/.github/workflows/commit-message-checker.yml 2026-03-24 18:49:06.695056858 +0100 +++ new/openQA-5.1774278862.ea002efa/.github/workflows/commit-message-checker.yml 2026-03-23 16:14:22.000000000 +0100 @@ -1 +1,12 @@ -symbolic link to ../../external/os-autoinst-common/.github/workflows/commit-message-checker.yml +--- +name: 'Commit message check' +# yamllint disable-line rule:truthy +on: + pull_request: + push: + branches: + - '!master' # we must not fix commit messages when they already reached master + +jobs: + check-commit-message: + uses: os-autoinst/os-autoinst-common/.github/workflows/base-commit-message-checker.yml@master diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/AGENTS.md new/openQA-5.1774278862.ea002efa/AGENTS.md --- old/openQA-5.1774104919.9788babf/AGENTS.md 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/AGENTS.md 2026-03-23 16:14:22.000000000 +0100 @@ -0,0 +1,35 @@ +# openQA Agent Guidelines + +Backend: Perl (Mojolicious), Minion job queue, PostgreSQL. Frontend: +JavaScript (Bootstrap). + +## Build & Test Commands + +- `make tidy`: Must pass before committing (runs `perltidy` + + `eslint/prettier`). +- `make test-checkstyle`: Must pass before committing. +- `make test-unit-and-integration TESTS=t/your_test.t`: Run specific tests. +- `make test`: Full test suite. + +## Conventions + +- Commits: [Conventional + Commits](https://www.conventionalcommits.org/en/v1.0.0/) format. Include + motivation and details for "feat" commits. +- Documentation: AsciiDoc (`.asciidoc`). + +## Agent Guidelines + +- **Planning:** Only create `.md` plan documents in `tasks/`. Do not change + other files. Every plan MUST include test adaptations or new tests. +- **Verification:** Every code change must have corresponding test adaptations + or new tests. `make tidy` and `make test-checkstyle` must pass before + creating git commits. + +## Constraints + +- `tasks/`: Read/write access for planning. NEVER run git add, git commit, or + git rm on this directory or delete files from there. +- Never run git clean or any command that deletes unversioned files. Ask the + user for confirmation. +- Commit message format: 50/80 rule, 80-char limit, wrap in single quotes. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/Makefile new/openQA-5.1774278862.ea002efa/Makefile --- old/openQA-5.1774104919.9788babf/Makefile 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/Makefile 2026-03-23 16:14:22.000000000 +0100 @@ -210,7 +210,7 @@ # note: Excluding dev dependencies like `eslint` via `--omit=dev` to pull in only dependencies needed at runtime (and for # regular tests). Development tests/tooling like `js-tidy` will invoke `npm clean-install …` to install missing # dependencies on its own anyway. -node_modules: package-lock.json +node_modules: package-lock.json ## Build web-related dependencies (NPM, JS, CSS) @which local-npm-registry >/dev/null 2>&1 || npm clean-install --no-audit --no-fund --ignore-scripts --omit=dev @touch node_modules @@ -291,11 +291,11 @@ endef .PHONY: run-webui-test-db -run-webui-test-db: setup-database +run-webui-test-db: setup-database ## Run a local web UI instance using a test database $(call RUN_SERVICE_TEST_DB,script/openqa-webui-daemon) .PHONY: run-gru-test-db -run-gru-test-db: setup-database +run-gru-test-db: setup-database ## Run a local GRU instance using a test database $(call RUN_SERVICE_TEST_DB,script/openqa-gru) # prepares running the tests within a container (eg. pulls os-autoinst) and then runs the tests considering diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/assets/javascripts/needlediff.js new/openQA-5.1774278862.ea002efa/assets/javascripts/needlediff.js --- old/openQA-5.1774104919.9788babf/assets/javascripts/needlediff.js 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/assets/javascripts/needlediff.js 2026-03-23 16:14:22.000000000 +0100 @@ -38,13 +38,6 @@ // Draw canvas into its container canvas.attr('width', width); canvas.attr('height', height); - container.css({ - border: '1px solid black', - margin: '0px', - position: 'relative', - width: width + 'px', - height: height + 'px' - }); container.append(canvas); Object.defineProperty(this, 'container', { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/cpanfile new/openQA-5.1774278862.ea002efa/cpanfile --- old/openQA-5.1774104919.9788babf/cpanfile 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/cpanfile 2026-03-23 16:14:22.000000000 +0100 @@ -120,6 +120,7 @@ requires 'Perl::Critic::Community'; requires 'Perl::Tidy', '== 20260204.0.0'; requires 'Test::CheckGitStatus'; + requires 'Test::Perl::Critic'; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/dependencies.yaml new/openQA-5.1774278862.ea002efa/dependencies.yaml --- old/openQA-5.1774104919.9788babf/dependencies.yaml 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/dependencies.yaml 2026-03-23 16:14:22.000000000 +0100 @@ -211,6 +211,7 @@ style_check_requires: python3-yamllint: + perl(Test::Perl::Critic): perl(Perl::Critic): perl(Perl::Critic::Community): perl(Code::TidyAll): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/dist/rpm/openQA.spec new/openQA-5.1774278862.ea002efa/dist/rpm/openQA.spec --- old/openQA-5.1774104919.9788babf/dist/rpm/openQA.spec 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/dist/rpm/openQA.spec 2026-03-23 16:14:22.000000000 +0100 @@ -90,7 +90,7 @@ %define qemu qemu %endif # The following line is generated from dependencies.yaml -%define style_check_requires ShellCheck perl(Code::TidyAll) perl(Perl::Critic) perl(Perl::Critic::Community) python3-gitlint python3-yamllint shfmt +%define style_check_requires ShellCheck perl(Code::TidyAll) perl(Perl::Critic) perl(Perl::Critic::Community) perl(Test::Perl::Critic) python3-gitlint python3-yamllint shfmt # The following line is generated from dependencies.yaml %define cover_requires perl(Devel::Cover) perl(Devel::Cover::Report::Codecovbash) # The following line is generated from dependencies.yaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/docs/WritingTests.asciidoc new/openQA-5.1774278862.ea002efa/docs/WritingTests.asciidoc --- old/openQA-5.1774104919.9788babf/docs/WritingTests.asciidoc 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/docs/WritingTests.asciidoc 2026-03-23 16:14:22.000000000 +0100 @@ -135,6 +135,8 @@ * *fatal*: When set to `1` the whole test suite is aborted if the test module fails. The overall state is set to `failed`. +* *always_run*: When set to `1` the test module is executed even if a previous + test module failed with `fatal`. * *ignore_failure*: When set to `1` and the test module fails, it will not affect the overall result at all. * *milestone*: After this test succeeds, update the 'lastgood' snapshot of the @@ -539,7 +541,8 @@ they match the serial output which is done after the test is executed. In case it does not make sense to continue the test run even if the current test module does not have the fatal flag, use `fatal` as serial failure type, so all -subsequent test modules will not be executed if such failure was detected. +subsequent test modules (unless marked with `always_run`) will not be +executed if such failure was detected. To use this functionality the test developer needs to define the patterns to look for in the serial output either in the main.pm or in the test itself. Any @@ -2111,7 +2114,7 @@ In both modes there is no need to modify tests (i.e. adding `milestone` test flag as the behaviour is implied). In the latter mode every test module is also considered `fatal`. This means the job is aborted after the first failed test -module. +module (unless subsequent modules are marked with `always_run`). [id="snapshots-for-each-module"] ==== Enable snapshots for each module diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/lib/OpenQA/BuildResults.pm new/openQA-5.1774278862.ea002efa/lib/OpenQA/BuildResults.pm --- old/openQA-5.1774104919.9788babf/lib/OpenQA/BuildResults.pm 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/lib/OpenQA/BuildResults.pm 2026-03-23 16:14:22.000000000 +0100 @@ -15,10 +15,8 @@ use Time::Seconds; sub init_job_figures ($job_result) { - # relevant distributions for the build (hash is used as a set) $job_result->{distris} = {}; - # number of passed/failed/... jobs $job_result->{passed} = 0; $job_result->{failed} = 0; @@ -31,7 +29,6 @@ } sub count_job ($job, $jr, $labels) { - $jr->{total}++; if ($job->state eq OpenQA::Jobs::Constants::DONE) { if ($job->result eq OpenQA::Jobs::Constants::PASSED) { @@ -69,18 +66,15 @@ } sub add_review_badge ($build_res) { - $build_res->{all_passed} = $build_res->{passed} + $build_res->{softfailed} >= $build_res->{total} ? 1 : 0; $build_res->{reviewed} = $build_res->{labeled} >= $build_res->{failed} ? 1 : 0; $build_res->{commented} = $build_res->{comments} >= $build_res->{failed} ? 1 : 0; } sub filter_subgroups ($group, $subgroup_filter) { - my @group_ids; my @children; my $group_name = $group->name; - for my $child ($group->children) { my $full_name = $child->full_name; if (grep { $_ eq '' || regex_match($_, $full_name) } @$subgroup_filter) { @@ -95,29 +89,24 @@ } sub find_child_groups ($group, $subgroup_filter) { - # handle regular (non-parent) groups return { group_ids => [$group->id], children => [], } unless $group->can('children'); - # handle simple case where no filter for subgroups present return { group_ids => $group->child_group_ids, children => [$group->children], } unless @$subgroup_filter; - return filter_subgroups($group, $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); my $group_ids = $child_groups->{group_ids}; my $children = $child_groups->{children}; - my @sorted_results; my %result = ( build_results => \@sorted_results, @@ -127,11 +116,7 @@ id => $group->id, name => $group->name }); - - if (defined($limit) && int($limit) <= 0) { - return \%result; - } - + return \%result if defined($limit) && int($limit) <= 0; # build sorting my $buildver_sort_mode = BUILD_SORT_BY_NAME; $buildver_sort_mode = $group->build_version_sort if $group->can('build_version_sort'); @@ -147,11 +132,8 @@ rows => $row_limit ); my %search_filter = (group_id => {in => $group_ids}); - if ($time_limit_days) { - $search_filter{t_created} - = {'>' => time2str('%Y-%m-%d %H:%M:%S', time - ONE_DAY * $time_limit_days, 'UTC')}; - } - + $search_filter{t_created} = {'>' => time2str('%Y-%m-%d %H:%M:%S', time - ONE_DAY * $time_limit_days, 'UTC')} + if $time_limit_days; # add search filter for tags # caveat: a tag that references only a build, not including a version, might be ambiguous if ($tags) { @@ -165,7 +147,6 @@ $search_filter{BUILD} = {-in => \@builds}; $search_filter{VERSION} = {-in => \@versions} if @versions; } - # find relevant builds my $jobs_resultset = $group->result_source->schema->resultset('Jobs'); my @builds = $jobs_resultset->search(\%search_filter, \%search_opts)->all; @@ -175,15 +156,12 @@ $build->{key} = join '-', $version, $buildnr; $versions_per_build{$buildnr}->{$version} = 1; } - if ($buildver_sort_mode == BUILD_SORT_BY_NAME) { - @builds = reverse sort { versioncmp($a->{key}, $b->{key}); } @builds; - } - + @builds = reverse sort { versioncmp($a->{key}, $b->{key}); } @builds + if $buildver_sort_mode == BUILD_SORT_BY_NAME; my $max_jobs = 0; my $newest = ($buildver_sort_mode == BUILD_SORT_BY_OLDEST_JOB || $buildver_sort_mode == BUILD_SORT_BY_NAME) ? 0 : 1; for my $build (@builds) { last if defined($limit) && (--$limit < 0); - my ($version, $buildnr) = ($build->VERSION, $build->BUILD); my $jobs = $jobs_resultset->search( { @@ -200,10 +178,7 @@ version_count => scalar keys %{$versions_per_build{$buildnr}}, ); init_job_figures(\%jr); - for my $child (@$children) { - init_job_figures($jr{children}->{$child->id} = {}); - } - + init_job_figures($jr{children}->{$_->id} = {}) for @$children; my %seen; my @jobs = map { my $key = $_->TEST . '-' . $_->ARCH . '-' . $_->FLAVOR . '-' . ($_->MACHINE // ''); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/lib/OpenQA/Setup.pm new/openQA-5.1774278862.ea002efa/lib/OpenQA/Setup.pm --- old/openQA-5.1774104919.9788babf/lib/OpenQA/Setup.pm 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/lib/OpenQA/Setup.pm 2026-03-23 16:14:22.000000000 +0100 @@ -76,8 +76,8 @@ return \%hash; } -sub read_config ($app) { - my %defaults = ( +sub default_config () { + return { global => { appname => 'openQA', base_url => undef, @@ -280,7 +280,7 @@ influxdb => { ignored_failed_minion_jobs => '', }, - carry_over => \%CARRY_OVER_DEFAULTS, + carry_over => {%CARRY_OVER_DEFAULTS}, 'test_preset example' => { title => 'Create example test', info => 'Parameters to create an example test have been pre-filled in the following form. ' @@ -288,13 +288,17 @@ casedir => 'https://github.com/os-autoinst/os-autoinst-distri-example.git', distri => 'example', build => 'openqa', - }); + }}; +} + +sub read_config ($app) { + my $defaults = default_config(); # in development and test mode we use fake auth and log to stderr my %devel_and_test_defaults = (auth => {method => 'Fake'}, logging => {file => undef, level => 'debug'}); my %mode_defaults = (development => \%devel_and_test_defaults, test => \%devel_and_test_defaults); - my $config = _load_config($app, \%defaults, \%mode_defaults); + my $config = _load_config($app, $defaults, \%mode_defaults); my $global_config = $config->{global}; $global_config->{recognized_referers} = [split /\s+/, $global_config->{recognized_referers}]; if (my $regex = $global_config->{auto_clone_regex}) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/t/config.t new/openQA-5.1774278862.ea002efa/t/config.t --- old/openQA-5.1774104919.9788babf/t/config.t 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/t/config.t 2026-03-23 16:14:22.000000000 +0100 @@ -20,8 +20,9 @@ use OpenQA::Setup; use OpenQA::JobGroupDefaults; use OpenQA::Task::Job::Limit; -use Mojo::File 'tempdir'; +use Mojo::File qw(path tempdir); use Time::Seconds; +use Storable 'dclone'; my $quiet_log = Mojo::Log->new(level => 'warn'); @@ -44,177 +45,29 @@ $app->mode('test'); my $config = read_config($app, 'reading config from default with mode test'); is length($config->{_openid_secret}), 16, 'config has openid_secret'; - my $test_config = { - global => { - appname => 'openQA', - branding => 'openSUSE', - hsts => 365, - audit_enabled => 1, - max_rss_limit => 0, - profiling_enabled => 0, - monitoring_enabled => 0, - mcp_enabled => 'no', - hide_asset_types => 'repo', - file_security_policy => 'download-prompt', - recognized_referers => [], - changelog_file => '/usr/share/openqa/public/Changelog', - job_investigate_ignore => '"(JOBTOKEN|NAME)"', - job_investigate_git_timeout => 20, - job_investigate_git_log_limit => 200, - search_results_limit => 50000, - worker_timeout => DEFAULT_WORKER_TIMEOUT, - force_result_regex => '', - parallel_children_collapsable_results_sel => ' .status:not(.result_passed):not(.result_softfailed)', - auto_clone_limit => 20, - api_hmac_time_tolerance => 300, - frontpage_builds => 3, - scenario_definitions_allowed_hosts => 'github.com raw.githubusercontent.com', - }, - rate_limits => { - search => 5, - }, - auth => { - method => 'Fake', - require_for_assets => 0, - }, - 'scm git' => { - update_remote => '', - update_branch => '', - do_push => 'no', - do_cleanup => 'no', - git_auto_clone => 'yes', - git_auto_commit => '', - git_auto_update => 'no', - git_auto_update_method => 'best-effort', - checkout_needles_sha => 'no', - allow_arbitrary_url_fetch => 'no', - temp_needle_refs_retention => 2 * ONE_MINUTE, - }, - 'scheduler' => { - max_job_scheduled_time => 7, - max_running_jobs => -1, - }, - openid => { - provider => 'https://www.opensuse.org/openid/user/', - httpsonly => 1, - }, - oauth2 => { - provider => '', - key => '', - secret => '', - authorize_url => '', - token_url => '', - user_url => '', - token_scope => '', - token_label => '', - id_from => 'id', - nickname_from => '', - unique_name => '', - }, - hypnotoad => { - listen => ['http://localhost:9526/'], - proxy => 1, - }, - audit => { - blacklist => '', - blocklist => '', - }, - plugin_links => { - operator => {}, - admin => {} - }, - amqp => { - reconnect_timeout => 5, - publish_attempts => 10, - publish_retry_delay => 1, - publish_retry_delay_factor => 1.75, - url => 'amqp://guest:guest@localhost:5672/', - exchange => 'pubsub', - topic_prefix => 'suse', - cacertfile => '', - certfile => '', - keyfile => '' - }, - obs_rsync => { - home => '', - retry_interval => 60, - retry_max_count => 1400, - queue_limit => 200, - concurrency => 2, - project_status_url => '', - username => '', - ssh_key_file => '', - }, - cleanup => { - concurrent => 0, - }, - default_group_limits => { - asset_size_limit => OpenQA::JobGroupDefaults::SIZE_LIMIT_GB, - log_storage_duration => OpenQA::JobGroupDefaults::KEEP_LOGS_IN_DAYS, - important_log_storage_duration => OpenQA::JobGroupDefaults::KEEP_IMPORTANT_LOGS_IN_DAYS, - result_storage_duration => OpenQA::JobGroupDefaults::KEEP_RESULTS_IN_DAYS, - important_result_storage_duration => OpenQA::JobGroupDefaults::KEEP_IMPORTANT_RESULTS_IN_DAYS, - job_storage_duration => OpenQA::JobGroupDefaults::KEEP_JOBS_IN_DAYS, - important_job_storage_duration => OpenQA::JobGroupDefaults::KEEP_IMPORTANT_JOBS_IN_DAYS, - }, - no_group_limits => { - log_storage_duration => OpenQA::JobGroupDefaults::KEEP_LOGS_IN_DAYS, - important_log_storage_duration => OpenQA::JobGroupDefaults::KEEP_IMPORTANT_LOGS_IN_DAYS, - result_storage_duration => OpenQA::JobGroupDefaults::KEEP_RESULTS_IN_DAYS, - important_result_storage_duration => OpenQA::JobGroupDefaults::KEEP_IMPORTANT_RESULTS_IN_DAYS, - job_storage_duration => OpenQA::JobGroupDefaults::KEEP_JOBS_IN_DAYS, - important_job_storage_duration => OpenQA::JobGroupDefaults::KEEP_IMPORTANT_JOBS_IN_DAYS, - }, - minion_task_triggers => { - on_job_done => [], - }, - misc_limits => { - untracked_assets_storage_duration => 14, - result_cleanup_max_free_percentage => 100, - asset_cleanup_max_free_percentage => 100, - screenshot_cleanup_batch_size => OpenQA::Task::Job::Limit::DEFAULT_SCREENSHOTS_PER_BATCH, - screenshot_cleanup_batches_per_minion_job => OpenQA::Task::Job::Limit::DEFAULT_BATCHES_PER_MINION_JOB, - minion_job_max_age => ONE_WEEK, - generic_default_limit => 10000, - generic_max_limit => 100000, - tests_overview_max_jobs => 2000, - all_tests_default_finished_jobs => 500, - all_tests_max_finished_jobs => 5000, - list_templates_default_limit => 5000, - list_templates_max_limit => 20000, - next_jobs_default_limit => 500, - next_jobs_max_limit => 10000, - previous_jobs_default_limit => 500, - previous_jobs_max_limit => 10000, - job_settings_max_recent_jobs => 20000, - assets_default_limit => 100000, - assets_max_limit => 200000, - max_online_workers => 1000, - wait_for_grutask_retries => 6, - worker_limit_retry_delay => ONE_HOUR / 4, - mcp_max_result_size => 500000, - scheduled_product_min_storage_duration => 34, - prio_throttling_parameters => 'MAX_JOB_TIME:0.007', - }, - archiving => { - archive_preserved_important_jobs => 0, - }, - job_settings_ui => { - keys_to_render_as_links => '', - default_data_dir => 'data', - }, - influxdb => { - ignored_failed_minion_jobs => '', - }, - carry_over => { - lookup_depth => 10, - state_changes_limit => 3, - }, - webui => { - render_batch_size => 50, - }, - secrets => {github_token => ''}, - }; + + my $test_config = dclone(OpenQA::Setup::default_config()); + # apply transformations done in read_config + $test_config->{global}->{recognized_referers} = []; + $test_config->{global}->{parallel_children_collapsable_results_sel} + = ' .status:not(.result_passed):not(.result_softfailed)'; + $test_config->{auth}->{method} = 'Fake'; + $test_config->{minion_task_triggers}->{on_job_done} = []; + for my $l ($test_config->{default_group_limits}, $test_config->{no_group_limits}) { + $l->{result_storage_duration} = OpenQA::JobGroupDefaults::KEEP_RESULTS_IN_DAYS; + $l->{important_result_storage_duration} = OpenQA::JobGroupDefaults::KEEP_IMPORTANT_RESULTS_IN_DAYS; + $l->{job_storage_duration} = OpenQA::JobGroupDefaults::KEEP_JOBS_IN_DAYS; + $l->{important_job_storage_duration} = OpenQA::JobGroupDefaults::KEEP_IMPORTANT_JOBS_IN_DAYS; + } + delete $test_config->{'test_preset example'}; + delete $test_config->{global}->{auto_clone_regex}; + delete $test_config->{global}->{parallel_children_collapsable_results}; + for my $k (keys %$test_config) { + my $section = $test_config->{$k}; + next unless ref $section eq 'HASH'; + delete $section->{$_} for grep { !defined $section->{$_} } keys %$section; + delete $test_config->{$k} unless %$section; + } # Test configuration generation with "test" mode $test_config->{_openid_secret} = $config->{_openid_secret}; @@ -292,6 +145,43 @@ 'default job_storage_duration extended to result_storage_duration (no group)'; }; +subtest 'openqa.ini documentation check' => sub { + my $defaults = OpenQA::Setup::default_config(); + my $ini_path = path($FindBin::Bin)->child('..', 'etc', 'openqa', 'openqa.ini'); + ok -r $ini_path, "can read $ini_path"; + my $content = $ini_path->slurp; + + my %documented; + my $current_section; + for (split /\n/, $content) { + if (/^#?\[([^\]]+)\]/) { + $current_section = $1; + } + elsif ($current_section && /^#?\s*([a-z0-9_]+)\s*=/) { + $documented{$current_section}->{$1} = 1; + } + } + + for my $section (sort keys %$defaults) { + # skip internal/dynamic sections + next if $section =~ /^(plugin_links|hooks|test_preset example|assets\/storage_duration|carry_over)$/; + for my $key (sort keys %{$defaults->{$section}}) { + # skip deprecated/internal/currently undocumented keys + next + if $section eq 'global' + && $key + =~ /^(scm|parallel_children_collapsable_results_sel|file_domain|prio_throttling_data|access_control_allow_origin_header|changelog_file|file_subdomain|search_results_limit)$/; + next if $section eq 'hypnotoad'; + next if $section eq 'job_settings_ui' && $key eq 'default_data_dir'; + next if $section eq 'misc_limits' && $key =~ /^(prio_throttling_data|mcp_max_result_size)$/; + next if $section eq 'rate_limits' && $key eq 'search'; + next if $section eq 'secrets'; + next if $section eq 'audit' && $key eq 'blacklist'; + ok $documented{$section}->{$key}, "key '$key' in section '[$section]' is documented in openqa.ini"; + } + } +}; + subtest 'trim whitespace characters from both ends of openqa.ini value' => sub { my $t_dir = tempdir; local $ENV{OPENQA_CONFIG} = $t_dir; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1774104919.9788babf/t/ui/13-admin.t new/openQA-5.1774278862.ea002efa/t/ui/13-admin.t --- old/openQA-5.1774104919.9788babf/t/ui/13-admin.t 2026-03-21 15:55:19.000000000 +0100 +++ new/openQA-5.1774278862.ea002efa/t/ui/13-admin.t 2026-03-23 16:14:22.000000000 +0100 @@ -585,6 +585,12 @@ # Make changes in a separate tab my $second_tab = open_new_tab($driver->get_current_url()); $driver->switch_to_window($second_tab); + wait_until( + sub { + return $driver->execute_script('return typeof editor !== "undefined" && editor.getValue().length > 0;'); + }, + 'editor loaded initial data' + ); $form = $driver->find_element_by_id('editor-form'); $result = $form->child('.result'); $yaml .= ' # additional comment'; ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.5K1o7y/_old 2026-03-24 18:49:18.155529727 +0100 +++ /var/tmp/diff_new_pack.5K1o7y/_new 2026-03-24 18:49:18.167530222 +0100 @@ -1,5 +1,5 @@ name: openQA -version: 5.1774104919.9788babf -mtime: 1774104919 -commit: 9788babf3deee39e4b607035084754486cfcc637 +version: 5.1774278862.ea002efa +mtime: 1774278862 +commit: ea002efad2c929be8c52a16632770814e06827ff
