From 786851cc4660e93c434a1c9997de1b8b1942f221 Mon Sep 17 00:00:00 2001 From: Flavio Soibelmann Glock Date: Thu, 27 Aug 2026 09:29:41 +0200 Subject: [PATCH] fix: attribute resumed CPAN build failures to parent modules Map resumed distribution archive lines back to their selected module before recording configure or build failures, so completed dependencies are not incorrectly marked failed. Generated with [Codex](https://openai.com/codex/) Co-Authored-By: Codex --- dev/tools/cpan_random_tester.pl | 13 ++++++++ dev/tools/tests/cpan_random_tester_parser.t | 33 +++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/dev/tools/cpan_random_tester.pl b/dev/tools/cpan_random_tester.pl index af29fe534..4dbd964a2 100644 --- a/dev/tools/cpan_random_tester.pl +++ b/dev/tools/cpan_random_tester.pl @@ -591,6 +591,13 @@ sub parse_all_module_results { if ($line =~ /Running (?:test|install) for module '([^']+)'/) { $last_mod = $1; } + # CPAN resumes the parent distribution after processing dependencies + # without necessarily repeating "Running test for module". Associate + # its archive path with the module recorded during Pass 1 so a later + # configure/build failure is not charged to the last dependency. + if ($line =~ m{(?:Configuring|Running (?:make|Build) for) \S+/(\S+)\.tar\.gz}) { + $last_mod = $dist_to_mod{$1} if $dist_to_mod{$1}; + } # Configure failed if ($last_mod && !$seen{$last_mod} @@ -701,6 +708,12 @@ sub parse_all_module_results_from_file { if ($line =~ /Running (?:test|install) for module '([^']+)'/) { $last_mod = $1; } + # See the equivalent Pass 3 association in + # parse_all_module_results: a parent archive can resume after a + # dependency without another module-selection line. + if ($line =~ m{(?:Configuring|Running (?:make|Build) for) \S+/(\S+)\.tar\.gz}) { + $last_mod = $dist_to_mod{$1} if $dist_to_mod{$1}; + } if ($last_mod && !$seen{$last_mod} && $line =~ /(?:Makefile\.PL|Build\.PL) -- NOT OK/) { diff --git a/dev/tools/tests/cpan_random_tester_parser.t b/dev/tools/tests/cpan_random_tester_parser.t index bfc97edbd..5061e82c0 100644 --- a/dev/tools/tests/cpan_random_tester_parser.t +++ b/dev/tools/tests/cpan_random_tester_parser.t @@ -63,6 +63,39 @@ is_deeply( 'streaming parser preserves the target association too', ); +my $build_failure_after_dependency = <<'LOG'; +Running test for module 'Marpa::R2' +Checksum for /tmp/cpan/sources/authors/id/J/JK/JKEGL/Marpa-R2-14.000000.tar.gz ok +---- Unsatisfied dependencies detected during ---- + PPI [configure_requires] +Running test for module 'PPI' +Checksum for /tmp/cpan/sources/authors/id/M/MI/MITHALDU/PPI-1.291.tar.gz ok +Configuring M/MI/MITHALDU/PPI-1.291.tar.gz with Makefile.PL +Running make for M/MI/MITHALDU/PPI-1.291.tar.gz + /usr/bin/make -- OK +Configuring J/JK/JKEGL/Marpa-R2-14.000000.tar.gz with Build.PL +Running Build for J/JK/JKEGL/Marpa-R2-14.000000.tar.gz + /tmp/jperl Build -- NOT OK +LOG + +my @build_results = parse_all_module_results($build_failure_after_dependency); +is_deeply( + [map { $_->{module} } @build_results], + ['Marpa::R2'], + 'parent build failure is not attributed to the completed dependency', +); +is($build_results[0]{error}, 'Build failed', 'parent build failure is retained'); + +my ($build_log_fh, $build_log_path) = tempfile(); +print {$build_log_fh} $build_failure_after_dependency; +close $build_log_fh or die "cannot close $build_log_path: $!"; +my @streamed_build_results = parse_all_module_results_from_file($build_log_path); +is_deeply( + [map { $_->{module} } @streamed_build_results], + ['Marpa::R2'], + 'streaming parser attributes resumed-parent build failure correctly', +); + my %slow = ('Image::ExifTool' => 3600); is_deeply( [effective_timeout_limits('Image::ExifTool', 120, 600, 300, \%slow)],