From 0c5c726ff744d7c586b047be96a4d47f8ebe7c87 Mon Sep 17 00:00:00 2001 From: ybonatakis Date: Sat, 10 Feb 2024 00:10:59 +0100 Subject: [PATCH] Clone external/os-autoinst-common subrepo: subdir: "external/os-autoinst-common" merged: "db78c61" upstream: origin: "https://github.com/os-autoinst/os-autoinst-common.git" branch: "master" commit: "db78c61" git-subrepo: version: "0.4.6" origin: "???" commit: "???" Signed-off-by: ybonatakis --- external/os-autoinst-common/.editorconfig | 12 + .../workflows/base-commit-message-checker.yml | 57 +++++ .../workflows/commit-message-checker.yml | 15 ++ .../.github/workflows/perl-author-tests.yml | 14 ++ .../.github/workflows/perl-critic.yml | 14 ++ .../.github/workflows/perl-lint-checks.yml | 14 ++ .../.github/workflows/yamllint.yml | 15 ++ external/os-autoinst-common/.gitignore | 1 + external/os-autoinst-common/.gitrepo | 12 + external/os-autoinst-common/.mergify.yml | 29 +++ external/os-autoinst-common/.perlcriticrc | 49 +++++ external/os-autoinst-common/.perltidyrc | 14 ++ external/os-autoinst-common/.tidyallrc | 3 + external/os-autoinst-common/.yamlignore | 0 external/os-autoinst-common/.yamllint | 25 +++ external/os-autoinst-common/LICENSE | 21 ++ external/os-autoinst-common/Makefile | 19 ++ external/os-autoinst-common/README.md | 68 ++++++ external/os-autoinst-common/cpanfile | 26 +++ external/os-autoinst-common/dependencies.yaml | 31 +++ .../lib/OpenQA/Test/PatchDeparse.pm | 67 ++++++ .../lib/OpenQA/Test/TimeLimit.pm | 76 +++++++ .../Policy/ArgumentInUseStrictWarnings.pm | 42 ++++ .../Perl/Critic/Policy/HashKeyQuotes.pm | 36 +++ .../Critic/Policy/RedundantStrictWarning.pm | 56 +++++ .../Critic/Policy/SpaceAfterSubroutineName.pm | 91 ++++++++ external/os-autoinst-common/tools/perlcritic | 20 ++ external/os-autoinst-common/tools/tidyall | 71 ++++++ external/os-autoinst-common/tools/update-deps | 206 ++++++++++++++++++ external/os-autoinst-common/xt/00-tidy.t | 7 + .../xt/01-compile-check-all.t | 20 ++ .../xt/01-make-update-deps.t | 28 +++ 32 files changed, 1159 insertions(+) create mode 100644 external/os-autoinst-common/.editorconfig create mode 100644 external/os-autoinst-common/.github/workflows/base-commit-message-checker.yml create mode 100644 external/os-autoinst-common/.github/workflows/commit-message-checker.yml create mode 100644 external/os-autoinst-common/.github/workflows/perl-author-tests.yml create mode 100644 external/os-autoinst-common/.github/workflows/perl-critic.yml create mode 100644 external/os-autoinst-common/.github/workflows/perl-lint-checks.yml create mode 100644 external/os-autoinst-common/.github/workflows/yamllint.yml create mode 100644 external/os-autoinst-common/.gitignore create mode 100644 external/os-autoinst-common/.gitrepo create mode 100644 external/os-autoinst-common/.mergify.yml create mode 100644 external/os-autoinst-common/.perlcriticrc create mode 100644 external/os-autoinst-common/.perltidyrc create mode 100644 external/os-autoinst-common/.tidyallrc create mode 100644 external/os-autoinst-common/.yamlignore create mode 100644 external/os-autoinst-common/.yamllint create mode 100644 external/os-autoinst-common/LICENSE create mode 100644 external/os-autoinst-common/Makefile create mode 100644 external/os-autoinst-common/README.md create mode 100644 external/os-autoinst-common/cpanfile create mode 100644 external/os-autoinst-common/dependencies.yaml create mode 100644 external/os-autoinst-common/lib/OpenQA/Test/PatchDeparse.pm create mode 100644 external/os-autoinst-common/lib/OpenQA/Test/TimeLimit.pm create mode 100644 external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/ArgumentInUseStrictWarnings.pm create mode 100644 external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/HashKeyQuotes.pm create mode 100644 external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/RedundantStrictWarning.pm create mode 100644 external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/SpaceAfterSubroutineName.pm create mode 100755 external/os-autoinst-common/tools/perlcritic create mode 100755 external/os-autoinst-common/tools/tidyall create mode 100755 external/os-autoinst-common/tools/update-deps create mode 100755 external/os-autoinst-common/xt/00-tidy.t create mode 100755 external/os-autoinst-common/xt/01-compile-check-all.t create mode 100755 external/os-autoinst-common/xt/01-make-update-deps.t diff --git a/external/os-autoinst-common/.editorconfig b/external/os-autoinst-common/.editorconfig new file mode 100644 index 0000000..503c34c --- /dev/null +++ b/external/os-autoinst-common/.editorconfig @@ -0,0 +1,12 @@ +[*] +indent_style = space +indent_size = 4 +binary_next_line = true +switch_case_indent = true +space_redirects = true + +[.bpan/**] +ignore = true + +[*~] +ignore = true 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..f83b61a --- /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 (clone|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 + - "#check-failure=0" + - "#check-pending=0" + - linear-history + 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..523db5c --- /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 )} \ No newline at end of file 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/.yamlignore b/external/os-autoinst-common/.yamlignore new file mode 100644 index 0000000..e69de29 diff --git a/external/os-autoinst-common/.yamllint b/external/os-autoinst-common/.yamllint new file mode 100644 index 0000000..0b3d54a --- /dev/null +++ b/external/os-autoinst-common/.yamllint @@ -0,0 +1,25 @@ +extends: default +ignore-from-file: [.gitignore, .yamlignore] + +rules: + line-length: + max: 160 + document-start: disable + indentation: + indent-sequences: true + spaces: 2 + + # Allows aligning subsequent lines with [] sequences + brackets: + min-spaces-inside: 0 + max-spaces-inside: -1 + commas: + max-spaces-after: -1 + + # Allows aligning key value pairs + colons: + max-spaces-after: -1 + + truthy: + allowed-values: ['true', 'false'] + check-keys: false 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/Makefile b/external/os-autoinst-common/Makefile new file mode 100644 index 0000000..c22489f --- /dev/null +++ b/external/os-autoinst-common/Makefile @@ -0,0 +1,19 @@ +.PHONY: help +help: + @echo Call one of the available targets: + @sed -n 's/\(^[^.#[:space:]A-Z]*\):.*$$/\1/p' Makefile | uniq + +.PHONY: update-deps +update-deps: + tools/update-deps --cpanfile cpanfile + +.PHONY: test +test: test-tidy test-author + +.PHONY: test-tidy +test-tidy: + tools/tidyall --all --check-only + +.PHONY: test-author +test-author: + prove -l -r xt/ diff --git a/external/os-autoinst-common/README.md b/external/os-autoinst-common/README.md new file mode 100644 index 0000000..537ea4b --- /dev/null +++ b/external/os-autoinst-common/README.md @@ -0,0 +1,68 @@ +# 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). + + +`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) + +## Usage + +### Clone + +To use it in your repository, you would usually do something like this: + + % 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. + +`ext` 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): + + % 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: + + % git subrepo pull ext/os-autoinst-common + +If that doesn't work for whatever reason, you can also simply reclone it like +that: + + % 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: + + % 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..bd53e7e --- /dev/null +++ b/external/os-autoinst-common/cpanfile @@ -0,0 +1,26 @@ +################################################## +# WARNING +# This file is autogenerated by tools/update-deps +# from dependencies.yaml +################################################## + +requires 'Module::CPANfile'; +requires 'Storable', '>= 3.06'; + +on 'test' => sub { + requires 'Test::Most'; + requires 'Test::Warnings'; + +}; + +on 'develop' => sub { + requires 'Code::TidyAll'; + requires 'Perl::Critic'; + requires 'Perl::Critic::Community'; + requires 'Perl::Tidy', '== 20230912'; + +}; + +feature 'coverage', 'coverage for CI' => sub { + +}; diff --git a/external/os-autoinst-common/dependencies.yaml b/external/os-autoinst-common/dependencies.yaml new file mode 100644 index 0000000..091db9d --- /dev/null +++ b/external/os-autoinst-common/dependencies.yaml @@ -0,0 +1,31 @@ +--- +# % is placeholder for section. +# e.g.: +# % => develop +# %_requires => develop_requires +targets: + # List all %_requires into a cpanfile + cpanfile: [main, develop, test] + cpanfile-targets: + # save %_require into cpanfile section + develop: develop + test: test + +main_requires: + # Needed until preaction/Log-Any#105 is solved. + perl(Storable): '>= 3.06' + perl(Module::CPANfile): + +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): + +test_requires: + perl(Test::Most): + perl(Test::Warnings): 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..ee69f2f --- /dev/null +++ b/external/os-autoinst-common/lib/OpenQA/Test/PatchDeparse.pm @@ -0,0 +1,67 @@ +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 ValuesAndExpressions::ProhibitInterpolationOfLiterals) +# 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..2a2dc70 --- /dev/null +++ b/external/os-autoinst-common/lib/OpenQA/Test/TimeLimit.pm @@ -0,0 +1,76 @@ +# Copyright 2020-2021 SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package OpenQA::Test::TimeLimit; +use Test::Most; + +my $SCALE_FACTOR = $ENV{OPENQA_TEST_TIMEOUT_SCALE_FACTOR} // 1; + +sub import { + my ($package, $limit) = @_; + 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 { + return $_[0] * $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..8290eab --- /dev/null +++ b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/HashKeyQuotes.pm @@ -0,0 +1,36 @@ +# 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) } +# we only want the check quoted expressions +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) { + # skip anything that's not a hash key + return () unless is_hash_key($elem); + + my $k = $elem->literal; + # skip anything that has a special symbol in the content + return () unless $k =~ m/^\w+$/; + + # report violation + my $desc = q{Hash key with quotes}; + my $expl = qq{Avoid useless quotes for key "$k"}; + 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..1f6a3b1 --- /dev/null +++ b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/RedundantStrictWarning.pm @@ -0,0 +1,56 @@ +# 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 $use_stmts = $doc->find($self->_generate_is_use_strict()); + + # Bail if there's none. + return unless $use_stmts; + + # Bail out if there's only one. TestingAndDebugging::RequireUseStrict will report + # that there's no use strict/warnings. + return if scalar @{$use_stmts} == 1; + + # If the 'use strict' or 'use warnings' statement is present as well as a + # module already providing that behavior, -> it violates. + return map { $self->_make_violation($_) } grep { !$_->pragma() } @{$use_stmts}; +} + +sub _make_violation ($self, $statement) { + return $self->violation($policy_title, sprintf($policy_explanation, $statement), $statement); +} + +1; + diff --git a/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/SpaceAfterSubroutineName.pm b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/SpaceAfterSubroutineName.pm new file mode 100644 index 0000000..c796785 --- /dev/null +++ b/external/os-autoinst-common/lib/perlcritic/Perl/Critic/Policy/SpaceAfterSubroutineName.pm @@ -0,0 +1,91 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +package Perl::Critic::Policy::SpaceAfterSubroutineName; + +use strict; +use warnings; +use version 0.77; +use experimental 'signatures'; + +use base 'Perl::Critic::Policy::Subroutines::ProhibitSubroutinePrototypes'; + +use Perl::Critic::Utils qw{ :severities }; + +our $VERSION = '0.0.1'; + +my $DESC = q{Inconsistent sub declaration}; +my $EXPL = q{Sub '%s' must have only one space surrounding name, parenthesis and/or block body.}; + +sub default_themes { qw(openqa) } +sub default_severity { $SEVERITY_HIGHEST } +sub supported_parameters { () } +sub applies_to { 'PPI::Statement::Sub' } + +# check that use strict/warnings is not present when equivalent modules are. +sub violates ($self, $elem, $doc) { + # Grep the first 7 tokens: each function will validate the cases. + my @tokens = ($elem->tokens())[0 .. 6]; + + return () if $elem->forward(); + return $self->check_reserved_sub($elem, @tokens) if _is_reserved_sub($elem); + return $self->check_classic_sub($elem, @tokens) unless defined($elem->prototype); + return $self->check_complete_sub($elem, @tokens); +} + +sub report_violation ($self, $elem) { + return $self->violation($DESC, sprintf($EXPL, $elem->name), $elem); +} + +sub check_reserved_sub ($self, $elem, @tokens) { + # "Reserved Sub" token desired layout + # 0. Word - END/BEGIN/etc. + # 1. Whitespace + # 2. Structure - the actual code block. + return () if _is_only_one_space($tokens[1]) && _is_block($tokens[2]); + return $self->report_violation($elem); +} + +sub check_classic_sub ($self, $elem, @tokens) { + # "Classic Sub" token desired layout + # 0. Word "sub" + # 1. Whitespace - must be 1 + # 2. Word - the sub name + # 3. Whitespace - must be 1 + # 4. Structure - the actual code block + + return () if _is_surrounded_by_one_space($tokens[2]); + return $self->report_violation($elem); +} + +sub check_complete_sub ($self, $elem, @tokens) { + # "Complete Sub" token desired layout + # 0. Word "sub" + # 1. Whitespace - must be 1 + # 2. Word - the sub name + # 3. Whitespace - must be 1 + # 4. Prototype - sub's prototype/signature + # 5. Whitespace - must be 1 + # 6. Structure - the actual code block + + return () if _is_surrounded_by_one_space($tokens[2]) && _is_surrounded_by_one_space($tokens[4]); + return $self->report_violation($elem); +} + +sub _is_block ($token) { + return $token->isa('PPI::Token::Structure'); +} + +sub _is_only_one_space ($token) { + return $token->isa('PPI::Token::Whitespace') && $token->content eq ' '; +} + +sub _is_surrounded_by_one_space ($token) { + return _is_only_one_space($token->previous_sibling) && _is_only_one_space($token->next_sibling); +} + +sub _is_reserved_sub ($elem) { + return $elem->isa('PPI::Statement::Scheduled'); +} + +1; diff --git a/external/os-autoinst-common/tools/perlcritic b/external/os-autoinst-common/tools/perlcritic new file mode 100755 index 0000000..80b85b4 --- /dev/null +++ b/external/os-autoinst-common/tools/perlcritic @@ -0,0 +1,20 @@ +#!/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 = map { ("$Bin/../$_", "$Bin/../external/os-autoinst-common/$_") } @extra_paths; + + # 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..69a9be4 --- /dev/null +++ b/external/os-autoinst-common/tools/tidyall @@ -0,0 +1,71 @@ +#!/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 version; +use Perl::Tidy; +use Module::CPANfile; +use FindBin '$Bin'; + +=item perltidy_version () + +Grabs the perltidy version from cpanfile using Module::CPANfile. + +=cut + +sub perltidy_version () { + my $cpanfile_location; + # Try searching for a cpanfile in: + # - the current working directory + # - a directory above this command + # - the catch-all location in external/os-autoinst-common + my @locations = ('.', "$Bin/..", "$Bin/../external/os-autoinst-common"); + + foreach my $path (@locations) { + next unless -e "$path/cpanfile"; + $cpanfile_location = "$path/cpanfile" and last; + } + + my $version = Module::CPANfile->load($cpanfile_location) + ->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. + # + # Additionally version will take care of 1.2.0 being equal to 1.2 + return version->new((split ' ', $version)[-1]); +} + +sub is_force_flag { $_ eq '--force' } + +my $required_version = perltidy_version(); +my $detected_version = version->new($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..3b6bdb3 --- /dev/null +++ b/external/os-autoinst-common/tools/update-deps @@ -0,0 +1,206 @@ +#!/usr/bin/env perl +# Copyright 2020 SUSE LLC +# SPDX-License-Identifier: MIT +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, + cpanfile => \my $cpanfile, + 'specfile=s' => \my $specfile, + 'dockerfile=s' => \my $dockerfile, +); + +usage(0) if $help; +usage(1) unless ($cpanfile || $specfile || $dockerfile); + +my $proj_root = "$Bin/.."; + +my $scriptname = path(__FILE__)->to_rel($proj_root); +my $dependencies_yaml_location = 'dependencies.yaml'; +my $file = "$proj_root/$dependencies_yaml_location"; +my $cpanfile_location = "$proj_root/cpanfile"; + +my $data = YAML::PP->new->load_file($file); + +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() if $specfile; +update_cpanfile($modules_by_target) if $cpanfile; +update_dockerfile($dockerfile) if $dockerfile; + +sub update_dockerfile { + my ($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 $dependencies_yaml_location +# 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 { + my $spec = path($specfile)->slurp; + + 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 $dependencies_yaml_location"; + 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 { + my ($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 { + # requires 'Archive::Extract', '> 0.7'; + my ($hash, $module) = @_; + my $version = $hash->{$module}; + my $line = "requires '$module'"; + $line .= qq{, '$version'} if $version; + $line .= ";\n"; + return $line; +} + +sub update_cpanfile { + my ($modules_by_target) = @_; + my $cpan = <<"EOM"; +################################################## +# WARNING +# This file is autogenerated by $scriptname +# from $dependencies_yaml_location +################################################## + +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->{develop}}) { + $devel_requires .= ' ' . _requires_line($modules_by_target->{develop}, $module); + } + $cpan .= <<"EOM"; + +on 'test' => sub { +$test_requires +}; + +on 'develop' => sub { +$devel_requires +}; + +feature 'coverage', 'coverage for CI' => sub { +$cover_requires +}; +EOM + + path($cpanfile_location)->spew($cpan); + say "Updated $cpanfile_location"; +} + +sub usage { + my ($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/00-tidy.t b/external/os-autoinst-common/xt/00-tidy.t new file mode 100755 index 0000000..c7daa9e --- /dev/null +++ b/external/os-autoinst-common/xt/00-tidy.t @@ -0,0 +1,7 @@ +#!/usr/bin/perl +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +use Test::Most; +use Test::Code::TidyAll; +tidyall_ok(); diff --git a/external/os-autoinst-common/xt/01-compile-check-all.t b/external/os-autoinst-common/xt/01-compile-check-all.t new file mode 100755 index 0000000..04643f0 --- /dev/null +++ b/external/os-autoinst-common/xt/01-compile-check-all.t @@ -0,0 +1,20 @@ +# Copyright SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +use Test::Most; +# We need :no_end_test here because otherwise it would output a no warnings +# test for each of the modules, but with the same test number +use Test::Warnings qw(:no_end_test :report_warnings); +use FindBin; +use lib "$FindBin::Bin/lib"; +use OpenQA::Test::TimeLimit '400'; + +use Test::Strict; + +push @Test::Strict::MODULES_ENABLING_STRICT, 'Test::Most'; +push @Test::Strict::MODULES_ENABLING_WARNINGS, 'Test::Most'; + +$Test::Strict::TEST_SYNTAX = 1; +$Test::Strict::TEST_STRICT = 1; +$Test::Strict::TEST_WARNINGS = 1; +all_perl_files_ok(qw(lib tools xt)); diff --git a/external/os-autoinst-common/xt/01-make-update-deps.t b/external/os-autoinst-common/xt/01-make-update-deps.t new file mode 100755 index 0000000..d6a5e7a --- /dev/null +++ b/external/os-autoinst-common/xt/01-make-update-deps.t @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +# Copyright 2022 SUSE LLC +# SPDX-License-Identifier: GPL-2.0-or-later + +use Test::Most; +use Test::Warnings; +use FindBin '$Bin'; + +if (not -e "$Bin/../.git") { + pass('Skipping all tests, not in a git repository'); + done_testing; + exit; +} + +my $build_dir = $ENV{OS_AUTOINST_BUILD_DIRECTORY} || "$Bin/.."; +my $make_tool = $ENV{OS_AUTOINST_MAKE_TOOL} || 'make'; +my $make_cmd = "$make_tool update-deps"; + +chdir $build_dir; +my @out = qx{$make_cmd}; +my $rc = $?; +die "Could not run $make_cmd: rc=$rc, out: @out" if $rc; + +my @status = grep { not m/^\?/ } qx{git -C "$Bin/.." status --porcelain}; +ok(!@status, "No changed files after '$make_cmd'") or diag @status; + +done_testing; +