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-05-06 19:18:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.30200 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Wed May 6 19:18:11 2026 rev:844 rq:1351023 version:5.1777995277.b985bea2 Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2026-05-05 15:16:03.780903051 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new.30200/openQA.changes 2026-05-06 19:19:37.881371989 +0200 @@ -1,0 +2,14 @@ +Tue May 05 15:34:46 UTC 2026 - [email protected] + +- Update to version 5.1777995277.b985bea2: + * style: Enforce perlcritic policy Variables::ProtectPrivateVars + * fix(docs): Fix links to documentation after converting to Markdown + * docs: fix broken references to former .asciidoc files + * docs: Fix wrapping list of directories after Markdown migration + * docs: Improve documentation of `git_auto_clone` feature + * docs: Make remark about worker cache service clearer using a comma + * docs: Fix casing of Git in the section about setting up Git support + * feat: Include log in IPA results + * feat: enhance dynamic job limit with fast ramp-up + +------------------------------------------------------------------- Old: ---- openQA-5.1777888278.38a3a85c.obscpio New: ---- openQA-5.1777995277.b985bea2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.vfsijO/_old 2026-05-06 19:19:39.409434923 +0200 +++ /var/tmp/diff_new_pack.vfsijO/_new 2026-05-06 19:19:39.413435088 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1777888278.38a3a85c +Version: 5.1777995277.b985bea2 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.vfsijO/_old 2026-05-06 19:19:39.457436901 +0200 +++ /var/tmp/diff_new_pack.vfsijO/_new 2026-05-06 19:19:39.461437065 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1777888278.38a3a85c +Version: 5.1777995277.b985bea2 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.vfsijO/_old 2026-05-06 19:19:39.497438548 +0200 +++ /var/tmp/diff_new_pack.vfsijO/_new 2026-05-06 19:19:39.501438713 +0200 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1777888278.38a3a85c +Version: 5.1777995277.b985bea2 Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.vfsijO/_old 2026-05-06 19:19:39.545440525 +0200 +++ /var/tmp/diff_new_pack.vfsijO/_new 2026-05-06 19:19:39.549440690 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1777888278.38a3a85c +Version: 5.1777995277.b985bea2 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.vfsijO/_old 2026-05-06 19:19:39.585442173 +0200 +++ /var/tmp/diff_new_pack.vfsijO/_new 2026-05-06 19:19:39.589442337 +0200 @@ -99,7 +99,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1777888278.38a3a85c +Version: 5.1777995277.b985bea2 Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0-or-later ++++++ openQA-5.1777888278.38a3a85c.obscpio -> openQA-5.1777995277.b985bea2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/.github/checklist.yml new/openQA-5.1777995277.b985bea2/.github/checklist.yml --- old/openQA-5.1777888278.38a3a85c/.github/checklist.yml 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/.github/checklist.yml 2026-05-05 17:34:37.000000000 +0200 @@ -2,6 +2,6 @@ 'assets/stylesheets/**': - Consider providing screenshots in a PR comment to show the difference visually 'docs/*.md': - - Consider generating documentation locally to verify it is rendered correctly. See https://open.qa/docs/#_making_documentation_changes + - Consider generating documentation locally to verify it is rendered correctly. See https://open.qa/docs/#making-documentation-changes 'external/**': - Consider doing this change in the upstream repository directly, see external/os-autoinst-common/README.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/.perlcriticrc new/openQA-5.1777995277.b985bea2/.perlcriticrc --- old/openQA-5.1777888278.38a3a85c/.perlcriticrc 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/.perlcriticrc 2026-05-05 17:34:37.000000000 +0200 @@ -1,6 +1,6 @@ theme = community + openqa severity = 4 -include = strict ValuesAndExpressions::ProhibitInterpolationOfLiterals CodeLayout::ProhibitParensWithBuiltins BuiltinFunctions::RequireBlockMap BuiltinFunctions::ProhibitStringySplit ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions ValuesAndExpressions::RequireQuotedHeredocTerminator Variables::ProhibitUnusedVariables ValuesAndExpressions::RequireNumberSeparators CodeLayout::ProhibitQuotedWordLists RegularExpressions::ProhibitSingleCharAlternation BuiltinFunctions::RequireBlockGrep RegularExpressions::ProhibitUselessTopic +include = strict ValuesAndExpressions::ProhibitInterpolationOfLiterals CodeLayout::ProhibitParensWithBuiltins BuiltinFunctions::RequireBlockMap BuiltinFunctions::ProhibitStringySplit ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions ValuesAndExpressions::RequireQuotedHeredocTerminator Variables::ProhibitUnusedVariables ValuesAndExpressions::RequireNumberSeparators CodeLayout::ProhibitQuotedWordLists RegularExpressions::ProhibitSingleCharAlternation BuiltinFunctions::RequireBlockGrep RegularExpressions::ProhibitUselessTopic Variables::ProtectPrivateVars # ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions # No operators like < =~ ! allowed in 'unless' or 'until', only simple diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/README.md new/openQA-5.1777995277.b985bea2/README.md --- old/openQA-5.1777888278.38a3a85c/README.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/README.md 2026-05-05 17:34:37.000000000 +0200 @@ -31,7 +31,7 @@ [our Codespace](https://codespaces.new/os-autoinst/openQA?quickstart=1). See also: [GitHub Codespaces documentation](https://docs.github.com/en/codespaces) -See [openQA in a browser](https://open.qa/docs/#_openqa_in_a_browser) for +See [openQA in a browser](https://open.qa/docs/#openqa-in-a-browser) for documentation on how to use it. # Contributing diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/container/helm/README.md new/openQA-5.1777995277.b985bea2/container/helm/README.md --- old/openQA-5.1777888278.38a3a85c/container/helm/README.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/container/helm/README.md 2026-05-05 17:34:37.000000000 +0200 @@ -121,4 +121,4 @@ ### Worker The worker requires some basic configuration, as described in the -[documentation](http://open.qa/docs/#_run_openqa_workers). +[documentation](http://open.qa/docs/#run-openqa-workers). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/docs/ContainerizedSetup.md new/openQA-5.1777995277.b985bea2/docs/ContainerizedSetup.md --- old/openQA-5.1777888278.38a3a85c/docs/ContainerizedSetup.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/docs/ContainerizedSetup.md 2026-05-05 17:34:37.000000000 +0200 @@ -251,7 +251,7 @@ You have to put your tests under `data/tests` directory and ISOs under `data/factory/iso` directory. For testing openSUSE, follow -[this guide](https://github.com/os-autoinst/openQA/blob/master/docs/GettingStarted.asciidoc#testing-opensuse-or-fedora). +[this guide](GettingStarted.md#get-testing). The test distribution might have additional dependencies which need to be installed into the worker container before tests can run. To install those diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/docs/Contributing.md new/openQA-5.1777995277.b985bea2/docs/Contributing.md --- old/openQA-5.1777888278.38a3a85c/docs/Contributing.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/docs/Contributing.md 2026-05-05 17:34:37.000000000 +0200 @@ -263,7 +263,7 @@ For openSUSE you need the packages `openQA` and `os-autoinst`. That should be everything necessary to run an openQA instance. For more -details check \<\<Installing.asciidoc#\_installation,Installation\>. +details check [Installation](Installing.md#installation). If you have to manually install packages, look into the `dependencies.yaml` file or the spec file, e.g. `dist/rpm/openQA.spec` (or `dist/rpm/*.spec` in general). You can leave out sections starting with `test_requires` for example. @@ -300,8 +300,8 @@ The following explains in detail what is necessary to develop openQA code. For a setup with containers you can check out the -\<\<Contributing.asciidoc#quick-container-development-setup,Quick container -development setup\>\> below with a complete list of instructions. +[Quick container development setup](#quick-container-development-setup) +below with a complete list of instructions. Otherwise follow the detailed steps below. This setup is applicable to a container environment as well as without. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/docs/Installing.md new/openQA-5.1777995277.b985bea2/docs/Installing.md --- old/openQA-5.1777888278.38a3a85c/docs/Installing.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/docs/Installing.md 2026-05-05 17:34:37.000000000 +0200 @@ -829,18 +829,18 @@ [Cleanup of assets, results and other data](UsersGuide.md#cleanup) section. -## Setting up git support +## Setting up Git support -If your tests and needles are stored in git, openQA can perform various operations: +If your tests and needles are stored in Git, openQA can perform various operations: - Automatically commit needles created in the web UI editor back to the repository - Automatically update the repository when scheduling tests -- Update the server's tests and needles from git repos specified in a job's `CASEDIR` and `NEEDLES_DIR` variables +- Update the server's tests and needles from Git repos specified in a job's `CASEDIR` and `NEEDLES_DIR` variables - Attempt to have the web UI display the correct needles each job was executed with via - temporary git checkouts, based on its variables + temporary Git checkouts, based on its variables By default, cloning based on `CASEDIR` and `NEEDLES_DIR` is enabled, but the other features are disabled. To control these features, you can use these config settings: @@ -858,8 +858,11 @@ - `git_auto_update` controls automatic test/needle updating when scheduling tests. - `git_auto_clone` controls the automatic cloning of repos referenced by `CASEDIR` and `NEEDLES_DIR`, at job schedule time. + Check out the + [section about directories](Installing.md#terms-and-variables-for-certain-directories-used-by-openqa-and-isotovideo) + for where the repositories will be stored. - `checkout_needles_sha` controls the feature whereby, when a job viewed in the web UI has - variables indicating the needles came from a specific git repository and ref, openQA will + variables indicating the needles came from a specific Git repository and ref, openQA will attempt to clone that ref and display the needles from it. ### Configuration of automatic needle commit feature @@ -905,7 +908,7 @@ ``` If you clone the needle repository via HTTP, you can still make `geekotest` -able to push via SSH with a git configuration. For GitHub, it would look like +able to push via SSH with a Git configuration. For GitHub, it would look like this: ``` sh @@ -922,7 +925,7 @@ pushInsteadOf = https://github.com/ ``` -You can apply the same kind of thing for any other git hosting provider. +You can apply the same kind of thing for any other Git hosting provider. ## Referer settings to auto-mark important jobs @@ -1270,7 +1273,7 @@ instance) it results in downloading the same assets several times. In such case, one can setup local cache on their own (without using openqa-worker-cacheservice service) and share it with workers using -some network filesystem (see [Installing.asciidoc#Configuring remote workers](Installing.md#Configuring remote workers) +some network filesystem (see [Configuring remote workers](Installing.md#configuring_remote_workers) section above). Such setups can use `SYNC_ASSETS_HOOK` in [the web UI configuration](GettingStarted.md#configuration) to ensure the @@ -1804,59 +1807,77 @@ ## Terms and variables for certain directories used by openQA and isotovideo - the "base directory" - - by default `/var/lib` - - configurable via environment variable `OPENQA_BASEDIR` - - referred as `$basedir` within openQA - the "project directory" - - defined as `$basedir/openqa`, by default `/var/lib/openqa` - - referred as `$prjdir` within openQA - the "archive directory" - - defined as `$prjdir/openqa`, by default `/var/lib/openqa/archive` - - referred as `$archivedir` within openQA -- the "share directory": contains directories shared between web UI and (remote) workers - +- the "share directory": contains directories shared between web UI and (remote) + workers - defined as `$prjdir/share`, by default `/var/lib/openqa/share` - - referred as `$sharedir` within openQA - the "test case directory": contains a test distribution - - by default `$sharedir/tests/$distri` or `$sharedir/tests/$distri-$version` + - configurable via the test variable `CASEDIR` (see backend variables + documentation) - this default is provided by openQA; when starting + isotovideo manually the `CASEDIR` variable **must** be initialized by hand + - relative paths are relative to `$sharedir/tests`; to avoid symlinking, use + e.g. `CASEDIR=opensuse` for `$sharedir/tests/opensuse` despite differing + `DISTRI` + - specifying a Git URL as `CASEDIR` is also possible; with `git_auto_clone` + enabled, openQA will create a checkout of the repository under the mentioned + default location if it does not already exist + - no de-duplication is done, e.g. + `CASEDIR=https://github.com/…/…-distri-opensuse.git` will lead to a + checkout under `$sharedir/tests/opensuse` with `DISTRI=opensuse` and a + separate checkout under `$sharedir/tests/microos` with `DISTRI=microos` + - separate checkouts can be avoided by manual symlinking, e.g. a symlink + for `microos` pointing to `opensuse` will prevent the duplicate + checkouts in this example + - might contain the sub directory `lib` for placing Perl modules used by the + tests - - configurable via the test variable `CASEDIR` (see backend variables documentation) - this default is provided by openQA; when starting isotovideo manually the `CASEDIR` variable **must** be - initialized by hand - - - relative paths are relative to `$sharedir/tests`; to avoid symlinking, use e.g. `CASEDIR=opensuse` for `$sharedir/tests/opensuse` despite differing `DISTRI` - - - might contain the sub directory `lib` for placing Perl modules used by the tests - the "product directory": contains the test schedule (`main.pm`) for a certain product within a test distribution - +- the "product directory": contains the test schedule (`main.pm`) for a certain + product within a test distribution - by default identical to the "test case directory" + - usually a directory `products/$distri` within the "test case directory" + - configurable via the test variable `PRODUCTDIR` (see backend variables + documentation) - - usually a directory `products/$distri` within the "test case directory" - configurable via the test variable `PRODUCTDIR` (see backend variables documentation) - -- the "needles directory": contains reference images for a certain product within a test distribution - +- the "needles directory": contains reference images for a certain product + within a test distribution - by default `$PRODUCTDIR/needles` - - - configurable via the test variable `NEEDLES_DIR` (see backend variables documentation) + - configurable via the test variable `NEEDLES_DIR` (see backend variables + documentation) + - specifying a Git URL as `NEEDLES_DIR` is also possible; with + `git_auto_clone` enabled, openQA will create a checkout of the repository + under the mentioned default location if it does not already exist ### Further notes +- The mentioned `git_auto_clone` setting is part of the general + [Git support](Installing.md#setting-up-git-support) and works best if used + consistently. If e.g. only specifying a Git URL for `CASEDIR` but not for + `NEEDLES_DIR`, only the former will be cloned and needles will be missing if + they are provided by a separate repository. + + - As mentioned, there is no de-duplication of checkouts. So when cloning a job + with e.g. `CASEDIR=https://github.com/…/…-distri-opensuse.git` and + `DISTRI=microos` but no `NEEDLES_DIR`, needles will be missing despite being + present for `DISTRI=opensuse`. - Setting the test variables has only an influence on os-autoinst. The web UI on the other hand always relies on the directory structure described above. For the exact details how these paths are computed by the web UI have a look at `lib/OpenQA/Utils.pm`. -- When enabling the worker cache parts of the usual "share directory" are located in the specified cache +- When enabling the worker cache, parts of the usual "share directory" are located in the specified cache directory on the worker host. # Automatic installation of the operating systems for openQA machines diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/docs/UsersGuide.md new/openQA-5.1777995277.b985bea2/docs/UsersGuide.md --- old/openQA-5.1777888278.38a3a85c/docs/UsersGuide.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/docs/UsersGuide.md 2026-05-05 17:34:37.000000000 +0200 @@ -1371,7 +1371,7 @@ `SCENARIO_DEFINITIONS_YAML_FILE` which expects the file path of the YAML document on the openQA host. One can also specify an HTTP/HTTPs URL via that variable when `async=1` is used (see -[UsersGuide.asciidoc#\_spawning_multiple_jobs_based_on_templates_isos_post](UsersGuide.md#spawning_multiple_jobs_based_on_templates_isos_post) +[Spawning multiple jobs based on templates - isos post](UsersGuide.md#spawning_multiple_jobs_based_on_templates_isos_post) for details). Then this file is downloaded by the openQA host. The specified host name must be allowed via the configuration setting `scenario_definitions_allowed_hosts`. @@ -1896,11 +1896,11 @@ to handle flaky issues and even automatically retrigger according tests - In case of known sporadic issues that can not be fixed quickly consider - automatic retries of jobs <http://open.qa/docs/#_automatic_retries_of_jobs> + [automatic retries of jobs](WritingTests.md#automatic-retries-of-jobs). - In case of known non-sporadic test issues that can not be fixed quickly - consider overwriting the result of jobs - <http://open.qa/docs/#_overwrite_result_of_job> + consider + [overwriting the result of jobs](UsersGuide.md#overwrite-result-of-job). - To quickly label and - as desired - restart multiple jobs consider using the command line application `openqa-label-all`. Call `openqa-label-all --help` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/docs/WritingTests.md new/openQA-5.1777995277.b985bea2/docs/WritingTests.md --- old/openQA-5.1777888278.38a3a85c/docs/WritingTests.md 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/docs/WritingTests.md 2026-05-05 17:34:37.000000000 +0200 @@ -914,8 +914,9 @@ ### Handling of dependencies when cloning jobs -Be sure to have read the [job dependencies](WritingTests.md#_job_dependencies) section to have an understanding of different dependency types -and the distinction between parents and children. +Be sure to have read the [job dependencies](WritingTests.md#job-dependencies) +section to have an understanding of different dependency types and the +distinction between parents and children. When cloning a job via `openqa-clone-job`, parent jobs are cloned as well by default, regardless of the type. Use `--skip-deps` to avoid cloning parent jobs. Use `--skip-chained-deps` to avoid cloning parents of the types `CHAINED` and `DIRECTLY_CHAINED`. When cloning a job via `openqa-clone-job`, child jobs of the type `PARALLEL` are cloned by default. Use `--clone-children` to clone child jobs of other types as diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/etc/openqa/openqa.ini new/openQA-5.1777995277.b985bea2/etc/openqa/openqa.ini --- old/openQA-5.1777888278.38a3a85c/etc/openqa/openqa.ini 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/etc/openqa/openqa.ini 2026-05-05 17:34:37.000000000 +0200 @@ -228,7 +228,7 @@ ## Sets the storage duration in days for the different audit event types [audit/storage_duration] -## By default cleanup is disabled, see http://open.qa/docs/#_auditing_tracking_openqa_changes +## By default cleanup is disabled, see https://open.qa/docs/#auditing---tracking-openqa-changes ## The following categories with example values can be uncommented as needed #startup = 10 #jobgroup = 365 @@ -463,10 +463,14 @@ #dynamic_job_limit_enabled = 0 ## Minimum effective job limit when dynamic scaling is active. Defaults to 50. #dynamic_job_limit_min = 50 -## Load average above which the effective limit is scaled down. 0 = auto-detect (nproc * 0.85). +## Load average above which the effective limit is scaled down. 0 = auto-detect (nproc * dynamic_job_limit_load_threshold_factor). #dynamic_job_limit_load_threshold = 0 -## Load average for emergency cutback (3x step decrease). 0 = auto-detect (nproc * 1.5). +## Factor for auto-detecting the load threshold. Defaults to 0.85. +#dynamic_job_limit_load_threshold_factor = 0.85 +## Load average for emergency cutback (3x step decrease). 0 = auto-detect (nproc * dynamic_job_limit_load_critical_factor). #dynamic_job_limit_load_critical = 0 +## Factor for auto-detecting the critical load threshold. Defaults to 1.5. +#dynamic_job_limit_load_critical_factor = 1.5 ## Number of jobs to add/remove per adjustment. Defaults to 10. #dynamic_job_limit_step = 10 ## Minimum seconds between dynamic limit adjustments. Defaults to 60. @@ -483,6 +487,10 @@ ## stored on; scheduling is suspended if the free storage falls under the ## specified percentage. Defaults to 5. Set to 0 to disable. #assets_min_free_storage_space_percentage = 5 +## Fraction of threshold below which all load averages must fall to scale up. Defaults to 0.7. +#dynamic_job_limit_scale_up_hysteresis = 0.7 +## Fraction of threshold below which "fast ramp-up" (double step) is active. Defaults to 0.3. +#dynamic_job_limit_fast_ramp_up_load_factor = 0.3 ## Configuration of the label/bugref carry-over [carry_over] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Git.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/Git.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Git.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/Git.pm 2026-05-05 17:34:37.000000000 +0200 @@ -141,7 +141,7 @@ 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.'; + .= '. See https://open.qa/docs/#setting-up-git-support on how to setup git support and possibly push via ssh.'; $e->msg($msg); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Parser/Format/IPA.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/Parser/Format/IPA.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Parser/Format/IPA.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/Parser/Format/IPA.pm 2026-05-05 17:34:37.000000000 +0200 @@ -60,6 +60,7 @@ my $details = {result => $result->{result}}; my $text_fn = "IPA-$t_name.txt"; my $content = join "\n", $t_name, $result->{result}; + $content .= "\nlog:\t$res->{test}->{log}" if (defined $res->{test}->{log}); $details->{text} = $text_fn; $details->{title} = $t_name; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Scheduler/DynamicLimit.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/Scheduler/DynamicLimit.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Scheduler/DynamicLimit.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/Scheduler/DynamicLimit.pm 2026-05-05 17:34:37.000000000 +0200 @@ -10,10 +10,29 @@ use OpenQA::Utils qw(load_avg); use Time::HiRes 'time'; -# Fraction of threshold below which all load averages must fall to scale up. -use constant SCALE_UP_HYSTERESIS => 0.7; -# Multiplier applied to step on an emergency (critical) cutback. -use constant EMERGENCY_STEP_MULTIPLIER => 3; +use constant { + SCALE_UP_HYSTERESIS => 0.7, + FAST_RAMP_UP_LOAD_FACTOR => 0.3, + LOAD_THRESHOLD_FACTOR => 0.85, + LOAD_CRITICAL_FACTOR => 1.5, + STEP => 10, + MIN => 50, + INTERVAL => 60, + EMERGENCY_STEP_MULTIPLIER => 3, +}; + +use constant DEFAULTS => { + dynamic_job_limit_load_threshold => 0, + dynamic_job_limit_load_threshold_factor => LOAD_THRESHOLD_FACTOR, + dynamic_job_limit_load_critical => 0, + dynamic_job_limit_load_critical_factor => LOAD_CRITICAL_FACTOR, + dynamic_job_limit_step => STEP, + dynamic_job_limit_min => MIN, + max_running_jobs => -1, + dynamic_job_limit_interval => INTERVAL, + dynamic_job_limit_scale_up_hysteresis => SCALE_UP_HYSTERESIS, + dynamic_job_limit_fast_ramp_up_load_factor => FAST_RAMP_UP_LOAD_FACTOR, +}; has effective_limit => undef; @@ -25,13 +44,14 @@ # Returns the number of online CPUs by counting processor entries in /proc/cpuinfo. sub _nproc () { - scalar grep { /^processor\s*:/ } split /\n/, path('/proc/cpuinfo')->slurp; + state $cpus = scalar grep { /^processor\s*:/ } split /\n/, path('/proc/cpuinfo')->slurp; + return $cpus; } # Returns a resolved (non-zero) threshold, falling back to nproc * $factor. sub _resolve_threshold ($configured, $factor) { return $configured if $configured > 0; - state $nproc = _nproc(); + my $nproc = _nproc(); return $nproc > 0 ? $nproc * $factor : 10 * $factor; } @@ -39,13 +59,24 @@ # Returns a hash reference of typed values; this is the single point coupling # DynamicLimit to the config key names. sub _extract_config ($config) { + my $defaults = DEFAULTS(); return { - threshold => _resolve_threshold($config->{dynamic_job_limit_load_threshold}, 0.85), - critical => _resolve_threshold($config->{dynamic_job_limit_load_critical}, 1.5), - step => $config->{dynamic_job_limit_step}, - min => $config->{dynamic_job_limit_min}, - max => $config->{max_running_jobs}, - interval => $config->{dynamic_job_limit_interval}, + threshold => _resolve_threshold( + $config->{dynamic_job_limit_load_threshold} // $defaults->{dynamic_job_limit_load_threshold}, + $config->{dynamic_job_limit_load_threshold_factor} // $defaults->{dynamic_job_limit_load_threshold_factor} + ), + critical => _resolve_threshold( + $config->{dynamic_job_limit_load_critical} // $defaults->{dynamic_job_limit_load_critical}, + $config->{dynamic_job_limit_load_critical_factor} // $defaults->{dynamic_job_limit_load_critical_factor} + ), + step => $config->{dynamic_job_limit_step} // $defaults->{dynamic_job_limit_step}, + min => $config->{dynamic_job_limit_min} // $defaults->{dynamic_job_limit_min}, + max => $config->{max_running_jobs} // $defaults->{max_running_jobs}, + interval => $config->{dynamic_job_limit_interval} // $defaults->{dynamic_job_limit_interval}, + scale_up_hysteresis => $config->{dynamic_job_limit_scale_up_hysteresis} + // $defaults->{dynamic_job_limit_scale_up_hysteresis}, + fast_ramp_up_load_factor => $config->{dynamic_job_limit_fast_ramp_up_load_factor} + // $defaults->{dynamic_job_limit_fast_ramp_up_load_factor}, }; } @@ -54,9 +85,10 @@ sub _adjust ($self, $load, $p) { my $current = $self->effective_limit; my ($l1, $l5, $l15) = @$load; + my $load_max = max($l1, $l5, $l15); my $new; - if (max($l1, $l5, $l15) > $p->{critical}) { + if ($load_max > $p->{critical}) { # Emergency: cut back aggressively $new = max($p->{min}, $current - $p->{step} * EMERGENCY_STEP_MULTIPLIER); } @@ -64,17 +96,19 @@ # Load rising above threshold: decrease conservatively $new = max($p->{min}, $current - $p->{step}); } - elsif (max($l1, $l5, $l15) < $p->{threshold} * SCALE_UP_HYSTERESIS) { + elsif ($load_max < $p->{threshold} * $p->{scale_up_hysteresis}) { # Load well below threshold on all horizons: increase conservatively - $new = $p->{max} >= 0 ? min($p->{max}, $current + $p->{step}) : $current + $p->{step}; + # Double step for fast ramp-up if load is very low + my $step = $load_max < $p->{threshold} * $p->{fast_ramp_up_load_factor} ? $p->{step} * 2 : $p->{step}; + $new = $p->{max} >= 0 ? min($p->{max}, $current + $step) : $current + $step; } else { $new = $current; } $self->effective_limit($new); - log_debug(sprintf 'Dynamic job limit: %d (load: %.2f/%.2f/%.2f, threshold: %.2f, critical: %.2f)', - $new, $l1, $l5, $l15, $p->{threshold}, $p->{critical}); + log_debug(sprintf 'Dynamic job limit: %d (min: %d, max: %d, load: %.2f/%.2f/%.2f, threshold: %.2f, critical: %.2f)', + $new, $p->{min}, $p->{max}, $l1, $l5, $l15, $p->{threshold}, $p->{critical}); return $new; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Schema/Result/Jobs.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/Schema/Result/Jobs.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Schema/Result/Jobs.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/Schema/Result/Jobs.pm 2026-05-05 17:34:37.000000000 +0200 @@ -789,7 +789,7 @@ die "Direct parent $parent_id needs to be cloned as well for the directly chained dependency " . 'to work correctly. It is generally better to restart the parent which will restart all children ' . 'as well. Check out the ' - . '<a href="https://open.qa/docs/#_handling_of_related_jobs_on_failure_cancellation_restart">' + . '<a href="https://open.qa/docs/#handling-of-related-jobs-on-failure--cancellation--restart">' . "documentation</a> for more information.\n" if $no_directly_chained_parent; $p->cluster_jobs(jobs => $jobs, skip_children => 1, cancelmode => $cancelmode); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Setup.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/Setup.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Setup.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/Setup.pm 2026-05-05 17:34:37.000000000 +0200 @@ -20,6 +20,7 @@ use OpenQA::Constants qw(DEFAULT_WORKER_TIMEOUT MAX_TIMER); use OpenQA::JobGroupDefaults; use OpenQA::Jobs::Constants qw(OK_RESULTS); +use OpenQA::Scheduler::DynamicLimit; use OpenQA::Task::Job::Limit; use Feature::Compat::Try; @@ -153,13 +154,8 @@ }, scheduler => { max_job_scheduled_time => 7, - max_running_jobs => -1, dynamic_job_limit_enabled => 0, - dynamic_job_limit_min => 50, - dynamic_job_limit_load_threshold => 0, - dynamic_job_limit_load_critical => 0, - dynamic_job_limit_step => 10, - dynamic_job_limit_interval => 60, + %{OpenQA::Scheduler::DynamicLimit->DEFAULTS}, results_min_free_storage_space_percentage => 5, archive_min_free_storage_space_percentage => 5, assets_min_free_storage_space_percentage => 5, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Task/Git/Clone.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/Task/Git/Clone.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/Task/Git/Clone.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/Task/Git/Clone.pm 2026-05-05 17:34:37.000000000 +0200 @@ -121,7 +121,7 @@ die <<~"END_OF_MESSAGE" unless $git->is_workdir_clean; NOT updating dirty Git checkout at '$path'. In case this is expected (e.g. on a development openQA instance) you can disable auto-updating. - Then the Git checkout will no longer be kept up-to-date, though. Check out http://open.qa/docs/#_getting_tests for details. + Then the Git checkout will no longer be kept up-to-date, though. Check out https://open.qa/docs/#getting-tests for details. END_OF_MESSAGE unless ($requested_branch) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/lib/OpenQA/WebAPI/Plugin/Helpers.pm new/openQA-5.1777995277.b985bea2/lib/OpenQA/WebAPI/Plugin/Helpers.pm --- old/openQA-5.1777888278.38a3a85c/lib/OpenQA/WebAPI/Plugin/Helpers.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/lib/OpenQA/WebAPI/Plugin/Helpers.pm 2026-05-05 17:34:37.000000000 +0200 @@ -171,7 +171,7 @@ $c->help_popover( 'Help for the <em>TODO</em>-filter', '<p>Shows only jobs that need to be labeled for the black review badge to show up</p>', - 'http://open.qa/docs/#_review_badges', + 'https://open.qa/docs/#review-badges', 'documentation about review badges' ); }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/profiles/apparmor.d/local/usr.share.openqa.script.openqa new/openQA-5.1777995277.b985bea2/profiles/apparmor.d/local/usr.share.openqa.script.openqa --- old/openQA-5.1777888278.38a3a85c/profiles/apparmor.d/local/usr.share.openqa.script.openqa 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/profiles/apparmor.d/local/usr.share.openqa.script.openqa 2026-05-05 17:34:37.000000000 +0200 @@ -1,3 +1,3 @@ # Site-specific additions and overrides for 'usr.share.openqa.script.openqa' # For example to cover custom "job done" hooks, see -# http://open.qa/docs/#_enable_custom_hook_scripts_on_job_done_based_on_result +# https://open.qa/docs/#enable-custom-hook-scripts-on-job-done-based-on-result diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/public/openqa-cli.yaml new/openQA-5.1777995277.b985bea2/public/openqa-cli.yaml --- old/openQA-5.1777888278.38a3a85c/public/openqa-cli.yaml 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/public/openqa-cli.yaml 2026-05-05 17:34:37.000000000 +0200 @@ -92,12 +92,12 @@ FLAVOR=my-flavor VERSION=42 BUILD=42 TEST=my-test # Trigger a single set of jobs (see - # https://open.qa/docs/#_spawning_single_new_jobs_jobs_post for details) + # https://open.qa/docs/#spawning-single-new-jobs---jobs-post for details) openqa-cli api -X POST jobs \ TEST:0=first-job TEST:1=second-job _START_AFTER:1=0 # Trigger jobs on ISO "foo.iso" creating a "scheduled product" (see - # https://open.qa/docs/#_spawning_multiple_jobs_based_on_templates_isos_post + # https://open.qa/docs/#spawning-multiple-jobs-based-on-templates---isos-post # for details, e.g for considering to use the `async` flag) openqa-cli api --o3 -X POST isos ISO=foo.iso \ DISTRI=my-distri FLAVOR=my-flavor ARCH=my-arch VERSION=42 BUILD=1234 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/systemd/openqa-webui.service new/openQA-5.1777995277.b985bea2/systemd/openqa-webui.service --- old/openQA-5.1777888278.38a3a85c/systemd/openqa-webui.service 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/systemd/openqa-webui.service 2026-05-05 17:34:37.000000000 +0200 @@ -3,7 +3,7 @@ Wants=openqa-setup-db.service openqa-livehandler.service openqa-websockets.service openqa-gru.service openqa-enqueue-asset-cleanup.timer openqa-enqueue-result-cleanup.timer openqa-enqueue-bug-cleanup.timer openqa-minion-restart.path After=postgresql.service openqa-setup-db.service nss-lookup.target remote-fs.target apache2.service nginx.service caddy.service Before=openqa-gru.service openqa-scheduler.service openqa-livehandler.service -Documentation=https://open.qa/docs/#_run_the_web_ui +Documentation=https://open.qa/docs/#run-the-web-ui [Service] User=geekotest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/systemd/[email protected] new/openQA-5.1777995277.b985bea2/systemd/[email protected] --- old/openQA-5.1777888278.38a3a85c/systemd/[email protected] 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/systemd/[email protected] 2026-05-05 17:34:37.000000000 +0200 @@ -6,7 +6,7 @@ Description=openQA Worker #%i After=openqa-slirpvde.service network.target nss-lookup.target remote-fs.target time-sync.target PartOf=openqa-worker.target -Documentation=https://open.qa/docs/#_run_openqa_workers +Documentation=https://open.qa/docs/#run-openqa-workers [Service] Type=simple diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/04-scheduler.t new/openQA-5.1777995277.b985bea2/t/04-scheduler.t --- old/openQA-5.1777888278.38a3a85c/t/04-scheduler.t 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/04-scheduler.t 2026-05-05 17:34:37.000000000 +0200 @@ -487,8 +487,8 @@ local $conf->{dynamic_job_limit_step} = 5; local $conf->{dynamic_job_limit_interval} = 0; $scheduler->dynamic_limit(OpenQA::Scheduler::DynamicLimit->new); - # load 0.5 < 8*0.7=5.6 => scale up from min=30 by step=5 => 35 - is $scheduler->effective_job_limit, 35, 'dynamic limit: min+step returned on low load'; + # load 0.5 < 8*0.3=2.4 => scale up from min=30 by step=5*2=10 => 40 + is $scheduler->effective_job_limit, 40, 'dynamic limit: min+step*2 returned on low load'; }; subtest 'dynamic limit enforced in scheduling: fewer jobs than max_running_jobs allocated' => sub { @@ -513,8 +513,8 @@ local $conf->{dynamic_job_limit_interval} = 0; $scheduler->dynamic_limit(OpenQA::Scheduler::DynamicLimit->new); my $res = $scheduler->schedule(); - # effective_limit = min=2 + step=1 = 3; only 3 jobs allocated despite 5 scheduled and 5 workers - is scalar @$res, 3, 'dynamic limit of 3 (min+step) respected in scheduling'; + # effective_limit = min=2 + step=1*2 = 4; only 4 jobs allocated despite 5 scheduled and 5 workers + is scalar @$res, 4, 'dynamic limit of 4 (min+step*2) respected in scheduling'; # Clean up only the jobs and workers created in this subtest $jobs->search({id => \@dyn_job_ids})->delete; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/14-grutasks-git.t new/openQA-5.1777995277.b985bea2/t/14-grutasks-git.t --- old/openQA-5.1777888278.38a3a85c/t/14-grutasks-git.t 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/14-grutasks-git.t 2026-05-05 17:34:37.000000000 +0200 @@ -474,8 +474,8 @@ $args{needle_ids} = [4]; stderr_like { $res = run_gru_job(@gru_args) } qr{Git command failed: .*push}, 'Got error on stderr'; is $res->{state}, 'finished', 'git job finished'; - like $res->{result}->{errors}->[0]->{message}, - qr{Unable to push Git commit. See .*_setting_up_git_support on how to setup}, 'Got error for push'; + like $res->{result}->{errors}->[0]->{message}, qr{Unable to push Git commit.*See.*on how to setup}, + 'Got error for push'; $openqa_git->redefine( run_cmd_with_log_return_error => sub ($cmd, %args) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/24-worker-jobs.t new/openQA-5.1777995277.b985bea2/t/24-worker-jobs.t --- old/openQA-5.1777888278.38a3a85c/t/24-worker-jobs.t 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/24-worker-jobs.t 2026-05-05 17:34:37.000000000 +0200 @@ -1148,7 +1148,7 @@ subtest 'Dynamic schedule' => sub { my $job_mock = Test::MockModule->new('OpenQA::Worker::Job'); - my $orig = \&OpenQA::Worker::Job::_read_json_file; + my $orig = \&OpenQA::Worker::Job::_read_json_file; ## no critic (Variables::ProtectPrivateVars) my $read_schedule = 0; $job_mock->redefine( _read_json_file => sub { @@ -1228,7 +1228,7 @@ }; subtest 'image optimization' => sub { - my $opt = \&OpenQA::Worker::Job::_optimize_image; + my $opt = \&OpenQA::Worker::Job::_optimize_image; ## no critic (Variables::ProtectPrivateVars) local $ENV{OPENQA_LOGFILE} = undef; combined_like { is $opt->('foo', {OPTIMIZE_IMAGES => 0}), 0, 'image optimization can be skipped'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/26-dynamic-job-limit.t new/openQA-5.1777995277.b985bea2/t/26-dynamic-job-limit.t --- old/openQA-5.1777888278.38a3a85c/t/26-dynamic-job-limit.t 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/26-dynamic-job-limit.t 2026-05-05 17:34:37.000000000 +0200 @@ -53,15 +53,25 @@ }; sub _config (%args) { - return { + my %config = ( max_running_jobs => $args{max} // 200, dynamic_job_limit_enabled => 1, - dynamic_job_limit_min => $args{min} // 50, - dynamic_job_limit_load_threshold => $args{threshold} // 8, - dynamic_job_limit_load_critical => $args{critical} // 16, - dynamic_job_limit_step => $args{step} // 10, - dynamic_job_limit_interval => $args{interval} // 0, - }; + ); + my %map = ( + min => 'dynamic_job_limit_min', + threshold => 'dynamic_job_limit_load_threshold', + threshold_factor => 'dynamic_job_limit_load_threshold_factor', + critical => 'dynamic_job_limit_load_critical', + critical_factor => 'dynamic_job_limit_load_critical_factor', + step => 'dynamic_job_limit_step', + interval => 'dynamic_job_limit_interval', + hysteresis => 'dynamic_job_limit_scale_up_hysteresis', + fast_up_factor => 'dynamic_job_limit_fast_ramp_up_load_factor', + ); + for my $k (keys %args) { + $config{$map{$k} // $k} = $args{$k} if defined $args{$k} && exists $map{$k}; + } + return \%config; } sub test_dynamic_limit (%args) { @@ -72,7 +82,7 @@ my $dl = OpenQA::Scheduler::DynamicLimit->new; $dl->effective_limit($args{initial}) if defined $args{initial}; $args{block} ? $dl->block_adjustment_for : $dl->force_next_adjustment; - my %conf = (min => 50, threshold => 8, step => 10, max => 200, %{$args{config} // {}}); + my %conf = (threshold => 8, critical => 16, max => 200, %{$args{config} // {}}); my $limit = $dl->current_limit(_config(%conf)); is $limit, $args{expected}, $args{message} // "limit is $args{expected}"; }; @@ -80,10 +90,17 @@ my @cases = ( {name => 'initial', block => 1, expected => 50, config => {interval => 60}}, - {name => 'scales up', initial => 100, load => '1.0 1.0 1.0', expected => 110}, + {name => 'scales up', initial => 100, load => '4.0 4.0 4.0', expected => 110}, + {name => 'fast up', initial => 100, load => '1.0 1.0 1.0', expected => 120}, {name => 'steady', initial => 100, load => '6.0 6.5 6.0', expected => 100}, {name => 'scales down', initial => 100, load => '10.0 7.0 6.0', expected => 90}, - {name => 'emergency', initial => 100, load => '20.0 18.0 15.0', expected => 70, config => {critical => 16}}, + { + name => 'emergency', + initial => 100, + load => '20.0 18.0 15.0', + expected => 70, + config => {critical => 16} + }, {name => 'floor', load => '20.0 18.0 15.0', initial => 55, expected => 50, config => {critical => 16}}, {name => 'ceiling', load => '1.0 1.0 1.0', initial => 195, expected => 200}, { @@ -94,22 +111,41 @@ expected => 100, config => {interval => 60} }, - {name => 'unlimited', initial => 100, load => '1.0 1.0 1.0', expected => 110, config => {max => -1}}, + {name => 'unlimited', initial => 100, load => '4.0 4.0 4.0', expected => 110, config => {max => -1}}, ); test_dynamic_limit(%$_) for @cases; subtest 'auto-detects threshold from nproc when configured as 0' => sub { my $mock_dl = Test::MockModule->new('OpenQA::Scheduler::DynamicLimit'); - $mock_dl->mock(_nproc => sub { 4 }); # 4 CPUs; threshold = 4*0.85 = 3.4; load 1.0 < 3.4*0.7=2.38 => scale up + $mock_dl->mock(_nproc => sub { 4 }); # 4 CPUs; threshold = 4*0.85 = 3.4; load 1.0 < 3.4*0.3=1.02 => fast up test_dynamic_limit( name => 'autothresh', initial => 100, load => '1.0 1.0 1.0', - expected => 110, + expected => 120, config => {threshold => 0}); }; +subtest 'auto-detects threshold from nproc (1 CPU)' => sub { + my $mock_dl = Test::MockModule->new('OpenQA::Scheduler::DynamicLimit'); + $mock_dl->mock(_nproc => sub { 1 }); # 1 CPU; threshold = 1*0.85 = 0.85; critical = 1*1.5 = 1.5 + test_dynamic_limit( + name => 'autothresh_1cpu_scale_up', + initial => 100, + load => '0.2 0.2 0.2', + # threshold = 0.85. 0.2 < 0.85*0.3 = 0.255. Fast up. + expected => 120, + config => {threshold => 0, critical => 0}); + test_dynamic_limit( + name => 'autothresh_1cpu_emergency', + initial => 100, + load => '2.0 2.0 2.0', + # critical = 1.5. 2.0 > 1.5. Emergency. + expected => 70, + config => {threshold => 0, critical => 0}); +}; + subtest '_nproc returns positive number of CPUs' => sub { my $nproc = OpenQA::Scheduler::DynamicLimit::_nproc(); cmp_ok $nproc, '>', 0, '_nproc returns a positive integer'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/35-script_clone_job.t new/openQA-5.1777995277.b985bea2/t/35-script_clone_job.t --- old/openQA-5.1777888278.38a3a85c/t/35-script_clone_job.t 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/35-script_clone_job.t 2026-05-05 17:34:37.000000000 +0200 @@ -52,7 +52,7 @@ ); subtest 'running command' => sub { - my $run = \&OpenQA::Script::CloneJob::_run_cmd; + my $run = \&OpenQA::Script::CloneJob::_run_cmd; ## no critic (Variables::ProtectPrivateVars) combined_like { like $run->('does-not-exist'), qr/Failed.*does-not-exist.*No such/i, 'error if command does not exist' } @@ -61,7 +61,7 @@ is $run->('true'), '', 'no error if command succeeds'; subtest 'get URL from command' => sub { - my $url_from_cmd = \&OpenQA::Script::CloneJob::_url_from_cmd; + my $url_from_cmd = \&OpenQA::Script::CloneJob::_url_from_cmd; ## no critic (Variables::ProtectPrivateVars) my $res = $url_from_cmd->(echo => qw(-n http://foo/bar)); is $res, 'http://foo/bar', 'got URL'; is ref $res, 'Mojo::URL', 'URL returned as Mojo::URL ref'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/api/10-jobgroups.t new/openQA-5.1777995277.b985bea2/t/api/10-jobgroups.t --- old/openQA-5.1777888278.38a3a85c/t/api/10-jobgroups.t 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/api/10-jobgroups.t 2026-05-05 17:34:37.000000000 +0200 @@ -597,7 +597,7 @@ }; subtest 'helper for removing test suite defaults' => sub { - my $helper = \&OpenQA::Schema::Result::JobGroups::_remove_test_suite_defaults; + my $helper = \&OpenQA::Schema::Result::JobGroups::_remove_test_suite_defaults; ## no critic (Variables::ProtectPrivateVars) my $group = {scenarios => {x86_64 => {product => [{foo => {machine => '64bit'}}]}}}; my $test_suites = {x86_64 => {foo => 1}}; my $scenarios = []; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/t/lib/OpenQA/Test/Utils.pm new/openQA-5.1777995277.b985bea2/t/lib/OpenQA/Test/Utils.pm --- old/openQA-5.1777888278.38a3a85c/t/lib/OpenQA/Test/Utils.pm 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/t/lib/OpenQA/Test/Utils.pm 2026-05-05 17:34:37.000000000 +0200 @@ -304,8 +304,8 @@ if ($bogus) { monkey_patch 'OpenQA::WebSockets::Controller::Worker', ws => sub { my $c = shift; - $c->on(json => \&OpenQA::WebSockets::Controller::Worker::_message); - $c->on(finish => \&OpenQA::WebSockets::Controller::Worker::_finish); + $c->on(json => \&OpenQA::WebSockets::Controller::Worker::_message); ## no critic (Variables::ProtectPrivateVars) + $c->on(finish => \&OpenQA::WebSockets::Controller::Worker::_finish); ## no critic (Variables::ProtectPrivateVars) }; } local @ARGV = ('daemon'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/admin/job_template/index.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/admin/job_template/index.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/admin/job_template/index.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/admin/job_template/index.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -71,7 +71,7 @@ <p> A job template is a combination of machine, product and test suite settings. These combination are used to produce actual jobs within a certain job group. Check out - <a href="http://open.qa/docs/#_using_job_templates_to_automate_jobs_creation" target="blank">the documentation</a> + <a href="https://open.qa/docs/#using-job-templates-to-automate-jobs-creation" target="blank">the documentation</a> for more details. </p> % if (!$force_yaml_editor) { @@ -182,7 +182,7 @@ <div class="row"> <div class="col-sm-5 editor-yaml-guide" style="display: none"> <p class="buttons"> - <a href="http://open.qa/docs/#_job_group_editor_gh2111" target="blank" class="btn btn-light"> + <a href="https://open.qa/docs/#job-group-editor-gh" target="blank" class="btn btn-light"> <i class="fa-solid fa-book"></i><span>YAML editor documentation</span> </a> </p> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/admin/mcp_help.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/admin/mcp_help.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/admin/mcp_help.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/admin/mcp_help.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -4,5 +4,5 @@ %= include 'layouts/info' <p> To configure an MCP client to connect to openQA, check out the - <%= link_to 'documentation about MCP support' => url_for('https://open.qa/docs/#_mcp_support') %>. + <%= link_to 'documentation about MCP support' => url_for('https://open.qa/docs/#mcp-support') %>. </p> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/comments/add_comment_form_groups.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/comments/add_comment_form_groups.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/comments/add_comment_form_groups.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/comments/add_comment_form_groups.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -58,7 +58,7 @@ % } <br> %= include_branding 'commenting_tools'; - %= help_popover 'Help for comments' => $help_text, 'https://open.qa/docs/#_use_of_the_web_interface' => 'the documentation' + %= help_popover 'Help for comments' => $help_text, 'https://open.qa/docs/#use-of-the-web-interface' => 'the documentation' </span> </div> </div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/main/index.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/main/index.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/main/index.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/main/index.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -68,14 +68,14 @@ <input value="1" name="show_tags" type="checkbox" id="filter-show-tags"> <label class="form-label" for="filter-show-tags">Show tags</label> <%= help_popover('Help for <i>Show tags</i>' => '<p>Show tags from the corresponding group overview comments</p>', - 'https://open.qa/docs/#_build_tagging' => 'the documentation') + 'https://open.qa/docs/#build-tagging' => 'the documentation') %> <input value="1" name="only_tagged" type="checkbox" id="filter-only-tagged"> <label class="form-label" for="filter-only-tagged">Only tagged</label> <%= help_popover('Help for <i>Only tagged</i>' => ' <p>Show only builds that have been tagged in the corresponding group overview comments</p> <p>Implies <i>Show tags</i></p>', - 'https://open.qa/docs/#_build_tagging' => 'the documentation') + 'https://open.qa/docs/#build-tagging' => 'the documentation') %> <input value="1" name="fullscreen" type="checkbox" id="filter-fullscreen"> <label class="form-label" for="filter-fullscreen">Full screen</label> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/test/create.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/test/create.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/test/create.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/test/create.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -49,7 +49,7 @@ <div class="col-md-6"> <label for="create-tests-casedir" class="form-label"><strong>Test repository (<code>CASEDIR</code>)</strong></label> <%= help_popover('Test repository' => '<p>Specifies the URL of the Git repository containing tests. May also be left blank or point to a local directory.</p>', - 'https://open.qa/docs/#_triggering_tests_based_on_an_any_remote_git_refspec_or_open_github_pull_request', 'the documentation', 'left') %> + 'https://open.qa/docs/#triggering-tests-based-on-an-any-remote-git-refspec-or-open-github-pull-request', 'the documentation', 'left') %> <input type="text" class="form-control" id="create-tests-casedir" value="<%= $preset->{casedir} // '' %>" name="CASEDIR"> </div> <div class="col-md-6"> @@ -62,7 +62,7 @@ <label for="create-tests-settings" class="form-label"><strong>Additional settings</strong></label> <%= help_popover('Test repository' => '<p>Specifies additional settings as newline-separated <code>KEY=value</code>-pairs that will be assigned to each job. ' . 'Some settings also influence the job creation itself, e.g. <code>_OBSOLETE</code>.</p>', - 'https://open.qa/docs/#_spawning_multiple_jobs_based_on_templates_isos_post', 'the documentation', 'left') %> + 'https://open.qa/docs/#spawning-multiple-jobs-based-on-templates---isos-post', 'the documentation', 'left') %> <textarea class="form-control key-value-pairs" id="create-tests-settings" rows="15"></textarea> </div> <div class="col-md-6"> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/test/infopanel.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/test/infopanel.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/test/infopanel.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/test/infopanel.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -130,7 +130,7 @@ <span class="prio-value"><%= $job->priority %></span> % } % } - <a href="https://open.qa/docs/#_job_groups_2" target="_blank"><i class="fa-regular fa-circle-question" data-bs-toggle="tooltip" data-bs-title="Jobs with lower priority values are scheduled earlier (default: 50)"></i></a> + <a href="https://open.qa/docs/#job-groups-1" target="_blank"><i class="fa-regular fa-circle-question" data-bs-toggle="tooltip" data-bs-title="Jobs with lower priority values are scheduled earlier (default: 50)"></i></a> </div> % } % if ($worker) { @@ -187,7 +187,7 @@ </ul> All rules are applied recursively. Advanced restarting options allow changing the behavior, e.g. excluding parents and $ok_results_explanation children. You can open the menu of advanced restarting options by clicking on the triangle icon on the left side of the <em>$restart_text</em> button for jobs with dependencies.", - 'https://open.qa/docs/#_handling_of_related_jobs_on_failure_cancellation_restart', 'documentation', 'bottom', class => 'help_popover fa-solid fa-circle-question btn btn-secondary'); + 'https://open.qa/docs/#handling-of-related-jobs-on-failure--cancellation--restart', 'documentation', 'bottom', class => 'help_popover fa-solid fa-circle-question btn btn-secondary'); %> </div> % } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1777888278.38a3a85c/templates/webapi/test/overview.html.ep new/openQA-5.1777995277.b985bea2/templates/webapi/test/overview.html.ep --- old/openQA-5.1777888278.38a3a85c/templates/webapi/test/overview.html.ep 2026-05-04 11:51:18.000000000 +0200 +++ new/openQA-5.1777995277.b985bea2/templates/webapi/test/overview.html.ep 2026-05-05 17:34:37.000000000 +0200 @@ -94,7 +94,7 @@ <p>Additional tweaking of the query is possible by leaving out query parameters completely or specifying them multiple times equivalent to an logical "or" search.</p>', - 'https://open.qa/docs/#_allow_group_overview_query_by_result_gh531' => 'the documentation') + 'https://open.qa/docs/#allow-group-overview-query-by-result-gh' => 'the documentation') %> <span>no filter present, click to toggle filter form</span> </div> ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.vfsijO/_old 2026-05-06 19:20:01.650350928 +0200 +++ /var/tmp/diff_new_pack.vfsijO/_new 2026-05-06 19:20:01.658351257 +0200 @@ -1,5 +1,5 @@ name: openQA -version: 5.1777888278.38a3a85c -mtime: 1777888278 -commit: 38a3a85c92a8473b9eb1fe3472cea5faa9e06263 +version: 5.1777995277.b985bea2 +mtime: 1777995277 +commit: b985bea28944e9257ed84ebc4f95af73d2f34a52
