diff --git a/external/os-autoinst-common/.github/workflows/base-commit-message-checker.yml b/external/os-autoinst-common/.github/workflows/base-commit-message-checker.yml new file mode 100644 index 0000000..480b718 --- /dev/null +++ b/external/os-autoinst-common/.github/workflows/base-commit-message-checker.yml @@ -0,0 +1,57 @@ +--- +name: 'Commit message check' + +on: + workflow_call: + secrets: + accessToken: + required: true + +jobs: + base-check-commit-message: + name: Check commit message + runs-on: ubuntu-latest + steps: + - name: Check subject beginning + uses: gsactions/commit-message-checker@v2 + with: + pattern: '^([A-Z]|\S+:|git subrepo pull)' + flags: 'g' + error: 'The subject does not start with a capital or tag.' + excludeDescription: 'true' + excludeTitle: 'true' + checkAllCommitMessages: 'true' + accessToken: ${{ secrets.accessToken }} + + - name: Check subject line length + uses: gsactions/commit-message-checker@v2 + with: + pattern: '^.{1,72}(\n|$)' + flags: 'g' + error: 'The maximum subject line length of 72 characters is exceeded.' + excludeDescription: 'true' + excludeTitle: 'true' + checkAllCommitMessages: 'true' + accessToken: ${{ secrets.accessToken }} + + - name: Check subject ending + uses: gsactions/commit-message-checker@v2 + with: + pattern: '^.+(?=2" + - "#changes-requested-reviews-by=0" + # https://doc.mergify.io/examples.html#require-all-requested-reviews-to-be-approved + - "#review-requested=0" + - -label~=^acceptance-tests-needed|not-ready + - base=master + actions: + merge: + method: merge + - name: automatic merge on special label + conditions: + - -label~=^acceptance-tests-needed|not-ready + - "label=merge-fast" + - base=master + actions: + merge: + method: merge + - name: ask to resolve conflict + conditions: + - conflict + actions: + comment: + message: This pull request is now in conflicts. Could you fix it? 🙏 diff --git a/external/os-autoinst-common/.perlcriticrc b/external/os-autoinst-common/.perlcriticrc new file mode 100644 index 0000000..0addc1f --- /dev/null +++ b/external/os-autoinst-common/.perlcriticrc @@ -0,0 +1,49 @@ +theme = community + openqa +severity = 4 +include = strict ValuesAndExpressions::ProhibitInterpolationOfLiterals + +verbose = ::warning file=%f,line=%l,col=%c,title=%m - severity %s::[%p] %e\n + +# == Perlcritic Policies +# -- Test::Most brings in strict & warnings +[TestingAndDebugging::RequireUseStrict] +equivalent_modules = Test::Most + +[TestingAndDebugging::RequireUseWarnings] +equivalent_modules = Test::Most + +# -- Avoid double quotes unless there's interpolation or a single quote. +[ValuesAndExpressions::ProhibitInterpolationOfLiterals] +allow_if_string_contains_single_quote = 1 +severity = 3 + +# -- Prohibit deep nesting +[ControlStructures::ProhibitDeepNests] +severity = 4 +add_themes = community +max_nests = 4 + +# == Community Policies +# -- Test::Most brings in strict & warnings +[Freenode::StrictWarnings] +extra_importers = Test::Most + +# -- Test::Most brings in strict & warnings +[Community::StrictWarnings] +extra_importers = Test::Most + +[Community::DiscouragedModules] +severity = 3 + +# Test modules have no package declaration +[Community::PackageMatchesFilename] +severity = 1 + +# == Custom Policies +# -- Useless quotes on hashes +[HashKeyQuotes] +severity = 5 + +# -- Superfluous use strict/warning. +[RedundantStrictWarning] +equivalent_modules = Test::Most diff --git a/external/os-autoinst-common/.perltidyrc b/external/os-autoinst-common/.perltidyrc new file mode 100644 index 0000000..60eb7ef --- /dev/null +++ b/external/os-autoinst-common/.perltidyrc @@ -0,0 +1,14 @@ +# Workaround needed for handling non-ASCII in files. +# # See . +--character-encoding=none +--no-valign +-l=160 +-fbl # don't change blank lines +-fnl # don't remove new lines +-nsfs # no spaces before semicolons +-baao # space after operators +-bbao # space before operators +-pt=2 # no spaces around () +-bt=2 # no spaces around [] +-sbt=2 # no spaces around {} +-sct # stack closing tokens )} diff --git a/external/os-autoinst-common/.proverc b/external/os-autoinst-common/.proverc new file mode 100644 index 0000000..4c07390 --- /dev/null +++ b/external/os-autoinst-common/.proverc @@ -0,0 +1,3 @@ +--formatter TAP::Formatter::File +--lib +xt/ diff --git a/external/os-autoinst-common/.tidyallrc b/external/os-autoinst-common/.tidyallrc new file mode 100644 index 0000000..d4c7a45 --- /dev/null +++ b/external/os-autoinst-common/.tidyallrc @@ -0,0 +1,3 @@ +[PerlTidy] +select = **/*.{pl,pm,t} tools/tidyall tools/perlcritic tools/update-deps +argv = --profile=$ROOT/.perltidyrc diff --git a/external/os-autoinst-common/LICENSE b/external/os-autoinst-common/LICENSE new file mode 100644 index 0000000..7ee9616 --- /dev/null +++ b/external/os-autoinst-common/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 openQA Development + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/os-autoinst-common/README.md b/external/os-autoinst-common/README.md new file mode 100644 index 0000000..ec95bdf --- /dev/null +++ b/external/os-autoinst-common/README.md @@ -0,0 +1,123 @@ +# Common files for os-autoinst/os-autoinst and os-autoinst/openQA + +This repository is to be used as a [git-subrepo] +(https://github.com/ingydotnet/git-subrepo). See the instructions below in the +[Git Subrepo Usage](#git-subrepo-usage) section + +All dependencies in this project are sourced from what's available in openSUSE +Tumbleweed RPM repositories. + +For developers not using RPM the tumbleweed repositories, a `cpanfile` is +provided and maintained in a best-effort basis. + +## Tooling offered + +This repo offers: + +* Static check configuration for perl projects: `.perltidyrc`, `.perlcriticrc`, + `.proverc` & `.tidyallrc`. +* Perlcritic policies that `os-autoinst/os-autoinst` and `os-autoinst/openQA` + share. +* Useful tools for linting & testing: + * A `perlcritic` wrapper that will automatically add Perlcritic rules + defined under `lib/perlcritic` and + `ext/os-autoinst-common/lib/perlcritic`. + * A `tidyall` wrapper that will validate the Perltidy version against the + `cpanfile` definition. + Because `Perl::Tidy` defaults may vary between versions this tool ensures + the version of perltidy matches the required version specified in the + `cpanfile` for non-`cpanm` based installs. + +* Example Github Actions for linting and unit testing for Perl. + +All files can be either copied or symlinked for any downstream repository +consuming these tools. + +## Running tools and tests from scratch + +```bash +# Run a container with the project mounted in it. +podman run -it -v "$PWD:/host/project" --workdir /host/project opensuse/leap:latest bash + +# Inside the container +zypper in -y perl-App-cpanminus make gcc +cpanm --installdeps . --with-develop + +prove . +./tools/tidyall --check-only --all --quiet +./tools/perlcritic --quiet . +``` + +## Git Subrepo Usage + +`git-subrepo` is available in the following repositories: + +[![Packaging status](https://repology.org/badge/vertical-allrepos/git-subrepo.svg)](https://repology.org/project/git-subrepo/versions) + +### Clone + +To use it in your repository, you would usually do something like this: + +```bash +cd your-repo +git subrepo clone git@github.com:os-autoinst/os-autoinst-common.git ext/os-autoinst-common +``` + +This will automatically create a commit with information on what command +was used. + +And then, if necessary, link files via symlinks to the places where you need +them. + +The cloned repository files will be part of your actual repository, so anyone +cloning this repo will have the files automatically without needing to use +`git-subrepo` themselves. + +`external` is just a convention, you can clone it into any directory. + +It's also possible to clone a branch (or a specific tag or sha): + +```bash +git subrepo clone git@github.com:os-autoinst/os-autoinst-common.git \ + -b branchname ext/os-autoinst-common +``` + +After cloning, you should see a file `ext/os-autoinst-common/.gitrepo` with +information about the cloned commit. + +### Pull + +To get the latest changes, you can pull: + +```bash +git subrepo pull ext/os-autoinst-common +``` + +If that doesn't work for whatever reason, you can also simply reclone it like +that: + +```bash +git subrepo clone --force git@github.com:os-autoinst/os-autoinst-common.git \ + ext/os-autoinst-common +``` + +### Making changes + +If you make changes in the subrepo inside of your top repo, you can simply +commit them and then do: + +```bash +git subrepo push ext/os-autoinst-common +``` + +## git-subrepo + +You can find more information here: + +* [Repository and usage](https://github.com/ingydotnet/git-subrepo) +* [A good comparison between subrepo, submodule and + subtree](https://github.com/ingydotnet/git-subrepo/blob/master/Intro.pod) + +## License + +This project is licensed under the MIT license, see LICENSE file for details. diff --git a/external/os-autoinst-common/cpanfile b/external/os-autoinst-common/cpanfile new file mode 100644 index 0000000..39389e7 --- /dev/null +++ b/external/os-autoinst-common/cpanfile @@ -0,0 +1,19 @@ +################################################## +# WARNING +# This file is autogenerated by tools/update-deps +# from dependencies.yaml +################################################## + +# Needed until preaction/Log-Any#105 is solved. +requires 'Storable', '>= 3.06'; + +feature 'cover' => sub { + requires 'Devel::Cover'; + requires 'Devel::Cover::Report::Codecov'; +}; +on 'develop' => sub { + requires 'Code::TidyAll'; + requires 'Perl::Critic'; + requires 'Perl::Critic::Community'; + requires 'Perl::Tidy', '== 20230912'; +}; diff --git a/external/os-autoinst-common/dependencies.yaml b/external/os-autoinst-common/dependencies.yaml new file mode 100644 index 0000000..2fccb0e --- /dev/null +++ b/external/os-autoinst-common/dependencies.yaml @@ -0,0 +1,26 @@ +--- +# % is placeholder for section. +# e.g.: +# % => develop +# %_requires => develop_requires +targets: + # List all %_requires into a cpanfile + cpanfile: [main, develop, cover] + cpanfile-targets: + # save %_require into cpanfile section + develop: develop + cover: cover + +main_requires: + # Needed until preaction/Log-Any#105 is solved. + perl(Storable): '>= 3.06' + +develop_requires: + perl(Perl::Tidy): '== 20230912' + perl(Code::TidyAll): + perl(Perl::Critic): + perl(Perl::Critic::Community): + +cover_requires: + perl(Devel::Cover): + perl(Devel::Cover::Report::Codecov): diff --git a/external/os-autoinst-common/lib/OpenQA/Test/PatchDeparse.pm b/external/os-autoinst-common/lib/OpenQA/Test/PatchDeparse.pm new file mode 100644 index 0000000..fa59761 --- /dev/null +++ b/external/os-autoinst-common/lib/OpenQA/Test/PatchDeparse.pm @@ -0,0 +1,65 @@ +package OpenQA::Test::PatchDeparse; +use Test::Most; + +# Monkeypatch B::Deparse +# https://progress.opensuse.org/issues/40895 +# related: https://github.com/pjcj/Devel--Cover/issues/142 +# http://perlpunks.de/corelist/mversion?module=B::Deparse + + +# This might be fixed in newer versions of perl/B::Deparse +# We only see a warning when running with Devel::Cover +if ( + $B::Deparse::VERSION + and ($B::Deparse::VERSION >= '1.40' and ($B::Deparse::VERSION <= '1.54')) + ) +{ + +#<<< do not let perltidy nor perlcritic touch this +## no critic (TestingAndDebugging::ProhibitNoStrict) +# This is not our code, and formatting should stay the same for +# better comparison with new versions of B::Deparse +# <---- PATCH +package B::Deparse; +no warnings 'redefine'; +no strict 'refs'; + +*{'B::Deparse::walk_lineseq'} = sub { + + my ($self, $op, $kids, $callback) = @_; + my @kids = @$kids; + for (my $i = 0; $i < @kids; $i++) { + my $expr = ''; + if (is_state $kids[$i]) { + # Patch for: + # Use of uninitialized value $expr in concatenation (.) or string at /usr/lib/perl5/5.26.1/B/Deparse.pm line 1794. + $expr = $self->deparse($kids[$i++], 0) // ''; # prevent undef $expr + if ($i > $#kids) { + $callback->($expr, $i); + last; + } + } + if (is_for_loop($kids[$i])) { + $callback->($expr . $self->for_loop($kids[$i], 0), + $i += $kids[$i]->sibling->name eq 'unstack' ? 2 : 1); + next; + } + my $expr2 = $self->deparse($kids[$i], (@kids != 1)/2) // ''; # prevent undef $expr2 + $expr2 =~ s/^sub :(?!:)/+sub :/; # statement label otherwise + $expr .= $expr2; + $callback->($expr, $i); + } + +}; +# ----> PATCH +#>>> + +} +elsif ($B::Deparse::VERSION) { + # when we update to a new perl version, this will remind us about checking + # if the bug is still there + diag + "Using B::Deparse v$B::Deparse::VERSION. If you see 'uninitialized' warnings, update patch in t/lib/OpenQA/Test/PatchDeparse.pm"; +} +## use critic +1; diff --git a/external/os-autoinst-common/lib/OpenQA/Test/TimeLimit.pm b/external/os-autoinst-common/lib/OpenQA/Test/TimeLimit.pm new file mode 100644 index 0000000..3f43182 --- /dev/null +++ b/external/os-autoinst-common/lib/OpenQA/Test/TimeLimit.pm @@ -0,0 +1,76 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package OpenQA::Test::TimeLimit; +use Test::Most; +use experimental 'signatures'; + +my $SCALE_FACTOR = $ENV{OPENQA_TEST_TIMEOUT_SCALE_FACTOR} // 1; + +sub import ($package, $limit = undef) { + die "$package: Need argument on import, e.g. use: use OpenQA::Test::TimeLimit '42';" unless $limit; + # disable timeout if requested by ENV variable or running within debugger + return if ($ENV{OPENQA_TEST_TIMEOUT_DISABLE} or $INC{'perl5db.pl'}); + $SCALE_FACTOR *= $ENV{OPENQA_TEST_TIMEOUT_SCALE_COVER} // 3 if Devel::Cover->can('report'); + $SCALE_FACTOR *= $ENV{OPENQA_TEST_TIMEOUT_SCALE_CI} // 2 if $ENV{CI}; + $limit *= $SCALE_FACTOR; + $SIG{ALRM} = sub { BAIL_OUT "test '$0' exceeds runtime limit of '$limit' seconds\n" }; + alarm $limit; +} + +sub scale_timeout ($time) { + return $time * $SCALE_FACTOR; +} + +1; + +=encoding utf8 + +=head1 NAME + +OpenQA::Test::TimeLimit - Limit test runtime + +=head1 SYNOPSIS + + use OpenQA::Test::TimeLimit '42'; + +=head1 DESCRIPTION + +This aborts a test if the specified runtime limit in seconds is +exceeded. + +Example output for t/basic.t: + + t/basic.t .. run... failed: test exceeds runtime limit of '1' seconds + +Example output for t/full-stack.t: + + ok 1 - assets are prefetched + [info] [pid:4324] setting database search path to public when registering Minion plugin + [info] Listening at "http://127.0.0.1:35182" + Server available at http://127.0.0.1:35182 + Bailout called. Further testing stopped: get: Server returned error message test exceeds runtime limit of '6' seconds at /home/okurz/local/os-autoinst/openQA/t/lib/OpenQA/SeleniumTest.pm:107 + Bail out! get: Server returned error message test exceeds runtime limit of '6' seconds at /home/okurz/local/os-autoinst/openQA/t/lib/OpenQA/SeleniumTest.pm:107 + FAILED--Further testing stopped: get: Server returned error message test exceeds runtime limit of '6' seconds at /home/okurz/local/os-autoinst/openQA/t/lib/OpenQA/SeleniumTest.pm:107 + +The timeout is scaled up when C is active as well as when +running in a CI environment where the environment variable C is set. Both +scaling factors can be overridden with environment variables +C and C +respectively. + +=head2 Alternatives considered + +* Just checking the runtime while not aborting the test - this idea has +not been followed as we want to prevent any external runners to run into +timeout first which can cause less obvious results +* https://metacpan.org/pod/Time::Limit - nice syntax that inspired me to +use a parameter on import but fails to completely stop tests including +all subprocesses +* https://metacpan.org/pod/Time::Out - applies a timeout to blocks, not +a complete module +* https://metacpan.org/pod/Time::SoFar - easy and simple but not +providing enough value to include +* https://metacpan.org/pod/Acme::Time::Baby - Just kidding ;) + +=cut diff --git a/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/ArgumentInUseStrictWarnings.pm b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/ArgumentInUseStrictWarnings.pm new file mode 100644 index 0000000..4c24edb --- /dev/null +++ b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/ArgumentInUseStrictWarnings.pm @@ -0,0 +1,42 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package Perl::Critic::Policy::ArgumentInUseStrictWarnings; + +use strict; +use warnings; +use experimental 'signatures'; +use base 'Perl::Critic::Policy'; + +use Perl::Critic::Utils qw( :severities :classification :ppi ); + +our $VERSION = '0.0.1'; + +sub default_severity { return $SEVERITY_HIGH } +sub default_themes { return qw(openqa) } +sub applies_to { return qw(PPI::Statement::Include) } + +my $desc = q{use strict/warnings with arguments}; +my $expl = q{Remove argument from: %s.}; + +# check that use use strict and warnings don't have arguments. +sub violates ($self, $elem, $document) { + # skip if it's not a use + return unless $elem->type() eq 'use'; + # skip if it's not a pragma + return unless my $pragma = $elem->pragma(); + # skip if it's not warnings or strict + return unless ($pragma eq 'warnings' || $pragma eq 'strict'); + + my @args = $elem->arguments(); + # skip if it doesn't have arguments + return if scalar(@args) == 0; + + # allow promoting warnings to FATAL + return if scalar(grep { $_->content eq 'FATAL' } @args); + + # Report the problem. + return $self->violation($desc, sprintf($expl, $elem), $elem); +} + +1; diff --git a/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/HashKeyQuotes.pm b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/HashKeyQuotes.pm new file mode 100644 index 0000000..d71f441 --- /dev/null +++ b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/HashKeyQuotes.pm @@ -0,0 +1,34 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package Perl::Critic::Policy::HashKeyQuotes; + +use strict; +use warnings; +use experimental 'signatures'; +use base 'Perl::Critic::Policy'; + +use Perl::Critic::Utils qw( :severities :classification :ppi ); + +our $VERSION = '0.0.1'; + +sub default_severity { return $SEVERITY_HIGH } +sub default_themes { return qw(openqa) } +sub applies_to { return qw(PPI::Token::Quote::Single PPI::Token::Quote::Double) } + +# check that hashes are not overly using quotes +# (os-autoinst coding style) +sub violates ($self, $elem, $document) { + #we only want the check hash keys + return if !is_hash_key($elem); + + my $c = $elem->content; + # special characters + return if $c =~ m/[- \/<>.=_:\\\$\|]/; + + my $desc = q{Hash key with quotes}; + my $expl = q{Avoid useless quotes}; + return $self->violation($desc, $expl, $elem); +} + +1; diff --git a/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/RedundantStrictWarning.pm b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/RedundantStrictWarning.pm new file mode 100644 index 0000000..80c099b --- /dev/null +++ b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/RedundantStrictWarning.pm @@ -0,0 +1,60 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package Perl::Critic::Policy::RedundantStrictWarning; + +use strict; +use warnings; +use version 0.77; +use experimental 'signatures'; + +use base 'Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict'; +use Perl::Critic::Utils qw{ $EMPTY }; +use Perl::Critic::Utils::Constants qw{ :equivalent_modules }; + +our $VERSION = '0.0.1'; +my $policy_title = q{Superfluoux use of strict/warning}; +my $policy_explanation = q{%s is equivalent to 'use strict; use warnings;'}; + +sub default_themes { return qw(openqa) } + +sub supported_parameters { + return ( + { + name => 'equivalent_modules', + description => + q, + default_string => $EMPTY, + behavior => 'string list', + list_always_present_values => ['warnings', 'strict', @STRICT_EQUIVALENT_MODULES], + }, + ); +} + +# check that use strict/warnings is not present when equivalent modules are. +sub violates ($self, $, $doc) { + # Find all equivalents of use strict/warnings. + my $stmnts_ref = $doc->find($self->_generate_is_use_strict()); + + # Bail if there's none. + return unless $stmnts_ref; + + # Bail out if there's only one. TestingAndDebugging::RequireUseStrict will report + # that there's no use strict/warnings. + return if scalar @{$stmnts_ref} == 1; + + # If the 'use strict' or 'use warnings' statement is present as well as a + # module already providing that behavior, -> it violates. + + my @viols; + + for my $stmnt (@{$stmnts_ref}) { + # skip pragmas + next if $stmnt->pragma(); + # Report the equivalent module. + push @viols, $self->violation($policy_title, sprintf($policy_explanation, $stmnt), $stmnt); + } + return @viols; +} + +1; diff --git a/external/os-autoinst-common/tools/perlcritic b/external/os-autoinst-common/tools/perlcritic new file mode 100755 index 0000000..8d2926a --- /dev/null +++ b/external/os-autoinst-common/tools/perlcritic @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later +# +# perlcritic with auto-injection of custom perlcritic rules. +use strict; +use warnings; +use experimental 'signatures'; +use FindBin '$Bin'; + +sub extra_include_paths (@extra_paths) { + my @paths = (); + foreach my $path (@extra_paths) { + push @paths, "$Bin/../$path"; + push @paths, "$Bin/../external/os-autoinst-common/$path"; + } + + # Remove non existing paths + return grep { -e $_ } @paths; +} + +$ENV{PERL5LIB} = join(':', (extra_include_paths('lib/perlcritic'), $ENV{PERL5LIB} // '')); + +exec 'perlcritic', @ARGV; diff --git a/external/os-autoinst-common/tools/tidyall b/external/os-autoinst-common/tools/tidyall new file mode 100755 index 0000000..91dba95 --- /dev/null +++ b/external/os-autoinst-common/tools/tidyall @@ -0,0 +1,55 @@ +#!/usr/bin/env perl +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Tidyall command with perltidy version constraint. +use strict; +use warnings; +use Perl::Tidy; +use Module::CPANfile; + +=item perltidy_version() + +Grabs the perltidy version from cpanfile using Module::CPANfile. + +=cut + +sub perltidy_version() { + my $version = Module::CPANfile->load('cpanfile') + ->prereq_for_module('Perl::Tidy') + ->requirement + ->version; + # Version requirements may contain qualifiers >=, ==, <, etc. The convention + # is to separate the qualifier from the actual version with a space. + # + # It's safe enough to assume that the last item is really the version. + return (split ' ', $version)[-1]; +} + +sub is_force_flag() { $_ eq '--force' } + +my $required_version = perltidy_version(); +my $detected_version = $Perl::Tidy::VERSION; +my @tidyall_argv = @ARGV; + +unless ($detected_version eq $required_version) { + print STDERR "Incorrect version of perltidy.\n"; + printf STDERR "- Detected: %s\n+ Required: %s\n\n", $detected_version, $required_version; + + my $force_run = grep { is_force_flag } @ARGV; + + unless ($force_run) { + printf STDERR "Please install the appropriate version of perltidy.\n"; + printf STDERR "If you want to proceed anyways, re run with --force flag.\n"; + exit 1; + } + + # tidyall does not know about the --force flag. + @tidyall_argv = grep { !is_force_flag } @tidyall_argv; + + print STDERR 'Proceeding to run with incorrect version of perltidy. '; + print STDERR "Results might not be consistent.\n"; + print STDERR "==================\n"; +} + +exec 'tidyall', @tidyall_argv; diff --git a/external/os-autoinst-common/tools/update-deps b/external/os-autoinst-common/tools/update-deps new file mode 100755 index 0000000..6b6bcd7 --- /dev/null +++ b/external/os-autoinst-common/tools/update-deps @@ -0,0 +1,199 @@ +#!/usr/bin/env perl +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +use strict; +use warnings; +use 5.010; + +use YAML::PP; +use Data::Dumper; +use Mojo::File qw(path); +use Getopt::Long; +use FindBin qw($Bin); + +GetOptions( + 'help|h' => \my $help, + 'specfile=s' => \my $specfile, + 'dockerfile=s' => \my $dockerfile, +); + +usage(0) if $help; +usage(1) unless $specfile; + +my $scriptname = path(__FILE__)->to_rel("$Bin/.."); +my $yamlfile = 'dependencies.yaml'; +my $file = "$Bin/../$yamlfile"; +my $cpanfile = "$Bin/../cpanfile"; + +my $data = YAML::PP->new->load_file($file); +my $spec = path($specfile)->slurp; + +my $spectargets = $data->{targets}->{spec}; +my $cpantargets = $data->{targets}->{cpanfile}; +my $dockertargets = $data->{targets}->{docker}; +my $cpantarget_mapping = $data->{targets}->{'cpanfile-targets'}; + +my ($modules_by_target) = get_modules($data, $cpantargets, $cpantarget_mapping); + +update_spec(); +update_cpanfile($modules_by_target); +update_dockerfile($dockerfile) if $dockerfile; + +sub update_dockerfile ($dockerfile) { + my $docker = path($dockerfile)->slurp; + my @perl; + my @pkg; + for my $target (@$dockertargets) { + my $name = $target . '_requires'; + my $deps = $data->{$name}; + for my $key (sort keys %$deps) { + next if $key =~ m/^%/; + my $line = ' '; + + if ($key =~ m/\(/) { + $key = "'$key'"; + } + $line .= $key; + $line .= " \\\n"; + if ($key =~ m/perl\(/) { + push @perl, $line; + } + else { + push @pkg, $line; + } + } + } + @perl = sort @perl; + @pkg = sort @pkg; + my %seen; + my $dep = join '', grep { not $seen{$_}++ } @pkg, @perl; + my $begin = '# AUTODEPS START'; + my $end = '# AUTODEPS END'; + my $run = <<"EOM"; +# This part is autogenerated by $scriptname from $yamlfile +# hadolint ignore=DL3034,DL3037 +RUN zypper in -y -C \\ +$dep && zypper clean +EOM + $docker =~ s/($begin\n)(.*)($end\n)/$1$run$3/s; + path($dockerfile)->spew($docker); + say "Updated $dockerfile"; +} + +sub update_spec() { + + for my $target (@$spectargets) { + my $name = $target . '_requires'; + my $deps = $data->{$name}; + my $prefix = "%define $name"; + my $specline = $prefix; + for my $key (sort keys %$deps) { + my $version = $deps->{$key}; + if (ref $version) { + $version = $version->{rpm}; + } + $specline .= " $key"; + if ($key eq 'perl(Perl::Tidy)') { + undef $version; + } + if ($version) { + $specline .= " $version"; + } + } + my $comment = "# The following line is generated from $yamlfile"; + if ($spec =~ s/^# .*generated.*\n^$prefix.*/$comment\n$specline/m) { + next; + } + # No comment above the line yet + unless ($spec =~ s/^$prefix.*/$comment\n$specline/m) { + die "/^$prefix/ not found in $specfile"; + } + } + + path($specfile)->spew($spec); + say "Updated $specfile"; +} + +sub get_modules ($data, $cpantargets, $cpantarget_mapping) { + my %modules_by_target; + for my $target (@$cpantargets) { + my $name = $target . '_requires'; + my $deps = $data->{$name}; + for my $key (keys %$deps) { + my $module = $key; + next unless $module =~ s/^perl\((.*)\)$/$1/; + my $version = $deps->{$key}; + if (ref $version) { + $version = $version->{perl}; + } + my $cpantarget = $cpantarget_mapping->{$target} || 'main'; + $modules_by_target{$cpantarget}->{$module} = $version; + } + } + return \%modules_by_target; +} + +sub _requires_line ($modules, $module) { + # Generates the following: + # requires 'Archive::Extract', '> 0.7'; + my $version = $modules->{$module}; + my $line = "requires '$module'"; + $line .= qq{, '$version'} if $version; + $line .= ";\n"; + return $line; +} + +sub update_cpanfile ($modules_by_target) { + my $cpan = <<"EOM"; +################################################## +# WARNING +# This file is autogenerated by $scriptname +# from $yamlfile +################################################## + +EOM + for my $module (sort keys %{$modules_by_target->{main}}) { + $cpan .= _requires_line($modules_by_target->{main}, $module); + } + my $test_requires = ''; + for my $module (sort keys %{$modules_by_target->{test}}) { + $test_requires .= ' ' . _requires_line($modules_by_target->{test}, $module); + } + my $cover_requires = ''; + for my $module (sort keys %{$modules_by_target->{cover}}) { + $cover_requires .= ' ' . _requires_line($modules_by_target->{cover}, $module); + } + my $devel_requires = ''; + for my $module (sort keys %{$modules_by_target->{devel}}) { + $devel_requires .= ' ' . _requires_line($modules_by_target->{devel}, $module); + } + $cpan .= <<"EOM"; + +on 'test' => sub { +$test_requires +}; + +on 'devel' => sub { +$devel_requires +}; + +feature 'coverage', 'coverage for CI' => sub { +$cover_requires +}; +EOM + + path($cpanfile)->spew($cpan); + say "Updated $cpanfile"; +} + +sub usage ($exit) { + print <<"EOM"; +Usage: + # update cpanfile and dist/rpm/os-autoinst.spec + $0 + $0 --specfile dist/rpm/os-autoinst.spec + $0 --dockerfile docker/ci/Dockerfile +EOM + exit $exit; +} diff --git a/external/os-autoinst-common/xt/02-use-timelimit.t b/external/os-autoinst-common/xt/02-use-timelimit.t new file mode 100644 index 0000000..d3d62b0 --- /dev/null +++ b/external/os-autoinst-common/xt/02-use-timelimit.t @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +use Test::Most; +use Test::Exception; + +throws_ok { + require OpenQA::Test::TimeLimit; + import OpenQA::Test::TimeLimit; +} qr/OpenQA::Test::TimeLimit: Need argument on import/, 'use without parameters is not allowed'; + +lives_ok { + require OpenQA::Test::TimeLimit; + import OpenQA::Test::TimeLimit 10; +} 'use with parameters is ok'; + +done_testing();