diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9032734 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI +on: + pull_request: + push: + branches: + - '*' + workflow_dispatch: + +jobs: + build: + name: Build distribution + runs-on: ubuntu-latest + container: + image: perldocker/perl-tester:5.42 + steps: + - id: checkout + name: Checkout + uses: actions/checkout@v6 + - id: run-tests + name: Run Tests + env: + PERL_USE_UNSAFE_INC: 0 + AUTHOR_TESTING: 1 + AUTOMATED_TESTING: 1 + EXTENDED_TESTING: 1 + RELEASE_TESTING: 1 + run: auto-build-and-test-dist + - id: upload-artifact + # Upload artifact to a GitHub Actions "storage". + name: Upload Build + uses: actions/upload-artifact@v7.0.1 + with: + name: build_dir + path: build_dir + coverage: + needs: build + runs-on: ubuntu-latest + container: + image: perldocker/perl-tester:5.42 + steps: + - id: checkout + name: Checkout + uses: actions/checkout@v6 + - id: download-artifact + # Download the artifact that was uploaded in earlier step. + name: Download Build + uses: actions/download-artifact@v8.0.1 + with: + name: build_dir + path: . + - id: install-deps + name: Install deps + run: cpan-install-dist-deps + - id: test + name: Test + run: test-dist + env: + CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}} + COVERALLS_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 9597177..f62a3d6 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,21 +1,20 @@ name: linux on: + pull_request: push: branches: - '*' - # tags-ignore: - # - '*' workflow_dispatch: -# pull_request: jobs: perl: env: - # some plugins still needs this to run their tests... + # some plugins still need this to run their tests... PERL_USE_UNSAFE_INC: 0 AUTHOR_TESTING: 1 AUTOMATED_TESTING: 1 + EXTENDED_TESTING: 1 RELEASE_TESTING: 1 runs-on: ubuntu-latest @@ -28,7 +27,7 @@ jobs: - '5.40' - '5.34' - '5.28' - - '5.20' + # - '5.20' No dzil # - '5.18' No dzil # - '5.16' No dzil # - '5.14' No dzil @@ -42,7 +41,7 @@ jobs: steps: - id: checkout name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - id: explore-tools-perl name: perl -V run: perl -V @@ -67,12 +66,14 @@ jobs: - id: list-deps-with-verbosity name: List Dependencies With Verbosity run: | - dzil --verbose listdeps --requires --develop recommends --suggests --cpanm-version --omit-core ${{ matrix.perl-version }} + dzil --verbose listdeps --requires --develop recommends --suggests --cpanm-version --omit-core "$(perl -E 'say $];')" + shell: bash - id: install-dzil-deps name: Install Dependencies run: | - dzil listdeps --requires --develop recommends --suggests --cpanm-version --omit-core ${{ matrix.perl-version }} \ + dzil listdeps --requires --develop recommends --suggests --cpanm-version --omit-core "$(perl -E 'say $];')" \ | cpanm --verbose --force --notest || true + shell: bash # - id: build-project-and-explore # name: Build Project And Explore # run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index bad8d9c..d687a05 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,71 +1,42 @@ name: windows on: + pull_request: push: branches: - '*' - tags-ignore: - - '*' workflow_dispatch: -# pull_request: jobs: - perl: - # name: Perl Perl ${{ matrix.perl }} on ${{ matrix.os }} - # https://justatheory.com/2021/11/cache-perl-github-workflows/ - env: - # some plugins still needs this to run their tests... - PERL_USE_UNSAFE_INC: 0 - AUTHOR_TESTING: 1 - AUTOMATED_TESTING: 1 - RELEASE_TESTING: 1 - - # strategy: - # matrix: - # os: [ windows ] - # perl: [ 'latest' ] + test: runs-on: windows-latest - # runs-on: ${{ matrix.os }}-latest - steps: - id: checkout name: Checkout - uses: actions/checkout@v4 - - # There is no strategy/matrix because Windows container has its own - # Strawberry Perl and we go with whatever version it is. - - # - id: cache-cpan - # name: Cache CPAN modules - # uses: actions/cache@v4 - # # env: - # # cache-name: cache-cpan-modules - # with: - # # npm cache files are stored in `~/.npm` on Linux/macOS - # # path: ~/.cpan - # # path: local - # path: C:/Strawberry/perl/site/lib - # # key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - # # key: perl-${{ steps.perl.outputs.perl-hash }} - # key: static - # # restore-keys: | - # # ${{ runner.os }}-build-${{ env.cache-name }}- - # # ${{ runner.os }}-build- - # # ${{ runner.os }}- + uses: actions/checkout@v6 + + - id: setup-strawberry-perl + name: Setup Strawberry Perl + uses: shogo82148/actions-setup-perl@v1 + with: + perl-version: '5.42' + distribution: strawberry # Critical for Windows compatibility + - id: explore-tools-perl name: Explore Tools Perl + shell: pwsh run: | perl -V + - id: explore-tools-cpan name: Explore Tools Cpan + shell: pwsh run: | cpan -V - - id: explore-tools-cpanm - name: Explore Tools Cpanm - run: | - cpanm -V + - id: explore-filesystem name: Explore Filesystem + shell: pwsh run: | dir dir C:\ @@ -76,57 +47,88 @@ jobs: dir D:\ # dir .cpan # dir .cpan\build + - id: explore-whoami name: Explore Who Am I + shell: pwsh run: | whoami + - id: explore-environment name: Explore Environment shell: pwsh run: | Get-ChildItem env: | Format-Table -Wrap - - id: install-dzil + + - id: install-test2 + name: Install Test2 + shell: pwsh + run: | + cpanm --notest --force Test2::Suite + + - id: install-dist-zilla name: Install Dist::Zilla + shell: pwsh run: | - cpanm --verbose --force --notest Dist::Zilla - # - id: install-extra - # name: Install Extra Dependencies Which Are Somehow Missing - # env: - # PUREPERL_ONLY: 1 - # run: | - # cpanm --verbose --force --notest Test::Perl::Critic - # # - id: - # name: Install Dependencies - # # #run: cpm install -g --no-test --show-build-log-on-failure --cpanfile cpanfile - # # run: cpm install -g --no-test --show-build-log-on-failure --cpanfile cpanfile - # # - id: - # name: Makefile.PL - # # run: perl Makefile.PL - - id: list-dzil-authordeps-with-verbosity - name: List Dist::Zilla Author Dependencies With Verbosity + cpanm --notest --force Dist::Zilla + + - id: explore-missing-dzil-authordeps + name: Explore Missing Dist::Zilla Author Dependencies + shell: pwsh run: | - dzil --verbose authordeps --cpanm-versions - - id: install-dzil-authordeps - name: Install Dist::Zilla Author Dependencies + dzil authordeps --missing --cpanm-versions + + - id: install-missing-dzil-authordeps + name: Install Missing Dist::Zilla Author Dependencies + shell: pwsh run: | - dzil authordeps --cpanm-versions \ - | cpanm --verbose --force --notest || true - - id: list-deps-with-verbosity - name: List Dependencies With Verbosity + $authDeps = dzil authordeps --missing --cpanm-versions + if ($authDeps) { + Write-Host "Installing missing author dependencies: $authDeps" + $authDeps | cpanm --verbose --force --notest + if ($LASTEXITCODE -eq 1) { + Write-Host "cpanm returned 1, but checking if work got done..." + $authDepsCheck = dzil authordeps --missing + # if ($authDepsCheck | ) { + # Write-Host "Work got done successfully despite exit code 1." + # $global:LASTEXITCODE = 0 + # } + } + $global:LASTEXITCODE = 0 + + } else { + Write-Host "No missing author dependencies found." + } + + - id: explore-missing-deps + name: Explore Missing Dependencies + shell: pwsh run: | - dzil --verbose listdeps --develop --requires --recommends --suggests --cpanm-version - - id: install-dzil-deps - name: Install Dependencies - # dzil listdeps --requires --develop recommends --suggests --cpanm-version --omit-core ${{ matrix.perl-version }} \ + dzil listdeps --missing --develop --requires --no-recommends --no-suggests --cpanm-version + + - id: install-missing-deps + name: Install Missing Dependencies + shell: pwsh run: | - dzil listdeps --requires --develop recommends --suggests --cpanm-version \ - | cpanm --verbose --force --notest || true - # - id: build-project-and-explore - # name: Build Project And Explore - # run: | - # dzil --verbose build \ - # && Get-ChildItem -Path -Recurse -Force -Exclude .git + $listDeps = dzil listdeps --missing --develop --requires --no-recommends --no-suggests --cpanm-version + if ($listDeps) { + Write-Host "Installing missing dependencies: $listDeps" + $listDeps | cpanm --verbose --force --notest + if ($LASTEXITCODE -eq 1) { + Write-Host "cpanm returned 1, but checking if work got done..." + dzil listdeps --missing --develop --requires --no-recommends --no-suggests + # if ($?) { + # Write-Host "Work got done successfully despite exit code 1." + # $global:LASTEXITCODE = 0 + # } + } + $global:LASTEXITCODE = 0 + } else { + Write-Host "No missing dependencies found." + } + - id: run-tests name: Run Tests + shell: pwsh run: | - dzil --verbose test --all --test-verbose + dzil test --no-author diff --git a/.weavefilerc b/.weavefilerc new file mode 100644 index 0000000..6b9f400 --- /dev/null +++ b/.weavefilerc @@ -0,0 +1,75 @@ +--- +snippets: + license: | + # LICENSE + + This software is copyright (c) 2026 by [% dist.author %]. + + This is free software; you can redistribute it and/or modify it under + the same terms as the Perl 5 programming language system itself. + + Terms of the Perl programming language system itself: + + a) the GNU General Public License as published by the Free + Software Foundation; either version 1, or (at your option) any + later version, or + b) the "Artistic License" + + The complete licenses are in the files LICENSE-Artistic-2.0 and LICENSE-GPL-3 + within this repository. If these files are missing, they can be downloaded + from the following urls: + + * https://www.gnu.org/licenses/ + * https://www.perlfoundation.org/artistic-license-20.html + badges: | + [![License: Artistic-2.0](https://img.shields.io/badge/License-Perl-0298c3.svg)](https://opensource.org/licenses/Artistic-2.0) + [![CPAN Version](https://img.shields.io/cpan/v/Env-Assert)](https://metacpan.org/dist/Env-Assert) + [![kwalitee](https://cpants.cpanauthors.org/dist/Env-Assert.svg)](https://cpants.cpanauthors.org/dist/Env-Assert) + [![codecov](https://codecov.io/gh/mikkoi/env-assert/graph/badge.svg?token=WSOLKXXEVK)](https://codecov.io/gh/mikkoi/env-assert) + [![Coverage Status](https://coveralls.io/repos/github/mikkoi/env-assert/badge.svg?branch=add-codecov-report)](https://coveralls.io/github/mikkoi/env-assert?branch=add-codecov-report) + [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mikkoi/env-assert) + [![GH Actions: Linux Build](https://github.com/mikkoi/env-assert/actions/workflows/linux.yml/badge.svg?event=push&branch=main)](https://github.com/mikkoi/env-assert/actions/workflows/linux.yml) + [![GH Actions: Windows Build](https://github.com/mikkoi/env-assert/actions/workflows/windows.yml/badge.svg?event=push&branch=main)](https://github.com/mikkoi/env-assert/actions/workflows/windows.yml) + packaging_badge: | + ### Packaging + + [![Packaging status](https://repology.org/badge/vertical-allrepos/env-assert.svg)](https://repology.org/project/env-assert/versions) +files: + "README.md": | + [% snippets.badges -%] + + # [% dist.name %] + + [% dist.abstract %] + + + [% pod("Env::Assert", "VERSION") %] + + + [% pod("Env::Assert", "SYNOPSIS") %] + + + [% pod("bin/envassert", "DESCRIPTION") %] + + + ## INSTALLATION + + [% snippets.packaging_badge -%] + + ### CLI interface without dependencies + + The **envassert** command is also available + as self contained executable. + You can download it and run it as it is without + additional installation of CPAN packages. + Of course, you still need Perl, but Perl comes with any + normal Linux installation. + + This can be convenient if you want to, for instance, + include **envassert** in a docker container build. + + curl -LSs -o envassert https://raw.githubusercontent.com/mikkoi/env-assert/main/envassert.self-contained + chmod +x ./envassert + + + [% snippets.license %] diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index e501de7..f49350e 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -17,5 +17,4 @@ local/ .lvimrc Session.vim dzil-generated-cpanfile -README.md envassert.self-contained diff --git a/README.md b/README.md index 559ad91..a0e5043 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,46 @@ [![License: Artistic-2.0](https://img.shields.io/badge/License-Perl-0298c3.svg)](https://opensource.org/licenses/Artistic-2.0) [![CPAN Version](https://img.shields.io/cpan/v/Env-Assert)](https://metacpan.org/dist/Env-Assert) [![kwalitee](https://cpants.cpanauthors.org/dist/Env-Assert.svg)](https://cpants.cpanauthors.org/dist/Env-Assert) +[![codecov](https://codecov.io/gh/mikkoi/env-assert/graph/badge.svg?token=WSOLKXXEVK)](https://codecov.io/gh/mikkoi/env-assert) +[![Coverage Status](https://coveralls.io/repos/github/mikkoi/env-assert/badge.svg?branch=add-codecov-report)](https://coveralls.io/github/mikkoi/env-assert?branch=add-codecov-report) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mikkoi/env-assert) +[![GH Actions: Linux Build](https://github.com/mikkoi/env-assert/actions/workflows/linux.yml/badge.svg?event=push&branch=main)](https://github.com/mikkoi/env-assert/actions/workflows/linux.yml) +[![GH Actions: Windows Build](https://github.com/mikkoi/env-assert/actions/workflows/windows.yml/badge.svg?event=push&branch=main)](https://github.com/mikkoi/env-assert/actions/workflows/windows.yml) -# envassert +# Env-Assert + +Ensure that the environment variables match what is requested, or abort. Module and executable. + + +# VERSION + +version 0.016 + + +# SYNOPSIS + + use Env::Assert 'assert'; + # or: + use Env::Assert assert => { + envdesc_file => 'another-envdesc', + break_at_first_error => 1, + }; + + # .envdesc file: + # MY_VAR=.+ + + # use any verified environment variable + say $ENV{MY_VAR}; + + # You can inline the envdesc file: + use Env::Assert assert => { + exact => 1, + envdesc => <<'EOF' + NUMERIC_VAR=^[[:digit:]]+$ + TIME_VAR=^\d{2}:\d{2}:\d{2}$ + EOF + }; -Ensure that the environment variables match -what is requested, or abort. # DESCRIPTION @@ -14,24 +48,83 @@ what is requested, or abort. with environment variables, matches with what you want. You can define your required environment in a file. -Default file is **.envdesc** but you can use any file. +Default file is `.envassert` but you can use any file. + It is advantageous to use **envassert** for example when running a container. If you check your environment for missing or wrongly defined environment variables at the beginning of the container run, your container will fail sooner instead of in a later point in execution when the variables are needed. -# SYNOPSIS +## Errors + +There are three kinds of errors: + +- ENV\_ASSERT\_MISSING\_FROM\_ENVIRONMENT + + "Variable <var\_name> is missing from environment" + +- ENV\_ASSERT\_INVALID\_CONTENT\_IN\_VARIABLE + + "Variable <var\_name> has invalid content" + +- ENV\_ASSERT\_MISSING\_FROM\_DEFINITION + + "Variable <var\_name> is missing from description" + + This error will only be reported if you have set + the special option **exact**. See below. + +## Environment Description Language -envassert [options] +Environment is described in file `.envdesc`. +Environment description file is a Unix shell compatible file, +similar to a `.env` file. -Options: +### `.envdesc` Format + +In `.envdesc` file there is only environment variables, comments +or empty rows. +Example: + + # Required env + ## envassert (opts: exact=1) + FILENAME=^[[:word:]]{1,}$ + +Env var name is followed by a regular expression. The regexp is +an extended Perl regular expression without quotation marks. +One env var and its descriptive regexp use one row. + +A comment begins at the beginning of the row and uses the whole row. +It start with '#' character. + +Two comment characters and the word **envassert** at the beginning of the row +mean this is an **envassert** meta command. +You can specify different environment related options with these commands. + +Supported options: + +- exact + + The option _exact_ means that all allowed env variables + are described in this file. Any unknown env var causes an error + when verifying. + +## CLI interface without dependencies + +The `envassert` command is also available +as self contained executable. +You can download it and run it as it is without +additional installation of CPAN packages. +Of course, you still need Perl, but Perl comes with any +normal Linux installation. + +This can be convenient if you want to, for instance, +include `envassert` in a docker container build. + + curl -LSs -o envassert https://raw.githubusercontent.com/mikkoi/env-assert/main/envassert.self-contained + chmod +x ./envassert - --help - --man - --version - --break-at-error - --env-description ## INSTALLATION @@ -54,9 +147,10 @@ include **envassert** in a docker container build. curl -LSs -o envassert https://raw.githubusercontent.com/mikkoi/env-assert/main/envassert.self-contained chmod +x ./envassert + # LICENSE -This software is copyright (c) 2023 by Mikko Koivunalho. +This software is copyright (c) 2026 by Mikko Koivunalho . This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/dist.ini b/dist.ini index 60736a6..b698f89 100644 --- a/dist.ini +++ b/dist.ini @@ -28,29 +28,43 @@ include_dotfiles = 1 [@Filter] -bundle = @MIKKOI --version = 0.003 +-version = 0.005 -remove = GatherDir -remove = Test::Perl::Critic +-remove = Readme ; No need to include README file because we include the weaved README.md +-remove = PodWeaver +-remove = PerlTidy -[Software::Policies / License] -policy_attribute = perl_5_double_license = true +[Prereqs / DevelopSuggests] +Dist::Zilla::App::Command::podpreview = 0.004 +Dist::Zilla::App::Command::cover = 0 +Devel::Cover::Report::Codecov = 0 +Devel::Cover::Report::Coveralls = 0 +App::RewriteVersion = 1.000 [Software::Policies / AIDisclosure] policy_attribute = ai_tools = Claude AI, Copilot and Gemini +[Software::Policies / CodeOfConduct] +class = ContributorCovenant +version = 2.1 + [Software::Policies / Contributing] policy_attribute = ai_disclosure = 1 policy_attribute = ai_assisted = 1 -[Software::Policies / CodeOfConduct] -class = ContributorCovenant -version = 2.1 +[Software::Policies / License] +policy_attribute = perl_5_double_license = true [Software::Policies / Security] policy_attribute = url = https://github.com/mikkoi/env-assert/blob/main/SECURITY.md policy_attribute = timeframe = 14 days policy_attribute = perl_support_years = 10 +[WeaveFile / README.md] + +[Test::WeaveFile] + ; After release, always update the self-contained executables to GitHub. ; Use the one that was released. It now contains the current version number. [Run::AfterRelease] diff --git a/lib/Env/Assert.pm b/lib/Env/Assert.pm index 4622802..eeb36c6 100644 --- a/lib/Env/Assert.pm +++ b/lib/Env/Assert.pm @@ -45,6 +45,14 @@ use constant { =for :stopwords env filepath filepaths +=head1 NAME + +Env::Assert - Ensure that the environment variables match what you need, or abort + +=head1 VERSION + +version 0.016 + =head1 SYNOPSIS =for test_synopsis BEGIN { die 'SKIP: no .envdesc file here' } @@ -137,8 +145,18 @@ Read environment variables from a F<.env> file directly into you program. There is also script F which can turn F<.env> file's content into environment variables for different shells. +=head1 AUTHOR + +Mikko Koivunalho + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2023 by Mikko Koivunalho. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + =cut 1; - __END__ diff --git a/lib/Env/Assert/Functions.pm b/lib/Env/Assert/Functions.pm index e4af7ee..22c285f 100644 --- a/lib/Env/Assert/Functions.pm +++ b/lib/Env/Assert/Functions.pm @@ -61,11 +61,13 @@ use constant { INDENT => q{ }, }; -=head1 STATUS +=head1 NAME -Package Env::Assert is currently being developed so changes in the API are possible, -though not likely. +Env::Assert::Functions - The functionality of Env::Assert and bin/envassert. + +=head1 VERSION +version 0.016 =head1 SYNOPSIS @@ -86,6 +88,10 @@ though not likely. print report_errors( $r->{'errors'} ); } +=head1 STATUS + +Package Env::Assert is currently being developed so changes in the API are possible, +though not likely. =head1 NOTES @@ -269,6 +275,17 @@ Read environment variables from a F<.env> file directly into you program. There is also script F which can turn F<.env> file's content into environment variables for different shells. +=head1 AUTHOR + +Mikko Koivunalho + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2023 by Mikko Koivunalho. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + =cut 1; diff --git a/t/lib/Test2/Require/Platform/OS/Unix.pm b/t/lib/Test2/Require/Platform/OS/Unix.pm index f763e73..20e394f 100644 --- a/t/lib/Test2/Require/Platform/OS/Unix.pm +++ b/t/lib/Test2/Require/Platform/OS/Unix.pm @@ -10,24 +10,24 @@ use English qw( -no_match_vars ) ; # Avoids regex performance my %PLATFORMS = ( 'aix' => 1, - 'bsdos' => 1, + 'bsdos' => 1, 'darwin' => 1, 'dynixptx' => 1, - 'freebsd' => 1, + 'freebsd' => 1, 'haiku' => 1, 'linux' => 1, 'hpux ' => 1, 'irix ' => 1, 'darwin' => 1, 'next' => 1, - 'openbsd' => 1, - 'dec_osf' => 1, - 'svr4' => 1, - 'sco_sv' => 1, - 'unicos' => 1, - 'unicosmk' => 1, - 'solaris' => 1, - 'sunos' => 1, + 'openbsd' => 1, + 'dec_osf' => 1, + 'svr4' => 1, + 'sco_sv' => 1, + 'unicos' => 1, + 'unicosmk' => 1, + 'solaris' => 1, + 'sunos' => 1, ); sub IS_PLATFORM {