diff --git a/assets/javascripts/overview.js b/assets/javascripts/overview.js index 6625f67bec7d..b13810cfe794 100644 --- a/assets/javascripts/overview.js +++ b/assets/javascripts/overview.js @@ -252,6 +252,12 @@ function setupOverview() { modules_results.push(val); modulesResultFilter.val(modules_results).trigger('chosen:updated').trigger('change'); return formatFilter(val); + } else if (key === 'group_glob') { + $('#group-glob').prop('value', val); + return val; + } else if (key === 'not_group_glob') { + $('#not-group-glob').prop('value', val); + return val; } }); diff --git a/cpanfile b/cpanfile index 9316b2014f3d..a67c0ef848c0 100644 --- a/cpanfile +++ b/cpanfile @@ -79,6 +79,7 @@ requires 'Sort::Versions'; requires 'Storable'; requires 'Test::More'; requires 'Text::Diff'; +requires 'Text::Glob'; requires 'Time::HiRes'; requires 'Time::Moment'; requires 'Time::ParseDate'; diff --git a/dependencies.yaml b/dependencies.yaml index 4f9f4763d186..be050498222e 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -44,6 +44,7 @@ common_requires: rpm: '>= 9.340.0' perl(Regexp::Common): perl(Storable): + perl(Text::Glob): perl(Time::Moment): perl(Try::Tiny): perl(Config::Tiny): diff --git a/dist/rpm/openQA.spec b/dist/rpm/openQA.spec index 609fbbeffa54..c2df3539d23a 100644 --- a/dist/rpm/openQA.spec +++ b/dist/rpm/openQA.spec @@ -49,7 +49,7 @@ # The following line is generated from dependencies.yaml %define assetpack_requires perl(CSS::Minifier::XS) >= 0.01 perl(JavaScript::Minifier::XS) >= 0.11 perl(Mojolicious::Plugin::AssetPack) >= 1.36 perl(YAML::PP) >= 0.026 # The following line is generated from dependencies.yaml -%define common_requires ntp-daemon perl >= 5.20.0 perl(Carp::Always) >= 0.14.02 perl(Config::IniFiles) perl(Config::Tiny) perl(Cpanel::JSON::XS) >= 4.09 perl(Cwd) perl(Data::Dump) perl(Data::Dumper) perl(Digest::MD5) perl(Filesys::Df) perl(Getopt::Long) perl(Minion) >= 10.25 perl(Mojolicious) >= 9.340.0 perl(Regexp::Common) perl(Storable) perl(Time::Moment) perl(Try::Tiny) +%define common_requires ntp-daemon perl >= 5.20.0 perl(Carp::Always) >= 0.14.02 perl(Config::IniFiles) perl(Config::Tiny) perl(Cpanel::JSON::XS) >= 4.09 perl(Cwd) perl(Data::Dump) perl(Data::Dumper) perl(Digest::MD5) perl(Filesys::Df) perl(Getopt::Long) perl(Minion) >= 10.25 perl(Mojolicious) >= 9.340.0 perl(Regexp::Common) perl(Storable) perl(Text::Glob) perl(Time::Moment) perl(Try::Tiny) # runtime requirements for the main package that are not required by other sub-packages # The following line is generated from dependencies.yaml %define main_requires %assetpack_requires bsdtar git-core hostname perl(BSD::Resource) perl(Carp) perl(CommonMark) perl(Config::Tiny) perl(DBD::Pg) >= 3.7.4 perl(DBI) >= 1.632 perl(DBIx::Class) >= 0.082801 perl(DBIx::Class::DeploymentHandler) perl(DBIx::Class::DynamicDefault) perl(DBIx::Class::OptimisticLocking) perl(DBIx::Class::ResultClass::HashRefInflator) perl(DBIx::Class::Schema::Config) perl(DBIx::Class::Storage::Statistics) perl(Date::Format) perl(DateTime) perl(DateTime::Duration) perl(DateTime::Format::Pg) perl(Exporter) perl(Fcntl) perl(File::Basename) perl(File::Copy) perl(File::Copy::Recursive) perl(File::Path) perl(File::Spec) perl(FindBin) perl(Getopt::Long::Descriptive) perl(IO::Handle) perl(IPC::Run) perl(JSON::Validator) perl(LWP::UserAgent) perl(Module::Load::Conditional) perl(Module::Pluggable) perl(Mojo::Base) perl(Mojo::ByteStream) perl(Mojo::IOLoop) perl(Mojo::JSON) perl(Mojo::Pg) perl(Mojo::RabbitMQ::Client) >= 0.2 perl(Mojo::URL) perl(Mojo::Util) perl(Mojolicious::Commands) perl(Mojolicious::Plugin) perl(Mojolicious::Plugin::OAuth2) perl(Mojolicious::Static) perl(Net::OpenID::Consumer) perl(POSIX) perl(Pod::POM) perl(SQL::Translator) perl(Scalar::Util) perl(Sort::Versions) perl(Text::Diff) perl(Time::HiRes) perl(Time::ParseDate) perl(Time::Piece) perl(Time::Seconds) perl(URI::Escape) perl(YAML::PP) >= 0.026 perl(YAML::XS) perl(aliased) perl(base) perl(constant) perl(diagnostics) perl(strict) perl(warnings) diff --git a/lib/OpenQA/Constants.pm b/lib/OpenQA/Constants.pm index 45c9133f3a19..4fdaa30438c1 100644 --- a/lib/OpenQA/Constants.pm +++ b/lib/OpenQA/Constants.pm @@ -99,7 +99,7 @@ use constant VIDEO_FILE_NAME_REGEX => qr/^.*\/video\.[^\/]*$/; use constant FRAGMENT_REGEX => qr'(#([-?/:@.~!$&\'()*+,;=\w]|%[0-9a-fA-F]{2})*)*'; use constant JOBS_OVERVIEW_SEARCH_CRITERIA => - (qw(distri version flavor build test modules modules_result module_re group groupid id)); + (qw(distri version flavor build test modules modules_result module_re group groupid id group_glob not_group_glob)); our @EXPORT_OK = qw( WEBSOCKET_API_VERSION DEFAULT_WORKER_TIMEOUT diff --git a/lib/OpenQA/WebAPI/Plugin/Helpers.pm b/lib/OpenQA/WebAPI/Plugin/Helpers.pm index 18b7f2c24103..27cc651a5815 100644 --- a/lib/OpenQA/WebAPI/Plugin/Helpers.pm +++ b/lib/OpenQA/WebAPI/Plugin/Helpers.pm @@ -10,6 +10,7 @@ use OpenQA::Schema; use OpenQA::Utils qw(bugurl human_readable_size render_escaped_refs href_to_bugref); use OpenQA::Events; use OpenQA::Jobs::Constants qw(EXECUTION_STATES PRE_EXECUTION_STATES ABORTED_RESULTS FAILED NOT_COMPLETE_RESULTS); +use Text::Glob qw(glob_to_regex_string); sub register ($self, $app, $config) { $app->helper( @@ -423,6 +424,9 @@ sub _compose_job_overview_search_args ($c) { my $regexp = $v->every_param('module_re'); $search_args{module_re} = shift @$regexp if $regexp && @$regexp; + my $group_glob = [split(/\s*,\s*/, $v->param('group_glob'))]; + my $not_group_glob = [split(/\s*,\s*/, $v->param('not_group_glob'))]; + # add group query params to search args # (By 'every_param' we make sure to use multiple values for groupid and # group at the same time as a logical or, i.e. all specified groups are @@ -435,6 +439,17 @@ sub _compose_job_overview_search_args ($c) { my @search_terms = (@group_id_search, @group_name_search); @groups = $schema->resultset('JobGroups')->search(\@search_terms)->all; } + + # use globs to filter job groups, first include all groups that match "group_glob" values, and then exclude those + # that also match "not_group_glob" values + elsif (@$group_glob || @$not_group_glob) { + my @inclusive = map { qr/^$_$/i } map { glob_to_regex_string($_) } @$group_glob; + my @exclusive = map { qr/^$_$/i } map { glob_to_regex_string($_) } @$not_group_glob; + @groups = $schema->resultset('JobGroups')->all; + @groups = grep { _match_group(\@inclusive, $_) } @groups if @inclusive; + @groups = grep { !_match_group(\@exclusive, $_) } @groups if @exclusive; + } + # add flash message if optional "groupid" parameter is invalid $c->stash(flash_error => 'Specified "groupid" is invalid and therefore ignored.') if $c->param('groupid') && !$v->is_valid('groupid'); @@ -481,6 +496,14 @@ sub _compose_job_overview_search_args ($c) { return (\%search_args, \@groups); } +sub _match_group ($regexes, $group) { + my $name = $group->name; + for my $regex (@$regexes) { + return 1 if $name =~ $regex; + } + return 0; +} + sub _param_hash ($c, $name) { my $v = $c->validation; $v->optional($name, 'comma_separated', 'not_empty'); diff --git a/templates/webapi/test/overview.html.ep b/templates/webapi/test/overview.html.ep index 620046715188..88e546439d20 100644 --- a/templates/webapi/test/overview.html.ep +++ b/templates/webapi/test/overview.html.ep @@ -147,6 +147,27 @@ +
+
+
+ + <%= help_popover('Help for the Include job group filter' => ' +

Shows jobs from job groups matching these globs

') %> + +
+
+
+
+ + <%= help_popover('Help for the Exclude job groups filter' => ' +

Do not show jobs matching these globs

') %> + +
+
+
Misc