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-10-22 15:51:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.2252680 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Thu Oct 22 15:51:12 2026 rev:896 rq:1387001 version:5.1792607148.117af9ef Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2026-10-21 20:59:06.752070671 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new.2252680/openQA.changes 2026-10-22 15:54:58.719879809 +0200 @@ -1,0 +2,14 @@ +Wed Oct 21 18:26:05 UTC 2026 - [email protected] + +- Update to version 5.1792607148.117af9ef: + * feat: Add seasonal Halloween decorations + * fix(webapi): Validate all appearance fields + * refactor(ui): Move theme init script to bundle + +------------------------------------------------------------------- +Wed Oct 21 06:37:05 UTC 2026 - [email protected] + +- Update to version 5.1792563360.efc0128c: + * chore(deps): Dependency cron 2026-10-21 + +------------------------------------------------------------------- Old: ---- openQA-5.1792527840.d945a1a7.obscpio New: ---- openQA-5.1792607148.117af9ef.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.uL0K9A/_old 2026-10-22 15:55:02.738048239 +0200 +++ /var/tmp/diff_new_pack.uL0K9A/_new 2026-10-22 15:55:02.743048449 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1792527840.d945a1a7 +Version: 5.1792607148.117af9ef Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.uL0K9A/_old 2026-10-22 15:55:02.784050167 +0200 +++ /var/tmp/diff_new_pack.uL0K9A/_new 2026-10-22 15:55:02.785050209 +0200 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1792527840.d945a1a7 +Version: 5.1792607148.117af9ef Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.uL0K9A/_old 2026-10-22 15:55:02.818051593 +0200 +++ /var/tmp/diff_new_pack.uL0K9A/_new 2026-10-22 15:55:02.821051718 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1792527840.d945a1a7 +Version: 5.1792607148.117af9ef Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.uL0K9A/_old 2026-10-22 15:55:02.889054569 +0200 +++ /var/tmp/diff_new_pack.uL0K9A/_new 2026-10-22 15:55:02.895054821 +0200 @@ -104,7 +104,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1792527840.d945a1a7 +Version: 5.1792607148.117af9ef Release: 0 Summary: Framework for automated system-level testing (web-frontend, scheduler and tools) Group: Development/Tools/Other ++++++ openQA-5.1792527840.d945a1a7.obscpio -> openQA-5.1792607148.117af9ef.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/assets/assetpack.def new/openQA-5.1792607148.117af9ef/assets/assetpack.def --- old/openQA-5.1792527840.d945a1a7/assets/assetpack.def 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/assets/assetpack.def 2026-10-21 20:25:48.000000000 +0200 @@ -149,6 +149,7 @@ < javascripts/fullscreen.js < javascripts/obs_rsync.js < javascripts/parent_group_overview.js +< javascripts/theme.js < ../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js < ../node_modules/chosen-js/chosen.jquery.js < ../node_modules/jquery-ujs/src/rails.js diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/assets/javascripts/theme.js new/openQA-5.1792607148.117af9ef/assets/javascripts/theme.js --- old/openQA-5.1792527840.d945a1a7/assets/javascripts/theme.js 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-5.1792607148.117af9ef/assets/javascripts/theme.js 2026-10-21 20:25:48.000000000 +0200 @@ -0,0 +1,6 @@ +(() => { + const html = document.documentElement; + let theme = html.dataset.themePreference; + if (theme === 'detect') theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + html.dataset.bsTheme = theme; +})(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/assets/stylesheets/halloween.scss new/openQA-5.1792607148.117af9ef/assets/stylesheets/halloween.scss --- old/openQA-5.1792527840.d945a1a7/assets/stylesheets/halloween.scss 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-5.1792607148.117af9ef/assets/stylesheets/halloween.scss 2026-10-21 20:25:48.000000000 +0200 @@ -0,0 +1,242 @@ +// Seasonal decorations: cartoonish, unobtrusive decorations layered behind the content. +// The layout renders the decoration markup only when decorations are enabled (the +// "Seasonal decorations" setting is on, or auto during October) and the theme is not +// light, so pages in light mode and pages outside the season ship no decoration markup. +// The activation key is the server-provided data-seasonal-decorations; CSS resolves the +// browser preference of a "detect" user with the dark color scheme media query, so the +// client never adds a theme state the server did not decide. +// AssetPack serves assets below /asset/<checksum>/, so a relative url() in the bundled +// CSS would resolve to the CSS asset itself and an absolute path breaks under a baseurl, +// so the cursor has to stay an inline data URI. +#hw-defs { + display: none; +} +#halloween-overlay { + display: none; + position: fixed; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + opacity: 0.45; + > div { + position: absolute; + } + .hw-svg { + width: 100%; + height: 100%; + } + .hw-web { + width: 130px; + height: 130px; + color: #8a8a8a; + animation: hw-sway 6s ease-in-out infinite; + } + .hw-tl { + top: 0; + left: 0; + } + .hw-tr { + top: 0; + right: 0; + .hw-svg { + transform: scaleX(-1); + } + } + .hw-bl { + bottom: 0; + left: 0; + .hw-svg { + transform: scaleY(-1); + } + } + .hw-br { + bottom: 0; + right: 0; + .hw-svg { + transform: scale(-1, -1); + } + } + .hw-spider { + top: 0; + right: 18vw; + width: 40px; + height: 120px; + color: #444; + transform-origin: top center; + animation: hw-swing 4s ease-in-out infinite; + } + .hw-bat { + width: 34px; + height: 17px; + color: #777; + animation: hw-fly 18s linear infinite; + .hw-svg { + animation: hw-flap 0.4s ease-in-out infinite; + } + } + .hw-bat1 { + top: 12vh; + } + .hw-bat2 { + top: 22vh; + animation-delay: -6s; + animation-duration: 22s; + } + .hw-bat3 { + top: 8vh; + animation-delay: -12s; + animation-duration: 26s; + } + .hw-bat4 { + top: 18vh; + animation-delay: -9s; + animation-duration: 24s; + } + .hw-bat5 { + top: 26vh; + animation-delay: -3s; + animation-duration: 20s; + } + .hw-ghost { + top: 30vh; + right: 12vw; + width: 50px; + height: 66px; + color: #cdd6ff; + opacity: 0.7; + animation: hw-bob 4s ease-in-out infinite; + } + .hw-pumpkin { + bottom: 0; + width: 70px; + height: 63px; + animation: hw-flicker 3s ease-in-out infinite; + } + .hw-pumpkin-bl { + left: 2vw; + } + .hw-pumpkin-br { + right: 2vw; + animation-delay: -1.5s; + } + .hw-zombie { + bottom: 0; + left: 50%; + width: 60px; + height: 45px; + animation: hw-peek 5s ease-in-out infinite; + } +} +@mixin seasonal-active { + body { + // cursor is inherited by all descendants + /* stylelint-disable @stylistic/selector-list-comma-space-after */ + cursor: + url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24'><path fill='%23ff7b00' d='M12 8C6 8 2 12 2 17c0 5 4 7 10 7s10-2 10-7C22 12 18 8 12 8Z'/><path fill='%232e7d32' d='M11 8q1-3 3-3-1 1.5-1 3Z'/><path fill='%23111' d='M8 14h3l-1.5 4ZM13 14h3l-1.5 4ZM7 20q3 2 6 0 3 2 6 0l-1 1.5q-3 2-5 0-3 2-5 0Z'/><g stroke='%23111' stroke-width='0.8' fill='none'><circle cx='12' cy='4' r='1.5' fill='%23111'/><path d='M12 4 8 1M12 4 16 1M12 4 7 4M12 4 17 4M12 5 8 7M12 5 16 7'/></g></svg>") + 12 1, + auto; + /* stylelint-enable @stylistic/selector-list-comma-space-after */ + } + .card, .navbar, .footer, .progress, .well { + box-shadow: 0 0 10px rgba(255, 120, 0, 18%); + } + #content, .footer { + position: relative; + z-index: 2; + } + .navbar { + position: relative; + z-index: 10; + } + #halloween-overlay { + display: block; + } +} +html[data-seasonal-decorations='true'][data-theme-preference='dark'] { + @include seasonal-active; +} +@media (prefers-color-scheme: dark) { + html[data-seasonal-decorations='true'][data-theme-preference='detect'] { + @include seasonal-active; + } +} +@keyframes hw-sway { + 0% { + transform: rotate(0deg); + } + 50% { + transform: rotate(1.5deg); + } + 100% { + transform: rotate(0deg); + } +} +@keyframes hw-fly { + 0% { + transform: translateX(-12vw); + } + 100% { + transform: translateX(112vw); + } +} +@keyframes hw-flap { + 0% { + transform: scaleY(1); + } + 50% { + transform: scaleY(0.55); + } + 100% { + transform: scaleY(1); + } +} +@keyframes hw-bob { + 0% { + transform: translateY(0); + } + 50% { + transform: translateY(-14px); + } + 100% { + transform: translateY(0); + } +} +@keyframes hw-flicker { + 0% { + opacity: 0.55; + } + 50% { + opacity: 0.85; + } + 100% { + opacity: 0.55; + } +} +@keyframes hw-peek { + 0% { + transform: translateY(18px); + } + 50% { + transform: translateY(0); + } + 100% { + transform: translateY(18px); + } +} +@keyframes hw-swing { + 0% { + transform: rotate(-6deg); + } + 50% { + transform: rotate(6deg); + } + 100% { + transform: rotate(-6deg); + } +} +@media (prefers-reduced-motion: reduce) { + #halloween-overlay, #halloween-overlay * { + animation: none !important; + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/assets/stylesheets/openqa.scss new/openQA-5.1792607148.117af9ef/assets/stylesheets/openqa.scss --- old/openQA-5.1792527840.d945a1a7/assets/stylesheets/openqa.scss 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/assets/stylesheets/openqa.scss 2026-10-21 20:25:48.000000000 +0200 @@ -24,3 +24,4 @@ @import 'comments'; @import 'overview'; @import 'parent_group_overview'; +@import 'halloween'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/lib/OpenQA/WebAPI/Controller/Appearance.pm new/openQA-5.1792607148.117af9ef/lib/OpenQA/WebAPI/Controller/Appearance.pm --- old/openQA-5.1792527840.d945a1a7/lib/OpenQA/WebAPI/Controller/Appearance.pm 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/lib/OpenQA/WebAPI/Controller/Appearance.pm 2026-10-21 20:25:48.000000000 +0200 @@ -11,10 +11,14 @@ sub save ($self) { my $validation = $self->validation; $validation->required('theme')->in('light', 'dark', 'detect'); - return $self->reply->exception('Invalid theme settings') unless $validation->is_valid; + $validation->optional('seasonal_decorations')->in('auto', 'on', 'off'); + # is_valid would only look at the last validated field + return $self->reply->exception('Invalid theme settings') if $validation->has_error; my $theme = $validation->param('theme'); $self->session->{theme} = $theme; + my $seasonal = $validation->param('seasonal_decorations'); + $self->session->{seasonal_decorations} = $seasonal if defined $seasonal; $self->flash(info => 'Theme preferences updated'); $self->redirect_to('appearance'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/lib/OpenQA/WebAPI/Plugin/Helpers.pm new/openQA-5.1792607148.117af9ef/lib/OpenQA/WebAPI/Plugin/Helpers.pm --- old/openQA-5.1792527840.d945a1a7/lib/OpenQA/WebAPI/Plugin/Helpers.pm 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/lib/OpenQA/WebAPI/Plugin/Helpers.pm 2026-10-21 20:25:48.000000000 +0200 @@ -81,6 +81,13 @@ $app->helper(current_job => sub ($c) { $c->stash('job') }); $app->helper(current_theme => sub ($c) { $c->session->{theme} || 'light' }); + $app->helper(seasonal_decorations => sub ($c) { $c->session->{seasonal_decorations} || 'auto' }); + $app->helper(is_seasonal_period => sub ($c = undef) { (localtime)[4] == 9 }); + $app->helper( + seasonal_decorations_enabled => sub ($c) { + my $mode = $c->seasonal_decorations; + $mode eq 'on' || ($mode eq 'auto' && $c->is_seasonal_period); + }); $app->helper(is_operator_js => sub ($c) { Mojo::ByteStream->new($c->helpers->is_operator ? 'true' : 'false') }); $app->helper(is_admin_js => sub ($c) { Mojo::ByteStream->new($c->helpers->is_admin ? 'true' : 'false') }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/t/ui/04-appearance.t new/openQA-5.1792607148.117af9ef/t/ui/04-appearance.t --- old/openQA-5.1792527840.d945a1a7/t/ui/04-appearance.t 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/t/ui/04-appearance.t 2026-10-21 20:25:48.000000000 +0200 @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later use Test::Most; +use Mojo::Base -signatures; use FindBin; use lib "$FindBin::Bin/../lib", "$FindBin::Bin/../../external/os-autoinst-common/lib"; @@ -14,50 +15,86 @@ $test_case->init_data(fixtures_glob => '03-users.pl'); my $t = Test::Mojo->new('OpenQA::WebAPI'); +my $season = $t->app->is_seasonal_period ? 'true' : 'false'; + +sub check_form ($theme, $mode) { + $t->get_ok('/appearance')->status_is(200)->element_exists(qq{select#theme option[selected][value="$theme"]}) + ->element_exists(qq{select#seasonal_decorations option[selected][value="$mode"]}); +} + +sub check_page ($theme, $enabled, $overlay) { + $t->get_ok('/')->status_is(200)->element_exists(qq{html[data-theme-preference="$theme"]}) + ->element_exists(qq{html[data-seasonal-decorations="$enabled"]}); + if ($overlay) { + $t->element_exists('div#halloween-overlay'); + } + else { + $t->element_exists_not('div#halloween-overlay'); + } +} subtest 'No login, no themes' => sub { $t->get_ok('/appearance')->status_is(302); }; -subtest 'So lets grab the CSRF token and login as Percival' => sub { +subtest 'Login as Percival' => sub { $t->get_ok('/tests'); - my $token = $t->tx->res->dom->at('meta[name=csrf-token]')->attr('content'); $test_case->login($t, 'percival'); + $t->ua->max_redirects(5); }; -subtest 'Default theme is light' => sub { - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="light"]'); +subtest 'Default is light theme with seasonal decorations enabled during October' => sub { + check_form('light', 'auto'); + check_page('light', $season, 0); }; -subtest 'We can switch to dark theme' => sub { - $t->ua->max_redirects(5); - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="light"]') - ->element_exists_not('select option[selected][value="dark"]'); - $t->post_ok('/appearance' => form => {theme => 'dark'})->status_is(200) - ->element_exists('select option[selected][value="dark"]') - ->element_exists_not('select option[selected][value="light"]'); - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="dark"]') - ->element_exists_not('select option[selected][value="light"]'); -}; - -subtest 'We can switch to theme detection' => sub { - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="dark"]') - ->element_exists_not('select option[selected][value="detect"]'); - $t->post_ok('/appearance' => form => {theme => 'detect'})->status_is(200) - ->element_exists('select option[selected][value="detect"]') - ->element_exists_not('select option[selected][value="dark"]'); - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="detect"]') - ->element_exists_not('select option[selected][value="dark"]'); -}; - -subtest 'We can switch back to light theme' => sub { - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="detect"]') - ->element_exists_not('select option[selected][value="light"]'); - $t->post_ok('/appearance' => form => {theme => 'light'})->status_is(200) - ->element_exists('select option[selected][value="light"]') - ->element_exists_not('select option[selected][value="detect"]'); - $t->get_ok('/appearance')->status_is(200)->element_exists('select option[selected][value="light"]') - ->element_exists_not('select option[selected][value="detect"]'); +subtest 'Explicit dark theme gets decorations during October' => sub { + $t->post_ok('/appearance' => form => {theme => 'dark', seasonal_decorations => 'auto'})->status_is(200); + check_form('dark', 'auto'); + check_page('dark', $season, $season eq 'true'); +}; + +subtest 'Theme detection is resolved by the browser, so the markup is shipped during October' => sub { + $t->post_ok('/appearance' => form => {theme => 'detect', seasonal_decorations => 'auto'})->status_is(200); + check_form('detect', 'auto'); + check_page('detect', $season, $season eq 'true'); +}; + +subtest 'Seasonal decorations can be enabled all year' => sub { + $t->post_ok('/appearance' => form => {theme => 'dark', seasonal_decorations => 'on'})->status_is(200); + check_form('dark', 'on'); + check_page('dark', 'true', 1); +}; + +subtest 'Seasonal decorations can be disabled' => sub { + $t->post_ok('/appearance' => form => {theme => 'dark', seasonal_decorations => 'off'})->status_is(200); + check_form('dark', 'off'); + check_page('dark', 'false', 0); +}; + +subtest 'Seasonal decorations are not shown in light mode' => sub { + $t->post_ok('/appearance' => form => {theme => 'light', seasonal_decorations => 'on'})->status_is(200); + check_form('light', 'on'); + check_page('light', 'true', 0); +}; + +subtest 'Omission of seasonal_decorations preserves existing preference' => sub { + $t->post_ok('/appearance' => form => {theme => 'dark'})->status_is(200); + check_form('dark', 'on'); + check_page('dark', 'true', 1); +}; + +subtest 'Seasonal decoration labels are sentence case' => sub { + $t->get_ok('/appearance')->status_is(200); + is $t->tx->res->dom->at('label[for=seasonal_decorations]')->text, 'Seasonal decorations', 'label is sentence case'; + is $t->tx->res->dom->at('select#seasonal_decorations option[value=auto]')->text, + 'Automatically during October', 'auto option is sentence case'; +}; + +subtest 'Invalid parameters are rejected' => sub { + $t->post_ok('/appearance' => form => {theme => 'dark', seasonal_decorations => 'bogus'})->status_is(500); + $t->post_ok('/appearance' => form => {theme => 'bogus', seasonal_decorations => 'auto'})->status_is(500); + check_form('dark', 'on'); }; done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/templates/webapi/appearance/index.html.ep new/openQA-5.1792607148.117af9ef/templates/webapi/appearance/index.html.ep --- old/openQA-5.1792527840.d945a1a7/templates/webapi/appearance/index.html.ep 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/templates/webapi/appearance/index.html.ep 2026-10-21 20:25:48.000000000 +0200 @@ -7,8 +7,8 @@ <div class="card-body"> %= form_for appearance => (method => 'post') => begin <div class="mb-3"> - <label class="form-label" for="expiration">Theme</label> - <select name="theme" class="form-select"> + <label class="form-label" for="theme">Theme</label> + <select name="theme" id="theme" class="form-select"> % my $theme = current_theme; <option value="light"<%= $theme eq 'light' ? ' selected' : '' %>>Light mode</option> <option value="dark"<%= $theme eq 'dark' ? ' selected' : '' %>>Dark mode</option> @@ -16,6 +16,15 @@ </select> </div> <div class="mb-3"> + <label class="form-label" for="seasonal_decorations">Seasonal decorations</label> + <select name="seasonal_decorations" id="seasonal_decorations" class="form-select"> + % my $mode = seasonal_decorations; + <option value="auto"<%= $mode eq 'auto' ? ' selected' : '' %>>Automatically during October</option> + <option value="on"<%= $mode eq 'on' ? ' selected' : '' %>>Always</option> + <option value="off"<%= $mode eq 'off' ? ' selected' : '' %>>Never</option> + </select> + </div> + <div class="mb-3"> %= submit_button 'Save', class => 'btn btn-primary' </div> % end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/templates/webapi/layouts/bootstrap.html.ep new/openQA-5.1792607148.117af9ef/templates/webapi/layouts/bootstrap.html.ep --- old/openQA-5.1792527840.d945a1a7/templates/webapi/layouts/bootstrap.html.ep 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/templates/webapi/layouts/bootstrap.html.ep 2026-10-21 20:25:48.000000000 +0200 @@ -1,5 +1,7 @@ +% my $theme = current_theme; +% my $decorations = seasonal_decorations_enabled; <!DOCTYPE html> -<html lang="en"> +<html lang="en" data-theme-preference="<%= $theme %>" data-seasonal-decorations="<%= $decorations ? 'true' : 'false' %>"> <head> <!-- Meta, title, CSS, favicons, etc. --> <meta charset="utf-8"> @@ -77,10 +79,8 @@ </div> </div> </footer> - <script> - let theme = '<%= current_theme %>'; - if (theme === 'detect') theme = window.matchMedia('(prefers-color-scheme: dark)').matches === true ? 'dark' : 'light'; - document.documentElement.dataset.bsTheme = theme; - </script> +% if ($decorations && $theme ne 'light') { +%= include 'layouts/halloween' +% } </body> </html> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/templates/webapi/layouts/halloween.html.ep new/openQA-5.1792607148.117af9ef/templates/webapi/layouts/halloween.html.ep --- old/openQA-5.1792527840.d945a1a7/templates/webapi/layouts/halloween.html.ep 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-5.1792607148.117af9ef/templates/webapi/layouts/halloween.html.ep 2026-10-21 20:25:48.000000000 +0200 @@ -0,0 +1,55 @@ +<svg id="hw-defs" aria-hidden="true"> + <defs> + <symbol id="hw-web" viewBox="0 0 100 100"> + <g fill="none" stroke="currentColor" stroke-width="1.4"> + <path d="M0 0 100 0M0 0 96.6 25.9M0 0 86.6 50M0 0 70.7 70.7M0 0 50 86.6M0 0 25.9 96.6M0 0 0 100" /> + <path d="M30 0A30 30 0 0 1 0 30M60 0A60 60 0 0 1 0 60M90 0A90 90 0 0 1 0 90M100 0A100 100 0 0 1 0 100" /> + </g> + </symbol> + <symbol id="hw-bat" viewBox="0 0 100 50"> + <path fill="currentColor" d="M50 18C42 9 27 7 16 16c7-4 13-2 15 4C21 18 12 24 8 32c10-6 18-4 24 2 8-6 14-6 18-2 4-4 10-4 18 2 6-6 14-8 22-2-4-8-13-14-23-12 2-6 8-8 15-4C73 7 58 9 50 18Z" /> + <path fill="currentColor" d="M46 12 50 5 54 12Z" /> + </symbol> + <symbol id="hw-ghost" viewBox="0 0 60 80"> + <path fill="currentColor" d="M30 4C15 4 8 19 8 33v27l6-6 6 10 10-10 10 10 6-10 6 6V33C52 19 45 4 30 4Z" /> + <circle cx="22" cy="28" r="4" fill="#111" /> + <circle cx="38" cy="28" r="4" fill="#111" /> + <path d="M24 40q6 6 12 0" stroke="#111" stroke-width="2" fill="none" /> + </symbol> + <symbol id="hw-pumpkin" viewBox="0 0 100 90"> + <path fill="#ff7b00" d="M50 18C30 18 12 34 12 54c0 20 18 32 38 32s38-12 38-32C88 34 70 18 50 18Z" /> + <path fill="#2e7d32" d="M48 18q2-12 6-12-2 6-2 12Z" /> + <path fill="#111" d="M35 45h10l-5 12ZM55 45h10l-5 12ZM30 62q10 8 20 0 10 8 20 0l-2 6q-10 8-18 0-10 8-18 0Z" /> + </symbol> + <symbol id="hw-zombie" viewBox="0 0 80 60"> + <path fill="#7cb342" d="M10 60V30C10 12 30 6 40 6s30 6 30 24v30Z" /> + <circle cx="28" cy="32" r="6" fill="#fff" /> + <circle cx="52" cy="32" r="6" fill="#fff" /> + <circle cx="28" cy="32" r="2.5" fill="#222" /> + <circle cx="52" cy="32" r="2.5" fill="#222" /> + <path d="M22 48q18 10 36 0" stroke="#222" stroke-width="3" fill="none" /> + </symbol> + <symbol id="hw-spider" viewBox="0 0 40 60"> + <line x1="20" y1="0" x2="20" y2="26" stroke="currentColor" stroke-width="1" /> + <ellipse cx="20" cy="34" rx="6" ry="8" fill="currentColor" /> + <circle cx="20" cy="26" r="3.5" fill="currentColor" /> + <path d="M20 28 8 18M20 28 32 18M20 30 6 30M20 30 34 30M20 36 8 46M20 36 32 46M20 38 12 52M20 38 28 52" stroke="currentColor" stroke-width="1.2" fill="none" /> + </symbol> + </defs> +</svg> +<div id="halloween-overlay" aria-hidden="true"> + <div class="hw-web hw-tl"><svg class="hw-svg"><use href="#hw-web" /></svg></div> + <div class="hw-web hw-tr"><svg class="hw-svg"><use href="#hw-web" /></svg></div> + <div class="hw-web hw-bl"><svg class="hw-svg"><use href="#hw-web" /></svg></div> + <div class="hw-web hw-br"><svg class="hw-svg"><use href="#hw-web" /></svg></div> + <div class="hw-spider"><svg class="hw-svg"><use href="#hw-spider" /></svg></div> + <div class="hw-bat hw-bat1"><svg class="hw-svg"><use href="#hw-bat" /></svg></div> + <div class="hw-bat hw-bat2"><svg class="hw-svg"><use href="#hw-bat" /></svg></div> + <div class="hw-bat hw-bat3"><svg class="hw-svg"><use href="#hw-bat" /></svg></div> + <div class="hw-bat hw-bat4"><svg class="hw-svg"><use href="#hw-bat" /></svg></div> + <div class="hw-bat hw-bat5"><svg class="hw-svg"><use href="#hw-bat" /></svg></div> + <div class="hw-ghost"><svg class="hw-svg"><use href="#hw-ghost" /></svg></div> + <div class="hw-pumpkin hw-pumpkin-bl"><svg class="hw-svg"><use href="#hw-pumpkin" /></svg></div> + <div class="hw-pumpkin hw-pumpkin-br"><svg class="hw-svg"><use href="#hw-pumpkin" /></svg></div> + <div class="hw-zombie"><svg class="hw-svg"><use href="#hw-zombie" /></svg></div> +</div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1792527840.d945a1a7/tools/ci/autoinst.sha new/openQA-5.1792607148.117af9ef/tools/ci/autoinst.sha --- old/openQA-5.1792527840.d945a1a7/tools/ci/autoinst.sha 2026-10-20 22:24:00.000000000 +0200 +++ new/openQA-5.1792607148.117af9ef/tools/ci/autoinst.sha 2026-10-21 20:25:48.000000000 +0200 @@ -1 +1 @@ -5.044000-2bd94ba81d9b441255ddd19aad6368f900501724 \ No newline at end of file +5.044000-82c2f16f64f0a38f9fe932524c90636826be875f \ No newline at end of file ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.uL0K9A/_old 2026-10-22 15:55:15.547585178 +0200 +++ /var/tmp/diff_new_pack.uL0K9A/_new 2026-10-22 15:55:15.555585514 +0200 @@ -1,5 +1,5 @@ name: openQA -version: 5.1792527840.d945a1a7 -mtime: 1792527840 -commit: d945a1a7467aaf6ac963b16bb77b4e53836bb996 +version: 5.1792607148.117af9ef +mtime: 1792607148 +commit: 117af9ef0fc009cf9afa792d2e3915730183000f
