From abe5d57a969fdeb4febec15ff32af8742081c729 Mon Sep 17 00:00:00 2001 From: brian d foy Date: Thu, 20 Feb 2025 16:01:19 -0500 Subject: [PATCH 1/9] skip the distro file in MANIFEST --- MANIFEST | 1 - MANIFEST.SKIP | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/MANIFEST b/MANIFEST index d741924..98c01f0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -13,7 +13,6 @@ LICENSE Makefile.PL MANIFEST This list of files MANIFEST.SKIP -Module-Release-2.136.tar.gz README.pod script/release script/release-test diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index 2bbe66f..e155f43 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -74,4 +74,6 @@ ToDo \.github_token \.gitattributes\b +Module-Release- + none From 38ddae51ce3bc94595730c5140f2d2c5e74262af Mon Sep 17 00:00:00 2001 From: brian d foy Date: Thu, 20 Feb 2025 18:06:34 -0500 Subject: [PATCH 2/9] Implement -c to specify the Changes items on the command line --- script/release | 74 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/script/release b/script/release index a8d73a9..d968390 100755 --- a/script/release +++ b/script/release @@ -115,11 +115,29 @@ repository. You should be able to checkout the code from any release. Set $ENV{AUTOMATED_TESTING} to true. You can also set C in the configuration file +=item -c STRING + +=item --changes STRING + +Specify the F file entry on the command line. If STRING does +not start with a C<*>, one will be added to the start along with a space. + + release -C "some change" + +translates to the F entry with the date and one bullet item: + + 3.11 2025-02-20T22:56:28Z + * some change + +STRING can also be a multiline string, but this will only append a C<*> +to the first line if it does not already have on. All lines will be +indented under the date though. + =item -C =item --skip-changes -Skip the Changes file. This is also the C config option +Skip the F file. This is also the C config option =item -d @@ -423,6 +441,7 @@ GetOptions( 'h|help|usage|?' => sub { usage(0) }, 'a|automated-testing!' => \$opts{a}, + 'c|changes=s' => \$opts{c}, 'C|skip-changes!' => \$opts{C}, 'd|skip-debug!' => \$opts{d}, 'D|skip-dist!' => \$opts{D}, @@ -700,7 +719,9 @@ if( $opts{t} // $release->config->dry_run ) { # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # CPAN::Spec::Changes $release->_print("============ Getting Changes\n"); -unless( $release->debug or $opts{C} or $release->config->skip_changes ) { +say STDERR "OPTS{c} is $opts{c}"; + +unless( $opts{C} or $release->config->skip_changes ) { $release->show_recent_contributors; my $changes = "Changes"; @@ -708,32 +729,49 @@ unless( $release->debug or $opts{C} or $release->config->skip_changes ) { die "Changes file does not exist!\n" unless -e $changes; - $release->_print( "\n", "-" x 73, "\n", "Enter Changes section\n\n> " ); my $str = $Version . ' ' . $release->get_release_date . "\n"; - while( ) { - $_ =~ s/\A \s* \* \s*/* /x; # Make top-level bullets (*) - $_ =~ s/\A \s* - \s*/\t- /x; # Make second-level bullets (-) - $_ =~ s/\A/\t/; # always indent + my $message = do { + if( $opts{'c'} ) { + $opts{'c'} + } + else { + $release->_print( "\n", "-" x 73, "\n", "Enter Changes section\n\n> " ); + local $/; + + } + }; + + $message =~ s/^ \s* \* \s*/* /mgx; # Make top-level bullets (*) + $message =~ s/^ \s* - \s*/\t- /mgx; # Make second-level bullets (-) - $str .= $_; - $release->_print( "> " ); - } + $message =~ s/\A\s+//; - $str .= "\n"; + $message =~ s/\A[^*]/* $&/; + + $message =~ s/^/\t/mgx; # always indent + $message =~ s/\s*\z/\n\n/; + + $message = $Version . ' ' . $release->get_release_date . "\n" . $message; rename $changes, $bak or die "Could not backup $changes. $!\n"; open my $in, '<:encoding(UTF-8)', $bak or $release->_die( "Could not read old $changes file! $!\n" ); open my $out, '>:encoding(UTF-8)', $changes; + # transfer the first part of the existing changes + my $header; while( <$in> ) { - print $out $_; + $header .= $_; last unless m/\S/; } - print $out $str; + $header =~ s/\s*\z/\n\n/; + # now the new stuff + print $out $header, $message; + + # and the rest of the old stuff print $out $_ while( <$in> ); close $in; @@ -750,7 +788,7 @@ unless( $release->debug or $opts{C} or $release->config->skip_changes ) { $release->vcs_commit_message( { version => $Version } ); } else { - sprintf '* for release %s', $Version; + sprintf 'release %s', $Version; } }; @@ -759,9 +797,10 @@ unless( $release->debug or $opts{C} or $release->config->skip_changes ) { $release->_print( $vcs_commit ); } else { - $release->_print( "Skipping Changes file" ); + $release->_print( "Skipping Changes file\n" ); } +exit; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Build the release in preparation for uploading @@ -779,7 +818,10 @@ $release->_debug( "This is where I should release stuff\n" ); while( $release->should_upload_to_pause ) { $release->load_mixin( 'Module::Release::WebUpload::Mojo' ); $release->_print("============ Uploading to PAUSE\n"); - last if $release->debug; + if( $release->debug ) { + $release->_print("debug is true, so skipping upload"); + last; + } $release->web_upload; last; } From 2244181c176f6d9a67b3643b28d815c84fa99cce Mon Sep 17 00:00:00 2001 From: brian d foy Date: Thu, 20 Feb 2025 18:06:41 -0500 Subject: [PATCH 3/9] Updated GitHub workflows from https://github.com/briandfoy/github_workflows * linux.yml upgraded: 20250101.001 -> 20250126.002 * macos.yml upgraded: 20250101.001 -> 20250125.002 * release.yml upgraded: 20241118.001 -> 20241125.002 * windows.yml upgraded: 20250101.001 -> 20250126.001 --- .github/workflows/linux.yml | 38 ++++++++++++++++++++++++++++------- .github/workflows/macos.yml | 23 +++++++++++++++++---- .github/workflows/release.yml | 22 +++++++++++++++++--- .github/workflows/windows.yml | 32 ++++++++++++++++++++++++++--- 4 files changed, 98 insertions(+), 17 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 9087bd9..c92e2ef 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,5 +1,5 @@ # brian's standard GitHub Actions Ubuntu config for Perl 5 modules -# version 20250101.001 +# version 20250126.002 # https://github.com/briandfoy/github_workflows # https://github.com/features/actions # This file is licensed under the Artistic License 2.0 @@ -8,6 +8,24 @@ # in your repo settings. Or not. It still works if it isn't defined. # In that environment, add whatever environment variables or secrets # that you want. +# +# Variables that you can set in the "automated_testing" environment: +# +# EXTRA_CPAN_MODULES - extra arguments to the first call to cpan. +# Just use EXTRA_CPANM_MODULES though. This is +# here for legacy +# +# EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 +# +# UBUNTU_EXTRA_APT_GET - extra packages to install before we start +# +# UBUNTU_EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm +# but only on Ubuntu. Other workflows won't use this. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 + --- name: ubuntu @@ -52,7 +70,7 @@ on: pull_request: # weekly build on the master branch just to see what CPAN is doing schedule: - - cron: "59 13 * * 0" + - cron: "37 3 * * 0" jobs: perl: environment: automated_testing @@ -81,13 +99,17 @@ jobs: - uses: actions/checkout@v3 - name: Platform check run: uname -a + - name: setup platform + run: | + apt-get upgrade + apt-get -y install curl ${{ vars.UBUNTU_EXTRA_APT_GET }} - name: Perl version check run: | perl -V perl -v | perl -0777 -ne 'm/(v5\.\d+)/ && print "PERL_VERSION=$1"' >> $GITHUB_ENV # Some older versions of Perl have trouble with hostnames in certs. I # haven't figured out why. - - name: Setup environment + - name: enhance environment run: | echo "PERL_LWP_SSL_VERIFY_HOSTNAME=0" >> $GITHUB_ENV # HTML::Tagset bumped its minimum version to v5.10 for no good reason @@ -102,13 +124,14 @@ jobs: - name: fix html-tagset for v5.8 if: env.PERL_VERSION == 'v5.8' run: | + cpan App::Cpan curl -L -O https://cpan.metacpan.org/authors/id/P/PE/PETDANCE/HTML-Tagset-3.24.tar.gz tar -xzf HTML-Tagset-3.24.tar.gz cd HTML-Tagset-3.24 rm META.* mv Makefile.PL Makefile.PL.orig perl -n -e 'next if /(^use 5)|(MIN_PERL)/; print' Makefile.PL.orig > Makefile.PL - cpan -T . + cpan -M http://www.cpan.org -T . cd .. pwd ls @@ -121,13 +144,14 @@ jobs: - name: Install cpanm and multiple modules run: | curl -L https://cpanmin.us | perl - App::cpanminus - cpanm --notest IO::Socket::SSL LWP::Protocol::https App::Cpan HTTP::Tiny ExtUtils::MakeMaker Test::Manifest Test::More + cpanm --notest IO::Socket::SSL LWP::Protocol::https App::Cpan HTTP::Tiny ExtUtils::MakeMaker Test::Manifest Test::More ${{ vars.EXTRA_CPANM_MODULES }} ${{ vars.UBUNTU_EXTRA_CPANM_MODULES }} + cpan -M http://www.cpan.org -T Test::Manifest ${{ vars.EXTRA_CPAN_MODULES }} # Install the dependencies, again not testing them. This installs the # module in the current directory, so we end up installing the module, # but that's not a big deal. - name: Install dependencies run: | - cpanm --notest --installdeps --with-suggests --with-recommends . ${{ vars.EXTRA_CPAN_MODULES }} + cpanm --notest --installdeps --with-suggests --with-recommends . - name: Show cpanm failures if: ${{ failure() }} run: | @@ -167,7 +191,7 @@ jobs: - name: Run coverage tests if: env.PERL_VERSION != 'v5.8' && env.PERL_VERSION != 'v5.10' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | cpanm --notest Devel::Cover Devel::Cover::Report::Coveralls perl Makefile.PL diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 83fee1f..11492fc 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -1,5 +1,5 @@ # brian's standard GitHub Actions macOS config for Perl 5 modules -# version 20250101.001 +# version 20250125.002 # https://github.com/briandfoy/github_workflows # https://github.com/features/actions # This file is licensed under the Artistic License 2.0 @@ -8,6 +8,21 @@ # in your repo settings. Or not. It still works if it isn't defined. # In that environment, add whatever environment variables or secrets # that you want. +# +# Variables that you can set in the "automated_testing" environment: +# +# EXTRA_CPAN_MODULES - extra arguments to the first call to cpan. +# Just use EXTRA_CPANM_MODULES though. This is +# here for legacy +# +# EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 +# +# MACOS_EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm +# but only on macOS. Other workflows won't use this. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 --- name: macos @@ -78,14 +93,14 @@ jobs: - name: Prepare cpan run: | openssl version - cpan -M http://www.cpan.org -T IO::Socket::SSL HTTP::Tiny - cpan -M https://www.cpan.org -T ExtUtils::MakeMaker Test::Manifest + cpan -M https://www.cpan.org -T App::cpanminus IO::Socket::SSL HTTP::Tiny ExtUtils::MakeMaker Test::Manifest ${{ vars.EXTRA_CPAN_MODULES }} + cpanm --notest Test::Manifest ${{ vars.EXTRA_CPANM_MODULES }} ${{ vars.MACOS_EXTRA_CPANM_MODULES }} # Install the dependencies, again not testing them. This installs the # module in the current directory, so we end up installing the module, # but that's not a big deal. - name: Install dependencies run: | - cpan -M https://www.cpan.org -T . ${{ vars.EXTRA_CPAN_MODULES }} + cpan -M https://www.cpan.org -T . - name: Run tests run: | perl Makefile.PL diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e430e10..c77ab28 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,5 @@ # brian's standard GitHub Actions release config for Perl 5 modules -# version 20241118.001 +# version 20241125.002 # https://github.com/briandfoy/github_workflows # https://github.com/features/actions # This file is licensed under the Artistic License 2.0 @@ -12,6 +12,21 @@ # This requires that you configure a repository secret named # RELEASE_ACTION_TOKEN with a GitHub Personal Access Token # that has "read and write" permissions on Repository/Contents +# +# Variables that you can set in the "automated_testing" environment: +# +# EXTRA_CPAN_MODULES - extra arguments to the first call to cpan. +# Just use EXTRA_CPANM_MODULES though. This is +# here for legacy +# +# EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 +# +# UBUNTU_EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm +# but only on Ubuntu. Other workflows won't use this. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 --- name: release @@ -74,13 +89,14 @@ jobs: - name: Install cpanm and multiple modules run: | curl -L https://cpanmin.us | perl - App::cpanminus - cpanm --notest IO::Socket::SSL HTTP::Tiny ExtUtils::MakeMaker Test::Manifest + cpanm --notest IO::Socket::SSL HTTP::Tiny ExtUtils::MakeMaker Test::Manifest ${{ vars.EXTRA_CPANM_MODULES }} ${{ vars.UBUNTU_EXTRA_CPANM_MODULES }} + cpan -M http://www.cpan.org -T Test::Manifest ${{ vars.EXTRA_CPAN_MODULES }} # Install the dependencies, again not testing them. This installs the # module in the current directory, so we end up installing the module, # but that's not a big deal. - name: Install dependencies run: | - cpanm --notest --installdeps --with-suggests --with-recommends . ${{ vars.EXTRA_CPAN_MODULES }} + cpanm --notest --installdeps --with-suggests --with-recommends . # This makes the distribution and tests it, but assumes by the time we # got here, everything else was already tested. - name: Create distro diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 37b5b2d..1d6e303 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,5 +1,5 @@ # brian's standard GitHub Actions Windows config for Perl 5 modules -# version 20250101.001 +# version 20250126.001 # https://github.com/briandfoy/github_workflows # https://github.com/features/actions # This file is licensed under the Artistic License 2.0 @@ -8,6 +8,19 @@ # in your repo settings. Or not. It still works if it isn't defined. # In that environment, add whatever environment variables or secrets # that you want. +# +# EXTRA_CPAN_MODULES - extra arguments to the first call to cpan. +# Just use EXTRA_CPANM_MODULES though. This is +# here for legacy +# +# EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 +# +# WINDOWS_EXTRA_CPANM_MODULES - extra arguments to the first call to cpanm +# but only on Windows. Other workflows won't use this. +# this is useful to install very particular +# modules, such as DBD::mysql@4.050 --- name: windows @@ -66,19 +79,32 @@ jobs: - uses: actions/checkout@v3 - name: Set up Perl run: | - choco install strawberryperl + choco uninstall strawberryperl + choco upgrade strawberryperl echo "C:\strawberry\c\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "C:\strawberry\perl\site\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "C:\strawberry\perl\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Perl version run: perl -V +# cpan can operate with https, but we need IO::SSL::Socket, which +# does not come with Perl. +# +# When using cpan, use -M to specify the CDN-backed www.cpan.org +# mirror. I've noticed that letting CPAN.pm auto-choose mirrors +# sometimes selects things that the action can't reach. +# +# Also, use the -T option to not test the dependencies. Assume these +# mainline modules are good and save lots of CI minutes. + - name: Install cpanm and multiple modules + run: | + cpan -M http://www.cpan.org -T App::cpanminus ${{ vars.EXTRA_CPAN_MODULES }} + cpanm --notest IO::Socket::SSL LWP::Protocol::https HTTP::Tiny ExtUtils::MakeMaker Test::Manifest Test::More ${{ vars.EXTRA_CPANM_MODULES }} ${{ vars.WINDOWS_EXTRA_CPANM_MODULES }} # Install the dependencies, again not testing them. This installs the # module in the current directory, so we end up installing the module, # but that's not a big deal. - name: Install dependencies run: | cpan -M https://www.cpan.org -T . - cpan -M https://www.cpan.org -T Test::Manifest ${{ vars.EXTRA_CPAN_MODULES }} - name: Run tests run: | perl Makefile.PL From ba1391905b927be3024075e358489b7be0d36f72 Mon Sep 17 00:00:00 2001 From: brian d foy Date: Thu, 20 Feb 2025 18:07:00 -0500 Subject: [PATCH 4/9] bump version from 2.136 to 2.137 --- lib/Module/Release.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Module/Release.pm b/lib/Module/Release.pm index a84083e..468cfa8 100644 --- a/lib/Module/Release.pm +++ b/lib/Module/Release.pm @@ -25,7 +25,7 @@ use strict; use warnings; no warnings; -our $VERSION = '2.136'; +our $VERSION = '2.137'; use Carp qw(carp croak); use File::Basename qw(dirname); From 2de9e0954f2bff47c2ef6142567034185332266b Mon Sep 17 00:00:00 2001 From: brian d foy Date: Fri, 21 Feb 2025 11:53:51 -0500 Subject: [PATCH 5/9] use subtests in run() --- t/run.t | 77 +++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/t/run.t b/t/run.t index fdb46f3..40cbf7c 100644 --- a/t/run.t +++ b/t/run.t @@ -12,58 +12,53 @@ require 'setup_common.pl'; my $class = 'Module::Release'; subtest setup => sub { - use_ok( $class ); - can_ok( $class, 'new' ); + use_ok $class; + can_ok $class, 'new'; }; my @subs = qw( run run_error _run_error_set _run_error_reset ); -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Create test object -my $release = $class->new; -isa_ok( $release, $class ); -can_ok( $release, @subs ); +my $release; +subtest 'make objects' => sub { + $release = $class->new; + isa_ok $release, $class; + can_ok $release, @subs; + }; -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Try setting some things -ok( ! defined $release->run_error, "run_error not set yet" ); +subtest 'settings' => sub { + ok ! defined $release->run_error, "run_error not set yet"; -ok( $release->_run_error_set, "Set run_error" ); -ok( $release->run_error, "run_error is set" ); + ok $release->_run_error_set, "Set run_error"; + ok $release->run_error, "run_error is set"; -ok( ! $release->_run_error_reset, "run_error is reset" ); -ok( ! $release->run_error, "run_error is not set" ); + ok ! $release->_run_error_reset, "run_error is reset"; + ok ! $release->run_error, "run_error is not set"; + }; -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Don't pass run a command -{ -my $rc = eval { $release->run }; -my $at = $@; -ok( defined $at, "run with no arguments dies" ); -like( $at, qr/Didn't get a command!/, "Error message with no arguments" ); -} +subtest 'no args to run' => sub { + my $rc = eval { $release->run }; + my $at = $@; + ok defined $at, "run with no arguments dies"; + like $at, qr/Didn't get a command!/, "Error message with no arguments"; + }; -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Pass run undef -{ -my $rc = eval { $release->run( undef ) }; -my $at = $@; -ok( defined $at, "run with undef argument dies" ); -like( $at, qr/Didn't get a command!/, "Error message with undef argument" ); -} +subtest 'undef arg' => sub { + my $rc = eval { $release->run( undef ) }; + my $at = $@; + ok defined $at, "run with undef argument dies"; + like $at, qr/Didn't get a command!/, "Error message with undef argument"; + }; -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Pass it a bad command -{ -local $ENV{PATH} = ''; -my $command = "foo"; -ok( ! -x $command, "$command is not executable (good)" ); +subtest 'bad command' => sub { + local $ENV{PATH} = ''; + my $command = "foo"; + ok ! -x $command, "$command is not executable (good)"; -my $message = eval { $release->run( qq|$command| ) }; -my $at = $@; -ok( defined $at, "Bad command dies" ); -like( $at, qr/Could not open command/, "Error message with bad command" ); -} + my $message = eval { $release->run( qq|$command| ) }; + my $at = $@; + ok defined $at, "Bad command dies"; + like $at, qr/Could not open command/, "Error message with bad command"; + }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pass it a cammand that exits with 255 (which should be bad) From e4643fab383a1fc240ed699f9181fc0847774bf1 Mon Sep 17 00:00:00 2001 From: brian d foy Date: Fri, 21 Feb 2025 12:23:48 -0500 Subject: [PATCH 6/9] Try to catch bad command on Windows --- t/run.t | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/t/run.t b/t/run.t index 40cbf7c..d200dec 100644 --- a/t/run.t +++ b/t/run.t @@ -51,13 +51,24 @@ subtest 'undef arg' => sub { subtest 'bad command' => sub { local $ENV{PATH} = ''; + my $warnings; + local $SIG{__WARN__} = sub { + $warnings = $_[0]; + }; + my $command = "foo"; ok ! -x $command, "$command is not executable (good)"; my $message = eval { $release->run( qq|$command| ) }; my $at = $@; ok defined $at, "Bad command dies"; - like $at, qr/Could not open command/, "Error message with bad command"; + + if( $^O eq 'MSWin32' ) { + like $warnings, qr/'foo' is not recognized/, 'Saw Windows error'; + } + else { + like $at, qr/Could not open command/, "Error message with bad command"; + } }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # From bf9820e75823ec3785921536d5724953f0a39d1c Mon Sep 17 00:00:00 2001 From: brian d foy Date: Fri, 21 Feb 2025 13:23:58 -0500 Subject: [PATCH 7/9] Try run with IPC::Open3 --- lib/Module/Release.pm | 31 ++++++++++++++++++++++++++----- t/run.t | 2 +- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/Module/Release.pm b/lib/Module/Release.pm index 468cfa8..e6b0193 100644 --- a/lib/Module/Release.pm +++ b/lib/Module/Release.pm @@ -30,7 +30,9 @@ our $VERSION = '2.137'; use Carp qw(carp croak); use File::Basename qw(dirname); use File::Spec; +use IPC::Open3; use Scalar::Util qw(blessed); +use Symbol 'gensym'; my %Loaded_mixins = ( ); @@ -1321,24 +1323,43 @@ sub run { $self->_debug( "$command\n" ); $self->_die( "Didn't get a command!" ) unless defined $command; - open my($fh), "-|", "$command" or $self->_die( "Could not open command [$command]: $!" ); - $fh->autoflush; + my $pid = IPC::Open3::open3( + my $child_in, my $child_out, my $child_err = gensym, + $command + ); + close $child_in; + + $child_out->autoflush; + + #open my($fh), "-|", "$command" or $self->_die( "Could not open command [$command]: $!" ); + #$fh->autoflush; my $output = ''; + my $error = ''; my $buffer = ''; local $| = 1; my $readlen = $self->debug ? 1 : 256; - while( read $fh, $buffer, $readlen ) { - $output .= $_; + while( read $child_out, $buffer, $readlen ) { $self->_debug( $_, $buffer ); $output .= $buffer; } + while( read $child_err, $buffer, $readlen ) { + $self->_debug( $_, $buffer ); + $error .= $buffer; + } + + if( $error =~ m/exec of .*? failed| Windows/x ) { + $self->_warn( "Could not run <$command>: $error" ); + } $self->_debug( $self->_dashes, "\n" ); - unless( close $fh ) { + waitpid( $pid, 0 ); + my $child_exit_status = $? >> 8; + + if( $child_exit_status ) { $self->_run_error_set; $self->_warn( "Command [$command] didn't close cleanly: $?" ); } diff --git a/t/run.t b/t/run.t index d200dec..caa1b77 100644 --- a/t/run.t +++ b/t/run.t @@ -67,7 +67,7 @@ subtest 'bad command' => sub { like $warnings, qr/'foo' is not recognized/, 'Saw Windows error'; } else { - like $at, qr/Could not open command/, "Error message with bad command"; + like $at, qr/exec of \Q$command\E failed/, "Error message with bad command"; } }; From c8f3d375300ebd365d967b0e8f8d7ce31ec8c760 Mon Sep 17 00:00:00 2001 From: brian d foy Date: Fri, 21 Feb 2025 13:36:24 -0500 Subject: [PATCH 8/9] output run error if there is one --- lib/Module/Release.pm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Module/Release.pm b/lib/Module/Release.pm index e6b0193..cb26991 100644 --- a/lib/Module/Release.pm +++ b/lib/Module/Release.pm @@ -1323,9 +1323,9 @@ sub run { $self->_debug( "$command\n" ); $self->_die( "Didn't get a command!" ) unless defined $command; - my $pid = IPC::Open3::open3( - my $child_in, my $child_out, my $child_err = gensym, - $command + my $pid = IPC::Open3::open3( + my $child_in, my $child_out, my $child_err = gensym, + $command ); close $child_in; @@ -1357,11 +1357,13 @@ sub run { $self->_debug( $self->_dashes, "\n" ); waitpid( $pid, 0 ); - my $child_exit_status = $? >> 8; + my $child_exit_status = $? >> 8; + + $self->_warn( $error ) if length $error; if( $child_exit_status ) { $self->_run_error_set; - $self->_warn( "Command [$command] didn't close cleanly: $?" ); + $self->_warn( "Command [$command] didn't close cleanly: $?" ); } return $output; From 010e629313acb8d89dc7fce50bc2c16091185629 Mon Sep 17 00:00:00 2001 From: brian d foy Date: Fri, 21 Feb 2025 13:59:49 -0500 Subject: [PATCH 9/9] capture Windows error --- lib/Module/Release.pm | 3 ++- t/run.t | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Module/Release.pm b/lib/Module/Release.pm index cb26991..1d48f23 100644 --- a/lib/Module/Release.pm +++ b/lib/Module/Release.pm @@ -1359,11 +1359,12 @@ sub run { waitpid( $pid, 0 ); my $child_exit_status = $? >> 8; + $self->_warn( $error ) if length $error; if( $child_exit_status ) { $self->_run_error_set; - $self->_warn( "Command [$command] didn't close cleanly: $?" ); + $self->_warn( "Command [$command] didn't close cleanly: $child_exit_status" ); } return $output; diff --git a/t/run.t b/t/run.t index caa1b77..a7b73d1 100644 --- a/t/run.t +++ b/t/run.t @@ -64,7 +64,7 @@ subtest 'bad command' => sub { ok defined $at, "Bad command dies"; if( $^O eq 'MSWin32' ) { - like $warnings, qr/'foo' is not recognized/, 'Saw Windows error'; + like $warnings, qr/didn't close cleanly/, 'Saw Windows error'; } else { like $at, qr/exec of \Q$command\E failed/, "Error message with bad command";