CPAN-Reporter-1.2010/0000775000175000017500000000000012132015716012574 5ustar garugaruCPAN-Reporter-1.2010/xt/0000775000175000017500000000000012132015716013227 5ustar garugaruCPAN-Reporter-1.2010/xt/release/0000775000175000017500000000000012132015716014647 5ustar garugaruCPAN-Reporter-1.2010/xt/release/minimum-version.t0000644000175000017500000000026612132015716020174 0ustar garugaru#!perl use Test::More; eval "use Test::MinimumVersion"; plan skip_all => "Test::MinimumVersion required for testing minimum versions" if $@; all_minimum_version_ok( qq{5.010} ); CPAN-Reporter-1.2010/xt/release/pod-coverage.t0000644000175000017500000000052712132015716017411 0ustar garugaru#!perl use Test::More; eval "use Test::Pod::Coverage 1.08"; plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" if $@; eval "use Pod::Coverage::TrustPod"; plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage" if $@; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); CPAN-Reporter-1.2010/xt/release/distmeta.t0000644000175000017500000000021712132015716016644 0ustar garugaru#!perl use Test::More; eval "use Test::CPAN::Meta"; plan skip_all => "Test::CPAN::Meta required for testing META.yml" if $@; meta_yaml_ok(); CPAN-Reporter-1.2010/xt/release/test-version.t0000644000175000017500000000064312132015716017477 0ustar garugaruuse strict; use warnings; use Test::More; # generated by Dist::Zilla::Plugin::Test::Version 0.002004 BEGIN { eval "use Test::Version; 1;" or die $@; } my @imports = ( 'version_all_ok' ); my $params = { is_strict => 0, has_version => 1, }; push @imports, $params if version->parse( $Test::Version::VERSION ) >= version->parse('1.002'); Test::Version->import(@imports); version_all_ok; done_testing; CPAN-Reporter-1.2010/xt/release/portability.t0000644000175000017500000000027712132015716017402 0ustar garugaru#!perl use Test::More; eval 'use Test::Portability::Files'; plan skip_all => 'Test::Portability::Files required for testing portability' if $@; options(test_one_dot => 0); run_tests(); CPAN-Reporter-1.2010/xt/release/pod-syntax.t0000644000175000017500000000021212132015716017133 0ustar garugaru#!perl use Test::More; eval "use Test::Pod 1.41"; plan skip_all => "Test::Pod 1.41 required for testing POD" if $@; all_pod_files_ok(); CPAN-Reporter-1.2010/xt/author/0000775000175000017500000000000012132015716014531 5ustar garugaruCPAN-Reporter-1.2010/xt/author/pod-spell.t0000644000175000017500000000107312132015716016614 0ustar garugaruuse strict; use warnings; use Test::More; # generated by Dist::Zilla::Plugin::Test::PodSpelling 2.004003 eval "use Test::Spelling 0.12; use Pod::Wordlist::hanekomu; 1" or die $@; add_stopwords(); all_pod_files_spelling_ok( qw( bin lib ) ); __DATA__ HTTPS IRC ISP's MSWin Modulino SMTP SSL Skipfile cpan cpanreporter exe ini metabase Metabase modulino na uri wiki Wiki David Golden dagolden Alexandr Ciornii alexchorny Breno de Oliveira garu Christian Walde walde Kent Fredric kentfredric Matthew Musgrove mr lib CPAN Reporter FAQ Config API History PrereqCheck CPAN-Reporter-1.2010/xt/author/critic.t0000644000175000017500000000043512132015716016173 0ustar garugaru#!perl use strict; use warnings; use Test::More; use English qw(-no_match_vars); eval "use Test::Perl::Critic"; plan skip_all => 'Test::Perl::Critic required to criticise code' if $@; Test::Perl::Critic->import( -profile => "perlcritic.rc" ) if -e "perlcritic.rc"; all_critic_ok(); CPAN-Reporter-1.2010/perlcritic.rc0000644000175000017500000000107512132015716015263 0ustar garugaruseverity = 5 verbose = 8 [Variables::ProhibitPunctuationVars] allow = $@ $! [TestingAndDebugging::ProhibitNoStrict] allow = refs # Turn these off [-BuiltinFunctions::ProhibitStringyEval] [-ControlStructures::ProhibitPostfixControls] [-ControlStructures::ProhibitUnlessBlocks] [-Documentation::RequirePodSections] [-InputOutput::ProhibitInteractiveTest] [-References::ProhibitDoubleSigils] [-RegularExpressions::RequireExtendedFormatting] [-InputOutput::ProhibitTwoArgOpen] [-Bangs::ProhibitBitwiseOperators] # Turn this on [Lax::ProhibitStringyEval::ExceptForRequire] CPAN-Reporter-1.2010/LICENSE0000644000175000017500000002635412132015716013611 0ustar garugaruThis software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. CPAN-Reporter-1.2010/META.json0000644000175000017500000000731112132015716014215 0ustar garugaru{ "abstract" : "Adds CPAN Testers reporting to CPAN.pm", "author" : [ "David Golden " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 4.300033, CPAN::Meta::Converter version 2.120921", "license" : [ "apache_2_0" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "CPAN-Reporter", "no_index" : { "directory" : [ "t", "xt", "examples", "corpus" ], "package" : [ "DB" ] }, "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.30" } }, "develop" : { "requires" : { "Pod::Coverage::TrustPod" : "0", "Test::CPAN::Meta" : "0", "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.08" } }, "runtime" : { "requires" : { "CPAN" : "1.9301", "CPAN::Version" : "0", "Capture::Tiny" : "0", "Carp" : "0", "Config" : "0", "Config::Tiny" : "2.08", "Devel::Autoflush" : "0.04", "Exporter" : "0", "ExtUtils::MakeMaker" : "6.36", "Fcntl" : "0", "File::Basename" : "0", "File::Find" : "0", "File::Glob" : "0", "File::HomeDir" : "0.58", "File::Path" : "0", "File::Spec" : "3.19", "File::Temp" : "0.16", "IO::File" : "0", "IPC::Cmd" : "0.76", "Parse::CPAN::Meta" : "0", "Probe::Perl" : "0", "Test::Reporter" : "1.54", "constant" : "0", "perl" : "5.006", "strict" : "0", "vars" : "0" } }, "test" : { "requires" : { "Archive::Tar" : "1.54", "File::Copy::Recursive" : "0.35", "File::Spec::Functions" : "0", "File::pushd" : "0.32", "IO::CaptureOutput" : "1.03", "List::Util" : "0", "Test::Harness" : "0", "Test::More" : "0.62", "warnings" : "0" } } }, "provides" : { "CPAN::Reporter" : { "file" : "lib/CPAN/Reporter.pm", "version" : "1.2010" }, "CPAN::Reporter::API" : { "file" : "lib/CPAN/Reporter/API.pm", "version" : "1.2010" }, "CPAN::Reporter::Config" : { "file" : "lib/CPAN/Reporter/Config.pm", "version" : "1.2010" }, "CPAN::Reporter::FAQ" : { "file" : "lib/CPAN/Reporter/FAQ.pm", "version" : "1.2010" }, "CPAN::Reporter::History" : { "file" : "lib/CPAN/Reporter/History.pm", "version" : "1.2010" }, "CPAN::Reporter::PrereqCheck" : { "file" : "lib/CPAN/Reporter/PrereqCheck.pm", "version" : "1.2010" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-CPAN-Reporter@rt.cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=CPAN-Reporter" }, "homepage" : "https://metacpan.org/release/CPAN-Reporter", "repository" : { "type" : "git", "url" : "git://github.com/dagolden/cpan-reporter.git", "web" : "https://github.com/dagolden/cpan-reporter" } }, "version" : "1.2010", "x_contributors" : [ "Alexandr Ciornii ", "Breno G. de Oliveira ", "Christian Walde ", "Kent Fredric ", "Matthew Musgrove " ] } CPAN-Reporter-1.2010/MANIFEST.SKIP0000644000175000017500000000001112132015716014460 0ustar garugaru^t/dist/ CPAN-Reporter-1.2010/README0000644000175000017500000001627412132015716013464 0ustar garugaruNAME CPAN::Reporter - Adds CPAN Testers reporting to CPAN.pm VERSION version 1.2010 SYNOPSIS From the CPAN shell: cpan> install Task::CPAN::Reporter cpan> reload cpan cpan> o conf init test_report Installing Task::CPAN::Reporter will pull in additional dependencies that new CPAN Testers will need. Advanced CPAN Testers with custom Test::Reporter::Transport setups may wish to install only CPAN::Reporter, which has fewer dependencies. DESCRIPTION The CPAN Testers project captures and analyzes detailed results from building and testing CPAN distributions on multiple operating systems and multiple versions of Perl. This provides valuable feedback to module authors and potential users to identify bugs or platform compatibility issues and improves the overall quality and value of CPAN. One way individuals can contribute is to send a report for each module that they test or install. CPAN::Reporter is an add-on for the CPAN.pm module to send the results of building and testing modules to the CPAN Testers project. Full support for CPAN::Reporter is available in CPAN.pm as of version 1.92. GETTING STARTED Installation The first step in using CPAN::Reporter is to install it using whatever version of CPAN.pm is already installed. CPAN.pm will be upgraded as a dependency if necessary. cpan> install CPAN::Reporter If CPAN.pm was upgraded, it needs to be reloaded. cpan> reload cpan Configuration If upgrading from a very old version of CPAN.pm, users may be prompted to renew their configuration settings, including the 'test_report' option to enable CPAN::Reporter. If not prompted automatically, users should manually initialize CPAN::Reporter support. After enabling CPAN::Reporter, CPAN.pm will automatically continue with interactive configuration of CPAN::Reporter options. cpan> o conf init test_report Users will need to enter an email address in one of the following formats: johndoe@example.com John Doe "John Q. Public" Users that are new to CPAN::Reporter should accept the recommended values for other configuration options. Users will be prompted to create a *Metabase profile* file that uniquely identifies their test reports. See "The Metabase" below for details. After completing interactive configuration, be sure to commit (save) the CPAN configuration changes. cpan> o conf commit See CPAN::Reporter::Config for advanced configuration settings. The Metabase CPAN::Reporter sends test reports to a server known as the Metabase. This requires an active Internet connection and a profile file. To create the profile, users will need to run "metabase-profile" from a terminal window and fill the information at the prompts. This will create a file called "metabase_id.json" in the current directory. That file should be moved to the ".cpanreporter" directory inside the user's home directory. Users with an existing metabase profile file (e.g. from another machine), should copy it into the ".cpanreporter" directory instead of creating a new one. Profile files may be located outside the ".cpanreporter" directory by following instructions in CPAN::Reporter::Config. Using CPAN::Reporter Once CPAN::Reporter is enabled and configured, test or install modules with CPAN.pm as usual. For example, to test the File::Marker module: cpan> test File::Marker If a distribution's tests fail, users will be prompted to edit the report to add additional information that might help the author understand the failure. UNDERSTANDING TEST GRADES CPAN::Reporter will assign one of the following grades to the report: * "pass" -- distribution built and tested correctly * "fail" -- distribution failed to test correctly * "unknown" -- distribution failed to build, had no test suite or outcome was inconclusive * "na" --- distribution is not applicable to this platform and/or version of Perl In returning results of the test suite to CPAN.pm, "pass" and "unknown" are considered successful attempts to "make test" or "Build test" and will not prevent installation. "fail" and "na" are considered to be failures and CPAN.pm will not install unless forced. An error from Makefile.PL/Build.PL or make/Build will also be graded as "unknown" and a failure will be signaled to CPAN.pm. If prerequisites specified in "Makefile.PL" or "Build.PL" are not available, no report will be generated and a failure will be signaled to CPAN.pm. PRIVACY WARNING CPAN::Reporter includes information in the test report about environment variables and special Perl variables that could be affecting test results in order to help module authors interpret the results of the tests. This includes information about paths, terminal, locale, user/group ID, installed toolchain modules (e.g. ExtUtils::MakeMaker) and so on. These have been intentionally limited to items that should not cause harmful personal information to be revealed -- it does *not* include your entire environment. Nevertheless, please do not use CPAN::Reporter if you are concerned about the disclosure of this information as part of your test report. Users wishing to review this information may choose to edit the report prior to sending it. BUGS Please report any bugs or feature using the CPAN Request Tracker. Bugs can be submitted through the web interface at When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. SEE ALSO Information about CPAN::Testers: * CPAN::Testers -- overview of CPAN Testers architecture stack * -- project home with all reports * -- documentation and wiki Additional Documentation: * CPAN::Reporter::Config -- advanced configuration settings * CPAN::Reporter::FAQ -- hints and tips SUPPORT Bugs / Feature Requests Please report any bugs or feature requests through the issue tracker at . You will be notified automatically of any progress on your issue. Source Code This is open source software. The code repository is available for public review and contribution under the terms of the license. git clone git://github.com/dagolden/cpan-reporter.git AUTHOR David Golden CONTRIBUTORS * Alexandr Ciornii * Breno G. de Oliveira * Christian Walde * Kent Fredric * Matthew Musgrove COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 CPAN-Reporter-1.2010/lib/0000775000175000017500000000000012132015716013342 5ustar garugaruCPAN-Reporter-1.2010/lib/CPAN/0000775000175000017500000000000012132015716014063 5ustar garugaruCPAN-Reporter-1.2010/lib/CPAN/Reporter.pm0000644000175000017500000015245112132015716016231 0ustar garugaruuse strict; package CPAN::Reporter; our $VERSION = '1.2010'; # VERSION use Config; use Capture::Tiny qw/ capture tee_merged /; use CPAN 1.9301 (); use CPAN::Version (); use File::Basename qw/basename dirname/; use File::Find (); use File::HomeDir (); use File::Path qw/mkpath rmtree/; use File::Spec 3.19 (); use File::Temp 0.16 qw/tempdir/; use IO::File (); use Parse::CPAN::Meta (); use Probe::Perl (); use Test::Reporter 1.54 (); use CPAN::Reporter::Config (); use CPAN::Reporter::History (); use CPAN::Reporter::PrereqCheck (); use constant MAX_OUTPUT_LENGTH => 1_000_000; #--------------------------------------------------------------------------# # create temp lib dir for Devel::Autoflush # so that PERL5OPT=-MDevel::Autoflush is found by any perl #--------------------------------------------------------------------------# use Devel::Autoflush 0.04 (); # directory fixture my $Autoflush_Lib = tempdir( "CPAN-Reporter-lib-XXXX", TMPDIR => 1, CLEANUP => 1 ); # copy Devel::Autoflush to directory or clear autoflush_lib variable _file_copy_quiet( $INC{'Devel/Autoflush.pm'}, File::Spec->catfile( $Autoflush_Lib, qw/Devel Autoflush.pm/ ) ) or undef $Autoflush_Lib; #--------------------------------------------------------------------------# # public API #--------------------------------------------------------------------------# sub configure { goto &CPAN::Reporter::Config::_configure; } sub grade_make { my @args = @_; my $result = _init_result( 'make', @args ) or return; _compute_make_grade($result); if ( $result->{grade} eq 'discard' ) { $CPAN::Frontend->myprint( "\nCPAN::Reporter: test results were not valid, $result->{grade_msg}.\n\n", $result->{prereq_pm}, "\n", "Test report will not be sent" ); CPAN::Reporter::History::_record_history( $result ) if not CPAN::Reporter::History::_is_duplicate( $result ); } else { _print_grade_msg($result->{make_cmd}, $result); if ( $result->{grade} ne 'pass' ) { _dispatch_report( $result ) } } return $result->{success}; } sub grade_PL { my @args = @_; my $result = _init_result( 'PL', @args ) or return; _compute_PL_grade($result); if ( $result->{grade} eq 'discard' ) { $CPAN::Frontend->myprint( "\nCPAN::Reporter: test results were not valid, $result->{grade_msg}.\n\n", $result->{prereq_pm}, "\n", "Test report will not be sent" ); CPAN::Reporter::History::_record_history( $result ) if not CPAN::Reporter::History::_is_duplicate( $result ); } else { _print_grade_msg($result->{PL_file} , $result); if ( $result->{grade} ne 'pass' ) { _dispatch_report( $result ) } } return $result->{success}; } sub grade_test { my @args = @_; my $result = _init_result( 'test', @args ) or return; _compute_test_grade($result); if ( $result->{grade} eq 'discard' ) { $CPAN::Frontend->myprint( "\nCPAN::Reporter: test results were not valid, $result->{grade_msg}.\n\n", $result->{prereq_pm}, "\n", "Test report will not be sent" ); CPAN::Reporter::History::_record_history( $result ) if not CPAN::Reporter::History::_is_duplicate( $result ); } else { _print_grade_msg( "Test", $result ); _dispatch_report( $result ); } return $result->{success}; } sub record_command { my ($command, $timeout) = @_; # XXX refactor this! # Get configuration options if ( -r CPAN::Reporter::Config::_get_config_file() ) { my $config_obj = CPAN::Reporter::Config::_open_config_file(); my $config; $config = CPAN::Reporter::Config::_get_config_options( $config_obj ) if $config_obj; $timeout ||= $config->{command_timeout}; # might still be undef } my ($cmd, $redirect) = _split_redirect($command); # Teeing a command loses its exit value so we must wrap the command # and print the exit code so we can read it off of output my $wrap_code; if ( $timeout ) { $wrap_code = $^O eq 'MSWin32' ? _timeout_wrapper_win32($cmd, $timeout) : _timeout_wrapper($cmd, $timeout); } # if no timeout or timeout wrap code wasn't available if ( ! $wrap_code ) { my $safecmd = quotemeta($cmd); $wrap_code = << "HERE"; my \$rc = system("$safecmd"); my \$ec = \$rc == -1 ? -1 : \$?; print "($safecmd exited with \$ec)\\n"; HERE } # write code to a tempfile for execution my $wrapper_name = _temp_filename( 'CPAN-Reporter-CW-' ); my $wrapper_fh = IO::File->new( $wrapper_name, 'w' ) or die "Could not create a wrapper for $cmd\: $!"; $wrapper_fh->print( $wrap_code ); $wrapper_fh->close; # tee the command wrapper my @tee_input = ( Probe::Perl->find_perl_interpreter, $wrapper_name ); push @tee_input, $redirect if defined $redirect; my $tee_out; { # ensure autoflush if we can local $ENV{PERL5OPT} = _get_perl5opt() if _is_PL($command); $tee_out = tee_merged { system( @tee_input ) }; } # cleanup unlink $wrapper_name unless $ENV{PERL_CR_NO_CLEANUP}; my @cmd_output = split qr{(?<=$/)}, $tee_out; if ( ! @cmd_output ) { $CPAN::Frontend->mywarn( "CPAN::Reporter: didn't capture command results for '$cmd'\n" ); return; } # extract the exit value my $exit_value; if ( $cmd_output[-1] =~ m{exited with} ) { ($exit_value) = $cmd_output[-1] =~ m{exited with ([-0-9]+)}; pop @cmd_output; } # bail out on some errors if ( ! defined $exit_value ) { $CPAN::Frontend->mywarn( "CPAN::Reporter: couldn't determine exit value for '$cmd'\n" ); return; } elsif ( $exit_value == -1 ) { $CPAN::Frontend->mywarn( "CPAN::Reporter: couldn't execute '$cmd'\n" ); return; } return \@cmd_output, $exit_value; } sub test { my ($dist, $system_command) = @_; my ($output, $exit_value) = record_command( $system_command ); return grade_test( $dist, $system_command, $output, $exit_value ); } #--------------------------------------------------------------------------# # private functions #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # _compute_make_grade #--------------------------------------------------------------------------# sub _compute_make_grade { my $result = shift; my ($grade,$msg); if ( $result->{exit_value} ) { $result->{grade} = "unknown"; $result->{grade_msg} = "Stopped with an error" } else { $result->{grade} = "pass"; $result->{grade_msg} = "No errors" } _downgrade_known_causes( $result ); $result->{success} = $result->{grade} eq 'pass'; return; } #--------------------------------------------------------------------------# # _compute_PL_grade #--------------------------------------------------------------------------# sub _compute_PL_grade { my $result = shift; my ($grade,$msg); if ( $result->{exit_value} ) { $result->{grade} = "unknown"; $result->{grade_msg} = "Stopped with an error" } else { $result->{grade} = "pass"; $result->{grade_msg} = "No errors" } _downgrade_known_causes( $result ); $result->{success} = $result->{grade} eq 'pass'; return; } #--------------------------------------------------------------------------# # _compute_test_grade # # Don't shortcut to unknown unless _has_tests because a custom # Makefile.PL or Build.PL might define tests in a non-standard way # # With test.pl and 'make test', any t/*.t might pass Test::Harness, but # test.pl might still fail, or there might only be test.pl, # so use exit code directly # # Likewise, if we have recursive Makefile.PL, then we don't trust the # reverse-order parsing and should just take the exit code directly # # Otherwise, parse in reverse order for Test::Harness output or a couple # other significant strings and stop after the first match. Going in # reverse and stopping is done to (hopefully) avoid picking up spurious # results from any test output. But then we have to check for # unsupported OS strings in case those were printed but were not fatal. #--------------------------------------------------------------------------# sub _compute_test_grade { my $result = shift; my ($grade,$msg); my $output = $result->{output}; # In some cases, get a result straight from the exit code if ( $result->{is_make} && ( -f "test.pl" || _has_recursive_make() ) ) { if ( $result->{exit_value} ) { $grade = "fail"; $msg = "'make test' error detected"; } else { $grade = "pass"; $msg = "'make test' no errors"; } } # Otherwise, get a result from Test::Harness output else { # figure out the right harness parser _expand_result( $result ); my $harness_version = $result->{toolchain}{'Test::Harness'}{have}; my $harness_parser = CPAN::Version->vgt($harness_version, '2.99_01') ? \&_parse_tap_harness : \&_parse_test_harness; # parse lines in reverse for my $i ( reverse 0 .. $#{$output} ) { if ( $output->[$i] =~ m{No support for OS|OS unsupported}ims ) { # from any *.t file $grade = 'na'; $msg = 'This platform is not supported'; } elsif ( $output->[$i] =~ m{^.?No tests defined}ms ) { # from M::B $grade = 'unknown'; $msg = 'No tests provided'; } else { ($grade, $msg) = $harness_parser->( $output->[$i] ); } last if $grade; } # fallback on exit value if no recognizable Test::Harness output if ( ! $grade ) { $grade = $result->{exit_value} ? "fail" : "pass"; $msg = ( $result->{is_make} ? "'make test' " : "'Build test' " ) . ( $result->{exit_value} ? "error detected" : "no errors"); } } $result->{grade} = $grade; $result->{grade_msg} = $msg; _downgrade_known_causes( $result ); $result->{success} = $result->{grade} eq 'pass' || $result->{grade} eq 'unknown'; return; } #--------------------------------------------------------------------------# # _dispatch_report # # Set up Test::Reporter and prompt user for edit, send #--------------------------------------------------------------------------# sub _dispatch_report { my $result = shift; my $phase = $result->{phase}; $CPAN::Frontend->myprint( "CPAN::Reporter: preparing a CPAN Testers report for $result->{dist_name}\n" ); # Get configuration options my $config_obj = CPAN::Reporter::Config::_open_config_file(); my $config; $config = CPAN::Reporter::Config::_get_config_options( $config_obj ) if $config_obj; if ( ! $config->{email_from} ) { $CPAN::Frontend->mywarn( << "EMAIL_REQUIRED"); CPAN::Reporter: required 'email_from' option missing an email address, so test report will not be sent. See documentation for configuration details. Even though CPAN Testers no longer uses email, this email address will show up in the report and help identify the tester. This is required for compatibility with tools that process legacy reports for analysis. EMAIL_REQUIRED return; } # Need to know if this is a duplicate my $is_duplicate = CPAN::Reporter::History::_is_duplicate( $result ); # Abort if the distribution name is not formatted according to # CPAN Testers requirements: Dist-Name-version.suffix # Regex from CPAN-Testers should extract name, separator, version # and extension my @format_checks = $result->{dist_basename} =~ m{(.+)([\-\_])(v?\d.*)(\.(?:tar\.(?:gz|bz2)|tgz|zip))$}i; ; if ( ! grep { length } @format_checks ) { $CPAN::Frontend->mywarn( << "END_BAD_DISTNAME"); CPAN::Reporter: the distribution name '$result->{dist_basename}' does not appear to be packaged according to CPAN tester guidelines. Perhaps it is not a normal CPAN distribution. Test report will not be sent. END_BAD_DISTNAME # record this as a discard, instead $result->{grade} = 'discard'; CPAN::Reporter::History::_record_history( $result ) if not $is_duplicate; return; } # Gather 'expensive' data for the report _expand_result( $result); # Skip if distribution name matches the send_skipfile if ( $config->{send_skipfile} && -r $config->{send_skipfile} ) { my $send_skipfile = IO::File->new( $config->{send_skipfile}, "r" ); my $dist_id = $result->{dist}->pretty_id; while ( my $pattern = <$send_skipfile> ) { chomp($pattern); # ignore comments next if substr($pattern,0,1) eq '#'; # if it doesn't match, continue with next pattern next if $dist_id !~ /$pattern/i; # if it matches, warn and return $CPAN::Frontend->myprint( << "END_SKIP_DIST" ); CPAN::Reporter: '$dist_id' matched against the send_skipfile. Test report will not be sent. END_SKIP_DIST return; } } # Setup the test report my $tr = Test::Reporter->new; $tr->grade( $result->{grade} ); $tr->distribution( $result->{dist_name} ); # Older Test::Reporter doesn't support distfile, but we need it for # Metabase transport $tr->distfile( $result->{dist}->pretty_id ) if $Test::Reporter::VERSION >= 1.54; # Skip if duplicate and not sending duplicates if ( $is_duplicate ) { if ( _prompt( $config, "send_duplicates", $tr->grade) =~ /^n/ ) { $CPAN::Frontend->myprint(<< "DUPLICATE_REPORT"); CPAN::Reporter: this appears to be a duplicate report for the $phase phase: @{[$tr->subject]} Test report will not be sent. DUPLICATE_REPORT return; } } # Set debug and transport options, if supported $tr->debug( $config->{debug} ) if defined $config->{debug}; my $transport = $config->{transport}; unless ( defined $transport && length $transport ) { $CPAN::Frontend->mywarn( << "TRANSPORT_REQUIRED"); CPAN::Reporter: required 'transport' option missing so the test report will not be sent. See documentation for configuration details. TRANSPORT_REQUIRED return; } my @transport_args = split " ", $transport; # special hack for Metabase arguments if ($transport_args[0] eq 'Metabase') { @transport_args = _validate_metabase_args(@transport_args); unless (@transport_args) { $CPAN::Frontend->mywarn( "Test report will not be sent.\n\n" ); return; } } eval { $tr->transport( @transport_args ) }; if ($@) { $CPAN::Frontend->mywarn( "CPAN::Reporter: problem with Test::Reporter transport: \n" . "$@\n" . "Test report will not be sent\n" ); return; } # prepare mail transport $tr->from( $config->{email_from} ); # Populate the test report $tr->comments( _report_text( $result ) ); $tr->via( 'CPAN::Reporter ' . $CPAN::Reporter::VERSION ); # prompt for editing report if ( _prompt( $config, "edit_report", $tr->grade ) =~ /^y/ ) { my $editor = $config->{editor}; local $ENV{VISUAL} = $editor if $editor; ## no critic $tr->edit_comments; } # send_*_report can override send_report my $send_config = defined $config->{"send_$phase\_report"} ? "send_$phase\_report" : "send_report" ; if ( _prompt( $config, $send_config, $tr->grade ) =~ /^y/ ) { $CPAN::Frontend->myprint( "CPAN::Reporter: sending test report with '" . $tr->grade . "' via " . $transport_args[0] . "\n"); if ( $tr->send() ) { CPAN::Reporter::History::_record_history( $result ) if not $is_duplicate; } else { $CPAN::Frontend->mywarn( "CPAN::Reporter: " . $tr->errstr . "\n"); if ( $config->{retry_submission} ) { sleep(3); $CPAN::Frontend->mywarn( "CPAN::Reporter: second attempt\n"); $tr->errstr(''); if ( $tr->send() ) { CPAN::Reporter::History::_record_history( $result ) if not $is_duplicate; } else { $CPAN::Frontend->mywarn( "CPAN::Reporter: " . $tr->errstr . "\n"); } } } } else { $CPAN::Frontend->myprint("CPAN::Reporter: test report will not be sent\n"); } return; } #--------------------------------------------------------------------------# # _downgrade_known_causes # Downgrade failure/unknown grade if we can determine a cause # If platform not supported => 'na' # If perl version is too low => 'na' # If stated prereqs missing => 'discard' #--------------------------------------------------------------------------# sub _downgrade_known_causes { my ($result) = @_; my ($grade, $output) = ( $result->{grade}, $result->{output} ); my $msg = $result->{grade_msg} || q{}; # shortcut unless fail/unknown; but PL might look like pass but actually # have "OS Unsupported" messages if someone printed message and then # did "exit 0" return if $grade eq 'na'; return if $grade eq 'pass' && $result->{phase} ne 'PL'; # get prereqs _expand_result( $result ); # if process was halted with a signal, just set for discard and return if ( $result->{exit_value} & 127 ) { $result->{grade} = 'discard'; $result->{grade_msg} = 'Command interrupted'; return; } # look for perl version error messages from various programs # "Error evaling..." type errors happen on Perl < 5.006 when modules # define their version with "our $VERSION = ..." my ($harness_error, $version_error, $unsupported) ; for my $line ( @$output ) { if ( $result->{phase} eq 'test' && $line =~ m{open3: IO::Pipe: Can't spawn.*?TAP/Parser/Iterator/Process.pm} ) { $harness_error++; last; } if( $line =~ /Perl .*? required.*?--this is only/ims || $line =~ /Perl version .*? or higher required\. We run/ims || #EU::MM $line =~ /ERROR: perl: Version .*? is installed, but we need version/ims || $line =~ /ERROR: perl \(.*?\) is installed, but we need version/ims || $line =~ /Error evaling version line 'BEGIN/ims || $line =~ /Could not eval '/ims ) { $version_error++; last; } if ( $line =~ /No support for OS|OS unsupported/ims ) { $unsupported++; last; } } # if the test harness had an error, discard the report if ( $harness_error ) { $grade = 'discard'; $msg = 'Test harness failure'; } # check for explicit version error or just a perl version prerequisite elsif ( $version_error || $result->{prereq_pm} =~ m{^\s+!\s+perl\s}ims ) { $grade = 'na'; $msg = 'Perl version too low'; } # check again for unsupported OS in case we took 'fail' from exit value elsif ( $unsupported ) { $grade = 'na'; $msg = 'This platform is not supported'; } # check for Makefile without 'test' target; there are lots # of variations on the error message, e.g. "target test", "target 'test'", # "'test'", "`test'" and so on. elsif ( $result->{is_make} && $result->{phase} eq 'test' && ! _has_test_target() ) { $grade = 'unknown'; $msg = 'No make test target'; } # check the prereq report for missing or failure flag '!' elsif ( $grade ne 'pass' && $result->{prereq_pm} =~ m{n/a}ims ) { $grade = 'discard'; $msg = "Prerequisite missing:\n$result->{prereq_pm}"; } elsif ( $grade ne 'pass' && $result->{prereq_pm} =~ m{^\s+!}ims ) { $grade = 'discard'; $msg = "Prerequisite version too low:\n$result->{prereq_pm}"; } # in PL stage -- if pass but no Makefile or Build, then this should # be recorded as a discard elsif ( $result->{phase} eq 'PL' && $grade eq 'pass' && ! -f 'Makefile' && ! -f 'Build' ) { $grade = 'discard'; $msg = 'No Makefile or Build file found'; } elsif ( $result->{command} =~ /Build.*?-j/ ) { $grade = 'discard'; $msg = '-j is not a valid option for Module::Build (upgrade your CPAN.pm)'; } elsif ( $result->{is_make} && $result->{phase} eq 'make' && grep { /Makefile out-of-date with respect to Makefile.PL/ } @$output ) { $grade = 'discard'; $msg = 'Makefile out-of-date'; } # store results $result->{grade} = $grade; $result->{grade_msg} = $msg; return; } #--------------------------------------------------------------------------# # _expand_result - add expensive information like prerequisites and # toolchain that should only be generated if a report will actually # be sent #--------------------------------------------------------------------------# sub _expand_result { my $result = shift; return if $result->{expanded}++; # only do this once $result->{prereq_pm} = _prereq_report( $result->{dist} ); { # mirror PERL5OPT as in record_command local $ENV{PERL5OPT} = _get_perl5opt() if _is_PL($result->{command}); $result->{env_vars} = _env_report(); } $result->{special_vars} = _special_vars_report(); $result->{toolchain_versions} = _toolchain_report( $result ); $result->{perl_version} = CPAN::Reporter::History::_format_perl_version(); return; } #--------------------------------------------------------------------------# # _env_report #--------------------------------------------------------------------------# # Entries bracketed with "/" are taken to be a regex; otherwise literal my @env_vars= qw( /PERL/ /LC_/ LANG LANGUAGE PATH SHELL COMSPEC TERM TEMP TMPDIR AUTOMATED_TESTING /AUTHOR_TEST/ INCLUDE LIB LD_LIBRARY_PATH PROCESSOR_IDENTIFIER NUMBER_OF_PROCESSORS ); sub _env_report { my @vars_found; for my $var ( @env_vars ) { if ( $var =~ m{^/(.+)/$} ) { push @vars_found, grep { /$1/ } keys %ENV; } else { push @vars_found, $var if exists $ENV{$var}; } } my $report = ""; for my $var ( sort @vars_found ) { my $value = $ENV{$var}; $value = '[undef]' if ! defined $value; $report .= " $var = $value\n"; } return $report; } #--------------------------------------------------------------------------# # _file_copy_quiet # # manual file copy -- quietly return undef on failure #--------------------------------------------------------------------------# sub _file_copy_quiet { my ($source, $target) = @_; # ensure we have a target directory mkpath( dirname($target) ) or return; # read source local *FH; open FH, "<$source" or return; ## no critic my $pm_guts = do { local $/; }; close FH; # write target open FH, ">$target" or return; ## no critic print FH $pm_guts; close FH; return 1; } #--------------------------------------------------------------------------# # _get_perl5opt #--------------------------------------------------------------------------# sub _get_perl5opt { my $perl5opt = $ENV{PERL5OPT} || q{}; if ( $Autoflush_Lib ) { $perl5opt .= q{ } if length $perl5opt; $perl5opt .= "-I$Autoflush_Lib " if $] >= 5.008; $perl5opt .= "-MDevel::Autoflush"; } return $perl5opt; } #--------------------------------------------------------------------------# # _has_recursive_make # # Ignore Makefile.PL in t directories #--------------------------------------------------------------------------# sub _has_recursive_make { my $PL_count = 0; File::Find::find( sub { if ( $_ eq 't' ) { $File::Find::prune = 1; } elsif ( $_ eq 'Makefile.PL' ) { $PL_count++; } }, File::Spec->curdir() ); return $PL_count > 1; } #--------------------------------------------------------------------------# # _has_test_target #--------------------------------------------------------------------------# sub _has_test_target { my $fh = IO::File->new("Makefile") or return; return scalar grep { /^test[ ]*:/ } <$fh>; } #--------------------------------------------------------------------------# # _init_result -- create and return a hash of values for use in # report evaluation and dispatch # # takes same argument format as grade_*() #--------------------------------------------------------------------------# sub _init_result { my ($phase, $dist, $system_command, $output, $exit_value) = @_; unless ( defined $output && defined $exit_value ) { my $missing; if ( ! defined $output && ! defined $exit_value ) { $missing = "exit value and output" } elsif ( defined $output && !defined $exit_value ) { $missing = "exit value" } else { $missing = "output"; } $CPAN::Frontend->mywarn( "CPAN::Reporter: had errors capturing $missing. Tests abandoned" ); return; } my $result = { phase => $phase, dist => $dist, command => $system_command, is_make => _is_make( $system_command ), output => ref $output eq 'ARRAY' ? $output : [ split /\n/, $output ], exit_value => $exit_value, # Note: pretty_id is like "DAGOLDEN/CPAN-Reporter-0.40.tar.gz" dist_basename => basename($dist->pretty_id), dist_name => $dist->base_id, }; # Used in messages to user $result->{PL_file} = $result->{is_make} ? "Makefile.PL" : "Build.PL"; $result->{make_cmd} = $result->{is_make} ? $Config{make} : "Build"; # CPAN might fail to find an author object for some strange dists my $author = $dist->author; $result->{author} = defined $author ? $author->fullname : "Author"; $result->{author_id} = defined $author ? $author->id : "" ; return $result; } #--------------------------------------------------------------------------# # _is_make #--------------------------------------------------------------------------# sub _is_make { my $command = shift; return $command =~ m{\b(?:\S*make|Makefile.PL)\b}ims ? 1 : 0; } #--------------------------------------------------------------------------# # _is_PL #--------------------------------------------------------------------------# sub _is_PL { my $command = shift; return $command =~ m{\b(?:Makefile|Build)\.PL\b}ims ? 1 : 0; } #--------------------------------------------------------------------------# # _max_length #--------------------------------------------------------------------------# sub _max_length { my ($first, @rest) = @_; my $max = length $first; for my $term ( @rest ) { $max = length $term if length $term > $max; } return $max; } #--------------------------------------------------------------------------# # _parse_tap_harness # # As of Test::Harness 2.99_02, the final line is provided by TAP::Harness # as "Result: STATUS" where STATUS is "PASS", "FAIL" or "NOTESTS" #--------------------------------------------------------------------------# sub _parse_tap_harness { my ($line) = @_; if ( $line =~ m{^Result:\s+([A-Z]+)} ) { if ( $1 eq 'PASS' ) { return ('pass', 'All tests successful'); } elsif ( $1 eq 'FAIL' ) { return ('fail', 'One or more tests failed'); } elsif ( $1 eq 'NOTESTS' ) { return ('unknown', 'No tests were run'); } } elsif ( $line =~ m{Bailout called\.\s+Further testing stopped}ms ) { return ( 'fail', 'Bailed out of tests'); } return; } #--------------------------------------------------------------------------# # _parse_test_harness # # Output strings taken from Test::Harness:: # _show_results() -- for versions < 2.57_03 # get_results() -- for versions >= 2.57_03 #--------------------------------------------------------------------------# sub _parse_test_harness { my ($line) = @_; if ( $line =~ m{^All tests successful}ms ) { return ( 'pass', 'All tests successful' ); } elsif ( $line =~ m{^FAILED--no tests were run}ms ) { return ( 'unknown', 'No tests were run' ); } elsif ( $line =~ m{^FAILED--.*--no output}ms ) { return ( 'unknown', 'No tests were run'); } elsif ( $line =~ m{FAILED--Further testing stopped}ms ) { return ( 'fail', 'Bailed out of tests'); } elsif ( $line =~ m{^Failed }ms ) { # must be lowercase return ( 'fail', 'One or more tests failed'); } else { return; } } #--------------------------------------------------------------------------# # _prereq_report #--------------------------------------------------------------------------# my @prereq_sections = qw/requires build_requires configure_requires/; sub _prereq_report { my $dist = shift; my (%need, %have, %prereq_met, $report); # Extract requires/build_requires from CPAN dist my $prereq_pm = $dist->prereq_pm; if ( ref $prereq_pm eq 'HASH' ) { # is it the new CPAN style with requires/build_requires? if (join(q{ }, sort keys %$prereq_pm) eq "build_requires requires") { $need{requires} = $prereq_pm->{requires} if ref $prereq_pm->{requires} eq 'HASH'; $need{build_requires} = $prereq_pm->{build_requires} if ref $prereq_pm->{build_requires} eq 'HASH'; } else { $need{requires} = $prereq_pm; } } # Extract configure_requires from META.yml if it exists if ( $dist->{build_dir} && -d $dist->{build_dir} ) { my $meta_yml = File::Spec->catfile($dist->{build_dir}, 'META.yml'); if ( -f $meta_yml ) { my @yaml = eval { Parse::CPAN::Meta::LoadFile($meta_yml) }; if ( $@ ) { $CPAN::Frontend->mywarn( "CPAN::Reporter: error parsing META.yml\n" ); } if ( ref $yaml[0] eq 'HASH' && ref $yaml[0]{configure_requires} eq 'HASH' ) { $need{configure_requires} = $yaml[0]{configure_requires}; } } } # see what prereqs are satisfied in subprocess for my $section ( @prereq_sections ) { next unless ref $need{$section} eq 'HASH'; my @prereq_list = %{ $need{$section} }; next unless @prereq_list; my $prereq_results = _version_finder( @prereq_list ); for my $mod ( keys %{$prereq_results} ) { $have{$section}{$mod} = $prereq_results->{$mod}{have}; $prereq_met{$section}{$mod} = $prereq_results->{$mod}{met}; } } # find formatting widths my ($name_width, $need_width, $have_width) = (6, 4, 4); for my $section ( @prereq_sections ) { for my $module ( keys %{ $need{$section} } ) { my $name_length = length $module; my $need_length = length $need{$section}{$module}; my $have_length = length $have{$section}{$module}; $name_width = $name_length if $name_length > $name_width; $need_width = $need_length if $need_length > $need_width; $have_width = $have_length if $have_length > $have_width; } } my $format_str = " \%1s \%-${name_width}s \%-${need_width}s \%-${have_width}s\n"; # generate the report for my $section ( @prereq_sections ) { if ( keys %{ $need{$section} } ) { $report .= "$section:\n\n"; $report .= sprintf( $format_str, " ", qw/Module Need Have/ ); $report .= sprintf( $format_str, " ", "-" x $name_width, "-" x $need_width, "-" x $have_width ); for my $module (sort {lc $a cmp lc $b} keys %{ $need{$section} } ) { my $need = $need{$section}{$module}; my $have = $have{$section}{$module}; my $bad = $prereq_met{$section}{$module} ? " " : "!"; $report .= sprintf( $format_str, $bad, $module, $need, $have); } $report .= "\n"; } } return $report || " No requirements found\n"; } #--------------------------------------------------------------------------# # _print_grade_msg - #--------------------------------------------------------------------------# sub _print_grade_msg { my ($phase, $result) = @_; my ($grade, $msg) = ($result->{grade}, $result->{grade_msg}); $CPAN::Frontend->myprint( "CPAN::Reporter: $phase result is '$grade'"); $CPAN::Frontend->myprint(", $msg") if defined $msg && length $msg; $CPAN::Frontend->myprint(".\n"); return; } #--------------------------------------------------------------------------# # _prompt # # Note: always returns lowercase #--------------------------------------------------------------------------# sub _prompt { my ($config, $option, $grade, $extra) = @_; $extra ||= q{}; my %spec = CPAN::Reporter::Config::_config_spec(); my $dispatch = CPAN::Reporter::Config::_validate_grade_action_pair( $option, join(q{ }, "default:no", $config->{$option} || '') ); my $action = $dispatch->{$grade} || $dispatch->{default}; my $intro = $spec{$option}{prompt} . $extra . " (yes/no)"; my $prompt; if ( $action =~ m{^ask/yes}i ) { $prompt = CPAN::Shell::colorable_makemaker_prompt( $intro, "yes" ); } elsif ( $action =~ m{^ask(/no)?}i ) { $prompt = CPAN::Shell::colorable_makemaker_prompt( $intro, "no" ); } else { $prompt = $action; } return lc $prompt; } #--------------------------------------------------------------------------# # _report_text #--------------------------------------------------------------------------# my %intro_para = ( 'pass' => <<'HERE', Thank you for uploading your work to CPAN. Congratulations! All tests were successful. HERE 'fail' => <<'HERE', Thank you for uploading your work to CPAN. However, there was a problem testing your distribution. If you think this report is invalid, please consult the CPAN Testers Wiki for suggestions on how to avoid getting FAIL reports for missing library or binary dependencies, unsupported operating systems, and so on: http://wiki.cpantesters.org/wiki/CPANAuthorNotes HERE 'unknown' => <<'HERE', Thank you for uploading your work to CPAN. However, attempting to test your distribution gave an inconclusive result. This could be because your distribution had an error during the make/build stage, did not define tests, tests could not be found, because your tests were interrupted before they finished, or because the results of the tests could not be parsed. You may wish to consult the CPAN Testers Wiki: http://wiki.cpantesters.org/wiki/CPANAuthorNotes HERE 'na' => <<'HERE', Thank you for uploading your work to CPAN. While attempting to build or test this distribution, the distribution signaled that support is not available either for this operating system or this version of Perl. Nevertheless, any diagnostic output produced is provided below for reference. If this is not what you expect, you may wish to consult the CPAN Testers Wiki: http://wiki.cpantesters.org/wiki/CPANAuthorNotes HERE ); sub _report_text { my $data = shift; my $test_log = join(q{},@{$data->{output}}); if ( length $test_log > MAX_OUTPUT_LENGTH ) { $test_log = substr( $test_log, 0, MAX_OUTPUT_LENGTH) . "\n"; my $max_k = int(MAX_OUTPUT_LENGTH/1000) . "K"; $test_log .= "\n[Output truncated after $max_k]\n\n"; } # Flag automated report my $default_comment = $ENV{AUTOMATED_TESTING} ? "this report is from an automated smoke testing program\nand was not reviewed by a human for accuracy" : "none provided" ; # generate report my $output = << "ENDREPORT"; Dear $data->{author}, This is a computer-generated report for $data->{dist_name} on perl $data->{perl_version}, created by CPAN-Reporter-$CPAN::Reporter::VERSION\. $intro_para{ $data->{grade} } Sections of this report: * Tester comments * Program output * Prerequisites * Environment and other context ------------------------------ TESTER COMMENTS ------------------------------ Additional comments from tester: $default_comment ------------------------------ PROGRAM OUTPUT ------------------------------ Output from '$data->{command}': $test_log ------------------------------ PREREQUISITES ------------------------------ Prerequisite modules loaded: $data->{prereq_pm} ------------------------------ ENVIRONMENT AND OTHER CONTEXT ------------------------------ Environment variables: $data->{env_vars} Perl special variables (and OS-specific diagnostics, for MSWin32): $data->{special_vars} Perl module toolchain versions installed: $data->{toolchain_versions} ENDREPORT return $output; } #--------------------------------------------------------------------------# # _special_vars_report #--------------------------------------------------------------------------# sub _special_vars_report { my $special_vars = << "HERE"; \$^X = $^X \$UID/\$EUID = $< / $> \$GID = $( \$EGID = $) HERE if ( $^O eq 'MSWin32' && eval "require Win32" ) { ## no critic my @getosversion = Win32::GetOSVersion(); my $getosversion = join(", ", @getosversion); $special_vars .= " Win32::GetOSName = " . Win32::GetOSName() . "\n"; $special_vars .= " Win32::GetOSVersion = $getosversion\n"; $special_vars .= " Win32::FsType = " . Win32::FsType() . "\n"; $special_vars .= " Win32::IsAdminUser = " . Win32::IsAdminUser() . "\n"; } return $special_vars; } #--------------------------------------------------------------------------# # _split_redirect #--------------------------------------------------------------------------# sub _split_redirect { my $command = shift; my ($cmd, $prefix) = ($command =~ m{\A(.+?)(\|.*)\z}); if (defined $cmd) { return ($cmd, $prefix); } else { # didn't match a redirection return $command } } #--------------------------------------------------------------------------# # _temp_filename -- stand-in for File::Temp for backwards compatibility # # takes an optional prefix, adds 8 random chars and returns # an absolute pathname # # NOTE -- manual unlink required #--------------------------------------------------------------------------# # @CHARS from File::Temp my @CHARS = (qw/ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 _ /); sub _temp_filename { my ($prefix) = @_; $prefix = q{} unless defined $prefix; $prefix .= $CHARS[ int( rand(@CHARS) ) ] for 0 .. 7; return File::Spec->catfile(File::Spec->tmpdir(), $prefix); } #--------------------------------------------------------------------------# # _timeout_wrapper # Timeout technique adapted from App::cpanminus (thank you Miyagawa!) #--------------------------------------------------------------------------# sub _timeout_wrapper { my ($cmd, $timeout) = @_; # protect shell quotes $cmd = quotemeta($cmd); my $wrapper = sprintf << 'HERE', $timeout, $cmd, $cmd; use strict; my ($pid, $exitcode); eval { $pid = fork; if ($pid) { local $SIG{CHLD}; local $SIG{ALRM} = sub {die 'Timeout'}; alarm %s; my $wstat = waitpid $pid, 0; alarm 0; $exitcode = $wstat == -1 ? -1 : $?; } elsif ( $pid == 0 ) { setpgrp(0,0); # new process group exec "%s"; } else { die "Cannot fork: $!\n" unless defined $pid; } }; if ($pid && $@ =~ /Timeout/){ kill -9 => $pid; # and send to our child's whole process group waitpid $pid, 0; $exitcode = 9; # force result to look like SIGKILL } elsif ($@) { die $@; } print "(%s exited with $exitcode)\n"; HERE return $wrapper; } #--------------------------------------------------------------------------# # _timeout_wrapper_win32 #--------------------------------------------------------------------------# sub _timeout_wrapper_win32 { my ($cmd, $timeout) = @_; $timeout ||= 0; # just in case upstream doesn't guarantee it eval "use Win32::Job ();"; if ($@) { $CPAN::Frontend->mywarn( << 'HERE' ); CPAN::Reporter: you need Win32::Job for inactivity_timeout support. Continuing without timeout... HERE return; } my ($program) = split " ", $cmd; if (! File::Spec->file_name_is_absolute( $program ) ) { my $exe = $program . ".exe"; my ($path) = grep { -e File::Spec->catfile($_,$exe) } split /$Config{path_sep}/, $ENV{PATH}; if (! $path) { $CPAN::Frontend->mywarn( << "HERE" ); CPAN::Reporter: can't locate $exe in the PATH. Continuing without timeout... HERE return; } $program = File::Spec->catfile($path,$exe); } # protect shell quotes and other things $_ = quotemeta($_) for ($program, $cmd); my $wrapper = sprintf << 'HERE', $program, $cmd, $timeout; use strict; use Win32::Job; my $executable = "%s"; my $cmd_line = "%s"; my $timeout = %s; my $job = Win32::Job->new() or die $^E; my $ppid = $job->spawn($executable, $cmd_line); $job->run($timeout); my $status = $job->status; my $exitcode = $status->{$ppid}{exitcode}; if ( $exitcode == 293 ) { $exitcode = 9; # map Win32::Job kill (293) to SIGKILL (9) } elsif ( $exitcode & 255 ) { $exitcode = $exitcode << 8; # how perl expects it } print "($cmd_line exited with $exitcode)\n"; HERE return $wrapper; } #--------------------------------------------------------------------------#- # _toolchain_report #--------------------------------------------------------------------------# my @toolchain_mods= qw( CPAN CPAN::Meta Cwd ExtUtils::CBuilder ExtUtils::Command ExtUtils::Install ExtUtils::MakeMaker ExtUtils::Manifest ExtUtils::ParseXS File::Spec JSON JSON::PP Module::Build Module::Signature Parse::CPAN::Meta Test::Harness Test::More YAML YAML::Syck version ); sub _toolchain_report { my ($result) = @_; my $installed = _version_finder( map { $_ => 0 } @toolchain_mods ); $result->{toolchain} = $installed; my $mod_width = _max_length( keys %$installed ); my $ver_width = _max_length( map { $installed->{$_}{have} } keys %$installed ); my $format = " \%-${mod_width}s \%-${ver_width}s\n"; my $report = ""; $report .= sprintf( $format, "Module", "Have" ); $report .= sprintf( $format, "-" x $mod_width, "-" x $ver_width ); for my $var ( sort keys %$installed ) { $report .= sprintf(" \%-${mod_width}s \%-${ver_width}s\n", $var, $installed->{$var}{have} ); } return $report; } #--------------------------------------------------------------------------# # _validate_metabase_args # # This is a kludge to make metabase transport args a little less # clunky for novice users #--------------------------------------------------------------------------# sub _validate_metabase_args { my @transport_args = @_; shift @transport_args; # drop leading 'Metabase' my (%args, $error); if ( @transport_args % 2 != 0 ) { $error = << "TRANSPORT_ARGS"; CPAN::Reporter: Metabase 'transport' option had odd number of parameters in the config file. See documentation for proper configuration format. TRANSPORT_ARGS } else { %args = @transport_args; for my $key ( qw/uri id_file/ ) { if ( ! $args{$key} ) { $error = << "TRANSPORT_ARGS"; CPAN::Reporter: Metabase 'transport' option did not have a '$key' parameter in the config file. See documentation for proper configuration format. TRANSPORT_ARGS } } } if ( $error ) { $CPAN::Frontend->mywarn( $error ); return; } $args{id_file} = CPAN::Reporter::Config::_normalize_id_file( $args{id_file} ); if ( ! -r $args{id_file} ) { $CPAN::Frontend->mywarn( <<"TRANSPORT_ARGS" ); CPAN::Reporter: Could not find Metabase tranport 'id_file' parameter located at '$args{id_file}'. See documentation for proper configuration of the 'transport' setting. TRANSPORT_ARGS return; } return ('Metabase', %args); } #--------------------------------------------------------------------------# # _version_finder # # module => version pairs # # This is done via an external program to show installed versions exactly # the way they would be found when test programs are run. This means that # any updates to PERL5LIB will be reflected in the results. # # File-finding logic taken from CPAN::Module::inst_file(). Logic to # handle newer Module::Build prereq syntax is taken from # CPAN::Distribution::unsat_prereq() # #--------------------------------------------------------------------------# my $version_finder = $INC{'CPAN/Reporter/PrereqCheck.pm'}; sub _version_finder { my %prereqs = @_; my $perl = Probe::Perl->find_perl_interpreter(); my @prereq_results; my $prereq_input = _temp_filename( 'CPAN-Reporter-PI-' ); my $fh = IO::File->new( $prereq_input, "w" ) or die "Could not create temporary '$prereq_input' for prereq analysis: $!"; $fh->print( map { "$_ $prereqs{$_}\n" } keys %prereqs ); $fh->close; my $prereq_result = capture { system( $perl, $version_finder, '<', $prereq_input ) }; unlink $prereq_input; my %result; for my $line ( split "\n", $prereq_result ) { next unless length $line; my ($mod, $met, $have) = split " ", $line; unless ( defined($mod) && defined($met) && defined($have) ) { $CPAN::Frontend->mywarn( "Error parsing output from CPAN::Reporter::PrereqCheck:\n" . $line ); next; } $result{$mod}{have} = $have; $result{$mod}{met} = $met; } return \%result; } 1; # ABSTRACT: Adds CPAN Testers reporting to CPAN.pm =pod =encoding utf-8 =head1 NAME CPAN::Reporter - Adds CPAN Testers reporting to CPAN.pm =head1 VERSION version 1.2010 =head1 SYNOPSIS From the CPAN shell: cpan> install Task::CPAN::Reporter cpan> reload cpan cpan> o conf init test_report Installing L will pull in additional dependencies that new CPAN Testers will need. Advanced CPAN Testers with custom L setups may wish to install only CPAN::Reporter, which has fewer dependencies. =head1 DESCRIPTION The CPAN Testers project captures and analyzes detailed results from building and testing CPAN distributions on multiple operating systems and multiple versions of Perl. This provides valuable feedback to module authors and potential users to identify bugs or platform compatibility issues and improves the overall quality and value of CPAN. One way individuals can contribute is to send a report for each module that they test or install. CPAN::Reporter is an add-on for the CPAN.pm module to send the results of building and testing modules to the CPAN Testers project. Full support for CPAN::Reporter is available in CPAN.pm as of version 1.92. =for Pod::Coverage configure grade_PL grade_make grade_test record_command test =head1 GETTING STARTED =head2 Installation The first step in using CPAN::Reporter is to install it using whatever version of CPAN.pm is already installed. CPAN.pm will be upgraded as a dependency if necessary. cpan> install CPAN::Reporter If CPAN.pm was upgraded, it needs to be reloaded. cpan> reload cpan =head2 Configuration If upgrading from a very old version of CPAN.pm, users may be prompted to renew their configuration settings, including the 'test_report' option to enable CPAN::Reporter. If not prompted automatically, users should manually initialize CPAN::Reporter support. After enabling CPAN::Reporter, CPAN.pm will automatically continue with interactive configuration of CPAN::Reporter options. cpan> o conf init test_report Users will need to enter an email address in one of the following formats: johndoe@example.com John Doe "John Q. Public" Users that are new to CPAN::Reporter should accept the recommended values for other configuration options. Users will be prompted to create a I file that uniquely identifies their test reports. See L below for details. After completing interactive configuration, be sure to commit (save) the CPAN configuration changes. cpan> o conf commit See L for advanced configuration settings. =head3 The Metabase CPAN::Reporter sends test reports to a server known as the Metabase. This requires an active Internet connection and a profile file. To create the profile, users will need to run C<<< metabase-profile >>> from a terminal window and fill the information at the prompts. This will create a file called C<<< metabase_id.json >>> in the current directory. That file should be moved to the C<<< .cpanreporter >>> directory inside the user's home directory. Users with an existing metabase profile file (e.g. from another machine), should copy it into the C<<< .cpanreporter >>> directory instead of creating a new one. Profile files may be located outside the C<<< .cpanreporter >>> directory by following instructions in L. =head2 Using CPAN::Reporter Once CPAN::Reporter is enabled and configured, test or install modules with CPAN.pm as usual. For example, to test the File::Marker module: cpan> test File::Marker If a distribution's tests fail, users will be prompted to edit the report to add additional information that might help the author understand the failure. =head1 UNDERSTANDING TEST GRADES CPAN::Reporter will assign one of the following grades to the report: =over =item * C<<< pass >>> -- distribution built and tested correctly =item * C<<< fail >>> -- distribution failed to test correctly =item * C<<< unknown >>> -- distribution failed to build, had no test suite or outcome was inconclusive =item * C<<< na >>> --- distribution is not applicable to this platform andEor version of Perl =back In returning results of the test suite to CPAN.pm, "pass" and "unknown" are considered successful attempts to "make test" or "Build test" and will not prevent installation. "fail" and "na" are considered to be failures and CPAN.pm will not install unless forced. An error from Makefile.PLEBuild.PL or makeEBuild will also be graded as "unknown" and a failure will be signaled to CPAN.pm. If prerequisites specified in C<<< Makefile.PL >>> or C<<< Build.PL >>> are not available, no report will be generated and a failure will be signaled to CPAN.pm. =head1 PRIVACY WARNING CPAN::Reporter includes information in the test report about environment variables and special Perl variables that could be affecting test results in order to help module authors interpret the results of the tests. This includes information about paths, terminal, locale, userEgroup ID, installed toolchain modules (e.g. ExtUtils::MakeMaker) and so on. These have been intentionally limited to items that should not cause harmful personal information to be revealed -- it does I include your entire environment. Nevertheless, please do not use CPAN::Reporter if you are concerned about the disclosure of this information as part of your test report. Users wishing to review this information may choose to edit the report prior to sending it. =head1 BUGS Please report any bugs or feature using the CPAN Request Tracker. Bugs can be submitted through the web interface at L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 SEE ALSO Information about CPAN::Testers: =over =item * L -- overview of CPAN Testers architecture stack =item * L -- project home with all reports =item * L -- documentation and wiki =back Additional Documentation: =over =item * L -- advanced configuration settings =item * L -- hints and tips =back =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan =head1 SUPPORT =head2 Bugs / Feature Requests Please report any bugs or feature requests through the issue tracker at L. You will be notified automatically of any progress on your issue. =head2 Source Code This is open source software. The code repository is available for public review and contribution under the terms of the license. L git clone git://github.com/dagolden/cpan-reporter.git =head1 AUTHOR David Golden =head1 CONTRIBUTORS =over 4 =item * Alexandr Ciornii =item * Breno G. de Oliveira =item * Christian Walde =item * Kent Fredric =item * Matthew Musgrove =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # vim: ts=4 sts=4 sw=4 et: CPAN-Reporter-1.2010/lib/CPAN/Reporter/0000775000175000017500000000000012132015716015665 5ustar garugaruCPAN-Reporter-1.2010/lib/CPAN/Reporter/History.pm0000644000175000017500000003155712132015716017675 0ustar garugaruuse strict; package CPAN::Reporter::History; our $VERSION = '1.2010'; # VERSION use vars qw/@ISA @EXPORT_OK/; use Config; use Carp; use Fcntl qw/:flock/; use File::HomeDir (); use File::Path (qw/mkpath/); use File::Spec (); use IO::File (); use CPAN (); # for printing warnings use CPAN::Reporter::Config (); require Exporter; @ISA = qw/Exporter/; @EXPORT_OK = qw/have_tested/; #--------------------------------------------------------------------------# # Some platforms don't implement flock, so fake it if necessary #--------------------------------------------------------------------------# BEGIN { eval { my $temp_file = File::Spec->catfile( File::Spec->tmpdir(), $$ . time() ); my $fh = IO::File->new( $temp_file, "w" ); flock $fh, LOCK_EX; $fh->close; unlink $temp_file; }; if ( $@ ) { *CORE::GLOBAL::flock = sub (*$) { 1 }; } } #--------------------------------------------------------------------------# # Back-compatibility checks -- just once per load #--------------------------------------------------------------------------# # 0.99_08 changed the history file format and name # If an old file exists, convert it to the new name and format. Note -- # someone running multiple installations of CPAN::Reporter might have old # and new versions running so only convert in the case where the old file # exists and the new file does not { my $old_history_file = _get_old_history_file(); my $new_history_file = _get_history_file(); last if -f $new_history_file || ! -f $old_history_file; $CPAN::Frontend->mywarn("CPAN::Reporter: Your history file is in an old format. Upgrading automatically.\n"); # open old and new files my ($old_fh, $new_fh); if (! ( $old_fh = IO::File->new( $old_history_file ) ) ) { $CPAN::Frontend->mywarn("CPAN::Reporter: error opening old history file: $!\nContinuing without conversion.\n"); last; } if (! ($new_fh = IO::File->new( $new_history_file, "w" ) ) ) { $CPAN::Frontend->mywarn("CPAN::Reporter: error opening new history file: $!\nContinuing without conversion.\n"); last; } print {$new_fh} _generated_by(); while ( my $line = <$old_fh> ) { chomp $line; # strip off perl version and convert # try not to match 5.1 from "MSWin32-x86-multi-thread 5.1" # from really old CPAN::Reporter history formats my ($old_version, $perl_patch); if ( $line =~ m{ (5\.0\d{2,5}) ?(patch \d+)?\z} ) { ($old_version, $perl_patch) = ($1, $2); $line =~ s{ (5\.0\d{2,5}) ?(patch \d+)?\z}{}; } my $pv = $old_version ? "perl-" . _perl_version($old_version) : "unknown"; $pv .= " $perl_patch" if $perl_patch; my ($grade_dist, $arch_os) = ($line =~ /(\S+ \S+) (.+)/); print {$new_fh} "test $grade_dist ($pv) $arch_os\n"; } close $old_fh; close $new_fh; } #--------------------------------------------------------------------------# # Public methods #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # have_tested -- search for dist in history file #--------------------------------------------------------------------------# sub have_tested { ## no critic RequireArgUnpacking # validate arguments croak "arguments to have_tested() must be key value pairs" if @_ % 2; my $args = { @_ }; my @bad_params = grep { $_ !~ m{^(?:dist|phase|grade|perl|archname|osvers)$} } keys %$args; croak "bad parameters for have_tested(): " . join(q{, },@bad_params) if @bad_params; # DWIM: grades to upper case $args->{grade} = uc $args->{grade} if defined $args->{grade}; # default to current platform $args->{perl} = _format_perl_version() unless defined $args->{perl}; $args->{archname} = $Config{archname} unless defined $args->{archname}; $args->{osvers} = $Config{osvers} unless defined $args->{osvers}; my @found; my $history = _open_history_file('<') or return; flock $history, LOCK_SH; <$history>; # throw away format line while ( defined (my $line = <$history>) ) { my $fields = _split_history( $line ) or next; push @found, $fields if _match($fields, $args); } $history->close; return @found; } #--------------------------------------------------------------------------# # Private methods #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # _format_history -- # # phase grade dist-version (perl-version patchlevel) archname osvers #--------------------------------------------------------------------------# sub _format_history { my ($result) = @_; my $phase = $result->{phase}; my $grade = uc $result->{grade}; my $dist_name = $result->{dist_name}; my $perlver = "perl-" . _format_perl_version(); my $platform = "$Config{archname} $Config{osvers}"; return "$phase $grade $dist_name ($perlver) $platform\n"; } #--------------------------------------------------------------------------# # _format_perl_version #--------------------------------------------------------------------------# sub _format_perl_version { my $pv = _perl_version(); $pv .= " patch $Config{perl_patchlevel}" if $Config{perl_patchlevel}; return $pv; } sub _generated_by { return "# Generated by CPAN::Reporter " . "$CPAN::Reporter::History::VERSION\n"; } #--------------------------------------------------------------------------# # _get_history_file #--------------------------------------------------------------------------# sub _get_history_file { return File::Spec->catdir( CPAN::Reporter::Config::_get_config_dir(), "reports-sent.db" ); } #--------------------------------------------------------------------------# # _get_old_history_file -- prior to 0.99_08 #--------------------------------------------------------------------------# sub _get_old_history_file { return File::Spec->catdir( CPAN::Reporter::Config::_get_config_dir(), "history.db" ); } #--------------------------------------------------------------------------# # _is_duplicate #--------------------------------------------------------------------------# sub _is_duplicate { my ($result) = @_; my $log_line = _format_history( $result ); my $history = _open_history_file('<') or return; my $found = 0; flock $history, LOCK_SH; while ( defined (my $line = <$history>) ) { if ( $line eq $log_line ) { $found++; last; } } $history->close; return $found; } #--------------------------------------------------------------------------# # _match #--------------------------------------------------------------------------# sub _match { my ($fields, $search) = @_; for my $k ( keys %$search ) { next if $search->{$k} eq q{}; # empty string matches anything return unless $fields->{$k} eq $search->{$k}; } return 1; # all keys matched } #--------------------------------------------------------------------------# # _open_history_file #--------------------------------------------------------------------------# sub _open_history_file { my $mode = shift || '<'; my $history_filename = _get_history_file(); my $file_exists = -f $history_filename; # shortcut if reading and doesn't exist return if ( $mode eq '<' && ! $file_exists ); # open it in the desired mode my $history = IO::File->new( $history_filename, $mode ) or $CPAN::Frontend->mywarn("CPAN::Reporter: couldn't open history file " . "'$history_filename': $!\n"); # if writing and it didn't exist before, initialize with header if ( substr($mode,0,1) eq '>' && ! $file_exists ) { print {$history} _generated_by(); } return $history; } #--------------------------------------------------------------------------# # _perl_version #--------------------------------------------------------------------------# sub _perl_version { my $ver = shift || "$]"; $ver =~ qr/(\d)\.(\d{3})(\d{0,3})/; my ($maj,$min,$pat) = (0 + ($1||0), 0 + ($2||0), 0 + ($3||0)); my $pv; if ( $min < 6 ) { $pv = $ver; } else { $pv = "$maj\.$min\.$pat"; } return $pv; } #--------------------------------------------------------------------------# # _record_history #--------------------------------------------------------------------------# sub _record_history { my ($result) = @_; my $log_line = _format_history( $result ); my $history = _open_history_file('>>') or return; flock( $history, LOCK_EX ); seek( $history, 0, 2 ); # seek to end of file $history->print( $log_line ); flock( $history, LOCK_UN ); $history->close; return; } #--------------------------------------------------------------------------# # _split_history # # splits lines created with _format_history. Returns hash ref with # phase, grade, dist, perl, platform #--------------------------------------------------------------------------# sub _split_history { my ($line) = @_; chomp $line; my %fields; @fields{qw/phase grade dist perl archname osvers/} = $line =~ m{ ^(\S+) \s+ # phase (\S+) \s+ # grade (\S+) \s+ # dist \(perl- ([^)]+) \) \s+ # (perl-version-patchlevel) (\S+) \s+ # archname (.+)$ # osvers }xms; # return nothing if parse fails return if scalar keys %fields == 0;# grep { ! defined($_) } values %fields; # otherwise return hashref return \%fields; } 1; # ABSTRACT: Read or write a CPAN::Reporter history log __END__ =pod =encoding utf-8 =head1 NAME CPAN::Reporter::History - Read or write a CPAN::Reporter history log =head1 VERSION version 1.2010 =head1 SYNOPSIS use CPAN::Reporter::History 'have_tested'; @results = have_tested( dist => 'Dist-Name-1.23' ); =head1 DESCRIPTION Interface for interacting with the CPAN::Reporter history file. Most methods are private for use only within CPAN::Reporter itself. However, a public function is provided to query the history file for results. =head1 USAGE The following function is available. It is not exported by default. =head2 C<<< have_tested() >>> # all reports for Foo-Bar-1.23 @results = have_tested( dist => 'Foo-Bar-1.23' ); # all NA reports @results = have_tested( grade => 'NA' ); # all reports on the current Perl/platform @results = have_tested(); Searches the CPAN::Reporter history file for records exactly matching search criteria, given as pairs of field-names and desired values. Ordinary search criteria include: =over =item * C<<< dist >>> -- the distribution tarball name without any filename suffix; from a C<<< CPAN::Distribution >>> object, this is provided by the C<<< base_id >>> method. =item * C<<< phase >>> -- phase the report was generated during: either 'PL', 'make' or 'test' =item * C<<< grade >>> -- CPAN Testers grade: 'PASS', 'FAIL', 'NA' or 'UNKNOWN'; Also may be 'DISCARD' for any failing reports not sent due to missing prerequisites =back Without additional criteria, a search will be limited to the current version of Perl and the current architecture and OS version. Additional criteria may be specified explicitly or, by specifying the empty string, C<<< q{} >>>, will match that field for I record. # all reports for Foo-Bar-1.23 on any version of perl # on the current architecture and OS version @results = have_tested( dist => 'Foo-Bar-1.23', perl => q{} ); These additional criteria include: =over =item * C<<< perl >>> -- perl version and possible patchlevel; this will be dotted decimal (5.6.2) starting with version 5.6, or will be numeric style as given by C<<< $] >>> for older versions; if a patchlevel exists, it must be specified similar to "5.11.0 patch 12345" =item * C<<< archname >>> -- platform architecture name as given by $Config{archname} =item * C<<< osvers >>> -- operating system version as given by $Config{osvers} =back The function returns an array of hashes representing each test result, with all of the fields listed above. =head1 SEE ALSO =over =item * L =item * L =back =head1 AUTHOR David Golden =head1 CONTRIBUTORS =over 4 =item * Alexandr Ciornii =item * Breno G. de Oliveira =item * Christian Walde =item * Kent Fredric =item * Matthew Musgrove =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut CPAN-Reporter-1.2010/lib/CPAN/Reporter/FAQ.pm0000644000175000017500000001105312132015716016630 0ustar garugaruuse strict; # make CPANTS happy package CPAN::Reporter::FAQ; our $VERSION = '1.2010'; # VERSION 1; # ABSTRACT: Answers and tips for using CPAN::Reporter __END__ =pod =encoding utf-8 =head1 NAME CPAN::Reporter::FAQ - Answers and tips for using CPAN::Reporter =head1 VERSION version 1.2010 =head1 REPORT GRADES =head2 Why did I receive a report? Historically, CPAN Testers was designed to have each tester send a copy of reports to authors. This philosophy changed in September 2008 and CPAN Testers tools were updated to no longer copy authors, but some testers may still be using an older version. =head2 Why was a report sent if a prerequisite is missing? As of CPAN::Reporter 0.46, FAIL and UNKNOWN reports with unsatisfied prerequisites are discarded. Earlier versions may have sent these reports out by mistake as either an NA or UNKNOWN report. PASS reports are not discarded because it may be useful to know when tests passed despite a missing prerequisite. NA reports are sent because information about the lack of support for a platform is relevant regardless of prerequisites. =head1 SENDING REPORTS =head2 Why did I get an error sending a test report? Historically, test reports were sent via ordinary email. The most common reason for errors sending a report back then was that many Internet Service Providers (ISP's) would block outbound SMTP (email) connections as part of their efforts to fight spam. Since 2010, test reports are sent to the CPAN Testers Metabase over HTTPS. The most common reason for failures are systems which upgraded CPAN::Reporter but are still configured to use the deprecated and unsupported email system instead of Metabase for transport. If you are unsure which transport mechanism you're using, look for the C<<< transport >>> rule in the C<<< .cpanreporter/config.ini >>> file, in the user's home directory. See L for details on how to set the C<<< transport >>> option for Metabase. Other errors could be caused by the absence of the C<<< .cpanreporter/metabase_id.json >>> file in the user's home directory. This file should be manually created prior to sending any reports, via the C<<< metabase-profile >>> program. Simply run it and fill in the information accordingly, and it will create the C<<< metabase_id.json >>> file for you. Move that file to your C<<< .cpanreporter >>> directory and you're all set. If you experience intermittent network issues, you can set the 'retry_submission' option to make a second attempt at sending the report a few seconds later, in case the first one fails. This could be useful for extremely slow connections. Finally, lack of Internet connection or firewall filtering will prevent the report from reaching the CPAN Testers servers. If you are experiencing HTTPS issues or messages complaining about SSL modules, try installing the L module and trying again. If all fails, you may still change the transport uri to use HTTP instead of HTTPS, though this is I recommended. =head2 Why didn't my test report show up on CPAN Testers? There is a delay between the time reports are sent to the Metabase and when they they appear on the CPAN Testers website. There is a further delay before summary statistics appear on search.cpan.org. If your reports do not appear after 24 hours, please contact the cpan-testers-discuss email list (L) or join the C<<< #cpantesters-discuss >>> IRC channel on C<<< irc.perl.org >>>. =head1 CPAN TESTERS =head2 Where can I find out more about CPAN Testers? A good place to start is the CPAN Testers Wiki: L =head2 Where can I find statistics about reports sent to CPAN Testers? CPAN Testers statistics are compiled at L =head2 How do I make sure I get credit for my test reports? To get credit in the statistics, use the same Metabase profile file and the same email address wherever you run tests. =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR David Golden =head1 CONTRIBUTORS =over 4 =item * Alexandr Ciornii =item * Breno G. de Oliveira =item * Christian Walde =item * Kent Fredric =item * Matthew Musgrove =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut CPAN-Reporter-1.2010/lib/CPAN/Reporter/Config.pm0000644000175000017500000007604012132015716017435 0ustar garugaruuse strict; package CPAN::Reporter::Config; our $VERSION = '1.2010'; # VERSION use Config::Tiny 2.08 (); use File::Glob (); use File::HomeDir 0.58 (); use File::Path qw/mkpath/; use File::Spec 3.19 (); use IPC::Cmd 0.76 (); use IO::File (); use CPAN 1.9301 (); # for printing warnings #--------------------------------------------------------------------------# # Back-compatibility checks -- just once per load #--------------------------------------------------------------------------# # 0.28_51 changed Mac OS X config file location -- if old directory is found, # move it to the new location if ( $^O eq 'darwin' ) { my $old = File::Spec->catdir(File::HomeDir->my_documents,".cpanreporter"); my $new = File::Spec->catdir(File::HomeDir->my_home,".cpanreporter"); if ( ( -d $old ) && (! -d $new ) ) { $CPAN::Frontend->mywarn( << "HERE"); CPAN::Reporter: since CPAN::Reporter 0.28_51, the Mac OSX config directory has changed. Old: $old New: $new Your existing configuration file will be moved automatically. HERE mkpath($new); my $OLD_CONFIG = IO::File->new( File::Spec->catfile($old, "config.ini"), "<" ) or die $!; my $NEW_CONFIG = IO::File->new( File::Spec->catfile($new, "config.ini"), ">" ) or die $!; $NEW_CONFIG->print( do { local $/; <$OLD_CONFIG> } ); $OLD_CONFIG->close; $NEW_CONFIG->close; unlink File::Spec->catfile($old, "config.ini") or die $!; rmdir($old) or die $!; } } #--------------------------------------------------------------------------# # Public #--------------------------------------------------------------------------# sub _configure { my $config_dir = _get_config_dir(); my $config_file = _get_config_file(); mkpath $config_dir if ! -d $config_dir; if ( ! -d $config_dir ) { $CPAN::Frontend->myprint( "\nCPAN::Reporter: couldn't create configuration directory '$config_dir': $!" ); return; } my $config; my $existing_options; # explain grade:action pairs $CPAN::Frontend->myprint( _grade_action_prompt() ); # read or create if ( -f $config_file ) { $CPAN::Frontend->myprint( "\nCPAN::Reporter: found your CPAN::Reporter config file at:\n$config_file\n" ); $config = _open_config_file(); # if we can't read it, bail out if ( ! $config ) { $CPAN::Frontend->mywarn("\n CPAN::Reporter: configuration will not be changed\n"); return; } # clone what's in the config file $existing_options = { %{$config->{_}} } if $config; $CPAN::Frontend->myprint( "\nCPAN::Reporter: Updating your CPAN::Reporter configuration settings:\n" ); } else { $CPAN::Frontend->myprint( "\nCPAN::Reporter: no config file found; creating a new one.\n" ); $config = Config::Tiny->new(); } my %spec = _config_spec(); for my $k ( _config_order() ) { my $option_data = $spec{$k}; $CPAN::Frontend->myprint( "\n" . $option_data->{info}. "\n"); # options with defaults are mandatory if ( defined $option_data->{default} ) { # if we have a default, always show as a sane recommendation if ( length $option_data->{default} ) { $CPAN::Frontend->myprint( "(Recommended: '$option_data->{default}')\n\n" ); } # repeat until validated PROMPT: while ( defined ( my $answer = CPAN::Shell::colorable_makemaker_prompt( "$k?", $existing_options->{$k} || $option_data->{default} ) )) { if ( ! $option_data->{validate} || $option_data->{validate}->($k, $answer, $config->{_}) ) { $config->{_}{$k} = $answer; last PROMPT; } } } else { # only initialize options without default if # answer matches non white space and validates, # otherwise reset it my $answer = CPAN::Shell::colorable_makemaker_prompt( "$k?", $existing_options->{$k} || q{} ); if ( $answer =~ /\S/ ) { $config->{_}{$k} = $answer; } else { delete $config->{_}{$k}; } } # delete existing as we proceed so we know what's left delete $existing_options->{$k}; } # initialize remaining existing options $CPAN::Frontend->myprint( "\nYour CPAN::Reporter config file also contains these advanced " . "options:\n\n") if keys %$existing_options; for my $k ( keys %$existing_options ) { $config->{_}{$k} = CPAN::Shell::colorable_makemaker_prompt( "$k?", $existing_options->{$k} ); } $CPAN::Frontend->myprint( "\nCPAN::Reporter: writing config file to '$config_file'.\n" ); if ( $config->write( $config_file ) ) { return $config->{_}; } else { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: error writing config file to '$config_file':\n" . Config::Tiny->errstr(). "\n"); return; } } #--------------------------------------------------------------------------# # Private #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # _config_order -- determines order of interactive config. Only items # in interactive config will be written to a starter config file #--------------------------------------------------------------------------# sub _config_order { return qw( email_from edit_report send_report transport ); } #--------------------------------------------------------------------------# # _config_spec -- returns configuration options information # # Keys include # default -- recommended value, used in prompts and as a fallback # if an options is not set; mandatory if defined # prompt -- short prompt for EU::MM prompting # info -- long description shown before prompting # validate -- CODE ref; return normalized option or undef if invalid #--------------------------------------------------------------------------# my %option_specs = ( email_from => { default => '', prompt => 'What email address will be used to reference your reports?', info => <<'HERE', CPAN::Reporter requires a valid email address to identify senders in the body of a test report. Please use a standard email format like: "John Doe" HERE }, smtp_server => { default => undef, # (deprecated) prompt => "[DEPRECATED] It's safe to remove this from your config file.", }, edit_report => { default => 'default:ask/no pass/na:no', prompt => "Do you want to review or edit the test report?", validate => \&_validate_grade_action_pair, info => <<'HERE', Before test reports are sent, you may want to review or edit the test report and add additional comments about the result or about your system or Perl configuration. By default, CPAN::Reporter will ask after each report is generated whether or not you would like to edit the report. This option takes "grade:action" pairs. HERE }, send_report => { default => 'default:ask/yes pass/na:yes', prompt => "Do you want to send the report?", validate => \&_validate_grade_action_pair, info => <<'HERE', By default, CPAN::Reporter will prompt you for confirmation that the test report should be sent before actually doing it. This gives the opportunity to skip sending particular reports if you need to (e.g. if you caused the failure). This option takes "grade:action" pairs. HERE }, transport => { default => 'Metabase uri https://metabase.cpantesters.org/api/v1/ id_file metabase_id.json', prompt => 'Which transport system will be used to transmit the reports?', validate => \&_validate_transport, info => <<'HERE', CPAN::Reporter sends your reports over HTTPS using Metabase. This option lets you set a different uri, transport mechanism and metabase profile path. If you are receiving HTTPS errors, you may change the uri to use plain HTTP, though this is not recommended. Unless you know what you're doing, just accept the default value. HERE }, send_duplicates => { default => 'default:no', prompt => "This report is identical to a previous one. Send it anyway?", validate => \&_validate_grade_action_pair, info => <<'HERE', CPAN::Reporter records tests grades for each distribution, version and platform. By default, duplicates of previous results will not be sent at all, regardless of the value of the "send_report" option. This option takes "grade:action" pairs. HERE }, send_PL_report => { prompt => "Do you want to send the PL report?", default => undef, validate => \&_validate_grade_action_pair, }, send_make_report => { prompt => "Do you want to send the make/Build report?", default => undef, validate => \&_validate_grade_action_pair, }, send_test_report => { prompt => "Do you want to send the test report?", default => undef, validate => \&_validate_grade_action_pair, }, send_skipfile => { prompt => "What file has patterns for things that shouldn't be reported?", default => undef, validate => \&_validate_skipfile, }, cc_skipfile => { prompt => "What file has patterns for things that shouldn't CC to authors?", default => undef, validate => \&_validate_skipfile, }, command_timeout => { prompt => "If no timeout is set by CPAN, halt system commands after how many seconds?", default => undef, validate => \&_validate_seconds, }, email_to => { default => undef, }, editor => { default => undef, }, debug => { default => undef, }, retry_submission => { default => undef, }, ); sub _config_spec { return %option_specs } #--------------------------------------------------------------------------# # _generate_profile # # Run 'metabase-profile' in the .cpanreporter directory #--------------------------------------------------------------------------# sub _generate_profile { my ($id_file, $config) = @_; my $cmd = IPC::Cmd::can_run('metabase-profile'); return unless $cmd; # XXX this is an evil assumption about email addresses, but # might do for simple cases that users might actually provide my @opts = ("--output" => $id_file); my $email = $config->{email_from}; if ($email =~ /\A(.+)\s+<([^>]+)>\z/ ) { push @opts, "--email" => $2; my $name = $1; $name =~ s/\A["'](.*)["']\z/$1/; push ( @opts, "--name" => $1) if length $name; } else { push @opts, "--email" => $email; } # XXX profile 'secret' is really just a generated API key, so we # can create something fairly random for the user and use that push @opts, "--secret" => sprintf("%08x", rand(2**31)); return scalar IPC::Cmd::run( command => [ $cmd, @opts ], verbose => 1, ); } #--------------------------------------------------------------------------# # _get_config_dir #--------------------------------------------------------------------------# sub _get_config_dir { if ( defined $ENV{PERL_CPAN_REPORTER_DIR} && length $ENV{PERL_CPAN_REPORTER_DIR} ) { return $ENV{PERL_CPAN_REPORTER_DIR}; } my $conf_dir = File::Spec->catdir(File::HomeDir->my_home, ".cpanreporter"); if ($^O eq 'MSWin32') { my $alt_dir = File::Spec->catdir(File::HomeDir->my_documents, ".cpanreporter"); $conf_dir = $alt_dir if -d $alt_dir && ! -d $conf_dir; } return $conf_dir; } #--------------------------------------------------------------------------# # _get_config_file #--------------------------------------------------------------------------# sub _get_config_file { if ( defined $ENV{PERL_CPAN_REPORTER_CONFIG} && length $ENV{PERL_CPAN_REPORTER_CONFIG} ) { return $ENV{PERL_CPAN_REPORTER_CONFIG}; } else { return File::Spec->catdir( _get_config_dir, "config.ini" ); } } #--------------------------------------------------------------------------# # _get_config_options #--------------------------------------------------------------------------# sub _get_config_options { my $config = shift; # extract and return valid options, with fallback to defaults my %spec = CPAN::Reporter::Config::_config_spec(); my %active; OPTION: for my $option ( keys %spec ) { if ( exists $config->{_}{$option} ) { my $val = $config->{_}{$option}; if ( $spec{$option}{validate} && ! $spec{$option}{validate}->($option, $val) ) { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: invalid option '$val' in '$option'. Using default instead.\n\n" ); $active{$option} = $spec{$option}{default}; next OPTION; } $active{$option} = $val; } else { $active{$option} = $spec{$option}{default} if defined $spec{$option}{default}; } } return \%active; } #--------------------------------------------------------------------------# # _grade_action_prompt -- describes grade action pairs #--------------------------------------------------------------------------# sub _grade_action_prompt { return << 'HERE'; Some of the following configuration options require one or more "grade:action" pairs that determine what grade-specific action to take for that option. These pairs should be space-separated and are processed left-to-right. See CPAN::Reporter documentation for more details. GRADE : ACTION ======> EXAMPLES ------- ------- -------- pass yes default:no fail no default:yes pass:no unknown ask/no default:ask/no pass:yes fail:no na ask/yes default HERE } #--------------------------------------------------------------------------# # _is_valid_action #--------------------------------------------------------------------------# my @valid_actions = qw{ yes no ask/yes ask/no ask }; sub _is_valid_action { my $action = shift; return grep { $action eq $_ } @valid_actions; } #--------------------------------------------------------------------------# # _is_valid_grade #--------------------------------------------------------------------------# my @valid_grades = qw{ pass fail unknown na default }; sub _is_valid_grade { my $grade = shift; return grep { $grade eq $_ } @valid_grades; } #--------------------------------------------------------------------------# # _normalize_id_file #--------------------------------------------------------------------------# sub _normalize_id_file { my ($id_file) = @_; # Windows does not use ~ to signify a home directory if ( $^O eq 'MSWin32' && $id_file =~ m{^~/(.*)} ) { $id_file = File::Spec->catdir(File::HomeDir->my_home, $1); } elsif ( $id_file =~ /~/ ) { $id_file = File::Spec->canonpath(File::Glob::bsd_glob( $id_file )); } unless ( File::Spec->file_name_is_absolute( $id_file ) ) { $id_file = File::Spec->catfile( CPAN::Reporter::Config::_get_config_dir(), $id_file ); } return $id_file; } #--------------------------------------------------------------------------# # _open_config_file #--------------------------------------------------------------------------# sub _open_config_file { my $config_file = _get_config_file(); my $config = Config::Tiny->read( $config_file ) or $CPAN::Frontend->mywarn("CPAN::Reporter: couldn't read configuration file " . "'$config_file': \n" . Config::Tiny->errstr() . "\n"); return $config; } #--------------------------------------------------------------------------# # _validate # # anything is OK if there is no validation subroutine #--------------------------------------------------------------------------# sub _validate { my ($name, $value) = @_; return 1 if ! exists $option_specs{$name}{validate}; return $option_specs{$name}{validate}->($name, $value); } #--------------------------------------------------------------------------# # _validate_grade_action # returns hash of grade => action # returns undef #--------------------------------------------------------------------------# sub _validate_grade_action_pair { my ($name, $option) = @_; $option ||= "no"; my %ga_map; # grade => action PAIR: for my $grade_action ( split q{ }, $option ) { my ($grade_list,$action); if ( $grade_action =~ m{.:.} ) { # parse pair for later check ($grade_list, $action) = $grade_action =~ m{\A([^:]+):(.+)\z}; } elsif ( _is_valid_action($grade_action) ) { # action by itself $ga_map{default} = $grade_action; next PAIR; } elsif ( _is_valid_grade($grade_action) ) { # grade by itself $ga_map{$grade_action} = "yes"; next PAIR; } elsif( $grade_action =~ m{./.} ) { # gradelist by itself, so setup for later check $grade_list = $grade_action; $action = "yes"; } else { # something weird, so warn and skip $CPAN::Frontend->mywarn( "\nCPAN::Reporter: ignoring invalid grade:action '$grade_action' for '$name'.\n\n" ); next PAIR; } # check gradelist my %grades = map { ($_,1) } split( "/", $grade_list); for my $g ( keys %grades ) { if ( ! _is_valid_grade($g) ) { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: ignoring invalid grade '$g' in '$grade_action' for '$name'.\n\n" ); delete $grades{$g}; } } # check action if ( ! _is_valid_action($action) ) { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: ignoring invalid action '$action' in '$grade_action' for '$name'.\n\n" ); next PAIR; } # otherwise, it all must be OK $ga_map{$_} = $action for keys %grades; } return scalar(keys %ga_map) ? \%ga_map : undef; } sub _validate_transport { my ($name, $option, $config) = @_; my $transport = ''; if ( $option =~ /^(\w+(?:::\w+)*)\s?/ ) { $transport = $1; my $full_class = "Test::Reporter::Transport::$transport"; eval "use $full_class ()"; if ($@) { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: error loading $full_class. Please install the missing module or choose a different transport mechanism.\n\n" ); } } else { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: Please provide a transport mechanism.\n\n" ); return; } # we do extra validation for Metabase and offer to create the profile if ( $transport eq 'Metabase' ) { unless ( $option =~ /\buri\s+\S+/ ) { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: Please provide a target uri.\n\n" ); return; } unless ( $option =~ /\bid_file\s+(\S.+?)\s*$/ ) { $CPAN::Frontend->mywarn( "\nCPAN::Reporter: Please specify an id_file path.\n\n" ); return; } my $id_file = _normalize_id_file($1); # Offer to create if it doesn't exist if ( ! -e $id_file ) { my $answer = CPAN::Shell::colorable_makemaker_prompt( "\nWould you like to run 'metabase-profile' now to create '$id_file'?", "y" ); if ( $answer =~ /^y/i ) { return _generate_profile( $id_file, $config ); } else { $CPAN::Frontend->mywarn( <<"END_ID_FILE" ); You can create a Metabase profile by typing 'metabase-profile' in your command prompt and moving the resulting file to the location you specified. If you did not specify an absolute path, put it in your .cpanreporter directory. You will need to do this before continuing. END_ID_FILE return; } } # Warn and fail validation if there but not readable elsif ( not ( -r $id_file or -r File::Spec->catdir(_get_config_dir(), $id_file) ) ) { $CPAN::Frontend->mywarn( "CPAN::Reporter: '$id_file' was not readable.\n\n" ); return; } } # end Metabase return 1; } sub _validate_seconds { my ($name, $option) = @_; return unless defined($option) && length($option) && ($option =~ /^\d/) && $option >= 0; return $option; } sub _validate_skipfile { my ($name, $option) = @_; return unless $option; my $skipfile = File::Spec->file_name_is_absolute( $option ) ? $option : File::Spec->catfile( _get_config_dir(), $option ); return -r $skipfile ? $skipfile : undef; } 1; # ABSTRACT: Config file options for CPAN::Reporter =pod =encoding utf-8 =head1 NAME CPAN::Reporter::Config - Config file options for CPAN::Reporter =head1 VERSION version 1.2010 =head1 SYNOPSIS From the CPAN shell: cpan> o conf init test_report =head1 DESCRIPTION Default options for CPAN::Reporter are read from a configuration file C<<< .cpanreporter/config.ini >>> in the user's home directory. (On Win32 platforms, the directory will be located in the user's "Documents" directory.) The location of the configuration directory or file may be specified using environment variables instead. The configuration file is in "ini" format, with the option name and value separated by an "=" sign email_from = "John Doe" edit_report = no Interactive configuration of email address and common action prompts may be repeated at any time from the CPAN shell. cpan> o conf init test_report If a configuration file does not exist, it will be created the first time interactive configuration is performed. Subsequent interactive configuration will also include any advanced options that have been added manually to the configuration file. =head1 INTERACTIVE CONFIGURATION OPTIONS =head2 Email Address (required) email_from = CPAN::Reporter requires users to provide an email address that will be used in the header of the report. The email address provided should be a valid address format, e.g.: email_from = user@domain email_from = John Doe email_from = "John Q. Public" =head2 Transport (required) transport = [transport args] This sets the transport mechanism passed to the C<<< transport() >>> method of L. Normally, CPAN::Reporter uses 'Metabase' for transport class (i.e. L) and will provide a default set of transport arguments. Metabase transport arguments are two space-separated keyEvalue pairs: =over =item * C<<< uri >>> -- URI for the Metabase API. Defaults to C<<< https://metabase.cpantesters.org/api/v1/ >>> =item * C<<< id_file >>> -- path to the user's Metabase profile file. Defaults to C<<< metabase_id.json >>>. (Assumed to be in the C<<< .cpanreporter >>> directory). =back Prior to sending reports, a user must have a valid profile file at the path specified. For Metabase transport, CPAN::Reporter will automatically rewrite a relative C<<< id_file >>> path as an absolute path located in the C<<< .cpanreporter >>> directory. If the specified profile file does not exist, CPAN::Reporter will offer to run C<<< metabase-profile >>> to create it. For other transport types, see the documentation that comes with your choice of Test::Reporter::Transport subclass for the proper way to set the C<<< transport >>> configuration option. =head2 Action Prompts Several steps in the generation of a test report are optional. Configuration options control whether an action should be taken automatically or whether CPAN::Reporter should prompt the user for the action to take. The action to take may be different for each report grade. For example, users may wish to customize for which grades they wish to manually review a report before sending it. Most users should just accept the default settings until they have some experience as CPAN Testers. Valid actions, and their associated meaning, are as follows: =over =item * C<<< yes >>> -- automatic yes =item * C<<< no >>> -- automatic no =item * C<<< ask/no >>> or just C<<< ask >>> -- ask each time, but default to no =item * C<<< ask/yes >>> -- ask each time, but default to yes =back For "ask" prompts, the default will be used if return is pressed immediately at the prompt or if the C<<< PERL_MM_USE_DEFAULT >>> environment variable is set to a true value. Action prompt options take one or more space-separated "grade:action" pairs, which are processed left to right. edit_report = fail:ask/yes pass:no An action by itself is taken as a default to be used for any grade which does not have a grade-specific action. A default action may also be set by using the word "default" in place of a grade. edit_report = ask/no edit_report = default:ask/no A grade by itself is taken to have the action "yes" for that grade. edit_report = default:no fail Multiple grades may be specified together by separating them with a slash. edit_report = pass:no fail/na/unknown:ask/yes The action prompt options included in interactive configuration are: =over =item * C<<< edit_report = ... >>> -- edit the test report before sending? (default:askEno passEna:no) =item * C<<< send_report = ... >>> -- should test reports be sent at all? (default:askEyes passEna:yes) =back Note that if C<<< send_report >>> is set to "no", CPAN::Reporter will still go through the motions of preparing a report, but will discard it rather than send it. A better way to disable CPAN::Reporter temporarily is with the CPAN option C<<< test_report >>>: cpan> o conf test_report 0 =head2 Mail Server (DEPRECATED) CPAN::Reporter used to send mail directly to perl.org mail servers. The C<<< smtp_server >>> option is now deprecated and will be ignored if it exists. =head1 ADVANCED CONFIGURATION OPTIONS These additional options are only necessary in special cases, for example if the default editor cannot be found or if reports shouldn't be sent in certain situations or for automated testing, and so on. =over =item * C<<< command_timeout >>> -- if greater than zero and the CPAN config is C<<< inactivity_timeout >>> is not set, then any commands executed by CPAN::Reporter will be halted after this many seconds; useful for unattended smoke testing to stop after some amount of time; generally, this should be large -- 900 seconds or more -- as some distributions' tests take quite a long time to run. On MSWin32, L is a needed and trying to kill a processes may actually deadlock in some situations -- so use at your own risk. =item * C<<< editor = >>> -- editor to use to edit the test report; if not set, Test::Reporter will use environment variables C<<< VISUAL >>>, C<<< EDITOR >>> or C<<< EDIT >>> (in that order) to find an editor =item * C<<< retry_submission >>> -- if greater than zero, CPAN::Reporter will try to resend the report after a few seconds in case the first attempt fails. =item * C<<< send_duplicates = ... >>> -- should duplicates of previous reports be sent, regardless of C<<< send_report >>>? (default:no) =item * C<<< send_PL_report = ... >>> -- if defined, used in place of C<<< send_report >>> during the PL phase =item * C<<< send_make_report = ... >>> -- if defined, used in place of C<<< send_report >>> during the make phase =item * C<<< send_test_report = ... >>> -- if defined, used in place of C<<< send_report >>> during the test phase =item * C<<< send_skipfile = >>> -- filename containing regular expressions (one per line) to match against the distribution ID (e.g. 'AUTHOREDist-Name-0.01.tar.gz'); the report will not be sent if a match is found; non-absolute filename must be in the .cpanreporter config directory; =back If these options are manually added to the configuration file, they will be included (and preserved) in subsequent interactive configuration. =head2 Skipfile regular expressions Skip files are expected to have one regular expression per line and will be matched against the distribution ID, composed of the author's CPAN ID and the distribution tarball name. DAGOLDEN/CPAN-Reporter-1.00.tar.gz Lines that begin with a sharp (#) are considered comments and will not be matched. All regular expressions will be matched case insensitive and will not be anchored unless you provide one. As the format of a distribution ID is "AUTHOREtarball", anchoring at the start of the line with a caret (^) will match the author and with a slash (E) will match the distribution. # any distributions by JOHNDOE ^JOHNDOE # any distributions starting with Win32 /Win32 # a particular very specific distribution ^JOHNDOE/Foo-Bar-3.14 =head1 CONFIGURATION OPTIONS FOR DEBUGGING These options are useful for debugging only: =over =item * C<<< debug = >>> -- turns debugging onEoff =back =head1 ENVIRONMENT The following environment variables may be set to alter the default locations for CPAN::Reporter files: =over =item * C<<< PERL_CPAN_REPORTER_DIR >>> -- if set, this directory is used in place of the default C<<< .cpanreporter >>> directory; this will affect not only the location of the default C<<< config.ini >>>, but also the location of the L database and any other files that live in that directory =item * C<<< PERL_CPAN_REPORTER_CONFIG >>> -- if set, this file is used in place of the default C<<< config.ini >>> file; it may be in any directory, regardless of the choice of configuration directory =back =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR David Golden =head1 CONTRIBUTORS =over 4 =item * Alexandr Ciornii =item * Breno G. de Oliveira =item * Christian Walde =item * Kent Fredric =item * Matthew Musgrove =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut __END__ # vim: ts=4 sts=4 sw=4 et: CPAN-Reporter-1.2010/lib/CPAN/Reporter/PrereqCheck.pm0000644000175000017500000001355212132015716020423 0ustar garugaruuse strict; package CPAN::Reporter::PrereqCheck; our $VERSION = '1.2010'; # VERSION use ExtUtils::MakeMaker 6.36; use File::Spec; use CPAN::Version; _run() if ! caller(); sub _run { my %saw_mod; # read module and prereq string from STDIN local *DEVNULL; open DEVNULL, ">" . File::Spec->devnull; ## no critic # ensure actually installed, not ./inc/... or ./t/..., etc. local @INC = grep { $_ ne '.' } @INC; while ( <> ) { m/^(\S+)\s+([^\n]*)/; my ($mod, $need) = ($1, $2); die "Couldn't read module for '$_'" unless $mod; $need = 0 if not defined $need; # only evaluate a module once next if $saw_mod{$mod}++; # get installed version from file with EU::MM my($have, $inst_file, $dir, @packpath); if ( $mod eq "perl" ) { $have = $]; } else { @packpath = split( /::/, $mod ); $packpath[-1] .= ".pm"; if (@packpath == 1 && $packpath[0] eq "readline.pm") { unshift @packpath, "Term", "ReadLine"; # historical reasons } INCDIR: foreach my $dir (@INC) { my $pmfile = File::Spec->catfile($dir,@packpath); if (-f $pmfile){ $inst_file = $pmfile; last INCDIR; } } # get version from file or else report missing if ( defined $inst_file ) { $have = MM->parse_version($inst_file); $have = "0" if ! defined $have || $have eq 'undef'; # report broken if it can't be loaded # "select" to try to suppress spurious newlines select DEVNULL; ## no critic if ( ! _try_load( $mod, $have ) ) { select STDOUT; ## no critic print "$mod 0 broken\n"; next; } select STDOUT; ## no critic } else { print "$mod 0 n/a\n"; next; } } # complex requirements are comma separated my ( @requirements ) = split /\s*,\s*/, $need; my $passes = 0; RQ: for my $rq (@requirements) { if ($rq =~ s|>=\s*||) { # no-op -- just trimmed string } elsif ($rq =~ s|>\s*||) { if (CPAN::Version->vgt($have,$rq)){ $passes++; } next RQ; } elsif ($rq =~ s|!=\s*||) { if (CPAN::Version->vcmp($have,$rq)) { $passes++; # didn't match } next RQ; } elsif ($rq =~ s|<=\s*||) { if (! CPAN::Version->vgt($have,$rq)){ $passes++; } next RQ; } elsif ($rq =~ s|<\s*||) { if (CPAN::Version->vlt($have,$rq)){ $passes++; } next RQ; } # if made it here, then it's a normal >= comparison if (! CPAN::Version->vlt($have, $rq)){ $passes++; } } my $ok = $passes == @requirements ? 1 : 0; print "$mod $ok $have\n" } return; } sub _try_load { my ($module, $have) = @_; # M::I < 0.95 dies in require, so we can't check if it loads # Instead we just pretend that it works if ( $module eq 'Module::Install' && $have < 0.95 ) { return 1; } # loading Acme modules like Acme::Bleach can do bad things, # so never try to load them; just pretend that they work elsif( $module =~ /^Acme::/ ) { return 1; } my $file = "$module.pm"; $file =~ s{::}{/}g; return eval {require $file; 1}; ## no critic } 1; # ABSTRACT: Modulino for prerequisite tests __END__ =pod =encoding utf-8 =head1 NAME CPAN::Reporter::PrereqCheck - Modulino for prerequisite tests =head1 VERSION version 1.2010 =head1 SYNOPSIS require CPAN::Reporter::PrereqCheck; my $prereq_check = $INC{'CPAN/Reporter/PrereqCheck.pm'}; my $result = qx/$perl $prereq_check < $prereq_file/; =head1 DESCRIPTION This modulino determines whether a list of prerequisite modules are available and, if so, their version number. It is designed to be run as a script in order to provide this information from the perspective of a subprocess, just like CPAN::Reporter's invocation of C<<< perl Makefile.PL >>> and so on. It reads a module name and prerequisite string pair from each line of input and prints out the module name, 0 or 1 depending on whether the prerequisite is satisfied, and the installed module version. If the module is not available, it will print "nEa" for the version. If the module is available but can't be loaded, it will print "broken" for the version. Modules without a version will be treated as being of version "0". No user serviceable parts are inside. This modulino is packaged for internal use by CPAN::Reporter. =head1 BUGS Please report any bugs or feature using the CPAN Request Tracker. Bugs can be submitted through the web interface at L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 SEE ALSO =over =item * L -- main documentation =back =head1 AUTHOR David Golden =head1 CONTRIBUTORS =over 4 =item * Alexandr Ciornii =item * Breno G. de Oliveira =item * Christian Walde =item * Kent Fredric =item * Matthew Musgrove =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut CPAN-Reporter-1.2010/lib/CPAN/Reporter/API.pm0000644000175000017500000001215012132015716016631 0ustar garugaruuse strict; # make CPANTS happy package CPAN::Reporter::API; our $VERSION = '1.2010'; # VERSION 1; # ABSTRACT: Programmer's interface to CPAN::Reporter __END__ =pod =encoding utf-8 =head1 NAME CPAN::Reporter::API - Programmer's interface to CPAN::Reporter =head1 VERSION version 1.2010 =head1 FUNCTIONS CPAN::Reporter provides only a few public function for use within CPAN.pm. They are not imported during C<<< use >>>. Ordinary users will never need them. =head2 C<<< configure() >>> CPAN::Reporter::configure(); Prompts the user to edit configuration settings stored in the CPAN::Reporter C<<< config.ini >>> file. It will create the configuration file if it does not exist. It is automatically called by CPAN.pm when initializing the 'test_report' option, e.g.: cpan> o conf init test_report =head2 C<<< record_command() >>> ($output, $exit_value) = CPAN::Reporter::record_command( $cmd, $secs ); Takes a command to be executed via system(), but wraps and tees it to show the output to the console, capture the output, and capture the exit code. Returns an array reference of output lines (merged STDOUT and STDERR) and the return value from system(). Note that this is C<<< $? >>>, so the actual exit value of the command will need to be extracted as described in L. If the command matches E\b(?:MakefileEBuild)\.PL\bE, then L is added to C<<< PERL5OPT >>> to force autoflushing of user prompts. If the command includes a pipe character ('E'), only the part of the command prior to the pipe will be wrapped and teed. The pipe will be applied to the execution of the wrapper script. This is essential to capture the exit value of the command and should be otherwise transparent. If a non-zero C<<< $secs >>> argument is provided, the command will be run with a timeout of C<<< $secs >>> (seconds) if the appropriate process management modules are available. On Win32, L must be available; on Unix, L must be available. Otherwise, code will fall-back to running without a timeout. Also, on Win32, the first space-separated element of the command must be absolute, or else ".exe" will be appended and the PATH searched for a matching command. If the attempt to record fails, a warning will be issued and one or more of C<<< $output >>> or C<<< $exit_value >>> will be undefined. =head2 C<<< grade_make() >>> CPAN::Reporter::grade_make( $dist, $command, \@output, $exit); Given a CPAN::Distribution object, the system command used to build the distribution (e.g. "make", "perl Build"), an array of lines of output from the command and the exit value from the command, C<<< grade_make() >>> determines a grade for this stage of distribution installation. If the grade is "pass", C<<< grade_make() >>> does B send a CPAN Testers report for this stage and returns true to signal that the build was successful. Otherwise, a CPAN Testers report is sent and C<<< grade_make() >>> returns false. =head2 C<<< grade_PL() >>> CPAN::Reporter::grade_PL( $dist, $command, \@output, $exit); Given a CPAN::Distribution object, the system command used to run Makefile.PL or Build.PL (e.g. "perl Makefile.PL"), an array of lines of output from the command and the exit value from the command, C<<< grade_PL() >>> determines a grade for this stage of distribution installation. If the grade is "pass", C<<< grade_PL() >>> does B send a CPAN Testers report for this stage and returns true to signal that the Makefile.PL or Build.PL ran successfully. Otherwise, a CPAN Testers report is sent and C<<< grade_PL() >>> returns false. =head2 C<<< grade_test() >>> CPAN::Reporter::grade_test( $dist, $command, \@output, $exit); Given a CPAN::Distribution object, the system command used to run tests (e.g. "make test"), an array of lines of output from testing and the exit value from the system command, C<<< grade_test() >>> determines a grade for distribution tests. A CPAN Testers report is then sent unless specified prerequisites were not satisfied, in which case the report is discarded. This function returns true if the grade is "pass" or "unknown" and returns false, otherwise. =head2 C<<< test() >>> -- DEPRECATED CPAN::Reporter::test( $cpan_dist, $system_command ); This function is maintained for backwards compatibility. It effectively wraps the functionality of C<<< record_command() >>> and C<<< grade_test() >>> into a single function call. It takes a CPAN::Distribution object and the system command to run distribution tests. =head1 SEE ALSO =over =item * L =item * L =item * L =back =head1 AUTHOR David Golden =head1 CONTRIBUTORS =over 4 =item * Alexandr Ciornii =item * Breno G. de Oliveira =item * Christian Walde =item * Kent Fredric =item * Matthew Musgrove =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2006 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut CPAN-Reporter-1.2010/Changes0000644000175000017500000012653212132015716014076 0ustar garugaruRevision history for Perl module CPAN::Reporter 1.2010 2013-04-12 15:35:38 Europe/London [NEW FEATURES] - new option 'retry_submission' tries to send the report one extra time in case it fails. Defaults to undef (don't retry) (Patch by Alexandr "chorny" Ciornii) 1.2009 2012-12-18 16:08:37 America/New_York [BUG FIXES] - Expanded prerequisite load check skip to all Acme::* modules; prereqs still need to be installed and of sufficient version, but we don't check that Acme modules load without error to avoid side effects. 1.2008 2012-12-15 07:26:11 America/New_York [BUG FIXES] - Don't try to check if Acme::Bleach can be loaded if it's listed as a prereq 1.2007 2012-12-10 15:13:22 America/New_York [BUG FIXES] - Recognize another form of "Perl is too low" message [CHORNY] 1.2006 2012-04-10 18:44:20 America/New_York [BUG FIXES] - Changed how CPAN::Reporter::PrereqCheck attempts to load modules to avoid module reloading, which caused some prereqs to show up as 'broken' [rt.cpan.org #76394 and #75559] [OTHER] - Bumped IPC::Cmd prereq to 0.76 to avoid failures on some platforms 1.2005 2012-03-02 13:21:36 EST5EDT [BUG FIXES] - Canonicalise the config path returned by bsd_glob [rt.cpan.org #70504] [Kent Fredric] 1.2004 2012-02-13 16:25:07 EST5EDT [BUG FIXES] - Fix bug in testing tilde expansion on Windows [rt.cpan.org #72051] 1.2003 2011-12-06 11:07:04 EST5EDT [BUG FIXES] - Fix bug in transport class validation to allow multi-level class names [rt.cpan.org #73045] 1.2002 2011-08-10 17:52:08 America/New_York [BUG FIXES] - Fix failing tests on systems without Test::Reporter::Transport::Metabase - Minor test cleanups for use with 'prove' 1.2001 2011-08-07 05:05:58 America/New_York [BUG FIXES] - Fix failing test on Windows due to glob expansion of "~" [Christian Walde] 1.20 2011-08-05 13:17:20 America/New_York [BUG FIXES] - Removed Test::Reporter::Transport::Metabase as a prerequisite. New testers are recommended to install Task::CPAN::Reporter instead of CPAN::Reporter. 1.19_04 2011-06-29 17:39:25 America/New_York [NEW FEATURES] - Metabase profile generation will use as much of the provided email_from parameter as possible and will generate a random secret API key. If user provides email_from in a standard form like C<< "John Q. Public" >> then profile generation is entirely automatic without additional prompts from metabase-profile [David Golden] [DOCUMENTATION] - Swapped in Task::CPAN::Reporter in the SYNOPSIS [David Golden] [BUG FIXES] - Expands "~" into user directory before attempting to locate 'relative' pathname in .cpanreporter directory [David Golden] 1.19_03 2011-06-28 14:44:19 America/New_York [NEW FEATURES] - During configuration, if 'Metabase' is the requested transport and a Metabase profile file is not found, configuration will offer to run metabase-profile to create it. [David Golden] - For Metabase transport (only), the 'id_file' may have a relative file path, treated as relative to the .cpanreporter directory. [David Golden] [BUG FIXES] - updated CPAN::Reporter to go with Metabase by default, instead of the deprecated SMTP transport system. This provides more up-to-date information for new testers on how to setup their systems and addresses RT#64316 (and maybe also RT#61735) [Breno G. de Oliveira] - Replaced use of Tee.pm with Capture::Tiny as the two don't play well together on some systems. [Christian Walde] [DOCUMENTATION] - Docs have been substantially re-written to reflect the new HTTP-based transport instead of email-based transport. [Breno G. de Oliveira and David Golden] 1.1902 2011-01-28 15:22:35 EST5EDT [BUG FIXES] - Updated Tee prereq to 0.14 to fix an instability on Windows 1.1901 2011-01-24 20:23:23 EST5EDT - Fixes some space and backslash escaping for Windows [Christian Walde] 1.1900 2011-01-21 10:55:28 EST5EDT - No changes from 1.18_06 1.18_06 2010-12-07 05:18:51 EST5EDT Fixed: - Reports with a "can't spawn" error from TAP::Parser::Iterator::Process are discarded instead of reporting FAIL Other: - CPAN::Reporter is now released using Dist::Zilla. This required some changes to various files help dzil find/skip various bits of data. It should have no runtime effect. 1.18_05 Sun Oct 24 21:25:22 EDT 2010 Fixed: - Fixed error in calling prerequisite detection script when there are spaces in the path [RURBAN] 1.18_04 NOT RELEASED TO CPAN Changed: - Executed processes are given their own process group and timeouts are now handled by sending SIGKILL to the entire child process group. This is an attempt to address RT#61912 1.1803 Thu Sep 30 21:49:10 EDT 2010 Fixed: - Fixed t/13_record_command.t to reflect removal of Proc::ProcessTable as a conditional dependency and fixed a resulting bug in the test - Removed mention of Proc::ProcessTable in CPAN::Reporter::Config 1.1802 Wed Sep 29 23:19:15 EDT 2010 Changed: - Given the migration to CT2.0, the maximum report length before truncation has been increased from 50 to 1,000 kB. - Removed dependency on Proc::ProcessTable for using a command timeout on non-Win32 platforms. 1.1801 Fri Sep 10 16:34:29 EDT 2010 Changed: - Default config directory now uses File::HomeDir->my_home on windows instead of ->my_documents. If that directory doesn't exist, it will fall back to ->my_documents. 1.1800 Mon Jul 26 16:02:06 EDT 2010 Changed: - "sending test report..." message now shows transport method, not the old email list address for less confusion when using non-email transports - Enhances missing "email_from" prompt to clarify why an email is still needed under non-email transports for legacy compatibililty 1.1711 Wed Feb 17 13:52:14 EST 2010 Bugs fixed: - Tests for "no make test" were failing due to internationalization of the error message. Rather than try to interpret every possible make error message, CPAN::Reporter now just looks inside the Makefile for a "test" target. Hopefully, that will prove more robust. 1.1710 Wed Feb 10 10:30:51 EST 2010 Bugs fixed: - Tests for "no make test" were failing on some systems due to the incredibly wide range of error messages possible from make/nmake/dmake on various systems. The error message check is now even more liberal. 1.1709 Mon Feb 1 22:39:59 EST 2010 Bugs fixed: - Fixed PrereqCheck for modules like "if.pm" that could be confused with Perl syntax (RT#53477 by Serguei Trouchelle) - Added PrereqCheck special-case for Module::Install and improved diagnostics when prereqs are missing or too low (RT#51257) - Distributions with no 'make test' target should be UNKNOWN, not FAIL (RT#52139) - Improved detection of Test::Reporter capable of setting 'distfile' parameter Documentation changes: - Added 'Port' example for transport options - Adopted new format for Changes 1.1708 Mon Jun 1 23:31:58 EDT 2009 *** Emergency fix -- 1.1706/1.1707 can prevent subsequent module *** *** installation if installed with an older Test::Reporter. *** *** Disable test reporting (From CPAN, 'o conf test_report 0') *** *** and install CPAN::Reporter 1.1708. Then re-enable test *** *** reports. *** - Fixed: in the case where an old Test::Reporter without the distfile() method is installed, CPAN::Reporter would crash and prevent installation of modules (including newer Test::Reporter); now checks for a Test::Reporter 1.1707 Sun May 31 21:44:07 EDT 2009 - Prereq: bumped Test::Reporter to 1.54 1.1706 Sun May 31 14:00:43 EDT 2009 - Changed: URL of CPAN Testers wiki is now wiki.cpantesters.org - Added: support for setting 'distfile' parameter for test reports if supported by Test::Reporter (1.53_01+) 1.1705 Tue Jan 20 10:51:24 EST 2009 - Docs: CPAN Testers website updated to www.cpantesters.org (David Westbrook) 1.1704 Sun Dec 7 06:24:07 EST 2008 - Fixed: protect CPAN::Reporter tests from older versions of itself - Prereq: bumped Devel::Autoflush to 0.04 and CPAN to 1.9301 1.1703 Fri Dec 5 23:06:20 EST 2008 - Changed: Devel::Autoflush only added to PERL5OPT when capturing output from Makefile.PL or Build.PL - Prereq: bumped Devel::Autoflush to 0.03 for various fixes 1.1702 Sat Sep 13 07:20:04 EDT 2008 *** Emergency fix -- 1.1701 tickled a new Test::Harness bug *** - Changed: reverted to old -I and -M flag order in PERL5OPT; -I flag only added on Perl 5.8+; this should still fix Perl < 5.8 that can only take a single flag without provoking the T::H bug 1.1701 Thu Sep 11 23:56:41 EDT 2008 - Fixed: changed order of -I and -M flags in PERL5OPT to have -M first (since Perl 5.6.2 only supports a single flag); 5.6.2 testers may yet again see complaints about missing Devel::Autoflush when authors call 'perl' instead of $^X in tests (oh, well...) - Changed: bumped Test::Reporter prereq to 1.50 1.17 Sat Sep 6 19:35:44 EDT 2008 - Changed: In line with changes to CPAN Testers grade definitions, failures during the PL or make/Build phase will now be reported as UNKNOWN instead of FAIL - Removed: In line with the CPAN Testers decision to no longer have individual testers send reports to authors, the "cc_author" option has been removed - Fixed: "Build -j3" type errors are detected and reports discarded - Fixed: Makefile out of date vs Makefile.PL errors detected and discarded - Docs: updated FAQ 1.16_51 Wed Jul 16 12:41:48 EDT 2008 - Fixed: t/11_env_config was failing when tested under CPAN::Reporter due to PERL5OPT manipulations 1.16_50 Wed Jul 16 09:41:20 EDT 2008 - Added: restored "-I" for PERL5OPT, but to a temporary lib directory containing a copy of Devel::Autoflush. - Fixed: enviroment variables section of report now reflects PERL5OPT as used during build and testing 1.1601 Sat Jul 5 09:37:14 EDT 2008 - Fixed: reverted 1.15_56 PERL5OPT changes; Devel::Autoflush INC path no longer added with "-I" as it causes old modules to be found during testing. Testers will have to live with authors complaining about Devel::Autoflush missing when authors call 'perl' instead of $^X - Fixed: timeout support on *nix checks for *both* Proc::Killfam and Proc::ProcessTable to protect against unauthorized copies of only Proc::Killfam bundled in distributions like Tk-ExecuteCommand 1.16 Fri Jul 4 09:14:52 EDT 2008 - No changes since 1.15_56 - Summary of major features/fixes since 1.15: - Added: support for 'configure_requires' in META.yml (adds Parse::CPAN::Meta as dependency) - Fixed: uses Devel::Autoflush to ensure buggy *.PL files that prompt without a newline are always visible through the 'tee' pipe - Fixed: on Unix, changed command timeout approach to avoid disconnecting STDIN from the terminal; timeouts now require Proc::Killfam on *nix platforms 1.15_56 Thu Jun 19 22:19:33 EDT 2008 - Fixed: when multiple versions of perl are installed, distributions that called 'perl' during testing instead of '$^X' would die trying to load Devel::Autoflush if the first perl in PATH didn't have Devel::Autoflush installed; fixed by added -I flag to PERL5OPT with the path to Devel::Autoflush to ensure it can be found; (calling 'perl' is actually a subtle testing bug, but this way it doesn't look like it's the tester's fault) - Documented: removed suggestion to subscribe to cpan-testers since that no longer is necessary now that cpan-testers is just a drop-box (noted by Jose Luis Martinez) 1.15_55 Mon Jun 9 08:11:01 EDT 2008 - Fixed: catch META.yml parse failures from Parse::CPAN::Meta (Reported by Andreas Koenig) 1.15_54 Fri Jun 6 14:06:57 EDT 2008 - Fixed: would disconnect from terminal input when running interactively with an inactivity timeout; fixed by avoiding use of setpgrp(), but now requires Proc::Killfam to support inactivity timeouts on non Win32 platforms. (Bug reported by Andy Armstrong) 1.15_53 Thu Jun 5 06:37:13 EDT 2008 - Fixed: PERL5OPT could was being set with a leading space, which can break distributions being tested under Test::Harness 1.15_52 Wed Jun 4 22:23:39 EDT 2008 - Fixed: t/11_env_config.t had a bug that would fail incorrectly if an environment variable had a leading space 1.15_51 Wed Jun 4 17:57:42 EDT 2008 - Fixed: t/13_record_command.t relative path tests are incompatible with Devel::Autoflush; removed the broken tests 1.15_50 Tue Jun 3 12:13:12 EDT 2008 - Added: on FAIL reports, now checks for missing configure_requires and discards the report if configure_requires is not satisfied. (Adds Parse::CPAN::Meta as dependency.) - Fixed: some *.PL files prompt without autoflush, which works normally, but appears to silently hang when piping to a tee. CPAN::Reporter now uses Devel::Autoflush in PERL5OPT to always turn on autoflush - Fixed: distributions with odd names wouldn't be recorded in history; now they are recorded as 'DISCARD' 1.15 Mon May 19 11:21:47 EDT 2008 - Changed: now requires Test::Reporter 1.40 - No other changes from 1.14_xx series 1.14_04 Thu Apr 17 06:37:26 EDT 2008 - Documented: added section on transport config option 1.14_03 Thu Apr 17 06:37:26 EDT 2008 - Uploaded without Changes file updated 1.14_02 Sun Apr 6 09:45:39 EDT 2008 - Changed: improved diagnostics messages for 'transport' failures 1.14_01 Sat Apr 5 18:30:44 EDT 2008 - Changed: if 'transport' configuration option is not valid according to Test::Reporter, no report will be sent instead of falling back to Net::SMTP 1.13 Mon Mar 24 09:22:44 EDT 2008 - Changed: Build.PL or Makefile.PL that returns without error but does *not* create either 'Makefile' or 'Build' will be marked as 'DISCARD' for the PL phase instead of 'PASS'. - Fixed: Prereq check would be confused if loading modules also printed anything to STDOUT (somehow CPAN.pm is a culprit); added "select DEVNULL" before requiring modules as a workaround 1.12 Mon Mar 10 08:55:48 EDT 2008 - Added: Win32::FsType() to special variables section of report - Added: diagnostic warning if PrereqCheck output can't be parsed 1.11 Mon Feb 25 18:47:03 EST 2008 - Bug fix: successful PL's where prereqs happen not to be satisfied were mistakenly being marked as 'DISCARD' for the PL phase. Fixed so that PL's that PASS will stay that way regardless of prerequisites. (This does not prevent a later make or test failure from being downgraded, - Bug fix: skipfiles patterns should match case-insensitive (Cantrell); also, documented lack of starting anchor - Bug fix: command_timeout option would not accept zero as valid; now zero is a valid option and disables command_timeout - more minor boilerplate tweaks 1.10 Mon Feb 25 10:07:28 EST 2008 I hereby dub 1.10 as the "I hate Windows" release - Bug fix (sort of): On Win32, child processes were not timing out. Changed from Win32::Process to Win32::Job to fix that. However, discovered that process termination on Win32 can deadlock in some cases, so timeout testing on Win32 will now skip unless $ENV{PERL_AUTHOR_TESTING} is set. Added warning to documentation. - Bug fix: On a Win32 virtual machine (VirtualBox), handles for output capture were not inherited by child processes, which caused Test::Harness to crash for some reason. 1.09 Mon Feb 18 22:10:55 EST 2008 - Simplified and shortened boilerplate - Bug fix (minor): better detection of make vs Build for progress messages - Test fix: skip interrupt testing on MSWin32 if Win32::Process is not installed 1.0801 Sun Feb 10 00:27:05 EST 2008 - Test fix: adjust timeout timings in t/14_command_timeout.t to try to avoid failures on heavily loaded machines 1.08 Sat Jan 26 18:52:45 EST 2008 - No changes from 1.07_06 (seems to pass smoke tests) - Summary of new features since 1.06: - Added have_tested() function to CPAN::Reporter::History - Added 'cc_skipfile' and 'send_skipfile' advanced config options - Added 'command_timeout' advanced config option - Added support for PERL_CPAN_REPORTER_DIR and PERL_CPAN_REPORTER_CONFIG environment variables 1.07_06 Fri Jan 25 11:27:28 EST 2008 - Added 'command_timeout' config to halt commands after a period of time - Added detection of commands killed with a signal; reports are discarded (N.B. this may change in a future version) - Bug fix: processes timing out could still hang with child processes (killing 'make test' still leaves the harness running); fixed by making 'make test' its own process group and killing the process group; hoping that's portable across non-Win32; Win32 timeouts use Win32::Process and do the right thing already - Downgraded lots of progress messages from CPAN's 'mywarn' to 'myprint' (from red to blue if you use CPAN's colored output) 1.07_05 Thu Jan 24 08:27:48 EST 2008 - Added PERL_CPAN_REPORTER_DIR and PERL_CPAN_REPORTER_CONFIG environment variables to specify alternate locations for default configuration directory and file (RT#30314) - Removed File::Temp as a full prerequisite; now only used in testing (Requested by Adam Foxson to extract features to CPAN::Testers::*) 1.07_04 Sun Jan 20 22:06:56 EST 2008 - Test fix: stopping cc on blead broke lots of other tests. Fixed those. Built my own blead perl so I can actually check these things in the future instead of relying on Andreas' blead smoking - Test fix: testing skipfile wasn't being created properly on Perl 5.005 1.07_03 Sat Jan 19 22:16:44 EST 2008 - Test fix: set sample history file writeable after copy 1.07_02 Sat Jan 19 20:33:55 EST 2008 - Added have_tested() function to CPAN::Reporter::History; provide ability to search the CPAN::Reporter history file - Bug fix: PL files that warned "OS Unsupported" and exited with 0 will now be flagged as NA; this bends the CPAN Testers "rules" slightly, but "OS Unsupported" is a hack anyway, so this should help things DWIM - Test fix: more changes to timeout testing to avoid false failures - Authors will never be CC'd on reports when running maint/blead perl (anything with $Config{perl_patchlevel} set) - Reports discarded due to missing prerequisites will now be recorded in the history file with a 'grade' of DISCARD (unless a duplicate DISCARD already exists) - Changed "edit_report" prompt to clarify this can be used to review reports in addition to just editing them - Shortened duplicate report warning to fit on one line 1.07_01 Tue Jan 8 01:41:02 EST 2008 - Added "cc_skipfile" and "send_skipfile" advanced config options to specify a text file of regex patterns; if a distribution ID ('AUTHOR/Dist-Name-0.01.tar.gz') matches any pattern in the file, the author will not be copied on the report (cc_skipfile) or no reports will be sent at all (skip_sendfile) 1.0602 Tue Dec 25 08:59:07 EST 2007 - Test fix: a timeout test would sometimes appear to fail on a highly loaded system; changed the runtime and timeout timings to try to prevent false failures; added better diagnostic output 1.0601 Tue Dec 11 12:19:25 EST 2007 - Test fix: Test::Harness 3.05 fixed a long standing bug; the fix broke our tests 1.06 Thu Nov 15 14:17:04 EST 2007 - Bug fix: if older versions of a module are in multiple locations in @INC, CPAN::Reporter could detect the older version instead of the newer one; fixed in CPAN::Reporter::PrereqCheck (RT#30345; additional investigation by Andy Armstrong) - Bug fix: "our $VERSION" check still wasn't working on 5.005; now fixed (reported by Slaven Rezic). Note, this situation only applies to Module::Build <= 0.2808, where Build.PL dies before a legitimate "require => { perl => 5.006 }" is processed. (Makefile.PL does not die in this situation and Makefile.PL has no way of signaling a required perl version other than "use 5.006" or equivalent in the Makefile.PL) - Bug fix: wasn't printing Test::Reporter error message if a report couldn't be sent (RT#30730 by BLOONIX) - Changed FAIL report boilerplate about CPAN::Testers wiki to be more explicit that the wiki teaches how to deal with dependencies, OS, etc. (suggested by Olly Betts) 1.05 Tue Nov 6 14:41:48 EST 2007 - Added checks for Makefile.PL/Build.PL dying early on Perl < 5.6 if modules define their version using "our $VERSION"; such cases will be graded NA (RT#30299; report and partial patch from Slaven Rezic) - Added author's email address to the prompt question for whether to CC the author. Also fixed typo in the prompt. (suggested by Slaven Rezic) - Added "CPAN::Reporter" consistently as a prefix to all console messages to distinguish them from messages from CPAN.pm. Noisy, but helps track errors/complaints to the right source. - Bug fix: on first installation, "reload cpan" might load CPAN::Reporter when an old version File::Temp is already loaded; added an explicit version check on File::Temp (reported by Andreas Koenig) 1.04 Fri Oct 26 06:56:32 EDT 2007 - Bug fix: temp files were being created in the current directory, not the File::Spec->tmpdir() directory; this broke distributions that used their own distribution directory for signature or MANIFEST checks 1.03 Wed Oct 24 17:13:59 EDT 2007 - Added a check for prerequisites that are present but fail to load; in such a case the prereq "have" field will show "broken" (e.g a dependency of that module is missing) - Refactored prerequisite checking code into a separate modulino CPAN::Reporter::PrereqCheck to cut down on excessive tempfile use and simplify testing - Added name templates for all tempfiles to help identify leakage or left-over files if tests are interrupted. All names are like CR-ZZ-XXXXXXXX, where ZZ is unique to each File::Temp call and X's are a random suffix - Testing bug fix: in the rare case where Module::Build is present but broken, we would only skip Build.PL tests once instead of always 1.02 Sun Oct 14 08:57:38 EDT 2007 - Bug fix: shell quotes in command passed to record_command() were not being properly escaped in creation of the wrapper script (found by Andreas Koenig) - Bug fix: wasn't detecting Perl version too low during make/Build phase. Reports were improperly graded as 'FAIL' instead of 'NA' (found by Slaven Rezic and David Cantrell) - Bug fix: wasn't detecting missing prerequisites during "make" phase and FAIL reports were being sent that should have been discarded (found by Michel Rodriguez and David Cantrell) 1.01 Sat Oct 13 03:21:40 EDT 2007 - Bug fix: no prompt for sending reports was being shown if advanced send_*_report options were set. (Found by David Cantrell) - Bug fix: was not detecting Module::Install's perl version warning (found by Slaven Rezic) 1.00 Wed Oct 10 20:39:42 EDT 2007 *** New major release -- API changes and other enhancements *** Summary of major changes from 0.XX series: * Added support for reporting for *.PL and make/Build stages; bumped CPAN.pm prerequisite to 1.9203 to take advantage of this support * Added support for the forthcoming Test::Harness 3.00 * Changed the name and format of the history file of sent reports to track history by PL/make/test phase. Old history.db will be automatically upgraded to new reports-sent.db. * Moved 'cc_author' and 'send_duplicates' options from interactive to advanced (manual) configuration; defaults are strongly recommended * Bumped Test::Reporter prereq to 1.34 for transport() method and set default transport to Net::SMTP on all platforms Additional minor new change in 1.00: - Added CPAN Testers wiki URL to explanation paragraph for FAIL reports (request by Slavan Rezic) 0.99_15 Mon Oct 8 08:33:56 EDT 2007 This release is dedicated to Slaven Rezic for boldly smoking with the pre-release of Perl 5.005_05. - Work around missing 5.005 Fcntl constants (noted by Slaven Rezic) - Fix bug detecting perl version failure in test output (found by Slaven Rezic while testing Sub::Uplevel on 5.00505) - Fix bug detecting OS unsupported in test.pl and make - Test output truncated at 50K to ensure reports will be accepted by perl.org's MX and to avoid excessive output in general (MX limitation noted by Slaven Rezic) - Added documentation note in History.pm that all methods are currently private - Removed API.pm and FAQ.pm from MANIFEST and tarball -- these are just source files for API.pod and FAQ.pod generated with Pod::WikiDoc 0.99_14 Tue Oct 2 14:49:40 EDT 2007 * Bumped CPAN.pm prereq to 1.9203 -- fixes a bug where make/build continues even if Makefile/Build is missing, causing FAIL reports for modules that exit(0) without generating a Makefile. - Set transport() default to Net::SMTP; ensures CPAN::Reporter can work out-of-the-box on systems that happen to have Mail::Send and a broken sendmail installation - eliminated several Perl::Critic level 4-5 complaints - added some entries to the FAQ 0.99_13 Thu Sep 27 06:24:00 EDT 2007 * Bump Test::Reporter prereq to 1.34 for transport() method. Added "transport" advanced configuration option. (Requested by Andreas Koenig) - Improved robustness of conversion of old history files on Win32 for really old CPAN::Reporter history formats - Minor report format tweaks 0.99_12 Sun Sep 23 13:14:08 EDT 2007 * Bumped CPAN.pm prereq to 1.92 (full support for PL/make) - Reordered report sections to move program output to immediately after tester comments; this keeps most relevant information at the top and prereqs and other context follow - Added perl version to the report intro paragraph since otherwise it doesn't appear until the "perl -V" output at the end of the report - Compressed UID/EUID variables to a single line in the report - Made report language less 'test' specific, since we can also report on PL or make failures - Changed the way perl version is stringified for history file entries to workaround an old bleadperl bug; (a "better safe than sorry" fix) (Reported by Andreas Koenig) - Cleans up temp directories in testing more frequently 0.99_11 Fri Sep 21 17:02:18 EDT 2007 - Fallback to "make test" or "Build test" exit value when output parsing fails. This supports custom testing in Makefile.PL or Build.PL (Reported on Prima by Dmitry Karasik) 0.99_10 Tue Sep 11 17:29:18 EDT 2007 - Added advanced options "send_PL_report", "send_make_report" and "send_test_report" to override "send_report" for individual phases (requested by David Cantrell) 0.99_09 Mon Sep 10 09:50:57 EDT 2007 - Fix test failure on bleadperl 0.99_08 Sat Sep 8 18:07:08 EDT 2007 * History file of sent reports has a new name ('reports-sent.db') and a new format with phase of testing for report ('PL', 'make', 'test') - More robust check for Test::Harness 2.99_01 (works even with out-of-date releases of version.pm) - More refactoring of config/history functions into separate modules 0.99_07 Wed Sep 5 18:20:37 EDT 2007 - Skips inactivity timeout on Win32 without Win32::Process >= 0.10 (bug found by Corion) - Bails out on Test::Harness 2.99_01 (not supported) 0.99_06 Wed Sep 5 16:56:23 EDT 2007 - Added support for new message format from Test::Harness alpha (2.99_02) - Changed grading for test files with no output from FAIL to UNKNOWN to harmonize with new Test::Harness approach - Falls back to overall 'make test' exit code for success or failure if recursive Makefile.PL's are detected; File::Find added to prereqs; Bumped EU::MM prereq to 6.36 to get bug fixes for recursion and more - record_command() wrappers do better error checking for exec failures - Bumped File::Copy::Recursive dependency to 0.35 (fixes Win32 bug) - More defensive test coding - changed to the Apache License, version 2.0; (it's clearer, relicensable, and is explicit about contributions) 0.99_05 Mon Aug 27 16:16:50 EDT 2007 - Fixed copy/paste typo that caused testing to fail; (serves me right for rushing out 0.99_04 without using my normal release-testing script) 0.99_04 Mon Aug 27 07:40:59 EDT 2007 - Merged changes from 0.4801 0.4801 Mon Aug 27 07:30:24 EDT 2007 - File::Copy::Recursive 0.34 is badly broken on Windows, causing our tests to fail; added an "xcopy" workaround 0.99_03 Fri Aug 10 12:03:07 EDT 2007 - Fixed broken PL tests when Module::Build is not available - Tweaked grade result message printed to screen - Noted in Pod that CPAN 1.91_53 is required for full support - Reordered Changes to be chronological 0.48 Tue Aug 7 16:28:42 EDT 2007 - Bumped Test::More prereq to 0.62 (from 0.99_02) - More portable directory checks in test helper module - Cleaned up DOS/unix line endings in many files 0.99_02 Tue Aug 7 06:54:59 EDT 2007 - Author tests (e.g. pod/pod-coverage) moved to 'author_t' directory - Module::Build subclass used for development moved to inc - Pulled forward maintenance changes from 0.47_01 - Bumped Test::More prereq to 0.62 0.47_01 Sat Aug 4 00:09:54 EDT 2007 - Added TEMP and TMPDIR to environment variables included in report - Changed inclusion of AUTHOR_TESTING environment variable to any matching /AUTHOR_TEST/ - Changed how "Build.PL" is executed in tests to diagnose odd Cygwin failure; increased test diagnostics 0.99_01 Tue Jul 31 22:28:25 EDT 2007 * Major API additions and configuration changes in preparation for adding Makefile/Build.PL and make/Build support into CPAN.pm * Deprecated test() function; test() separated into record_command() and grade_test() functions to support CPAN.pm sending reports from output generated indpendently from CPAN::Reporter, e.g. CPAN.pm using Expect with distroprefs * Added record_command() to wrap and tee a system() command and return results for further evaluation in grade_*() functions; wrapping used to capture exit values that would otherwise be lost from pipe to tee; will support CPAN inactivity timouts on both *nix and Win32 * Added grade_PL() function to evaluate results of 'perl Makefile.PL' or 'perl Build.PL'; recognizes 'require 5.xxxxx' and unsupported OS error messages to be 'NA' as well as ordinary pass/fail outcomes * Added grade_make() function to evaluate results of 'make' or 'Build' * Added grade_test() function to evaluate results of 'make test' or 'Build test' (refactored from old test() function) * Removed 'cc_author' and 'send_duplicates' options from normal interactive configuration; defaults will be used unless set manually in the configuration file - separated documentation into separate API and Config files to keep documentation simple in the primary CPAN::Reporter file - added YAML & YAML::Syck to list of toolchain module versions reported (i.e. determines if META.yml is used by CPAN.pm) - began refactoring configuration code: moved configuration defaults and validation into Config.pm - fixed bug in distribution-version string creation for .tar.bz2 0.46 Tue Jul 17 22:05:50 EDT 2007 *** Significant improvements to NA report handling *** * Changes as per CPAN Testers specifications from Barbie * NA reports should now be sent to CPAN Testers instead of discarded - Tests that fail with 'OS Unsupported' or 'No support for OS' are now correctly identified as NA - FAIL/UNKNOWN grades results with unsatisfied prerequisites are discarded immediately instead of being flagged as NA - changed default configurations to automatically send NA just like PASS - interactive configuration now always shows recommended options in addition to any prior configuration - added CPAN Testers website and wiki to SEE ALSO in docs - improved tests for detecting reports sent/not-sent 0.45 Tue Jul 3 17:07:30 EDT 2007 - distribution tests that bailout now detected as FAIL instead of UNKNOWN - UNKNOWN results when prereqs are missing are downgraded to NA (just like FAIL reports with missing prereqs already were) 0.44 Sun Jun 17 22:05:46 EDT 2007 - searches through duplicate history file instead of loading as a hash - added flocking to history file read/write (and faked it for platforms that don't support flock) - duplicate history includes $Config{perl_patchlevel} if it exists 0.43 Tue Apr 24 22:55:32 EDT 2007 - enhanced duplicate tracking to include Perl version (suggested by David Cantrell) 0.42 Tue Apr 24 00:27:56 EDT 2007 - added "send_duplicates" option with default "no"; compares CPAN Testers subject lines (grade, distribution, version and platform) to previous test results and skips sending duplicate reports 0.41 Sun Mar 25 09:39:07 EDT 2007 - test reports will not be sent if the distribution name doesn't appear appear to be an actual distribution with version and archive suffix (Suggested by Barbie) - refactored tests - fixed ID format in mock CPAN::Distributions used in testing 0.40 Wed Feb 28 23:30:13 EST 2007 - eliminated Perl::Critic level 5 and (most) level 4 complaints - added defensive code in case CPAN.pm can't provide a valid Author object (Reported by David Cantrell) 0.39 Sat Feb 10 19:28:13 EST 2007 - changed prereq version testing to better match approach used by CPAN.pm - added support for Module::Build-style extended prerequisite logic (e.g. ">= N.nn, !=M.mm" etc.) 0.38 Mon Dec 4 20:39:18 EST 2006 - fixed uninitialized value warning in "Preparing test report for..." 0.37 Mon Dec 4 08:44:54 EST 2006 - fixed false result given back to CPAN.pm when config file is missing but tests passed (Reported by Andreas Koenig) 0.36 Mon Dec 4 00:20:32 EST 2006 - changed default for send_report to "no" for "na" reports to avoid sending spurious reports from prerequisites failures - customized email report intros for better help to module authors receiving a CC for various types of reports - removed email address for RT to reduce spam - Added a FAQ and example config.ini 0.35 Fri Nov 10 01:52:47 EST 2006 - fixed environment report tests for the case of undefined/empty environment variables - added support for CPAN.pm ANSI color messages and prompts 0.34 Wed Nov 8 05:39:22 EST 2006 - fixed test skip block count when Module::Build is not installed (reported by rinceWind) 0.33 Tue Nov 7 07:37:08 EST 2006 - Added Test::Harness and Test::More to the modules included as part of the toolchain version report 0.32 Tue Nov 7 01:24:14 EST 2006 - Added versions of module toolchain (e.g. CPAN, ExtUtils::MakeMaker, Module::Build, etc.) to test report - Added Pod warning about potential privacy issues from sending environment and other information as part of the test report 0.31 Mon Nov 6 13:38:57 EST 2006 - replace broken 0.30 release 0.30 Mon Nov 6 13:29:03 EST 2006 - changed report output to have a different introductory paragraph for each test grade to better clarify the meaning of 'unknown' and 'na' results from testing - added select environment variables and Perl special variables to generated report - added some addition clarifications in Pod 0.29 Sat Oct 28 13:36:26 EDT 2006 *** Backward compatibility warning: See below and 0.28_51 change log *** * Config file location on Mac OS X * Config option format and semantics for action prompts - fixed RT#22557: recursive build directories with no tests will no longer cause an "unknown" grade if tests exist at the top-level directory - changed action prompt rules; default is always no unless otherwise specified -- the suggested rule from interactive configuration has no impact on parsing - changed default action for edit_report and send_report to "no" and "yes" respectively if the grade is pass to avoid holding up successful installations. (Suggested by Michael Schwern) - changed several tests to always mock configuration directory; prevents OS X config files from being migrated early during testing. (Reported by Michael Schwern). - added explanation of grade:action pairs during configuration - added validation of grade:action pairs during configuration 0.28_51 Mon Oct 23 23:47:33 EDT 2006 *** Backward compatibility warning: configuration options have changed and config directory on OS X has changed *** - changed config directory on Mac OS X to ~/.cpanreporter instead of ~/Documents/.cpanreporter to be more like Unix; automatically moves config file if old directory is detected. (RT#22120) - changed action prompt configuration option format to support grade- specific actions (RT#21690) - fixed success/failure parsing when recursive make output is included; line parsing is now done in reverse and only the first matching line is used - changed perl version prerequisite logic; report will only be marked "na" if a perl version was explicitly set in the prerequisites; autodetection of low perl version was removed to eliminate spurious matches from recursive makes - added tests for report output format 0.28 Sun Oct 8 12:47:46 EDT 2006 - fixed test programs to force cleanup temp directories (due to bug in File::Temp) 0.27 Wed Oct 4 14:04:08 EDT 2006 *** Emergency bug fix *** - fixed fatal bug in prereq collection from some versions of CPAN.pm 0.26 Wed Oct 4 09:25:08 EDT 2006 - fixed prereq tests: requiring "0" will now pass for modules with no $VERSION defined (will show that version '0' is installed) - fixed prereq tests for version.pm and bleadperl expansion of version numbers when stringified (1.2 becomes 1.200) - bumped ExtUtils::MakeMaker prereq version to 6.26 to ensure proper globbing of t/*.t files for Test::Harness 0.25 Tue Oct 3 23:00:02 EDT 2006 - fixed prereq testing: tests are conducted in a perl subprocess to use same $ENV{PERL5LIB} as used for testing itself; necessary to support prerequisites that may be tested by CPAN.pm but not yet installed - added special logic for perl prerequisite version checks now that CPAN.pm passes it along - added tests for prereq reporting 0.24 Sun Oct 1 04:27:51 EDT 2006 *** Emergency bug fix *** - added a dummy file to t/dist/NoTestFiles/t to ensure the directory is included in the distribution manifest and tarball; otherwise NoTestFiles tests fail 0.23 Fri Sep 29 14:35:49 EDT 2006 - changed test.pl/ExtUtils::MakeMaker handling to wrap 'make test' execution with a standardized (parsable) string; does not run test.pl twice anymore (Jonathan Rockway) - added additional test distributions and added tests for diagnostic messages explaining each grade (coverage now > 90%) 0.22 Thu Sep 28 23:44:54 EDT 2006 - added support for future CPAN.pm support for separate requires and build_requires prerequisites - changed prerequisites report for easier reading and to show requires and build_requires individually, if available from CPAN.pm - changed test.pl test grading under ExtUtils::MakeMaker from output parsing to determining the success or failure of a separate run of Makefile 0.21 Thu Sep 28 07:06:30 EDT 2006 - added test.pl support with full capture of output (Tim Bunce) - added support for "NA" grade when prerequisites are not meta or Perl version is too low - refactored tests into separate files by grade 0.20 Sun Sep 24 22:45:48 EDT 2006 - fixed RT#21626: "unknown" results will now be reported to CPAN.pm as success and will not interrupt module installation (Slaven Rezic) - added support for test.pl files -- though under "make", report is based on exit code only and no output is collected - added several new tests and test distributions for greater coverage and confirming bug closure - added user feedback for test grade assigned during report generation - changed format of test report 0.19 Fri Sep 22 16:54:02 EDT 2006 - changed test IO capture to IO::CaptureOutput (fixes test issues for Perl < 5.8) (Andreas Konig) 0.18 Thu Sep 21 21:03:57 EDT 2006 - added workaround for a bizarre VERSION() method confict when Module::Signature is installed on older Perls (Andreas Konig) - added note about location of config files for Mac OS X (SKUO) - updated "Getting Started" Pod now that CPAN 1.88 is out 0.17 Sat Sep 9 07:11:08 EDT 2006 - changed t/03_test_report.t to skip Module::Build tests if Module::Build is not installed 0.16 Fri Sep 8 07:19:25 EDT 2006 - fixed file mode bug in t/02_config_file_t (Slaven Rezic) - added first regression tests for pass/fail 0.15 Wed Sep 6 19:23:32 EDT 2006 - fixed broken test() -- all tests were reporting failed 0.14 Wed Sep 6 15:53:52 EDT 2006 - added configure() for config file generation and interactive config - removed automatic config file generation from the test() function - updated getting started documentation to reflect CPAN.pm 'o conf init test_report' syntax (as of 1.87_59) and new interactive config feature of CPAN::Reporter - added the 'fail' config value; equivalent to 'yes' if a test failed and 'no' otherwise - changed "cc_author" default to "fail" - added error checks and testing for config file generation 0.13 Tue Aug 29 06:31:38 EDT 2006 - added slightly more verbose progress messages, including for CC's and for reports not sent - minor documentation improvements 0.12 Sat Aug 26 19:05:54 EDT 2006 - updated docs to indicate that CPAN 1.87_57 supports CPAN::Reporter 0.11 Sat Aug 26 12:20:32 EDT 2006 - fail-safe test.pl files -- can't determine success for "make test" when teed and can't parse for Test::Harness output - fail-safe output parsing -- if the expected failure string from Test::Harness is not found, report "unknown" instead of fail - added compatibility for CPAN.pm "reload cpan" command (Andreas Konig) - added options "debug" and "editor" (Andreas Konig) - bumped Tee version requirement 0.10 Tue Aug 8 23:56:07 EDT 2006 - first public release -- support not yet available in CPAN.pm main branch # vi:tw=75 CPAN-Reporter-1.2010/README.PATCHING0000644000175000017500000000261612132015716014653 0ustar garugaruREADME.PATCHING Thank you for considering contributing to this distribution. This file contains instructions that will help you work with the source code. The distribution is managed with Dist::Zilla. This means than many of the usual files you might expect are not in the repository, but are generated at release time (e.g. Makefile.PL). However, you can run tests directly using the 'prove' tool: $ prove -l $ prove -lv t/some_test_file.t For most distributions, 'prove' is entirely sufficent for you to test any patches you have. Likewise, much of the documentation Pod is generated at release time. Depending on the distribution, some documentation may be written in a Pod dialect called WikiDoc. (See Pod::WikiDoc on CPAN.) If you would like to submit a documentation edit, please limit yourself to the documentation you see. If you see typos or documentation issues in the generated docs, please email or open a bug ticket instead of patching. Dist::Zilla is a very powerful authoring tool, but requires a number of author-specific plugins. If you would like to use it for contributing, install it from CPAN, then run one of the following commands, depending on your CPAN client: $ cpan `dzil authordeps` $ dzil authordeps | cpanm Once installed, here are some dzil commands you might try: $ dzil build $ dzil test $ dzil xtest You can learn more about Dist::Zilla at http://dzil.org/ CPAN-Reporter-1.2010/t/0000775000175000017500000000000012132015716013037 5ustar garugaruCPAN-Reporter-1.2010/t/MockCPANDist.pm0000644000175000017500000000300012132015716015543 0ustar garugarupackage t::MockCPANDist; use strict; BEGIN { if ( not $] < 5.006 ) { require warnings; warnings->import } } use File::Basename; #--------------------------------------------------------------------------# my $simulate_bad_author = 0; sub import { my $class = shift; $simulate_bad_author = grep { $_ eq 'bad_author' } @_; } #--------------------------------------------------------------------------# my %spec = ( prereq_pm => 'HASH', pretty_id => q{}, author_id => q{}, author_fullname => q{}, ); sub new { my ($class) = shift; die "Arguments to t::MockCPANDist::new() must be key => value pairs" if (@_ % 2); my %args = @_; for my $key ( keys %spec ) { if ( ! exists $args{$key} || ( defined ref $args{$key} && ref $args{$key} ne $spec{$key} ) ) { die "Argument '$key' must be a " . (defined $spec{$key} ? "$spec{$key} reference" : "scalar" ); } } bless \%args, $class; } # cheat on author() and let the mock handle it all unless we want it to fail sub author { return $simulate_bad_author ? undef : shift } sub prereq_pm { return shift->{prereq_pm} } sub pretty_id { return shift->{pretty_id} } sub id { return shift->{author_id} } sub fullname { return shift->{author_fullname} } sub base_id { my $self = shift; my $id = $self->pretty_id(); my $base_id = File::Basename::basename($id); $base_id =~ s{\.(?:tar\.(bz2|gz|Z)|t(?:gz|bz)|zip)$}{}i; return $base_id; } 1; CPAN-Reporter-1.2010/t/63_config_send_report.t0000644000175000017500000000631512132015716017410 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; use Probe::Perl; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $make = $Config{make}; my $perl = Probe::Perl->find_perl_interpreter(); my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my @cases = ( { label => "send_PL_report 'no'", name => "PL-Fail", version => 1.23, grade => "fail", phase => "PL", command => "$perl Makefile.PL", will_send => 0, options => { send_report => "yes", send_PL_report => "no", }, }, { label => "send_make_report 'no'", label => "first make failure", name => "make-Fail", version => 1.23, grade => "fail", phase => "make", command => "$make", will_send => 0, options => { send_report => "yes", send_make_report => "no", }, }, { label => "send_test_report 'no'", name => "t-Fail", grade => "fail", phase => "test", command => "$make test", will_send => 0, options => { send_report => "yes", send_test_report => "no", }, }, { label => "send_PL_report 'yes'", name => "PL-Fail", version => 1.23, grade => "fail", phase => "PL", command => "$perl Makefile.PL", will_send => 1, options => { send_report => "no", send_PL_report => "yes", }, }, { label => "send_make_report 'yes'", label => "first make failure", name => "make-Fail", version => 1.23, grade => "fail", phase => "make", command => "$make", will_send => 1, options => { send_report => "no", send_make_report => "yes", }, }, { label => "send_test_report 'yes'", name => "t-Fail", grade => "fail", phase => "test", command => "$make test", will_send => 1, options => { send_report => "no", send_test_report => "yes", }, }, ); my $expected_history_lines = 1; # opening comment line for my $c ( @cases ) { $expected_history_lines++ if not $c->{is_dup} } plan tests => 1 + @cases * ( test_fake_config_plan() + test_dispatch_plan() ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); my @results; for my $case ( @cases ) { $case->{dist} = $mock_dist; test_fake_config( %{$case->{options}} ); test_dispatch( $case, will_send => $case->{will_send}, ); } CPAN-Reporter-1.2010/t/64_transport.t0000644000175000017500000000467512132015716015603 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; use IO::CaptureOutput; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $make = $Config{make}; my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my $case = { label => "t-Pass", name => "t-Pass", dist => $mock_dist, version => 1.23, grade => "pass", phase => "test", command => "$make test", will_send => 1, options => { send_report => "yes", }, }; plan tests => 1 + 4 * (1 + test_fake_config_plan + test_dispatch_plan); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); #--------------------------------------------------------------------------# # no transport advanced option set #--------------------------------------------------------------------------# test_fake_config( %{$case->{options}} ); test_dispatch( $case, will_send => $case->{will_send}, ); is( Test::Reporter::Mocked->transport(), 'Metabase', "by default, transport should be be set to Metabase" ); #--------------------------------------------------------------------------# # transport set in config #--------------------------------------------------------------------------# for my $transport ( qw/Metabase Mail::Send/ ) { test_fake_config( %{$case->{options}}, transport => $transport ); test_dispatch( $case, will_send => $case->{will_send}, ); is( Test::Reporter::Mocked->transport(), $transport, "transport $transport in config was properly set" ); } #--------------------------------------------------------------------------# # invalid transport #--------------------------------------------------------------------------# test_fake_config( %{$case->{options}}, transport => 'LWP' ); my ($stdout, $stderr) = test_dispatch( $case, will_send => 0, ); like( $stdout, "/'LWP' is invalid/", "saw invalid transport warnings" ); CPAN-Reporter-1.2010/t/53_test_report_na.t0000644000175000017500000000521512132015716016564 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Frontend; use t::Helper; my @test_distros = ( # na { name => 't-PrereqPerl-NOK', prereq => { perl => 42 }, eumm_success => 0, eumm_grade => "na", eumm_msg => "Perl version too low", mb_success => 0, mb_grade => "na", mb_msg => "Perl version too low", }, { name => 'test.pl-PrereqPerl-NOK', prereq => { perl => 42 }, eumm_success => 0, eumm_grade => "na", eumm_msg => "Perl version too low", mb_success => 0, mb_grade => "na", mb_msg => "Perl version too low", }, { name => 't-NoSupport', prereq => { }, eumm_success => 0, eumm_grade => "na", eumm_msg => "This platform is not supported", mb_success => 0, mb_grade => "na", mb_msg => "This platform is not supported", }, { name => 't-OSUnsupported', prereq => { }, eumm_success => 0, eumm_grade => "na", eumm_msg => "This platform is not supported", mb_success => 0, mb_grade => "na", mb_msg => "This platform is not supported", }, { name => 'test.pl-OSUnsupported', prereq => { }, eumm_success => 0, eumm_grade => "na", eumm_msg => "This platform is not supported", mb_success => 0, mb_grade => "na", mb_msg => "This platform is not supported", }, { name => 't-RequirePerl', prereq => { }, eumm_success => 0, eumm_grade => "na", eumm_msg => "Perl version too low", mb_success => 0, mb_grade => "na", mb_msg => "Perl version too low", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => $case->{prereq}, author_id => "JOHNQP", author_fullname => "John Q. Public", ); test_grade_test( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/12_toolchain_versions.t0000644000175000017500000000306712132015716017442 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; my @toolchain= qw( CPAN Cwd ExtUtils::CBuilder ExtUtils::Command ExtUtils::Install ExtUtils::MakeMaker ExtUtils::Manifest ExtUtils::ParseXS File::Spec Module::Build Module::Signature Test::Harness Test::More version ); # paths # * cwd # * compiler # * $Config{make} # special handling # * umask # * locale -- how do I determine this? # * compiler tools versions plan tests => 1 + test_fake_config_plan() + 2 * @toolchain ; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my ($got, $expect); #--------------------------------------------------------------------------# # Begin tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); $got = CPAN::Reporter::_toolchain_report(); $got =~ s{[^\n]+?\n[^\n]+?\n}{}; # eat headers my %parse = split " ", $got; my $modules = CPAN::Reporter::_version_finder( map { $_ => 0 } @toolchain ); for my $var ( sort @toolchain ) { my $mod_name = quotemeta($var); ok( exists $parse{$var}, "found toolchain module entry for '$var'" ); is( $parse{$var}, $modules->{$var}{have}, "version of '$var' is correct" ); } CPAN-Reporter-1.2010/t/20_report_output.t0000644000175000017500000000354412132015716016464 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => {}, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my ($got, $prereq_pm); my %standard_case_info = ( phase => "test", command => "$Config{make} test", ); my @cases = ( { expected_grade => "pass", name => "t-Pass", automated => 0, }, { expected_grade => "fail", name => "t-Fail", automated => 0, }, { expected_grade => "unknown", name => "NoTestFiles", automated => 0, }, { expected_grade => "na", name => "t-NoSupport", automated => 0, }, { expected_grade => "fail", name => "t-Fail-LongOutput", automated => 0, }, { expected_grade => "pass", name => "t-Pass", automated => 1, }, ); plan tests => 1 + test_fake_config_plan() + test_report_plan() * @cases; #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config( send_report => "yes" ); for my $case ( @cases ) { local $ENV{AUTOMATED_TESTING} = $case->{automated} || 0; $case->{label} = $case->{name}; $case->{dist} = $mock_dist; $case->{$_} = $standard_case_info{$_} for keys %standard_case_info; test_report( $case ); } CPAN-Reporter-1.2010/t/54_test_report_split.t0000644000175000017500000000400312132015716017314 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; my @test_distros = ( # split pass/fail { name => 't-test.pl-Pass-NoOutput-OK', eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, { name => 't-Recurse-Fail-t', eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests provided", }, { name => 't-Recurse-Fail-test.pl', eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests provided", }, { name => 'NoTestTarget', eumm_success => 1, eumm_grade => "unknown", eumm_msg => "No make test target", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests provided", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { test_grade_test( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/04_option_parsing.t0000644000175000017500000000663112132015716016566 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::Frontend; use t::Helper; use IO::CaptureOutput qw/capture/; my @good_cases = ( { label => "empty input", option => "edit_report", input => "", output => { default => "no", } }, { label => "action (by itself)", option => "edit_report", input => "yes", output => { default => "yes", }, }, { label => "grade (by itself)", option => "edit_report", input => "fail", output => { "fail" => "yes", }, }, { label => "default:action", option => "edit_report", input => "default:no", output => { default => "no", }, }, { label => "grade:action", option => "edit_report", input => "fail:yes", output => { "fail" => "yes", }, }, { label => "grade:action action", option => "edit_report", input => "fail:yes no", output => { "fail" => "yes", default => "no", }, }, { label => "grade:action action grade:action", option => "edit_report", input => "fail:yes no fail:no", output => { "fail" => "no", default => "no", }, }, { label => "grade:action action grade2:action", option => "edit_report", input => "fail:yes no na:no", output => { "fail" => "yes", "na" => "no", default => "no", }, }, { label => "grade/grade2:action", option => "edit_report", input => "fail/na:ask/yes", output => { "fail" => "ask/yes", "na" => "ask/yes", }, }, { label => "grade/grade2", option => "edit_report", input => "fail/na", output => { "fail" => "yes", "na" => "yes", }, }, ); my @bad_cases = ( { label => "bad grade", option => "edit_report", input => "failed", output => undef, msg => "/ignoring invalid grade:action 'failed' for 'edit_report'/", }, { label => "bad action", option => "edit_report", input => "fail:run-away", output => undef, msg => "/ignoring invalid action 'run-away' in 'fail:run-away' for 'edit_report'/", }, ); plan tests => 1 + 2 * ( @good_cases + @bad_cases ); #--------------------------------------------------------------------------# # Begin tests #--------------------------------------------------------------------------# require_ok( "CPAN::Reporter::Config" ); for my $case ( @good_cases, @bad_cases ) { my ($got, $stdout, $stderr); capture sub { $got = CPAN::Reporter::Config::_validate_grade_action_pair( $case->{option}, $case->{input} ); }, \$stdout, \$stderr; is_deeply( $got, $case->{output}, $case->{label} ); if ( $case->{msg} ) { like( $stdout, $case->{msg}, $case->{label} ); } else { is( $stdout, '', "No warnings seen" ); } } CPAN-Reporter-1.2010/t/01_CPAN_Reporter.t0000644000175000017500000000172712132015716016134 0ustar garugaru# CPAN::Reporter tests use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::Helper; use t::Frontend; #--------------------------------------------------------------------------# # Bailout if we're on a broken dev version of Test::Harness #--------------------------------------------------------------------------# require Test::Harness; if ( $Test::Harness::VERSION eq "2.99_01" ) { warn "Detected Test::Harness 2.99_01\n"; BAIL_OUT("Your Test::Harness conflicts with CPAN::Reporter") } #--------------------------------------------------------------------------# my @api = qw( configure grade_PL grade_make grade_test record_command test ); my @modules = qw( CPAN::Reporter CPAN::Reporter::Config CPAN::Reporter::History ); plan tests => @api + @modules; require_ok( $_ ) for @modules; can_ok( 'CPAN::Reporter', $_ ) for @api; CPAN-Reporter-1.2010/t/31_PL_report_discard.t0000644000175000017500000000427312132015716017132 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Frontend; use t::Helper; my @test_distros = ( # discards { name => 'PL-PrereqMiss', prereq => { 'Unavailable::Module' => 0 }, eumm_success => 0, eumm_grade => "discard", mb_success => 0, mb_grade => "discard", }, { name => 'PL-PrereqMissOK', prereq => { 'Unavailable::Module' => 0 }, eumm_success => 1, eumm_grade => "pass", mb_success => 1, mb_grade => "pass", }, { name => 'PL-PrereqFail', prereq => { 'File::Spec' => 99999.9 }, eumm_success => 0, eumm_grade => "discard", mb_success => 0, mb_grade => "discard", }, { name => 'PL-NoMakefileOrBuild', prereq => {}, eumm_success => 0, eumm_grade => "discard", mb_success => 0, mb_grade => "discard", }, { name => 'PL-ConfigRequires', prereq => {}, eumm_success => 0, eumm_grade => "discard", mb_success => 0, mb_grade => "discard", }, { name => 'PL-ConfigRequiresError', prereq => {}, eumm_success => 0, eumm_grade => "unknown", mb_success => 0, mb_grade => "unknown", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_PL_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => $case->{prereq}, author_id => "JOHNQP", author_fullname => "John Q. Public", ); test_grade_PL( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/MockHomeDir.pm0000644000175000017500000000143312132015716015535 0ustar garugarupackage t::MockHomeDir; use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use File::Spec; use File::Temp qw/tempdir/; $INC{"File/HomeDir.pm"} = 1; # fake load # tester might have these set -- we need them unset so we use our # own temporary dir & config during our tests delete $ENV{PERL_CPAN_REPORTER_DIR}; delete $ENV{PERL_CPAN_REPORTER_CONFIG}; my $temp_home = tempdir( "CPAN-Reporter-testhome-XXXXXXXX", TMPDIR => 1, CLEANUP => 1 ) or die "Couldn't create a temporary config directory: $!\nIs your temp drive full?"; my $home_dir = File::Spec->rel2abs( $temp_home ); sub home_dir { $home_dir } package File::HomeDir; our $VERSION = 999; sub my_documents { return $home_dir }; sub my_home { return $home_dir }; sub my_data { return $home_dir }; 1; CPAN-Reporter-1.2010/t/50_test_report_pass.t0000644000175000017500000000527012132015716017132 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; my @test_distros = ( # pass { name => 't-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "All tests successful", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 'test.pl-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 't-test.pl-Pass-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 't-PrereqPerl-OK', eumm_success => 1, eumm_grade => "pass", eumm_msg => "All tests successful", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 'test.pl-PrereqPerl-OK', eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 't-Recurse-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 'custom-NoOutput-OK', eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 1, mb_grade => "pass", mb_msg => "'Build test' no errors", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { test_grade_test( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/13_record_command.t0000644000175000017500000001154712132015716016511 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::Helper; use t::Frontend; use Config; use File::Temp (); use IO::CaptureOutput qw/capture/; use Probe::Perl (); #--------------------------------------------------------------------------# # fixtures #--------------------------------------------------------------------------# my $perl = Probe::Perl->find_perl_interpreter(); my $quote = $^O eq 'MSWin32' || $^O eq 'MSDOS' ? q{"} : q{'}; #--------------------------------------------------------------------------# # Test planning #--------------------------------------------------------------------------# my @cases = ( { label => "Exit with 0", program => 'print qq{foo\n}; exit 0', args => '', output => [ "foo\n" ], exit_code => 0, }, { label => "Exit with 1", program => 'print qq{foo\n}; exit 1', args => '', output => [ "foo\n" ], exit_code => 1 << 8, }, { label => "Exit with 2", program => 'print qq{foo\n}; exit 2', args => '', output => [ "foo\n" ], exit_code => 2 << 8, }, { label => "Exit with args in shell quotes", program => 'print qq{foo $ARGV[0]\n}; exit 0', args => "${quote}apples oranges bananas${quote}", output => [ "foo apples oranges bananas\n" ], exit_code => 0, }, { label => "Exit with args and pipe", program => 'print qq{foo @ARGV\n}; exit 1', args => "bar=1 | $perl -pe 0", output => [ "foo bar=1\n" ], exit_code => 1 << 8, }, { label => "Timeout kills process", program => '$now=time(); 1 while( time() - $now < 60); print qq{foo\n}; exit 0', args => '', output => [], delay => 60, timeout => 5, exit_code => 9, }, { label => "Timeout not reached", program => '$now=time(); 1 while( time() - $now < 2); print qq{foo\n}; exit 0', args => '', output => ["foo\n"], delay => 2, timeout => 30, exit_code => 0, }, { label => "Timeout not reached (quoted args)", program => '$now=time(); 1 while( time() - $now < 2); print qq{foo $ARGV[0]\n}; exit 0', args => "${quote}apples oranges bananas${quote}", output => [ "foo apples oranges bananas\n" ], delay => 2, timeout => 30, exit_code => 0, }, ); my $tests_per_case = 4; plan tests => 1 + $tests_per_case * @cases; #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok( "CPAN::Reporter" ); for my $c ( @cases ) { SKIP: { if ( $^O eq 'MSWin32' && $c->{timeout} ) { skip "\$ENV{PERL_AUTHOR_TESTING} required for Win32 timeout testing", $tests_per_case unless $ENV{PERL_AUTHOR_TESTING}; eval "use Win32::Job ()"; skip "Win32::Job needed for timeout testing", $tests_per_case if $@; } my $fh = File::Temp->new() or die "Couldn't create a temporary file: $!\nIs your temp drive full?"; print {$fh} $c->{program}, "\n"; $fh->flush; my ($output, $exit); my ($stdout, $stderr); my $start_time = time(); my $cmd = $perl; warn "# sleeping for timeout test\n" if $c->{timeout}; eval { capture sub { ($output, $exit) = CPAN::Reporter::record_command( "$cmd $fh $c->{args}", $c->{timeout} ); }, \$stdout, \$stderr; }; sleep 1; # pad the run time into the next second my $run_time = time() - $start_time; diag $@ if $@; if ( $c->{timeout} ) { my ($time_ok, $verb, $range); if ( $c->{timeout} < $c->{delay} ) { # if process should time out $time_ok = $run_time <= $c->{delay}; $verb = "stopped"; $range = sprintf( "timeout (%d) : ran (%d) : sleep (%d)", $c->{timeout}, $run_time, $c->{delay} ); } else { # process should exit before timeout $time_ok = $run_time <= $c->{timeout}; $verb = "didn't stop"; $range = sprintf( "sleep (%d) : ran (%d) : timeout (%d)", $c->{delay}, $run_time, $c->{timeout} ); } ok( $time_ok, "$c->{label}: timeout $verb process") or diag $range; } else { pass "$c->{label}: No timeout requested"; } like( $stdout, "/" . quotemeta(join(q{},@$output)) . "/", "$c->{label}: captured stdout" ); is_deeply( $output, $c->{output}, "$c->{label}: output as expected" ) or diag "STDOUT:\n$stdout\n\nSTDERR:\n$stderr\n"; is( $exit, $c->{exit_code}, "$c->{label}: exit code correct" ); } # SKIP } CPAN-Reporter-1.2010/t/06_prompt_text.t0000644000175000017500000000700112132015716016112 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; use IO::CaptureOutput; #--------------------------------------------------------------------------# # We need Config to be writeable, so modify the tied hash #--------------------------------------------------------------------------# use Config; BEGIN { BEGIN { if (not $] < 5.006 ) { warnings->unimport('redefine') } } *Config::STORE = sub { $_[0]->{$_[1]} = $_[2] } } # For these tests, hide perl_patchlevel so all prompts are tested local $Config{perl_patchlevel}; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $perl = Probe::Perl->find_perl_interpreter(); my $make = $Config{make}; my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my $case = { label => "t-Fail", name => "t-Fail", dist => $mock_dist, version => 1.23, grade => "fail", phase => "test", command => "$make test", will_send => 1, }; my %prompts = ( edit_report => "Do you want to review or edit the test report?", send_report => "Do you want to send the report?", send_duplicates => "This report is identical to a previous one. Send it anyway?", ); my %phase_prompts = ( PL => "Do you want to send the PL report?", make => "Do you want to send the make/Build report?", test => "Do you want to send the test report?", ); my %phase_cmd = ( PL => "$perl Makefile.PL", make => "$make", test => "$make test", ); #--------------------------------------------------------------------------# # plan #--------------------------------------------------------------------------# # 7 my $config_plus_dispatch = test_fake_config_plan + test_dispatch_plan; plan tests => 2 + ( scalar keys %prompts ) + $config_plus_dispatch + (1 + $config_plus_dispatch) * (scalar keys %phase_prompts); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); require_ok('CPAN::Reporter::History'); test_fake_config( edit_report => "ask/no", send_report => "ask/yes", send_duplicates => "ask/yes", ); # create a fake result to force send_duplicates prompt my $dummy_result = CPAN::Reporter::_init_result( "test", $mock_dist, "make test", "fake output", 1 ); $dummy_result->{grade} = "fail"; CPAN::Reporter::History::_record_history( $dummy_result ); # capture dispatch output my ($stdout, $stderr) = test_dispatch( $case, will_send => $case->{will_send}, ); # check output for prompts for my $p ( keys %prompts ) { like( $stdout, "/" . quotemeta($prompts{$p}) . "/m", "prompt for $p" ); } # check for per-phase prompts for my $p ( keys %phase_prompts ) { test_fake_config( "send_$p\_report" => "ask/yes" ); my $prefix = $p eq 'test' ? 't' : $p; $case->{name} = "$prefix-Fail"; $case->{phase} = $p; $case->{command} = $phase_cmd{$p}; ($stdout, $stderr) = test_dispatch( $case, will_send => $case->{will_send}, ); like( $stdout, "/" . $phase_prompts{$p} . "/m", "prompt for send_$p\_report" ); } CPAN-Reporter-1.2010/t/70_darwin_move_config.t0000644000175000017500000000523212132015716017371 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use Config::Tiny; use IO::CaptureOutput qw/capture/; use File::Spec; use File::Temp qw/tempdir/; use File::Path qw/mkpath rmtree/; use t::Frontend; plan tests => 9; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $temp_home = File::Spec->catdir( File::Spec->tmpdir(), $$ ); my $old_home = File::Spec->rel2abs( $temp_home ); my $old_config_dir = File::Spec->catdir( $old_home, ".cpanreporter" ); my $old_config_file = File::Spec->catfile( $old_config_dir, "config.ini" ); my $new_home = $old_home . "-new"; my $new_config_dir = File::Spec->catdir( $new_home, ".cpanreporter" ); my $new_config_file = File::Spec->catfile( $new_config_dir, "config.ini" ); my ($rc, $stdout, $stderr); my $email_line = "email_address = johndoe\@doe.org\n"; mkpath $old_config_dir; open FILE, ">$old_config_file" or die $!; print FILE $email_line; close FILE; #--------------------------------------------------------------------------# # Mocking -- override support/system functions #--------------------------------------------------------------------------# BEGIN { $INC{"File/HomeDir.pm"} = 1; # fake load } package File::HomeDir; our $VERSION = 999; sub my_documents { return $old_home }; sub my_home { return $new_home }; package main; #--------------------------------------------------------------------------# # Make sure nothing happens when OS is not Darwin { local $^O = 'unknown'; require_ok('CPAN::Reporter::Config'); ok( -d $old_config_dir, "non-darwin logic: old config dir still in place" ); ok( ! -d $new_config_dir, "non-darwin logic: new config dir not created" ); } # Reset %INC to get CPAN::Reporter to load again delete $INC{'CPAN/Reporter/Config.pm'}; delete ${*CPAN::Reporter::Config}{$_} for ( keys %{*CPAN::Reporter::Config} ); { local $^O = 'darwin'; capture sub { require_ok( "CPAN::Reporter::Config" ); }; ok( $INC{'CPAN/Reporter/Config.pm'}, "CPAN::Reporter::Config reloaded" ); ok( ! -d $old_config_dir, "darwin logic: old config-dir removed" ); ok( -d $new_config_dir, "darwin logic: new config-dir created" ); open CONFIG, "<$new_config_file" or die $!; is( scalar , $email_line, "darwin logic: new config contents correct" ); close CONFIG; } # cleanup rmtree $new_home; rmtree $old_home; ok( ( ! -d $old_home) && ( ! -d $new_home ), "cleaned up temp directories" ); CPAN-Reporter-1.2010/t/30_PL_report.t0000644000175000017500000000565212132015716015442 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; my $lt_5006 = $] < 5.006; my @test_distros = ( { name => 't-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "No errors", mb_success => 1, mb_grade => "pass", mb_msg => "No errors", }, { name => 'PL-Fail', eumm_success => 0, eumm_grade => "unknown", eumm_msg => "Stopped with an error", mb_success => 0, mb_grade => "unknown", mb_msg => "Stopped with an error", }, { name => 'PL-RequirePerl', eumm_success => 0, eumm_grade => "na", eumm_msg => "Perl version too low", mb_success => 0, mb_grade => "na", mb_msg => "Perl version too low", }, { name => 'PL-MIRequirePerl', eumm_success => 0, eumm_grade => "na", eumm_msg => "Perl version too low", mb_success => 0, mb_grade => "na", mb_msg => "Perl version too low", }, { name => 'PL-OSUnsupported', eumm_success => 0, eumm_grade => "na", eumm_msg => "This platform is not supported", mb_success => 0, mb_grade => "na", mb_msg => "This platform is not supported", }, { name => 'PL-warn-OSUnsupported', eumm_success => 0, eumm_grade => "na", eumm_msg => "This platform is not supported", mb_success => 0, mb_grade => "na", mb_msg => "This platform is not supported", }, { name => 't-PrereqPerl-NOK-our', prereq => { perl => 42 }, eumm_success => $lt_5006 ? 0 : 1, eumm_grade => $lt_5006 ? "na" : "pass", eumm_msg => $lt_5006 ? "Perl version too low" : "No errors", mb_success => $lt_5006 ? 0 : 1, mb_grade => $lt_5006 ? "na" : "pass", mb_msg => $lt_5006 ? "Perl version too low" : "No errors", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_PL_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my %mock_dist_args = ( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { my $mock_dist = t::MockCPANDist->new( %mock_dist_args, %{$case->{prereq_pm}} ); test_grade_PL( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/perl5lib-shadow/0000775000175000017500000000000012132015716016040 5ustar garugaruCPAN-Reporter-1.2010/t/perl5lib-shadow/Bogus/0000775000175000017500000000000012132015716017117 5ustar garugaruCPAN-Reporter-1.2010/t/perl5lib-shadow/Bogus/Shadow.pm0000644000175000017500000000006712132015716020703 0ustar garugarupackage Bogus::Shadow; $VERSION = 2.72; use strict; 1; CPAN-Reporter-1.2010/t/bin/0000775000175000017500000000000012132015716013607 5ustar garugaruCPAN-Reporter-1.2010/t/bin/Build.PL0000644000175000017500000000006512132015716015102 0ustar garugaruuse strict; print( ($| ? "1" : "0"), "\n" ); exit; CPAN-Reporter-1.2010/t/bin/NotMakefile.PL0000644000175000017500000000006512132015716016241 0ustar garugaruuse strict; print( ($| ? "1" : "0"), "\n" ); exit; CPAN-Reporter-1.2010/t/bin/Makefile.PL0000644000175000017500000000006512132015716015560 0ustar garugaruuse strict; print( ($| ? "1" : "0"), "\n" ); exit; CPAN-Reporter-1.2010/t/bin/NotBuild.PL0000644000175000017500000000006512132015716015563 0ustar garugaruuse strict; print( ($| ? "1" : "0"), "\n" ); exit; CPAN-Reporter-1.2010/t/72_rename_history.t0000644000175000017500000000517712132015716016574 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use Config::Tiny; use IO::CaptureOutput qw/capture/; use File::Copy::Recursive qw/fcopy/; use File::Path qw/mkpath/; use File::Spec::Functions qw/catdir catfile rel2abs/; use File::Temp qw/tempdir/; use t::Frontend; use t::MockHomeDir; #plan 'no_plan'; plan tests => 12; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $config_dir = catdir( t::MockHomeDir::home_dir, ".cpanreporter" ); my $config_file = catfile( $config_dir, "config.ini" ); my $old_history_file = catfile( $config_dir, "history.db" ); my $new_history_file = catfile( $config_dir, "reports-sent.db" ); my $sample_old_file = catfile(qw/t history history.db/); my $sample_new_file = catfile(qw/t history reports-sent.db/); my ($rc, $stdout, $stderr); #--------------------------------------------------------------------------# sub re_require { delete $INC{'CPAN/Reporter/History.pm'}; eval { capture sub { require_ok( "CPAN::Reporter::History" ); } => \$stdout, \$stderr; }; die $@ if $@; return 1; } sub mtime { return (stat shift)[9]; } sub read_file { my $fh = IO::File->new(shift); local $/; return scalar <$fh>; } #--------------------------------------------------------------------------## # begin testing #--------------------------------------------------------------------------# mkpath( $config_dir ); ok( -d $config_dir, "temporary config dir created" ); ok( ! -f $old_history_file && ! -f $new_history_file, "no history files yet"); # Nothing should be created if nothing exists re_require(); ok( ! -f $old_history_file && ! -f $new_history_file, "still no history files"); # If old history exists, convert it fcopy( $sample_old_file, $old_history_file); ok( -f $old_history_file, "copied sample old history file to config directory"); re_require(); like( $stdout, "/Upgrading automatically/", "saw upgrading notice" ); ok( -f $old_history_file, "old history file still exists" ); ok( -f $new_history_file, "new history file was created" ); my $expected_file = scalar read_file($sample_new_file); $expected_file =~ s/VERSION/$CPAN::Reporter::History::VERSION/; is( scalar read_file($new_history_file), $expected_file, "new history contents as expected" ); # If new history exists, leave it alone my $mtime = mtime( $new_history_file ); sleep(2); # ensure mtime check works re_require(); is( mtime($new_history_file), $mtime, "new history file unmodified" ); CPAN-Reporter-1.2010/t/history/0000775000175000017500000000000012132015716014540 5ustar garugaruCPAN-Reporter-1.2010/t/history/reports-sent-longer.db0000644000175000017500000000244312132015716021001 0ustar garugaru# Generated by CPAN::Reporter 0.99_10 -- fake stuff won't collide with tester test PASS Devel-CheckLib-0.2 (perl-9.8.8) not-a-real-archname fake-os-version test PASS ExtUtils-CBuilder-0.19 (perl-9.002) also-not-an-archname another-fake-version test NA ExtUtils-ParseXS-2.18 (perl-9.002) also-not-an-archname another-fake-version test FAIL Module-Build-0.2808 (perl-9.002) also-not-an-archname another-fake-version test PASS Inline-0.44 (perl-9.8.8) not-a-real-archname fake-os-version make FAIL CPAN-Test-Dummy-Perl5-Make-FailLate-1.00 (perl-9.8.8) not-a-real-archname fake-os-version test PASS URI-Find-UTF8-0.02 (perl-9.10.0) not-a-real-archname fake-os-version test FAIL Proc-Exists-0.03 (perl-9.10.0) not-a-real-archname fake-os-version PL NA Mac-iTerm-LaunchPad-1.008 (perl-9.10.0) not-a-real-archname fake-os-version test PASS Cache-Memcached-Fast-0.07 (perl-9.10.0) not-a-real-archname fake-os-version test PASS PowerDNS-Control-Client-0.02 (perl-9.10.0) not-a-real-archname fake-os-version test PASS RPC-XML-0.59 (perl-9.10.0) not-a-real-archname fake-os-version test PASS Net-MirrorDir-0.07 (perl-9.10.0) not-a-real-archname fake-os-version test PASS ExtUtils-CBuilder-0.21 (perl-9.10.0) not-a-real-archname fake-os-version test PASS ExtUtils-ParseXS-2.18 (perl-9.10.0) not-a-real-archname fake-os-version CPAN-Reporter-1.2010/t/history/history.db0000644000175000017500000000042412132015716016546 0ustar garugaruPASS File-Marker-0.12 i686-linux-64int-ld 2.6.17-10-generic 5.008008 FAIL DateTime-0.38 i686-linux-64int-ld 2.6.17-10-generic 5.008 NA DateTime-0.38 i686-linux-64int-ld 2.6.17-10-generic 5.00504 PASS File-Marker-0.12 i686-linux-64int-ld 2.6.20-16-generic 5.009005 patch 31706 CPAN-Reporter-1.2010/t/history/reports-sent.db0000644000175000017500000000054412132015716017515 0ustar garugaru# Generated by CPAN::Reporter VERSION test PASS File-Marker-0.12 (perl-5.8.8) i686-linux-64int-ld 2.6.17-10-generic test FAIL DateTime-0.38 (perl-5.8.0) i686-linux-64int-ld 2.6.17-10-generic test NA DateTime-0.38 (perl-5.00504) i686-linux-64int-ld 2.6.17-10-generic test PASS File-Marker-0.12 (perl-5.9.5 patch 31706) i686-linux-64int-ld 2.6.20-16-generic CPAN-Reporter-1.2010/t/61_bad_dist_names.t0000644000175000017500000000622212132015716016466 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my %mock_dist_info = ( pretty_id => "PLACEHOLDER", prereq_pm => {}, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my %standard_case_info = ( name => "t-Fail", grade => "fail", phase => "test", command => "make test", ); my @cases = ( { label => "proper distribution name (tar.gz)", pretty_id => "JOHNQP/Bogus-Module-1.21.tar.gz", will_send => 1, }, { label => "proper distribution name (tar.bz2)", pretty_id => "JOHNQP/Bogus-Module-1.22.tar.gz", will_send => 1, }, { label => "proper distribution name (tgz)", pretty_id => "JOHNQP/Bogus-Module-1.23.tgz", will_send => 1, }, { label => "proper distribution name (zip)", pretty_id => "JOHNQP/Bogus-Module-1.24.zip", will_send => 1, }, { label => "proper distribution name (ZIP)", pretty_id => "JOHNQP/Bogus-Module-1.25.ZIP", will_send => 1, }, { label => "proper distribution name (v1.23)", pretty_id => "JOHNQP/Bogus-Module-v1.26.tgz", will_send => 1, }, { label => "proper distribution name (1.2_01)", pretty_id => "JOHNQP/Bogus-Module-1.2_01.tgz", will_send => 1, }, { label => "proper distribution name (v1.2a)", pretty_id => "JOHNQP/Bogus-Module-v1.2a.tgz", will_send => 1, }, { label => "proper distribution name (v1.2_01)", pretty_id => "JOHNQP/Bogus-Module-v1.2_02.tgz", will_send => 1, }, { label => "missing extension", pretty_id => "JOHNQP/Bogus-Module-1.31", will_send => 0, }, { label => "missing version", pretty_id => "JOHNQP/Bogus-Module.tgz", will_send => 0, }, { label => "raw pm file", pretty_id => "JOHNQP/Module.pm", will_send => 0, }, ); plan tests => 2 + test_fake_config_plan() + (1 + test_dispatch_plan()) * @cases; #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); require_ok('CPAN::Reporter::History'); test_fake_config(); for my $case ( @cases ) { $case->{dist} = t::MockCPANDist->new( %mock_dist_info ); $case->{dist}{pretty_id} = $case->{pretty_id}; $case->{$_} = $standard_case_info{$_} for keys %standard_case_info; test_dispatch( $case, will_send => $case->{will_send} ); my $hist_grade = $case->{will_send} ? 'FAIL' : 'DISCARD'; ok( scalar CPAN::Reporter::History::have_tested( dist => $case->{dist}->base_id, grade => $hist_grade, ), $case->{dist}->pretty_id . " seen in history as $hist_grade" ); } CPAN-Reporter-1.2010/t/10_prereq_pm.t0000644000175000017500000001361612132015716015523 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; my @prereq_cases = ( #module #need #have #ok? [ 'Bogus::Found', 1.23, 3.14, 1 ], [ 'Bogus::Shadow', 3.14, 3.14, 1 ], [ 'Bogus::NotFound', 1.49, "n/a", 0 ], [ 'Bogus::TooOld', 2.72, 0.01, 0 ], [ 'Bogus::NoVersion', 0, 0, 1 ], [ 'Bogus::GTE', '>= 3.14', 3.14, 1 ], [ 'Bogus::GT', '>3.14', 3.14, 0 ], [ 'Bogus::LTE', '<= 3.15', 3.14, 1 ], [ 'Bogus::LT', '<3.14', 3.14, 0 ], [ 'Bogus::Conflict', '!= 3.14', 3.14, 0 ], [ 'Bogus::Complex', '>= 3, !=3.14, < 4', 3.14, 0 ], [ 'Bogus::Broken', '0', 'broken', 0 ], [ 'perl', 5.00, $], 1 ], ); my @scenarios = ( [ "old CPAN-style", undef ], # undef is signal and helps keep count [ "only one", qw/requires/ ], [ "only one", qw/build_requires/ ], [ "both types", qw/requires build_requires/ ], ); my $scenario_count; $scenario_count += @$_ - 1 for @scenarios; plan tests => 2 + test_fake_config_plan() + $scenario_count * ( 1 + 4 * @prereq_cases ); #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my %prereq_pm = map { @{$_}[0,1] } @prereq_cases; my ($module_width, $prereq_width) = (0,0); for my $case ( @prereq_cases ) { $module_width = length $case->[0] if length $case->[0] > $module_width; $prereq_width = length $case->[1] if length $case->[1] > $prereq_width; } my $expect_regex = '\s+(!|\s)\s' . '(.{' . $module_width . '})\s' . '(.{' . $prereq_width . '})\s(\S+)'; # \s+ leading spaces # (!|\s) capture bang or space # \s separator space # (.{N}) module name # \s separator space # (.{N}) module version needed # \s separator space # (\S+) module version found my @mock_defaults = ( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", author_id => "JOHNQP", author_fullname => "John Q. Public", ); my ($got, @got, $expect); #--------------------------------------------------------------------------# # Begin tests #--------------------------------------------------------------------------# my $perl5lib = File::Spec->rel2abs( File::Spec->catdir( qw/ t perl5lib / ) ); my $shadowlib = File::Spec->rel2abs( File::Spec->catdir( qw/ t perl5lib-shadow / ) ); local $ENV{PERL5LIB} = join $Config{path_sep}, $perl5lib, $shadowlib, $ENV{PERL5LIB}; require_ok('CPAN::Reporter'); test_fake_config(); #--------------------------------------------------------------------------# # Test no prereq #--------------------------------------------------------------------------# { my $mock_dist = t::MockCPANDist->new( @mock_defaults, prereq_pm => { }, ); $got = CPAN::Reporter::_prereq_report( $mock_dist ); like( $got, '/^\s*No requirements found\s*$/ms', "No requirements specified message correct" ); } #--------------------------------------------------------------------------# # Scenario testing #--------------------------------------------------------------------------# for my $scene ( @scenarios ) { my ($label, @keys ) = @$scene; # initialize -- we need to have both keys for CPAN::Reporter # to detect new CPAN style my %scenario_prereq = ( requires => undef, build_requires => undef, ); # load up prereqs into one or more keys (new style) or replace # %scenario_prereq if old, flat style if ( @keys ) { if ( defined $keys[0] ) { $scenario_prereq{$_} = { %prereq_pm } for @keys; } else { # do it old style, but set up $keys[0] to act like "requires" # for analysis of output %scenario_prereq = %prereq_pm; $keys[0] = 'requires'; } } my $mock_dist = t::MockCPANDist->new( @mock_defaults, prereq_pm => { %scenario_prereq }, ); $got = CPAN::Reporter::_prereq_report( $mock_dist ); # diag $got; @got = split /\n+/ms, $got; for my $prereq_type ( @keys ) { like( shift( @got), '/^' . $prereq_type . ':\s*$/ms', "$label: '$prereq_type' header" ); # Dump header lines splice( @got, 0, 2 ); for my $case ( sort { lc $a->[0] cmp lc $b->[0] } @prereq_cases ) { my ($exp_module, $exp_need, $exp_have, $exp_ok) = @$case; my $line = shift(@got); my ($bang, $module, $need, $have) = ( $line =~ /^$expect_regex\s*$/ms ); # trim trailing spaces from fixed-width captures $module =~ s/\s*$//; $need =~ s/\s*$//; is( $module, $exp_module, "$label ($prereq_type): found '$exp_module' in report" ); is( $bang, ($exp_ok ? ' ' : '!'), "$label ($prereq_type): '$exp_module' flag correct" ) or diag "LINE: $line"; is( $exp_need, $need, "$label ($prereq_type): '$exp_module' needed version correct" ) or diag "LINE: $line"; # Check numerically, too, since version.pm/bleadperl will make # 1.2 into 1.200 ok( $exp_have eq $have || $exp_have == $have, "$label ($prereq_type): '$exp_module' installed version correct" ) or diag "LINE: $line"; } } } CPAN-Reporter-1.2010/t/40_make_report.t0000644000175000017500000000326612132015716016044 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; my @test_distros = ( { name => 't-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "No errors", mb_success => 1, mb_grade => "pass", mb_msg => "No errors", }, { name => 'make-Fail', eumm_success => 0, eumm_grade => "unknown", eumm_msg => "Stopped with an error", mb_success => 0, mb_grade => "unknown", mb_msg => "Stopped with an error", }, { name => 'make-RequirePerl', eumm_success => 0, eumm_grade => "na", eumm_msg => "Perl version too low", mb_success => 0, mb_grade => "na", mb_msg => "Perl version too low", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_make_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { test_grade_make( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/71_missing_config.t0000644000175000017500000000364112132015716016533 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use IO::CaptureOutput qw/capture/; my @test_distros = ( # pass { name => 't-Pass', eumm_success => 1, eumm_grade => "pass", eumm_msg => "All tests successful", mb_success => 1, mb_grade => "pass", mb_msg => "All tests successful", }, { name => 't-Fail', eumm_success => 0, eumm_grade => "fail", eumm_msg => "One or more tests failed", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, ); plan tests => 1 + test_grade_test_plan() * @test_distros + 3; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); # Config file not created in advance with test_config() for my $case ( @test_distros ) { test_grade_test( $case, $mock_dist ); } # Test warning messages my ($stdout, $stderr); capture sub { CPAN::Reporter::_dispatch_report( {} ); }, \$stdout, \$stderr; like( $stdout, "/couldn't read configuration file/", "config file not found warnings" ); like( $stdout, "/required 'email_from' option missing an email address/", "email address required warning" ); like( $stdout, "/report will not be sent/", "report not sent notice" ); CPAN-Reporter-1.2010/t/14_command_timeout.t0000644000175000017500000001570112132015716016716 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::Helper; use t::Frontend; use Config; use File::Temp (); use IO::CaptureOutput qw/capture/; use Probe::Perl (); #--------------------------------------------------------------------------# # Skip on Win32 except for release testing #--------------------------------------------------------------------------# if ( $^O eq "MSWin32" ) { plan skip_all => "\$ENV{RELEASE_TESTING} required for Win32 timeout testing", unless $ENV{RELEASE_TESTING}; eval "use Win32::Job ()"; plan skip_all => "Can't interrupt hung processes without Win32::Job" if $@; } #--------------------------------------------------------------------------# # fixtures #--------------------------------------------------------------------------# my $perl = Probe::Perl->find_perl_interpreter(); my $quote = $^O eq 'MSWin32' || $^O eq 'MSDOS' ? q{"} : q{'}; #--------------------------------------------------------------------------# # Test planning #--------------------------------------------------------------------------# my @cases = ( { label => "regular < global < delay", program => '$now=time(); 1 while( time() - $now < 60); print qq{foo\n}; exit 0', output => [], timeout => 5, command_timeout => 30, delay => 60, exit_code => 9, }, { label => "regular < delay < global", program => '$now=time(); 1 while( time() - $now < 30); print qq{foo\n}; exit 0', output => [], timeout => 5, delay => 30, command_timeout => 60, exit_code => 9, }, { label => "global < regular < delay", program => '$now=time(); 1 while( time() - $now < 60); print qq{foo\n}; exit 0', output => [], command_timeout => 2, timeout => 5, delay => 60, exit_code => 9, }, { label => "global < delay < regular", program => '$now=time(); 1 while( time() - $now < 5); print qq{foo\n}; exit 0', output => ["foo\n"], command_timeout => 2, delay => 5, timeout => 60, exit_code => 0, }, { label => "delay < regular < global", program => '$now=time(); 1 while( time() - $now < 2); print qq{foo\n}; exit 0', output => ["foo\n"], delay => 2, timeout => 30, command_timeout => 60, exit_code => 0, }, { label => "delay < global < regular", program => '$now=time(); 1 while( time() - $now < 2); print qq{foo\n}; exit 0', output => ["foo\n"], delay => 2, command_timeout => 30, timeout => 60, exit_code => 0, }, { label => "global < delay", program => '$now=time(); 1 while( time() - $now < 30); print qq{foo\n}; exit 0', output => [], command_timeout => 5, delay => 30, exit_code => 9, }, { label => "delay < global", program => '$now=time(); 1 while( time() - $now < 2); print qq{foo\n}; exit 0', output => ["foo\n"], delay => 2, command_timeout => 30, exit_code => 0, }, ); my $tests_per_case = 4 + test_fake_config_plan(); plan tests => 1 + $tests_per_case * @cases; #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok( "CPAN::Reporter" ); for my $c ( @cases ) { SKIP: { skip "Couldn't run perl with relative path", $tests_per_case if $c->{relative} && system("perl -e 1") == -1; my @extra_config = $c->{command_timeout} ? ( command_timeout => $c->{command_timeout} ) : (); test_fake_config( @extra_config ); my $fh = File::Temp->new( UNLINK => ! $ENV{PERL_CR_NO_CLEANUP} ) or die "Couldn't create a temporary file: $!\nIs your temp drive full?"; print {$fh} $c->{program}, "\n"; $fh->flush; my ($output, $exit); my ($stdout, $stderr); my $start_time = time(); my $cmd = $c->{relative} ? "perl" : $perl; $cmd .= " $fh"; warn "# sleeping for timeout test\n" if $c->{delay}; eval { capture sub { ($output, $exit) = CPAN::Reporter::record_command( $cmd, $c->{timeout} ); }, \$stdout, \$stderr; }; sleep 1; # pad the run time into the next second my $run_time = time() - $start_time; diag $@ if $@; my ($time_ok, $who, $diag); if ( $c->{timeout} ) { # (A) program delay, (B) regular timeout, (C) command timeout # ABC, ACB, BAC, BCA, CAB, CBA # Option 1 -- program ends before either timeout (ABC, ACB) if ( $c->{delay} < $c->{command_timeout} && $c->{delay} < $c->{timeout} ) { my ($next_t) = sort {$a <=> $b} ($c->{timeout}, $c->{command_timeout}); $time_ok = $run_time < $next_t; $who = "no"; } # Option 2 -- regular before program or command (BAC, BCA) elsif ( $c->{timeout} < $c->{command_timeout} && $c->{timeout} < $c->{delay} ) { my ($next_t) = sort {$a <=> $b} ($c->{delay},$c->{command_timeout}); $time_ok = $run_time < $next_t; $who = "regular"; } # Option 3 -- command before program or regular (CAB, CBA) # C does nothing so are A,B in right order? else { # command timeout should be the default if ( $c->{timeout} < $c->{delay} ) { # did command timeout kill? $time_ok = $run_time < $c->{delay}; $who = "regular" } else { # did no timeout happen $time_ok = $run_time < $c->{timeout}; $who = "no" } } $diag = sprintf( "timeout (%d) : command_timeout (%d) : ran (%d) : sleep (%d)", $c->{timeout}, $c->{command_timeout}, $run_time, $c->{delay} ); } else { # command timeout should be the default $diag = sprintf( "timeout (%d) : ran (%d) : sleep (%d)", $c->{command_timeout}, $run_time, $c->{delay} ); if ( $c->{command_timeout} < $c->{delay} ) { # did command timeout kill? $time_ok = $run_time < $c->{delay}; $who = "command" } else { # did no timeout happen $time_ok = $run_time < $c->{command_timeout}; $who = "no" } } ok( $time_ok, "$c->{label}: $who timeout") or diag $diag; like( $stdout, "/" . quotemeta(join(q{},@{ $output || [] })) . "/", "$c->{label}: captured stdout" ); is_deeply( $output, $c->{output}, "$c->{label}: output as expected" ) or diag "STDOUT:\n$stdout\n\nSTDERR:\n$stderr\n"; is( $exit, $c->{exit_code}, "$c->{label}: exit code correct" ); } # SKIP } CPAN-Reporter-1.2010/t/dist.tgz0000644000175000017500000003120012132015716014522 0ustar garugaru‹?œýLì]ûsÚH¶ö¯¡Šÿ¡Cr¨2ŽÞªØ“Tœ‰³I_ר;wëæ%ƒlk‚%FyTÖÿûí–=’›¶ÎW»ƒ„:}NwßéÓËó_m­…®ªì_QW…Ù'ØEE×TI–%iK]Ó¶ˆºâû 0ö|Ã%dk`|³ ÎË;þH1`ö?vÎMÏÿ`¹«i ËÙŸþWÓ5Agö—4YFûC fÿ÷ck8Ø9=äúÌÀš¢dÚ_VÔ˜ýQ·ˆÀõ.2Pqû=“x¾kõý½ûûÈŒ‡æînÐöjµ¹×·¶ù½Ej„â68г[“Lðæ-i¾w®ÇÞînø¹ævp.kd=cìß8îܹØ3%û;äŸÎp`Úä·qüõ®?2ìǽ~]¡ïš†oön¯æ•E¿v4 ¯à»ÆÀò-Ç6†ôÌvçmtâ%»Ýž×w­ýaë~ÈŒ˜ÿE˜kÈóUŠÇE$ô¼ ÇŽoîÿÆò³<ùnx„úªÓ¹6mÓ¥Î4 —?çãÂîîïÎíÈðÉ7Óõ¨óaGƒðqðÿð­! ´%±ÿ»{µ?]Ë7'-«ÖªMcižö>~><è6™7ÿºÛž=öù¸{¾xøáóYx¸éÑË4çN9Þ?:hf†è¤ƒÿ9˜ù’ÿý¿¹ƒÿ:8ë~>9î}<;9 ¯4´._W{^lgt;½Ó³ƒ³ƒÿîE7==Ö®=¾Póöã¹GññŸ¬"Žÿ bÿ°ñsüŽâöWh€ö‡@¦ý§Áïáß‘×ÿ‹¢³¿&Éöÿý¯ÆµIæúO:îuŒáX4h/6èûâyý=rK¹4‰ïŽÍÚ£ëú[sþÿ‘ŽÎ¸Æý Jôÿ¢ªcü‡@Âþ+`€Jð? m.ÿ€üOµ‘ðÿ0@ÅùU”püäÿ™óÿ0@%ƺ¤âø©öçÌ·¿* Ú ìÏ*Áÿ¨ê? @þ§ÚHøÿ ²ÁÊè?’„ñ)ö?;ØÿptÀñ;òâ¿ hqþGFýçlÞ7°\³ï;îOB_X¶oÚ!¥2üI.‡†ýCû“Eàÿ§‡†5\Upñø/‰ ŽÿA0gÿ•dæÇ…Nöâý?ê¿0Èãÿ–I“vA¼g<ÐþÂ|þÅn <ðø1çÿ+Éþ\‚ÿ×âóE”püþ? "3+GP"Xæü%ÙŸ¥Æºˆó$ìÏ=û³œþ£cþ/2ìÏ1û³ ÿ¯ªŠŽý?ÿ¯6æüE+ÁKôÿŠ€ùŸ ˆÙ_{A$Øñ9~GnüW¤ÄüÆø€“ÈjxñMÏ÷j³œPð‚©C¬opYÏ0vx"›Û‘°÷è‡[¤Á®A§‹Á\’Ñ í ›î b˜øÿ'þÞ(þë€`Îþëâÿõøø_VäÿAÇÿ¿ ±A¾7²lbØ6Úg±ëŽG3Øwno鑞oÝšÎØ¯yCÓYØ i?6°Ø&WÓÿ>GÙ`“0çÿëâÿå¸þ‡ü?²IûÕx>ý›…9ÿß$þó?@°ÿ¦ðÿXÿ ö_;ÿ¯bý7 ÿ_mÌùÿñÿ"ê¿ ˆÙsøœÿùÿjcâÿGŸÏ̿ǖkžš.ï…eÆÿ*òÿ H·?_! ŸÿO¬ÿ–Tã?–Éÿoœœí’m»ä_Qίº#ª †KÆèCÍÁ6¹ûä»Il“ö“ìà·oèɯ4‘üß,¤û?_! ÏÿÙ±˜ÿ벂þ°üÎAu>H÷¾B@ññŸ¢JÈÿƒ Ûþü„€âöW5ùäÙŸ‡Pœÿ×e ù ÿ_m¤û?_! Dÿ/IÈÿƒ Ëþ<…€âü¿ªcý7 ÿ_mLüÿØ™L¦OÜ`Ž¿æùŸ†ó?dÛŸŸÿe5^ÿM4äÿ@Çÿ›?,ŸÈÚ?Udû?? ÏÿU9>þÓT¬ÿþDµß4dû??  ÿ+ËXÿ‹íÏG(n ó?°Œýªæÿ%Ú°þÿ¯6²ýŸŸP¢ÿ$¬ÿ‚Eöç¥çÿ5UÇú? @þ¿Ú¸÷ÿîx4rÜU,+ÿeIÁù’öç_(—ÿ×õ„þ£àþ¿ Xªþ¿í/läÊqÉIkø<$ýŸ \þ_M¬ÿ—Dœÿƒ®þjAA`ÍHú?ÿ"@ÅÇŠ 8þƒ@ºýù*ÃÿhÈÿ€`‘ýy*Ìÿ‹š†ã ÿ_m$ýŸ?T‚ÿQã?ÒìÏ»Pqþ_•°þ3 ÿ¯6&þÒ½°£é¹É3÷Ÿ¡ÌüOÃõ¿ H·?lýYOÔÿ5¬ÿ‚¥øÿ“.™iHþ?!¤û?lýUMä 2ÎÿAÇÿ'ƒ’ÿëGºÿ¯½þ&cþ7²í¿Öú?:ê?0ȳÿšêÿ(ò? @þ¿ÚH÷ÿµ×ÿ‘%¬ÿ ‚,û¯·þ&àú/ ÿ_mLüÿÔ5]óï`pîßQBÿ•%äÿAbî rù?!^ÿGÑ$\ÿ‚™X_OÂ÷.lãmÆ%;Mêµzª P/"Ô®Ô—ÂSݰÎaÐ{ýªOIºfÊ ˆ.Åÿ¹/ÈõMMèê àÇÿ×3€ÅAdN¨×Z¡·%€èí ò?:šÉûGÇ”ôþ’lÿäÖæ‰þebHBèÚ›.RüŸû€óAGþö纠ÿ/ªÈÿƒ`¡ý9-(Îÿkº„ü?ÿ¯6RüŸû€üª!ÿ‚Tûs^ÿÕDþ¿,#ÿ‚¥øÿ›ÏtGfŸ°í¼Fà‰`Þÿ,ß²ß)Êðÿ˜ÿƒû¯ÿOæÿáþï0XŠÿÅþŸûÿÂ.ü™Ošù‘âÿkàÿSêãüpüzyJìÿ²yÔ€ÿßþ_ÄüdØÝü¿„ùÿ0Xhÿ5òÿ˜ÿäÿ«ÿßþ_Ãü¤Úø¬ÿäÿ«¤ÿŸü± ñ_Äúo Hµ?g /þ+j¢þ(âþ¿ ÈåÿŸÏ_Í,ÿl¤ú?g —ÿ—õÿqÿ' ÀðÿO‹ç|YþÙHõÎ @ þó?€iŽ @ þ_Áý¿`c. @qþ_—pý/ ÿ¯6RýŸ³P¢ÿ4ÔAa® @ þ_“0ÿÈÿWÿ? ù²SÓå_¨ÿ¯ÊÿAfÞ ò⿜¬ÿ!àú/äÕÿxt¢ïPû`áÿ'‡4ÿç½ —ÿWÄÿ/àø õÿãA ÿo ÒüŸ÷€óIÇü?dÙŸç€ü¿¬bþÛŸÏ€ü¿(cý? ÿ_m¤ù?ï%ø]Gýéöç» 7þ'÷ÿUeÌÿÖÿ¯6&þÿÝpíUm\bü/ ÿƒöç&äÅELìÿ)‹¸ÿ òøÖ.{wÃó‡å”9ø?7 —ÿ×âëtÚa ÿC„ÿ_"ˆ $°,ðn2@‰ñŸŠü? rìÏE(nMCþKÙÿ2@aþ_äÿa€üµ±Àÿ¹É%ú ù,´?' 8ÿ¯ ÈÿÃùÿj#ðÿ>uç¶s윌ýÑØïó­T<þ+ªˆëAiŽ‹òâ?+ößÿùäñÿ·?ÉËþõ oHŒè÷Æ—Á‘¬‹NzKšqª0h\’Þ˜ì¤ß~kè^¼o².¢F/Eö?g$ë7ȯP? ßí™Ã+úÕÞuEï½;I&¾_”¾œÚyëŽíÞÈt‡³ßº?­ó¶oøŒ^lýýýUð5¬_3ÝÑðU»=eè— ,“4΃.Îvȵ㠞±éìç®V ïšÎ‚ßûøÕŽLÿç¸ Çÿ5éÿŠŽþþÿ‰sûÛsä~m¨ý{¯–«^Ð 8²èS½rÛÙvÔ»°­Ûärì£g—5ŠkÒwŸžÿÝòo‚¯¦q+œQÄ|A:NÒeå³Möph°X@ºfŸýë±SjÓØÊ>ÈDzdÜ‹>Ú bí6ù/ç]ǥצ—x×Û›»0ë0^FÇtÏ»wä?ÿ!ÍfxšuEZÏ£ÿñÒÐÐÕlG?çÓ‹„qýʲAçà…%•4@³æÛŒX“ñ—>6cè9äÆp¬Ë˦ÿ³üÞÀr½¾a·Ú“Ÿòî6úY£±wC_m7jìn{´a¼?é¼—çÿ>=x<°//[‡Ÿÿ`o´Ãc¬q±žçý›ÝÉ»^ðÞ‡÷½îŸô­Î Vcï.Éî. ÿš¿lp˜¤ïN¿¾M¨µÙýwØÑ Óœ¾¢ç֞ѓO~ÿtÒ&ÁŸ'§ôJ Ö¿²ßwE§oFÿ&0ýi½û5y¶¿¨Ý‘»ÙÇ?1ã½úƒûÜ6i¾líÿAo'8þ²uºß=ÿtvÑnN¾iò4 }š´§§]æÂ{}þvZhØ9sÆþ‡…4h: qÅfþD;Sv& mbþðM›Å¦&íºÛµgc{hÒJԬ詫{ /ßýš}w{ñ›°§òþÍàミ´ÉY}f­ÑØ5{Ôé“çÎ.|â›eôhË´éý´èÃüxqxxzpvxvqÜn÷¾чÚ&ÑCµ¢ör. |_9vᙇ±ô/§¶ÜoO¿AÞ]à$ìngBn6â?iÁÍ¿ 'ý¾áC£áOòÝ$·ÆOrECkØù ÌI‡GèˆàÚôw§×"÷Ö&¡ÃN~ù;NCZôSmÓx½¡eµìëV›9Ö³X³¡ÑÙŸr¬ñíŸöÎ÷ÏþypÞoýY~ Úy5÷¹Ô&4Óv²¯8±Ëâ N®7×džÅù³D[yðθ½x»I6‰ÄÍa†˜C:`‰ CÒ 3oèÆ^üÔ¹5ïÁé÷ÝÔ_Že·mô6wĉeŽÿ9.,Ãÿcý,´?§E€%ôYÖÑþXÂþ^XBÿYýwœÿ¯¨ÿW™þ |¾£Dÿ¯è¸ÿÛÊý<è;òâ¿ Æë¿èÖ‡A®þdh‹(ã?Q¤ú?ç-€Jèÿ²®`ü‡@–ýyÖ,®ÿ«º bü‡êÿ¨ÿ§ù?Ï€%ôYCÿêÿ¨ÿ£þ?+¢þ?kFÔÿQÿGýõÔÿ+¤ÿsÞ°ÿ/âþo0Xd^5€Kèÿ’„úòíÿðÀ…õQ×1ÿ¨ÿWYþÏQþ/Wÿ×ÿƒ`¡ýùÈÿùú¿¢'ê¿«ÿA°”þêÿ“EàÿLEê|4,þ[ÿ(ÿ%UÁúo ˆÙŸ÷Öò⿦ÄÇÿŠ `þ/øëÿ˜Tø§õÕúàô‰€îÅûß÷»Ýæ6™p´3y`=#Hš|pIrE[êØ5§ ÛäBëWåO{L;óf)j¦ÒkXLJFëväxžuIï+ØG·Mr·¦ÒÄ1ÿo“ówäŽÿõeUÀúO ˜õÿÀÅN]‡6Ì[BÛ„e_GÒˆÅN¹3 ¹ƒÁ§„˜ÿóÞú3@žÿ«Z¼þ›¢JXÿ•ÿ³T79óéÇ’!´±Õ¿þÏ{ëÏÅç²,bþ7RìÏsëÏÅí¯ÈXÿ™öç³õg€âúŸ&ª˜ÿ Ôÿª˜ÿóÞú3@‰þŸÆŒÿHØŸïÖŸrã¢þ·¢ªÆ`ýïjãÞÿO]Ó5ÿ^… X"þëîÿ‚TûsVóâ¿®ÆùU’0ÿ3±¾ž"Ökõ¥$ÀúD¾»—?Z?ÌÁÑûÆv=Sø£Ýû‚¤ê~Äüf I#¹†Ž¼¦Øyýº1Y«ûò½Î]}*²‹ÎIõ"Z`ýáb`ýÁj`}v­sÊîŸFp•è‰ÌÐë©=qªÿsVsõ?%¾þWÑ4äÿAðÿ¤›e´ÄS@ªÿsVóõ¿”úú?øéõL°>¯Fƒ…Ú_ôÁ Ù/:š©øEÇb_ôþ’:ßäæç%¾úTâË虣ÏÑAJ{£âiªÿsVKè? ê?0È´?G°¸ýÕ€ÿCû¯9öç¢×ÿtYÆú @ý¯ÚHõÎ*`‰þ_Ô±þ?2ìÏU,®ÿ©ºŒù @ý¯Úˆûÿ‘åqÍýc(£ÿi¨ÿ ÕþÐúŸ–²ÿ®ÿÁJõ?Žêß…m|£Cã’}{xD¨²˜ò@‚Ë Å4ÀTÿ‡Öÿû?(:îÿ ƒ„ÿ§:ÚFQÖŽHõhýOû¿ª+˜ÿ Ôÿxë™óFJ€©þ¿~ýO•QÿA¦ý׫ÿi"ê ȱÿÚô?Üÿ ¨ÿU©þ¿~ýO’QÿA†ý×®ÿé¨ÿõ¿jãÞÿÏBªùÔty/,ÿEÇÿ H·?_0Wÿ“ÕÄþß2®ÿÁãYÿ§î¼PeÑml|~ò0Š/ø‹!Ýÿù €¹úŸ’à ùÌùÜÕ6‡¦F¬éþÏWÌÕÿ´¸þ§‰¸þ¨ÿñÖÿ}ôFê~¤û?_°ÄüOÿA¶ýù €%ô?íÿƒö_=òìÏC,¡ÿ©2îÿÔÿªtÿç+–èÿe×€ Ëþ<ÀâúŸ&Ê8ÿêÕFàÿ~ç½a OÆ+©þ\nÿ? ç ˆÙ-ûÿÉJ\ÿSã?òöÿ‹ ~ëÚX/Ò·n# ±7†Wð]c`±mÉŒasM;è=nÄü=ûIÉü¬ÿ ƒÚÿ w÷GÌÿ7fÿ/ ÷AŠý7aÿ/:DûC ÓþkÞÿ ëÃùÿj#æÿ³ÿ—„ëA°ÿöÿ’ùŸŠŠñæÿ%Æÿ;_[–K{v€09Àôí½Úûýχ½“‹óVãÔ5#qÀ$æ_fŸvcßwlvûx×ì;ö þyìTVŒÈÿYÙÏΡc_Ó 0â­”ÿK¸þöçªäòÿjbý*âúO,±þ'MXÏÒš¥T€‡­‡©2üŸ«ËÿËñýÿèüõ?¬!ÿ¿^kÕiõ%D€úR*@}¡ P/¡Ô ÷ÛõÚ# 7þÏU(1þÓ1ÿ ìÏM(nM1ÿ¹öç çÿuMÄü ÿ_mdø?W¨Œþ«¢þ ‚LûsÔrù11ÿ“Dœÿ€Oþÿm>-Ò`­(‘ÿ?°ŒkÒØoDÈ•ã’ÈΑ¨Åé ´?¡¶ÿƒ`²Ìøÿj’ÿ·Jåÿ º‚ñ³ö_IòÿV™üYÖ±þ0ÿ¿Ú˜õÿ•$ÿo•ÊÿÌÿæÿcþÿÄÿW’ü¿Ujü§)˜ÿ‚¸ý¹'ÿo•ÛÿSÑþH·?Çäÿ­2ü¿ªè¸þÈÿW³þ¿¢òeúõ_ÌÛÉÿ[eêÿ(¢€û?`õüÿº!b"ÿÿdØ×›ÅÿãúoÌÚ£øã?ÿ¯6fý£øÌÿòÿÈÿOü£øÌÿAÜþÃÿcý¤Ûíü¿*àú_ ÿ_mÌúÿ&ñÿ ê¿ ˜·ÿzøEÖü¿ˆü?øÔÿYTÿ¿ö‚üÅú odÙݬðlßtÝñ(š\öÛ[z¤ç[·¦3öƒgmç;íwØ;{D$ßoØÔ´¼&ðèoD‚/`›Á6ž?NÎ?œ‘Ÿ?ŸŸ\œ“N‡t?\²÷ÞOtîFè¹û»þÓ±›>qM£¿õu[gõˆüÿh<ô­ÑÎÒýþ ïn Ìø_Çø‚Tûsòâ¿.éññ¿¤cþ/òøÿe6ÿúéÆß1ª0è_Û™›€o‘–Ù<(÷kʬ±»ðÌá½ ïÆº¢÷:92ri_B_ìýá0ꕼq¿ozÞÕx¸óÅþb7îO®ÑyÛ½8=8ÛÝùªð”»Út/ñÚüNâOWñHõÎB@žÿkZ|ü§ê*ú?ÿçËÿ×&„ÊÑ¿÷j, ÚÀn/éƒ Ã™kúc—:þo 6¥Ái4vÍžA£×î.©}ñ¿¼l}¼8<¤êðìâ¸MÏ9®ßacÕZ}¤vÇs\šêÿœ…€âã?EÅü?dÚŸ£PÜþª&bþrìÏE(Îÿë˜ÿäÿ«TÿŸsðøŽ<ÿùšˆëÿa°ÔüyÝ7‰XRýê¿Ë˜ÿ‚ ûssljõ?ª®cþ'pýOµùÿ±þë ,“{H ýOÅú0H³?ïu@yñ?¹þGÿ‡®ÿ©6ÒüŸ÷: <ÿO®ÿQU ù? þ‡ëâþÏ{P‰ù¿Œë?`ežë€J芀õß@°Øþ|Ö•ÐÿD ó¿A€ú_µ‘æÿ¼×•èÿ ÷ÿAºýù®ÊÿÉüoUÃùŠóÿÁt¶8é,vw?8&}Eç‘»»?,–M}ÁcAÌÿ7¤þƒ,`þ âö_E °âü¿"‹ÿA€üµ÷ÿUÔ+Îÿ+º†ù @þùÿYÿ_E °ã¿`þ‡ã¿Õ#Íþ¼k€•à4õdÛŸ_ °âü¿¦HXÿ ÈÿWqÿ_T¢ÿ—4¬ÿ‚¤ýù×Ë‹ÿ5v<ÿSÂõ_ (Ìÿ¯û†\1õÿîxÄ}®B(ÿƒõŸÿW„ýW ”àÿó@€üµ‘ðÿÅùUTpþäÿ‘ÿŸóÿ%ƺ‚ù Hµ?g ¸ýUzÚ ìÏM(Áÿ«XÿÈÿW ÿ_T¢ÿWd¬ÿ‚ûsrã?=¯ÿŽûÀOýŸ÷ûŸ{l·†í/lIäÿÛ;ûÞ6n-÷ß Èw¸š`#eÞ8së^,6MÜ mÄén/Ö]C–ÇnIÜAîg_r$Ù’æ…CŠ>c‹Ï¯(bKŠdçÌÃ!Ÿsxx9Nñíãî57ú1žþ0ËŽÓ$M>¾NÍ-4æÿ‹úêâo* ÿÃ`sÿW‰øcü¿{vÊÿ¯äïl˜&ùÍéóÆ3ߪ6ZîSËý;÷©óÅâÌAþM¥¤þáüØbèŸøÿÛúÿMÆgå7»_Y‚:ý›J¨Ïÿ"—¡þŸYüM¤Ôã{êÿIhÿíRÊþ¿ïÆòÿ$Àÿ·›…þN~-|»ä¢ýüèzÿI(?ñù¯%ýŸŒÿ4ì”ÿc­‹£O©þ‰Ï-©ÿŒ#ìÿ!þê? ú¿ç¿bÿ' •ñoùüWÔÿÒ ‰[翆ò¿$Àÿ±›Rý߃óêH¨ˆ?ñù›ý"ã? ¦ë?ÇSgv{%¡øó¾³Ð¿ˆþô~¨ÿ¾h ñŸ€ÕøßEïgºÿð Æ àÿÛͪþï¢÷³@ÝÿÝó?àÿÃÿ_êÿ.z? 4æQŒýŸ$lÆßtïgzüƒõ¿4”Çß\ïgºÿÏX€ü? ðÿífUÿwsú—Öý?@ÿOÖão¾÷³@îÿû›ë¿|ÿÆÿ»ÇŒÿ?áù±³'Þƒ/óµ¤xÅžóäá­ˆìb©ÿ|×Ï«þðêžôÿg¨ÿ'¡óYÙø/š=mÖÿ1Ôÿ“°Sþ¿xåZÿ‡kîÛWCñ[œL’AîÚ}'è}—?ÿÅæ¼AQÿæ³Rÿß+œÿáãüÚòÿËÿZÏ_âöWøüJÿ¦·ßlüxÚy¸ÓÜ¢þÍgÔç¡ë£þŸ„òø›Í¨ÇŸy.êÿI¨‹¿©,€ºÿE ùàÿÛMQÿæ³þóPÿOBYüMg¤ã?Ûôÿ™¡ÿ3 üÿÛÅÏráƒ<Àް¦£]ŸoÑÿôÿ¡¡ÿüÿÂøFÆlñÿô¶2PÔ þ¿¿Ùÿ™ù8ÿ•øÿÍüÿÆãÇKõ?üôÿ¡¡<þíûÿèÿCC]ü[ôÿcô þ¿Ýõ?üôÿ¡¡,þÔþ¿ïÎ 0þÓ óÿÅ×ukìxجéÿ8I¯º‡G?udzÔà]@cý—ïÿÄø÷TÇß\@êÿü¿È àÿ‘`‹ÿ?á—vîÓ±¿Îìôú˨ֿ¹<€Ôÿw7ós±ÿ‡øÿÍüÿÒñãyýeTëß\@Ãÿ PÿMC}üÍäÔã ý?Ihÿmórÿãüw?o û?Uþ?¿ävŸjý›Ëhø?1úÿÑPSy©ÿï×ú?“`¦ÿÏÅ0qö^ͲYš8â"rFãÌŽ®“‘X>~J²=gxéìÿæüÝ }dî¥úo½þ+ˆÑÿŸ†òø›Ý ÷ÿ ý?ÑÿƒëüÿЇù¿B¹þÍîê?Ž7õãüoàÿ+úÿ7ãǘÿ_Uéßìõˆõ? Õñ7·@#ÿÃÐÿŸYüMìûÿ…óôÿ§õÿvS®³{4îÿúÿÓP“{Ôýcü§þ¿ÝõoÜþ×ñÿ#û¿I(¿á@rÿ¿0þ{.Î!Á:ÿŸÁþ_¥Tÿ†[ÉýÿBÿcþGüÕúÿ²ÿËõo¸ÆúõßDTÆß` ÿ? ÐÿIü´Òðÿ}/ÄýŸøÿvSªÃ-€4îÿ.ò¿4TÄßh éø_8ÿ—EêÿIÀù¿v³ÐÿÛd0K§IWœÒ5ÝNÃÿCôÿ'¡<þ´õÿA¸yþ/ó±ÿ—†òÿaé+S®ÚúæüŸØƒÿOB[þÿÂV/Í,ž«Ë,^RŸX¼¨ú¿‘P³åßòñ?*®ÿ"äÿHùÿû?_)NÜãC:ࡳÐÿêQÆ›Àk¬ÿ‚õ$TÆß`@ÝÿgÆàÿÛM¥þ fäþ¡þ3Àù_4 þÛjû¿Zÿ³þ¯‡óh¨¿¡,€zü#ßCÿ_Äë,€†ÿÇèÿKü»©Ô¿Á,€†ÿaÿ? 5ñ7–ŽÿÅþ_AŒü/ 8ÿÕnªõ¿ý¾Ÿ%êúg±‹úO°ÿÇn6ô/"Ø=ͲÉ,ëýÔNÿ'¨ÿ$Aÿvú?ùÎ%ù?»‘ê¿þO^»Èÿ“€üòµúo§ÿÃù44Š?}ÿ'¡þ›…øSö Ðÿ›äÿìFªy@û¿ïâü7Äë< ºÿÇ!ê?H€ÿo7rýß}ÿ?—mîÿ‹ýõß$HõŸü5Ì2ÞQjõo&ý§“ÿã@Ìÿ(ÅßÄ6@üŸçaü'ù?»‘éßÄ6@ü‹pþ7 Èÿ!ÿW§Û5ü¿ Bý Mâ¿í6@ü_bÿ' Í㯿 P#ÿçûØÿAòv#Ó¿‰m€÷õ4Èã¿ý6@ü_ä£þ›äÿìFªÛ¥ù¿0.ø¿8ÿ†Fù?ˆxg)Óÿ=èÿúèÿ@BeüÛíÿûØÿMòvS©ÿ–ûƨÿ'ù?äÿJõßrÿÏõ_$ÔÆ¿ÅþŸ!úÿ“Ð þôý?}×õáÿ€üŸÝTê¿åþŸê?H¨‰›ý?Cõß$ ÿg7Õúo·ÿg€ú/ »™ë¥û¯éÃ_¿Ò:ÿÕGþ†bü &þ¨çÿB†ü ÈÿÙMQÿ ÔóÌCþäÿÿ[׿ÁÄßù_Œü åñ7”ø[ ‘ÿu‘ÿ£¡.þ['þ(çÿ¼(Bþäÿ즨ƒÆïuÿ7dðiÀùov³¦Ó?-ÐÈÿ³ýI¨Ž¿9XÝÿ\ô¢þ¯ÝTëßœ¬îÿF,Dþ‡ø¿ðËõoÎÖðÿ‚þ õñ7ã«Ç? =ôÿ#¡Iü·õ•ý__tÄýŸø¿vS­s>°LÿÅó?"ÏEý 8ÿÃnÊõoÔþÕêÿÃÐÿ‘„Êø·Üÿ‡aü'þ¯ÝTê¿Ýþ?yÿ7èÿîÿ ÿ·Tÿíöÿñ}äÿI¨{ýõß$4ˆ+ýú?ÿ×n*õOØÿ¡Øÿåû ÿ»ýßífMÿG'¿Œ¦³ÉdœòU_›ý¿˜bþOBMü9Àêþo¨ÿ%þ¯ÝÔèߘ¬îÿÆü[èŸø¿ð+ôoÌÖ˜ÿÅ.êIÄ߈¬áÿÆ8ÿ›†FñßÒÖðYˆú_àÿÚMþ9ÀRý‡…úßõ_4˜éÿðÃó×?ŸýòÎÙ;:qV®¡½‡7!¶Œ5ý›>øsúü/ðÎ ¡ÿûÑÿ—¡ÿ ðí¦¨ÿ{Ñÿ×÷±þ#þ/üßuý߇þ¿¡ëcÿ åño½ÿ¯çâüêâßfÿßù_àÿÚMQÿ÷£ÿo„úpþ›Ý¬ë?MÒä£ñSà4æÿ¡‹ú_ªâoÒ–ÿaPèÿŨÿ%a§ü_ñJ~φi’ßœ>ßX3ß¾Šßâd’ r׿;Aï»üù/6ûÆUú7éKý_¯ÿÖ$´åÿ–;¿µž¯Äí­ðy•ÞMo·Ùøñ´óp§¹Uú7éëø8ÿ‹†ºø›rÕãù>êIÇ{XÙÿõÅ¢÷ àÿÚM•þMºÀRý³Mÿ—Åê¿HhäÿÞN~—_øÀ;B‰þß Wëø¿èÿ@CUüIýß’ñ?@þ[üßµëààÇq2e/ÿâ?Zîè¸O­4ƒ«ôOêÿòÅ~Ùù?ÐÿÝÿ·™ÿÛxüx`fp•þ[ö}ô ¡.þmú¿èÿ@ƒ<þíø¿èÿ@ü_»©Ò?¥ÿë»!Îÿi ™ÿ+¾®›û¢BøaS¢ÿã$½ÊO€4õóýh¨‹¿)XêÿúÅú¿þ –ø¿~M‹GBßN›·’:ý›ò€¥ú7ëÿc7`Ð?ðù¿…ñãÙ¼•Ôéß”¬1ÿ‹ÐÿYüMxÀþoŒþ44‹ÿv°†ÿ¢ÿ ðí¦Nÿ¦<`©ÿëoÖEA„ù? fú?\ gïÕ,›¥‰#.g4Μáè:‰åç$Ûs†—ÎþoÎßù nð=¢Jÿí_úß8@ý 5ñ';ÿ-,ôÿŒ|ýH°Ìÿe°שÑ?Ùùoa¼™ÿbÔÿÒÿWÉÿe;fÿÖé¿Íóߘ‹ü? ’ø·uþ‹BÄŸ‚Fñ§?ÿ-}Üÿ)€ÿk75ú'<ÿ­àÿúèÿFúÿÚM®ÿ㟻/Æ£Ëáïoæ‰Ù@Îÿ¸êc?p=áÿúâüwÌÿø=NîÿñgÌÃøOÂÊXÿ¨Äž?öóxп¦¸FøcJmáG*¾ð£íáÕ·8ç¿Cm~ÞòEìãGEÿØùò¨Ê)~´7¶ ý¿y~øúÕË“wF>C:ÿ›÷ÿ^ÕBÿ$,úNÉj¿³’è,¯ˆ¯¿þú˜ß]ñ Ç_æžñ´óæå»ç½O®:Ù3×;Ëß§—í†Bv‰þ{'?½>Þö3$úK¿ ýóe ò?$|ã<¿ó{í2“3²t|5—u¯szþöÅÉé9ÿóÅ‹?Ÿ^ïwN8íM¯GâQþÕàz:ü}Ä—†ûÎòÍĸ!s›Cê.œY6¼fŸnß|9Àð7=?ç#Ð⡜eã3ñÜò5Ãtºßù¿åzš_¢«¾:5‘ýù‹ö—_ôÎû™øf~§¿}Ë“ë$Ÿÿ\¯ýJó¡ïô| ?»8¿ý Yòa’àyðÇl²ü¼ó7ïe&âqþ¹üÿà|#¾ü†ÿŸ&ÿZùUŽNºÓI2^ó·x&~yþ´Ãÿ‰üé_IÖ¿ègý<?žœd<k¯8yóŸ”ÍFÙÍk—?8ÿg7ŸÕOï‡×|ÞÃÇô|/F†tx>Ó#ñ$Æôîü·û¿§§½Ó³ßþCü§jü_ÜÏ|†týæa„þ$t»ÝŽX«8«ï,n"³ïuæ+´¾>ê6[›u– ²ÅÛòÙå Mù§ÌFŒÆŽ:ƒüz›¥ÉÙrÁ%Þ~m¡É?¼s3Øž:ØÚo‹ü¿¹ã?¦ßòS¼Õ,½:pÞgÙäàÙ³ùš´›ê½éx–’Kþs&½Q’å—zþ·º×^Ïï½Ïø,Öqnþøc»<ÈUéßä!à2ý3æmÎÿ¼ýŸI0Uÿ#$xÆ5XYTô‘:uƒ7:ÙÛÀáݪ'Ž×&¾QÓô¯Ð¿ÑCÀ5üÿ˜¡ÿ 5ñ7v¸zü£|ÿ?â÷Hãoàð†õ?+ñ#œÿ@êì¦Bÿ™É ûÈÐÿ„Êøß¦q¶þ éø??ÿaõþï{ØÿKÎÿ±›rý¿LÓqJÝÿ1 Ü tÃ8ïÿîcÿ/ uñ'ëÿX¨ÿŠø€ñŸÔ¡þ«Jÿ¦ŠÀÔë¿¢€Aÿ$ þËnšèÛ"0õú¯ØCý7 ¨ÿBýê¿ì¥vü7T&­ÿðƒõÄ\Œÿ$,ë¿ÖÊ¿çç×_u^¾{yøîõÑáóŸ—oß½ÍûúõI:žð‘ð}úÞù#ù„j±‡[-V«¢þÿÅú¯˜?ýS€ú/ÔU韸ÿÿjýwcÿ7 ²øöÿ_ÿÅ4ñ' YüIúÿ߯ßw#÷Pÿe7uú7U¦qÿ#Ôÿ’P3E`êõ_1úú/»Éõ8ÞÞõÓߣ…¿ šÿ_(ôØÿAC1þF·~æÈÆÿ8 oâï†yÿçýßih«ÿ{¹c¦êÆ5r k-;âšÍ×Y.¨ÞüóûÎtvžßÿø‹ø3â»<Û¿:Ër­Móó>9÷§ÉÕå¾Ðš¾^òÛnþèþeÚÿ?–?ÙýÏ“_Ž_¾=8Øx‹ÇOÄ«/ý·3ý|z.>òôüËç/ÃSñdšd³t4Í÷/kwâ¢þ¶þË‘é?Èû?äúçòù¿0â·蟀:ÿ‡º(SÔ¿Ñ­ß9 ×ÿ«çyž‡ùåñ7¶õ;G=þÌCþ‡†ºøØúÓÐÿ_;ÿ)ÄüŸøÿv3?ÿ¡û~:J¦Óî«þðʸÔlüãØõü0ˆ„ÿÃ\ìÿ&¡,þ¦W€Rÿ' oâï±PÜÿù+0þS [ÿ âÃ9¿l,§³óÁ•pûùòl0¾HÄjìãÜÚ>Çó¢lôln~, ’üèýÑ·™“ü• fÂvêõzÎx’Œ‚çõÑÁÁñpœ¿f:éÿ9êýÏó×ïœÃ1ßÁû¹EÅ—‘Ã4dãô“ÓÏœÏDéŸçIš~z&ÎêËg1ïž?;î§Ó$}ö:VÖ8}vœŽüBç“çj8J~½Žö¾_œ *<œÜOéð_ú¾¯vÿÖyÄÓZËß2ý›v€%úçÒnõÍó¿ØÿGü_Ãþ¯ýÞüóà@ }g×ÃþÙû¹´Ö­Þ§Î¾¦„ãû_g+íÞivºÿøðèå‹=™¿ÆéòaSŒB½¥üqÆCvv5cÚÕãŸÅÀúñó½Y¿|y²é8ƒûDÙøoÚÔðÿø:ó ªâoÒÔðÿÑÿñ¿{êãoÆT÷ÿbûÿh€ÿg7eú7]¦>þqˆü åñ7Øüñ+óƒÿGƒ™ó/ùeóØÙWê~¸3þÎvCCPAN-Reporter-1.2010/t/51_test_report_fail.t0000644000175000017500000000535412132015716017103 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; my @test_distros = ( # fail { name => 't-BailOut', eumm_success => 0, eumm_grade => "fail", eumm_msg => "Bailed out of tests", mb_success => 0, mb_grade => "fail", mb_msg => "Bailed out of tests", }, { name => 't-Fail', eumm_success => 0, eumm_grade => "fail", eumm_msg => "One or more tests failed", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, { name => 't-MultipleMatch', eumm_success => 0, eumm_grade => "fail", eumm_msg => "One or more tests failed", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, { name => 'test.pl-Fail', eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, { name => 't-test.pl-Fail-Pass', eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, { name => 't-test.pl-Pass-NoOutput-NOK', eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, { name => 'custom-NoOutput-NOK', eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 0, mb_grade => "fail", mb_msg => "'Build test' error detected", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { test_grade_test( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/68_is_make.t0000644000175000017500000000205112132015716015145 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use Test::More; use t::Helper; use t::Frontend; my @cases = ( # Makefile.PL based stuff should be true ['perl Makefile.PL' => 1], ['perl Makefile.PL LIBS=/foo' => 1], ['make' => 1], ['make LIBS=/foo' => 1], ['make test' => 1], ['make test TEST_VERBOSE=1' => 1], # make variants ['dmake' => 1], ['dmake LIBS=/foo' => 1], ['dmake test' => 1], ['dmake test TEST_VERBOSE=1' => 1], ['nmake' => 1], ['nmake LIBS=/foo' => 1], ['nmake test' => 1], ['nmake test TEST_VERBOSE=1' => 1], # Build.PL based stuff should be false ['perl Build.PL' => 0], ['perl Build.PL LIBS=/foo' => 0], ['Build' => 0], ['Build LIBS=/foo' => 0], ['Build test' => 0], ['Build test TEST_VERBOSE=1' => 0], ); plan tests => 2 + @cases; require_ok( 'CPAN::Reporter' ); can_ok( 'CPAN::Reporter', '_is_make' ); for my $c (@cases) { my ($cmd, $expected) = @$c; is( CPAN::Reporter::_is_make($cmd), $expected, $cmd ); } CPAN-Reporter-1.2010/t/03_config_file.t0000644000175000017500000002545712132015716016005 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use Config::Tiny; use IO::CaptureOutput qw/capture/; use File::Basename qw/basename/; use File::Glob qw/bsd_glob/; use File::Spec; use File::Temp qw/tempdir/; use File::Path qw/mkpath/; use t::Frontend; use t::MockHomeDir; plan tests => 62; #plan 'no_plan'; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $config_dir = File::Spec->catdir( t::MockHomeDir::home_dir, ".cpanreporter" ); my $config_file = File::Spec->catfile( $config_dir, "config.ini" ); my $metabase_file = File::Spec->catfile( $config_dir, 'metabase_id.json' ); my $default_options = { email_from => '', edit_report => 'default:ask/no pass/na:no', send_report => 'default:ask/yes pass/na:yes', transport => "Metabase uri https://metabase.cpantesters.org/api/v1/ id_file metabase_id.json", # send_duplicates => 'default:no', }; my @additional_prompts = (); my ($rc, $stdout, $stderr); #--------------------------------------------------------------------------# # Mocking -- override support/system functions #--------------------------------------------------------------------------# { # touch our mock metabase_id.json file mkpath $config_dir; # 2-args open with bare descriptor to work in older perls open METABASE, ">$metabase_file"; close METABASE; ok -r $metabase_file, 'created mock metabase file for testing'; } #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); require_ok('CPAN::Reporter::Config'); is( CPAN::Reporter::Config::_get_config_dir(), $config_dir, "get config dir path" ); is( CPAN::Reporter::Config::_get_config_file(), $config_file, "get config file path" ); # id_file normalizations my @id_file_cases = ( [ $metabase_file => $metabase_file ], [ 'metabase_id.json' => $metabase_file ], [ '/other/path.json' => '/other/path.json' ], [ 'other.json' => File::Spec->catfile( $config_dir, 'other.json' )], [ '~/other.json' => File::Spec->catfile( $^O eq 'MSWin32' ? File::HomeDir->my_home : bsd_glob('~'), 'other.json' )], ); for my $c ( @id_file_cases ) { is( CPAN::Reporter::Config::_normalize_id_file( $c->[0] ), $c->[1], "normalize id_file: $c->[0]" ); } ok( ! -f $config_file, "no config file yet" ); is( capture(sub{CPAN::Reporter::Config::_open_config_file()}, \$stdout, \$stderr), undef, "opening non-existent file returns undef" ); like( $stdout, "/couldn't read configuration file/ms", "opening non-existent file gives a warning" ); { local $ENV{PERL_MM_USE_DEFAULT} = 1; # use prompt defaults eval { ok( $rc = capture(sub{CPAN::Reporter::configure()}, \$stdout, \$stderr), "configure() returned true" ); }; diag "STDOUT:\n$stdout\nSTDERR:$stderr\n" if $@; } for my $option ( keys %$default_options, @additional_prompts) { like( $stdout, "/$option/", "saw '$option' configuration prompt" ); } is( ref $rc, 'HASH', "configure() returned a hash reference" ); is_deeply( $rc, $default_options, "configure return value has expected defaults" ); ok( -f $config_file, "configuration successfully created a config file" ); my $new_config = Config::Tiny->read( $config_file ); is_deeply( $new_config->{_}, $default_options, "newly created config file has expected defaults" ); #--------------------------------------------------------------------------# # check error handling if not readable #--------------------------------------------------------------------------# my $original_mode = (stat $config_file)[2] & 07777; chmod 0, $config_file ; SKIP: { skip "Couldn't set config file unreadable; skipping related tests", 2 if -r $config_file; { local $ENV{PERL_MM_USE_DEFAULT} = 1; # use prompt defaults is( capture(sub{CPAN::Reporter::configure()}, \$stdout, \$stderr), undef, "configure() is undef if file not readable" ); } like( $stdout, "/couldn't read configuration file/", "opening non-readable file gives a warning" ); } chmod $original_mode, $config_file; ok( -r $config_file, "config file reset to readable" ); #--------------------------------------------------------------------------# # check error handling if not writeable #--------------------------------------------------------------------------# chmod 0444, $config_file; SKIP: { skip "Couldn't set config file unwritable; skipping related tests", 2 if -w $config_file; { local $ENV{PERL_MM_USE_DEFAULT} = 1; # use prompt defaults is( capture(sub{CPAN::Reporter::configure()}, \$stdout, \$stderr), undef, "configure() is undef if file not writeable" ); } like( $stdout, "/error writing config file/", "opening non-writeable file gives a warning" ); } chmod $original_mode, $config_file; ok( -w $config_file, "config file reset to writeable" ); #--------------------------------------------------------------------------# # confirm configure() preserves existing #--------------------------------------------------------------------------# SKIP: { skip "Couldn't set config file writable again; skipping related tests", 8 if ! -w $config_file; my $bogus_email = 'nobody@nowhere.com'; my $bogus_smtp = 'mail.mail.com'; my $bogus_debug = 1; my $tiny = Config::Tiny->read( $config_file ); $tiny->{_}{email_from} = $bogus_email; $tiny->{_}{smtp_server} = $bogus_smtp; $tiny->{_}{debug} = $bogus_debug; ok( $tiny->write( $config_file ), "updated config file with a new email address and smtp server" ); { local $ENV{PERL_MM_USE_DEFAULT} = 1; # use prompt defaults ok( capture(sub{CPAN::Reporter::configure()}, \$stdout, \$stderr), "configure() ran again successfully" ); } like( $stdout, "/$bogus_email/", "pre-existing email address was seen during configuration prompts" ); like( $stdout, "/$bogus_smtp/", "pre-existing smtp server was seen during configuration prompts" ); like( $stdout, "/debug/", "pre-existing debug prompt was seen during configuration prompts" ); is( $tiny->{_}{email_from}, $bogus_email, "updated config file preserved email address" ); is( $tiny->{_}{smtp_server}, $bogus_smtp, "updated config file preserved smtp server" ); is( $tiny->{_}{debug}, $bogus_debug, "updated config file preserved debug value" ); } #--------------------------------------------------------------------------# # confirm _get_config_options handles bad action pair validation #--------------------------------------------------------------------------# SKIP: { skip "Couldn't set config file writable again; skipping additional tests", 4 if ! -w $config_file; my $bogus_email = 'nobody@nowhere.com'; my $bogus_smtp = 'mail.mail.com'; my $bogus_debug = 1; my $tiny = Config::Tiny->read( $config_file ); $tiny->{_}{email_from} = $bogus_email; $tiny->{_}{edit_report} = "invalid:invalid"; ok( $tiny->write( $config_file ), "updated config file with a bad edit_report setting" ); $tiny = Config::Tiny->read( $config_file ); my $parsed_config; capture sub{ $parsed_config = CPAN::Reporter::Config::_get_config_options( $tiny ); }, \$stdout, \$stderr; like( $stdout, "/invalid option 'invalid:invalid' in 'edit_report'. Using default instead./", "bad option warning seen" ); is( $parsed_config->{edit_report}, "default:ask/no pass/na:no", "edit_report default returned" ); $tiny = Config::Tiny->read( $config_file ); is( $tiny->{_}{edit_report}, "invalid:invalid", "bad edit_report preserved in config.ini" ); delete $tiny->{_}{edit_report}; $tiny->write( $config_file ); } #--------------------------------------------------------------------------# # Test skipfile validation #--------------------------------------------------------------------------# SKIP: { skip "Couldn't set config file writable again; skipping other tests", 11 if ! -w $config_file; for my $skip_type ( qw/ send_skipfile cc_skipfile / ) { my $tiny = Config::Tiny->read( $config_file ); $tiny->{_}{$skip_type} = 'bogus.skipfile'; ok( $tiny->write( $config_file ), "updated config file with a bad $skip_type" ); $tiny = Config::Tiny->read( $config_file ); my $parsed_config; capture sub{ $parsed_config = CPAN::Reporter::Config::_get_config_options( $tiny ); }, \$stdout, \$stderr; like( $stdout, "/invalid option 'bogus.skipfile' in '$skip_type'. Using default instead./", "bad $skip_type option warning seen" ); is( $parsed_config->{skipfile}, undef, "$skip_type default returned" ); $tiny = Config::Tiny->read( $config_file ); is( $tiny->{_}{$skip_type}, "bogus.skipfile", "bogus $skip_type preserved in config.ini" ); my $skipfile = File::Temp->new( TEMPLATE => "CPAN-Reporter-testskip-XXXXXXXX", DIR => File::Spec->tmpdir(), ); ok( -r $skipfile, "generated a $skip_type in the temp directory" ); $tiny->{_}{$skip_type} = "$skipfile"; ok( $tiny->write( $config_file ), "updated config file with an absolute $skip_type path" ); $tiny = Config::Tiny->read( $config_file ); capture sub{ $parsed_config = CPAN::Reporter::Config::_get_config_options( $tiny ); }, \$stdout, \$stderr; is( $stdout, q{}, "absolute $skip_type ok" ); $skipfile = File::Temp->new( TEMPLATE => "CPAN-Reporter-testskip-XXXXXXXX", DIR => $config_dir, ); ok( -r $skipfile, "generated a $skip_type in the config directory" ); my $relative_skipfile = basename($skipfile); ok( ! File::Spec->file_name_is_absolute( $relative_skipfile ), "generated a relative $skip_type name" ); $tiny->{_}{$skip_type} = $relative_skipfile; ok( $tiny->write( $config_file ), "updated config file with a relative $skip_type path" ); $tiny = Config::Tiny->read( $config_file ); capture sub{ $parsed_config = CPAN::Reporter::Config::_get_config_options( $tiny ); }, \$stdout, \$stderr; is( $stdout, q{}, "relative $skip_type ok" ); delete $tiny->{_}{$skip_type}; $tiny->write( $config_file ); } } CPAN-Reporter-1.2010/t/65_skipfile.t0000644000175000017500000000601612132015716015345 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; use Probe::Perl; use File::Temp; #--------------------------------------------------------------------------# # We need Config to be writeable, so modify the tied hash #--------------------------------------------------------------------------# use Config; BEGIN { BEGIN { if (not $] < 5.006 ) { warnings->unimport('redefine') } } *Config::STORE = sub { $_[0]->{$_[1]} = $_[2] } } #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# # Need to have bleadperls pretend to be normal for these tests local $Config{perl_patchlevel}; my $make = $Config{make}; my $perl = Probe::Perl->find_perl_interpreter(); my $skipfile = File::Temp->new(); print {$skipfile} << 'SKIPFILE'; # comments should be ok ^JOHNDOE Bogus-SkipModule SKIPFILE $skipfile->close; my %mock_dist_options = ( prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my @cases = ( { label => "dist *not* in", pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$perl Makefile.PL", will_send => 1, }, { label => "dist author in", pretty_id => "JOHNDOE/Bogus-Module-1.23.tar.gz", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$perl Makefile.PL", will_send => 0, }, { label => "dist name in", pretty_id => "JOHNQP/Bogus-SkipModule-1.23.tar.gz", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$perl Makefile.PL", will_send => 0, }, { label => "dist name in - case insensitive", pretty_id => "johnqp/bogus-skipmodule-1.23.tar.gz", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$perl Makefile.PL", will_send => 0, }, ); plan tests => 1 + @cases * (test_fake_config_plan() + test_dispatch_plan()); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); # test send_skipfile for my $case ( @cases ) { local $case->{label} = $case->{label} . " send_skipfile"; $case->{dist} = t::MockCPANDist->new( pretty_id => $case->{pretty_id}, %mock_dist_options, ); test_fake_config( send_report => "yes", send_duplicates => "yes", send_skipfile => "$skipfile", ); test_dispatch( $case, will_send => $case->{will_send}, ); } CPAN-Reporter-1.2010/t/56_test_report_by_harness.t0000644000175000017500000000736512132015716020336 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; require Test::Harness; my $harness_version = Test::Harness->VERSION; my $is_th2xx = $harness_version < 3; my $is_th3xx = $harness_version >= 3; my $is_th305 = $harness_version >= '3.05'; # every distro must have th2xx as a fallback my @test_distros = ( { name => 't-NoOutput', th2xx => { eumm_success => 1, eumm_grade => "unknown", eumm_msg => "No tests were run", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests were run", }, th305 => { eumm_success => 0, eumm_grade => "fail", eumm_msg => "One or more tests failed", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, }, { name => 't-NoOutput-die', th2xx => { eumm_success => 1, eumm_grade => "unknown", eumm_msg => "No tests were run", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests were run", }, th305 => { eumm_success => 0, eumm_grade => "fail", eumm_msg => "One or more tests failed", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, }, { name => 'test.pl-NoOutput-OK', th2xx => { eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests were run", }, th305 => { eumm_success => 1, eumm_grade => "pass", eumm_msg => "'make test' no errors", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, }, { name => 'test.pl-NoOutput-NOK', th2xx => { eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests were run", }, th305 => { eumm_success => 0, eumm_grade => "fail", eumm_msg => "'make test' error detected", mb_success => 0, mb_grade => "fail", mb_msg => "One or more tests failed", }, }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { my $target_version = $is_th305 && exists $case->{th305} ? "th305" : $is_th3xx && exists $case->{th3xx} ? "th3xx" : "th2xx" ; my %target_case = ( name => $case->{name}, %{$case->{$target_version}}, ); test_grade_test( \%target_case, $mock_dist ); } CPAN-Reporter-1.2010/t/67_distfile.t0000644000175000017500000000307412132015716015345 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; use IO::CaptureOutput; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $make = $Config{make}; my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my $case = { label => "t-Pass", name => "t-Pass", dist => $mock_dist, version => 1.23, grade => "pass", phase => "test", command => "$make test", will_send => 1, options => { send_report => "yes", }, }; plan tests => 1 + 1 * (1 + test_fake_config_plan + test_dispatch_plan); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); #--------------------------------------------------------------------------# # no transport advanced option set #--------------------------------------------------------------------------# test_fake_config( %{$case->{options}} ); test_dispatch( $case, will_send => $case->{will_send}, ); is( Test::Reporter::Mocked->distfile(), $mock_dist->{pretty_id}, "CPAN::Reporter sets Test::Reporter->distfile" ); CPAN-Reporter-1.2010/t/60_discard_triggers.t0000644000175000017500000000522412132015716017051 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use IO::CaptureOutput; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my @cases = ( { label => "Build -j2", phase => "make", command => "Build -j2", output => "Output from './Build -j2'\n", exit_value => 1 << 8, result => { grade => "unknown" }, after => { grade => "discard", grade_msg => "-j is not a valid option for Module::Build (upgrade your CPAN.pm)" } }, { label => "Build -j3", phase => "make", command => "Build -j3", output => "Output from './Build -j3'\n", exit_value => 1 << 8, result => { grade => "unknown" }, after => { grade => "discard", grade_msg => "-j is not a valid option for Module::Build (upgrade your CPAN.pm)" } }, { label => "makefile out of date", phase => "make", command => "make", output => "blah blah\nMakefile out-of-date with respect to Makefile.PL\nblah blah\n", exit_value => 1 << 8, result => { grade => "unknown" }, after => { grade => "discard", grade_msg => "Makefile out-of-date", } }, ); #--------------------------------------------------------------------------# # plan #--------------------------------------------------------------------------# plan tests => 2 + test_fake_config_plan() + 2 * @cases; #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); require_ok('CPAN::Reporter::History'); test_fake_config(); for my $c ( @cases ) { # create a fake result to force send_duplicates prompt my $dummy_result = CPAN::Reporter::_init_result( $c->{phase}, $mock_dist, $c->{command}, $c->{output}, $c->{exit_value}, ); $dummy_result->{grade} = $c->{result}{grade}; $dummy_result->{grade_msg} = "test message"; CPAN::Reporter::_downgrade_known_causes( $dummy_result ); is( $dummy_result->{grade}, $c->{after}{grade}, "$c->{label}: grade is '$c->{after}{grade}'" ); is( $dummy_result->{grade_msg}, $c->{after}{grade_msg}, "$c->{label}: grade_msg is correct" ); } CPAN-Reporter-1.2010/t/73_autoflush.t0000644000175000017500000000244312132015716015550 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use IO::CaptureOutput qw/capture/; use File::Spec::Functions qw/catdir catfile rel2abs/; use t::Frontend; use t::MockHomeDir; use Probe::Perl (); # protect CPAN::Reporter from itself local %ENV = %ENV; delete $ENV{PERL5OPT}; my @cases = ( [ 'Makefile.PL' , 1 ], [ 'NotMakefile.PL' , 0 ], [ 'Build.PL' , 1 ], [ 'NotBuild.PL' , 0 ], ); plan tests => 1 + @cases; #--------------------------------------------------------------------------# # fixtures #--------------------------------------------------------------------------# my $perl = Probe::Perl->find_perl_interpreter(); my ($stdout, $stderr, $output, $exit, $line); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok( "CPAN::Reporter" ); for my $c ( @cases ) { my ($name, $expect) = @$c; my $bin = catfile( qw/t bin /, $name ); eval { capture sub { ($output, $exit) = CPAN::Reporter::record_command( "$perl $bin" ); }, \$stdout, \$stderr; }; chomp( $line = $output->[0] ); is( $line, $expect, "$name had \$| = $expect" ) or diag $stdout; } CPAN-Reporter-1.2010/t/Helper.pm0000644000175000017500000006651312132015716014625 0ustar garugarupackage t::Helper; use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use vars qw/@EXPORT/; @EXPORT = qw/ test_grade_make test_grade_make_plan test_grade_PL test_grade_PL_plan test_grade_test test_grade_test_plan test_fake_config test_fake_config_plan test_report test_report_plan test_dispatch test_dispatch_plan /; use Exporter (); our @ISA = 'Exporter'; use Config; use Archive::Tar 1.54 (); use File::Basename qw/basename/; use File::Copy::Recursive 0.35 qw/dircopy/; use File::Path qw/mkpath/; use File::pushd 0.32 qw/pushd tempd/; use File::Spec 3.19 (); use File::Temp 0.16 qw/tempdir/; use IO::CaptureOutput 1.03 qw/capture/; use Probe::Perl (); use Test::More 0.62; use t::MockHomeDir; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $perl = Probe::Perl->find_perl_interpreter(); my $make = $Config{make}; my $temp_stdout = File::Temp->new() or die "Couldn't make temporary file:$!\nIs your temp drive full?"; my $temp_dist_dir = tempdir( 'CR-t-dist-XXXXXX', CLEANUP => 1, TMPDIR => 1); my $dist_archive = File::Spec->rel2abs("t/dist.tgz"); { my $wd = pushd($temp_dist_dir); Archive::Tar->extract_archive($dist_archive, 1) or die "Could not extract test distributions: " . Archive::Tar->error; } my $home_dir = t::MockHomeDir::home_dir(); my $config_dir = File::Spec->catdir( $home_dir, ".cpanreporter" ); my $config_file = File::Spec->catfile( $config_dir, "config.ini" ); my $bogus_email_from = 'johndoe@example.com'; my $bogus_email_to = 'no_one@example.com'; my %tool_constants = ( 'eumm' => { module => 'ExtUtils::MakeMaker', have => eval "require ExtUtils::MakeMaker" || 0, PL => 'Makefile.PL', }, 'mb' => { module => 'Module::Build', have => eval "require Module::Build" || 0, PL => 'Build.PL' }, ); my $max_report_length = 1_000_000; # 1000K # used to capture from fixtures use vars qw/$sent_report @cc_list/; #--------------------------------------------------------------------------# # test config file prep #--------------------------------------------------------------------------# sub test_fake_config_plan() { 4 } sub test_fake_config { local $Test::Builder::Level = $Test::Builder::Level + 1; my %overrides = @_; is( File::HomeDir::my_documents(), t::MockHomeDir::home_dir(), "home directory mocked" ); mkpath $config_dir; ok( -d $config_dir, "config directory created" ); my $metabase_file = File::Spec->catfile( $config_dir, 'metabase_id.json' ); # 2-args open with bare descriptor to work in older perls open METABASE, ">$metabase_file"; close METABASE; ok -r $metabase_file, 'created mock metabase file for testing'; my $tiny = Config::Tiny->new(); $tiny->{_}{email_from} = $bogus_email_from; $tiny->{_}{email_to} = $bogus_email_to; # failsafe $tiny->{_}{send_report} = "yes"; $tiny->{_}{send_duplicates} = "yes"; # tests often repeat same stuff $tiny->{_}{transport} = "Metabase uri https://metabase.cpantesters.org/api/v1/ id_file metabase_id.json"; for my $key ( keys %overrides ) { $tiny->{_}{$key} = $overrides{$key}; } ok( $tiny->write( $config_file ), "created temp config file" ); } #--------------------------------------------------------------------------# # Test grade_PL #--------------------------------------------------------------------------# sub test_grade_PL_iter_plan() { 5 } sub test_grade_PL_plan() { test_grade_PL_iter_plan() * 2 } sub test_grade_PL { my ($case, $dist) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; local $ENV{PERL_MM_USE_DEFAULT} = 1; my $short_name = _short_name( $dist ); for my $tool ( qw/eumm mb/ ) { SKIP: { my ($have_tool,$tool_mod,$tool_PL) = @{$tool_constants{$tool}}{qw/have module PL/}; my $tool_label = $tool eq 'eumm' ? "Makefile.PL" : "Build.PL"; my $tool_cmd = "$perl $tool_label"; skip "$tool_mod not installed or working", test_grade_PL_iter_plan() if ! $have_tool; my $tempd = _ok_clone_dist_dir( $case->{name} ); local $dist->{build_dir} = "$tempd"; $t::Helper::sent_report = undef; $t::Helper::comments = undef; my ($stdout, $stderr, $build_rc, $test_build_rc, $output, $exit_value, $rc); eval { capture sub { ($output, $exit_value) = CPAN::Reporter::record_command($tool_cmd); $rc = CPAN::Reporter::grade_PL( $dist, $tool_cmd, $output, $exit_value ); }, \$stdout, \$stderr; }; if ( $@ ) { diag "DIED WITH:\n$@"; _diag_output( $stdout, $stderr ); skip "died grading PL", test_grade_PL_iter_plan() - 1; } my $is_rc_correct = $case->{"$tool\_success"} ? $rc : ! $rc; ok( $is_rc_correct, "$case->{name}: grade_PL() for $tool_PL returned " . $case->{"$tool\_success"} ); my $case_grade = $case->{"$tool\_grade"}; my $is_grade_correct; # Grade evaluation with special case if discarding my ($found_grade_result, $found_msg) = ( $stdout =~ /^CPAN::Reporter: ([^,]+), ([^\n]+)/ms ); if ( $case_grade eq 'discard' ) { is ($found_grade_result, "test results were not valid", "$case->{name}: '$tool_label' saw test results not valid message" ); like( $stdout, "/Test report will not be sent/", "$case->{name}: discard message correct" ) and $is_grade_correct++; ok( ! defined $t::Helper::sent_report, "$case->{name}: test results discarded" ); } else { my ($found_grade) = ( $found_grade_result =~ /$tool_label result is '([^']+)'/ ); is( $found_grade, $case_grade, "$case->{name}: '$tool_label' grade reported as '$case_grade'" ) or _diag_output( $stdout, $stderr ); my $ctr_regex = "/preparing a CPAN Testers report for \Q$short_name\E/"; if ( $case_grade eq 'pass' ) { unlike( $stdout, $ctr_regex , "$case->{name}: report notification correct" ) and $is_grade_correct++; ok( ! defined $t::Helper::sent_report, "$case->{name}: results not sent" ); } else { like( $stdout, $ctr_regex , "$case->{name}: report notification correct" ) and $is_grade_correct++; if ( -r $config_file ) { ok( defined $t::Helper::sent_report && length $t::Helper::sent_report, "$case->{name}: report was mock sent" ); } else { ok( ! defined $t::Helper::sent_report, "$case->{name}: results not sent" ); } } } _diag_output( $stdout, $stderr ) unless ( $is_rc_correct && $is_grade_correct ); } # SKIP } # for } #--------------------------------------------------------------------------# # Test grade_make #--------------------------------------------------------------------------# sub test_grade_make_iter_plan() { 6 } sub test_grade_make_plan() { test_grade_make_iter_plan() * 2 } sub test_grade_make { my ($case, $dist) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; local $ENV{PERL_MM_USE_DEFAULT} = 1; my $short_name = _short_name( $dist ); for my $tool ( qw/eumm mb/ ) { SKIP: { my ($have_tool,$tool_mod,$tool_PL) = @{$tool_constants{$tool}}{qw/have module PL/}; my $tool_cmd = $tool eq 'eumm' ? $Config{make} : "$perl Build"; my $tool_label = $tool eq 'eumm' ? $Config{make} : "Build"; skip "$tool_mod not installed or working", test_grade_make_iter_plan() if ! $have_tool; # Set up temporary directory for the case my $tempd = _ok_clone_dist_dir( $case->{name} ); $t::Helper::sent_report = undef; $t::Helper::comments = undef; my ($stdout, $stderr, $build_err, $test_build_rc, $output, $exit_value, $rc); capture sub { $build_err = system("$perl $tool_PL"); }, \$stdout, \$stderr; ok( ! $build_err, "$case->{name}: $tool_PL successful" ) or do { _diag_output( $stdout, $stderr ); skip "$tool_PL failed", test_grade_make_iter_plan() - 1; }; eval { capture sub { ($output, $exit_value) = CPAN::Reporter::record_command($tool_cmd); $rc = CPAN::Reporter::grade_make( $dist, $tool_cmd, $output, $exit_value ); }, \$stdout, \$stderr; }; if ( $@ ) { diag "DIED WITH:\n$@"; _diag_output( $stdout, $stderr ); skip "died grading make", test_grade_make_iter_plan() - 1; } my $is_rc_correct = $case->{"$tool\_success"} ? $rc : ! $rc; ok( $is_rc_correct, "$case->{name}: grade_make() for $tool_label returned " . $case->{"$tool\_success"} ); my $case_grade = $case->{"$tool\_grade"}; my $is_grade_correct; # Grade evaluation with special case if discarding my ($found_grade_result, $found_msg) = ( $stdout =~ /^CPAN::Reporter: ([^,]+), ([^\n]+)/ms ); if ( $case_grade eq 'discard' ) { is ($found_grade_result, "test results were not valid", "$case->{name}: '$tool_label' prerequisites not satisifed" ); like( $stdout, "/Test report will not be sent/", "$case->{name}: discard message correct" ) and $is_grade_correct++; ok( ! defined $t::Helper::sent_report, "$case->{name}: test results discarded" ); } else { my ($found_grade) = ( $found_grade_result =~ /\Q$tool_label\E result is '([^']+)'/ ); is( $found_grade, $case_grade, "$case->{name}: '$tool_label' grade reported as '$case_grade'" ) or _diag_output( $stdout, $stderr ); my $ctr_regex = "/preparing a CPAN Testers report for \Q$short_name\E/"; if ( $case_grade eq 'pass' ) { unlike( $stdout, $ctr_regex , "$case->{name}: report notification correct" ) and $is_grade_correct++; ok( ! defined $t::Helper::sent_report, "$case->{name}: results not sent" ); } else { like( $stdout, $ctr_regex , "$case->{name}: report notification correct" ) and $is_grade_correct++; if ( -r $config_file ) { ok( defined $t::Helper::sent_report && length $t::Helper::sent_report, "$case->{name}: report was mock sent" ); } else { ok( ! defined $t::Helper::sent_report, "$case->{name}: results not sent" ); } } } _diag_output( $stdout, $stderr ) unless ( $is_rc_correct && $is_grade_correct ); } #SKIP } #for } #--------------------------------------------------------------------------# # Test grade_test #--------------------------------------------------------------------------# sub test_grade_test_iter_plan() { 7 } sub test_grade_test_plan() { 2 * test_grade_test_iter_plan() } sub test_grade_test { my ($case, $dist) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; local $ENV{PERL_MM_USE_DEFAULT} = 1; my $short_name = _short_name( $dist ); for my $tool ( qw/eumm mb/ ) { SKIP: { my ($have_tool,$tool_mod,$tool_PL) = @{$tool_constants{$tool}}{qw/have module PL/}; my $tool_cmd = $tool eq 'eumm' ? "$make test" : "$perl Build test" ; my $tool_label = $tool eq 'eumm'? "make test" : "perl Build test" ; skip "$tool_mod not installed or working", test_grade_test_iter_plan() if ! $have_tool; my $tempd = _ok_clone_dist_dir( $case->{name} ); $t::Helper::sent_report = undef; $t::Helper::comments = undef; my ($stdout, $stderr, $build_err, $test_build_rc); capture sub { $build_err = system("$perl $tool_PL"); }, \$stdout, \$stderr; ok( ! $build_err, "$case->{name}: $tool_PL successful" ) or do { _diag_output( $stdout, $stderr ); skip "$tool_PL failed", test_grade_test_iter_plan() - 1; }; eval { capture sub { $test_build_rc = CPAN::Reporter::test( $dist, $tool_cmd ) }, \$stdout, \$stderr; }; if ( $@ ) { diag "DIED WITH:\n$@"; _diag_output( $stdout, $stderr ); skip "test() died", test_grade_test_iter_plan() - 1; } my $is_rc_correct = $case->{"$tool\_success"} ? $test_build_rc : ! $test_build_rc; ok( $is_rc_correct, "$case->{name}: '$tool_label' returned " . $case->{"$tool\_success"} ); # Grade evaluation with special case if discarding my ($found_grade_result, $found_msg) = ( $stdout =~ /^CPAN::Reporter: (Test result[^,]+), ([^\n]+)[.:]$/ims ); if ( $case->{"$tool\_grade"} eq 'discard' ) { is ($found_grade_result, "test results were not valid", "$case->{name}: '$tool_label' prerequisites not satisifed" ); like( $stdout, "/Test report will not be sent/", "$case->{name}: discard message correct" ); ok( ! defined $t::Helper::sent_report, "$case->{name}: test results discarded" ); } else { my $case_grade = $case->{"$tool\_grade"}; my ($found_grade) = ( $found_grade_result =~ /Test result is '([^']+)'/ ); is( $found_grade, $case_grade, "$case->{name}: '$tool_label' grade reported as '$case_grade'" ) or _diag_output( $stdout, $stderr ); like( $stdout, "/preparing a CPAN Testers report for \Q$short_name\E/", "$case->{name}: report notification correct" ); if ( -r $config_file ) { ok( defined $t::Helper::sent_report && length $t::Helper::sent_report, "$case->{name}: test report was mock sent" ); } else { ok( ! defined $t::Helper::sent_report, "$case->{name}: test results not sent" ); } } # Grade explanation message is( $found_msg, $case->{"$tool\_msg"} ? $case->{"$tool\_msg"} : q{}, "$case->{name}: '$tool_label' grade explanation correct" ); } #SKIP } #for } #--------------------------------------------------------------------------# # report tests #--------------------------------------------------------------------------# my %report_para = ( 'pass' => <<'HERE', Thank you for uploading your work to CPAN. Congratulations! All tests were successful. HERE 'fail' => <<'HERE', Thank you for uploading your work to CPAN. However, there was a problem testing your distribution. If you think this report is invalid, please consult the CPAN Testers Wiki for suggestions on how to avoid getting FAIL reports for missing library or binary dependencies, unsupported operating systems, and so on: http://wiki.cpantesters.org/wiki/CPANAuthorNotes HERE 'unknown' => << 'HERE', Thank you for uploading your work to CPAN. However, attempting to test your distribution gave an inconclusive result. This could be because your distribution had an error during the make/build stage, did not define tests, tests could not be found, because your tests were interrupted before they finished, or because the results of the tests could not be parsed. You may wish to consult the CPAN Testers Wiki: http://wiki.cpantesters.org/wiki/CPANAuthorNotes HERE 'na' => << 'HERE', Thank you for uploading your work to CPAN. While attempting to build or test this distribution, the distribution signaled that support is not available either for this operating system or this version of Perl. Nevertheless, any diagnostic output produced is provided below for reference. If this is not what you expect, you may wish to consult the CPAN Testers Wiki: http://wiki.cpantesters.org/wiki/CPANAuthorNotes HERE ); sub test_report_plan() { 13 }; sub test_report { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($case) = @_; my $label = "$case->{label}:"; my $expected_grade = $case->{expected_grade}; my $prereq = CPAN::Reporter::_prereq_report( $case->{dist} ); my $msg_re = $report_para{ $expected_grade }; my $default_comment = $ENV{AUTOMATED_TESTING} ? "this report is from an automated smoke testing program\nand was not reviewed by a human for accuracy" : "none provided" ; my $tempd = _ok_clone_dist_dir( $case->{name} ); my ($stdout, $stderr, $err, $test_output) = _run_report( $case ); is( $err, q{}, "$label report ran without error" ); ok( defined $msg_re && length $msg_re, "$label found '$expected_grade' grade paragraph" ); # set PERL_MM_USE_DEFAULT to mirror _run_report local $ENV{PERL_MM_USE_DEFAULT} = 1; my $env_vars = CPAN::Reporter::_env_report(); my $special_vars = CPAN::Reporter::_special_vars_report(); my $toolchain_versions = CPAN::Reporter::_toolchain_report(); like( $t::Helper::sent_report, '/' . quotemeta($msg_re) . '/ms', "$label correct intro paragraph" ); like( $t::Helper::sent_report, '/' . quotemeta($default_comment) . '/ms', "$label correct default comment" ); like( $t::Helper::sent_report, '/' . quotemeta($prereq) . '/ms', "$label found prereq report" ); like( $t::Helper::sent_report, '/' . quotemeta($env_vars) . '/ms', "$label found environment variables" ); like( $t::Helper::sent_report, '/' . quotemeta($special_vars) . '/ms', "$label found special variables" ); like( $t::Helper::sent_report, '/' . quotemeta($toolchain_versions) . '/ms', "$label found toolchain versions found" ); my $joined_output = join("", @$test_output); # extract just the test output my $found_test_output = q{}; if ( $t::Helper::sent_report =~ m/ ^Output\ from\ '[^\']+':\n # lead-in to test output ^\n # blank line ^(.+) \n # test output ending in newline ^------------------------------ \n # separator ^PREREQUISITES \n # next section /xms ) { $found_test_output = $1; } my $orig_found_length = length $found_test_output; ok( $orig_found_length, "$label located test output in report" ); # if output appears longer than max, the excess should only be the # error message, so look for it, strip it and check it my $length_error = q{}; my $max_in_k = int($max_report_length / 1000) . "K"; if ( $found_test_output =~ m/ ^(.+)\n # test output ending in a newline ^\n # blank line ^(\[[^\n]+\]) \n # stuff in brackets ^\n # blank line \z /xms ) { $found_test_output = $1; $length_error = $2; } if ( length $joined_output > $max_report_length ) { is( $length_error, "[Output truncated after $max_in_k]", "$label truncated length error message correct" ) } else { pass( "$label no truncation message seen" ); } # after extracting error, if any, the output should now be # less than the max length my $found_length = length $found_test_output; ok( $found_length <= $max_report_length, "$label test_output less than or equal to maximum length" ) or diag "length $found_length > $max_report_length"; # confirm that we indeed got the test output we expected # (whether all or just a truncated portion) if ( length $joined_output > $max_report_length ) { $joined_output = substr( $joined_output, 0, $max_report_length ); } like( $t::Helper::sent_report, '/' . quotemeta($joined_output) . '/ms', "$label found output matches expected output" ); return ($stdout, $stderr, $err, $test_output); }; #--------------------------------------------------------------------------# # test_dispatch # # case requires # label -- prefix for text output # dist -- mock dist object # name -- name for t/dist/name to copy # command -- command to execute within copy of dist dir # phase -- phase of PL/make/test to pass command results to #--------------------------------------------------------------------------# sub test_dispatch_plan { 4 }; sub test_dispatch { local $Test::Builder::Level = $Test::Builder::Level + 1; my $case = shift; my %opt = @_; my $tempd = _ok_clone_dist_dir( $case->{name} ); local $case->{dist}{build_dir} = "$tempd"; my ($stdout, $stderr, $err) = _run_report( $case ); is( $err, q{}, "generate report for $case->{label}" ); if ( $opt{will_send} ) { ok( defined $t::Helper::sent_report && length $t::Helper::sent_report, "report was sent for $case->{label}" ); like( $stdout, "/sending test report with/", "saw report sent message for $case->{label}" ); } else { ok( ! defined $t::Helper::sent_report, "report not sent for $case->{label}" ); like( $stdout, "/report will not be sent/", "saw report not sent message for $case->{label}" ); } return ($stdout, $stderr, $err); } #--------------------------------------------------------------------------# # _diag_output #--------------------------------------------------------------------------# sub _diag_output { my ( $stdout, $stderr ) = @_; diag "STDOUT:\n$stdout\n\nSTDERR:\n$stderr\n"; } #--------------------------------------------------------------------------# # _ok_clone_dist_dir #--------------------------------------------------------------------------# sub _ok_clone_dist_dir { local $Test::Builder::Level = $Test::Builder::Level + 1; my $dist_name = shift; my $dist_dir = File::Spec->catdir( $temp_dist_dir, "dist", $dist_name ); my $work_dir = tempd() or die "Couldn't create temporary distribution dir: $!\n"; # workaround badly broken F::C::R 0.34 on Windows if ( File::Copy::Recursive->VERSION eq '0.34' && $^O eq 'MSWin32' ) { ok( 0 == system("xcopy /q /e $dist_dir $work_dir"), "Copying $dist_name to temp directory (XCOPY)" ) or diag $!; } else { ok( defined( dircopy($dist_dir, "$work_dir") ), "Copying $dist_name to temp directory $work_dir" ) or diag $!; } return $work_dir; } #--------------------------------------------------------------------------# # _run_report #--------------------------------------------------------------------------# sub _run_report { my $case = shift; my $phase = $case->{phase}; # automate CPAN::Reporter prompting local $ENV{PERL_MM_USE_DEFAULT} = 1; my ($stdout, $stderr, $output, $exit_value); $t::Helper::sent_report = undef; $t::Helper::comments = undef; eval { capture sub { # run any preliminaries to the command we want to record if ( $phase eq 'make' || $phase eq 'test' ) { system("$perl Makefile.PL"); } if ( $phase eq 'test' ) { system("$make"); } ($output, $exit_value) = CPAN::Reporter::record_command( $case->{command} ); no strict 'refs'; &{"CPAN::Reporter::grade_$phase"}( $case->{dist}, $case->{command}, $output, $exit_value, ); } => \$stdout, \$stderr; }; if ( $@ ) { diag "DIED WITH:\n$@"; _diag_output( $stdout, $stderr ); } return ($stdout, $stderr, $@, $output); } #--------------------------------------------------------------------------# # _short_name #--------------------------------------------------------------------------# sub _short_name { my $dist = shift; my $short_name = basename($dist->pretty_id); $short_name =~ s/(\.tar\.gz|\.tgz|\.zip)$//i; return $short_name; } #--------------------------------------------------------------------------# # Mocking #--------------------------------------------------------------------------# BEGIN { $INC{"Test/Reporter.pm"} = 1; # fake load } package Test::Reporter; use vars qw/$AUTOLOAD $VERSION/; $VERSION = 999; # more than 1.54 (e.g. distfile exists) sub new { return bless {}, 'Test::Reporter::Mocked' } package Test::Reporter::Mocked; use Config; use vars qw/$AUTOLOAD/; sub comments { shift; $t::Helper::comments = shift } sub send { shift; $t::Helper::sent_report = $t::Helper::comments; return 1 } sub subject { my $self = shift; return uc($self->grade) . ' ' . $self->distribution . " $Config{archname} $Config{osvers}"; } my %mocked_data; my @valid_transport = qw/Metabase Mail::Send/; sub transport { my ($self) = shift; if (@_) { my $t = shift; die __PACKAGE__ . ":transport: '$t' is invalid\n" unless grep { $t eq $_ } @valid_transport; $mocked_data{transport} = $t; } return $mocked_data{transport}; } sub AUTOLOAD { my $self = shift; if ( @_ ) { $mocked_data{ $AUTOLOAD } = shift; } return $mocked_data{ $AUTOLOAD }; } 1; CPAN-Reporter-1.2010/t/00-report-prereqs.t0000644000175000017500000000356712132015716016444 0ustar garugaru#!perl use strict; use warnings; use Test::More tests => 1; use ExtUtils::MakeMaker; use File::Spec::Functions; use List::Util qw/max/; my @modules = qw( Archive::Tar CPAN CPAN::Version Capture::Tiny Carp Config Config::Tiny Devel::Autoflush Exporter ExtUtils::MakeMaker Fcntl File::Basename File::Copy::Recursive File::Find File::Glob File::HomeDir File::Path File::Spec File::Spec::Functions File::Temp File::pushd IO::CaptureOutput IO::File IPC::Cmd List::Util Parse::CPAN::Meta Probe::Perl Test::Harness Test::More Test::Reporter constant perl strict vars warnings ); # replace modules with dynamic results from MYMETA.json if we can # (hide CPAN::Meta from prereq scanner) my $cpan_meta = "CPAN::Meta"; if ( -f "MYMETA.json" && eval "require $cpan_meta" ) { ## no critic if ( my $meta = eval { CPAN::Meta->load_file("MYMETA.json") } ) { my $prereqs = $meta->prereqs; delete $prereqs->{develop}; my %uniq = map {$_ => 1} map { keys %$_ } map { values %$_ } values %$prereqs; $uniq{$_} = 1 for @modules; # don't lose any static ones @modules = sort keys %uniq; } } my @reports = [qw/Version Module/]; for my $mod ( @modules ) { next if $mod eq 'perl'; my $file = $mod; $file =~ s{::}{/}g; $file .= ".pm"; my ($prefix) = grep { -e catfile($_, $file) } @INC; if ( $prefix ) { my $ver = MM->parse_version( catfile($prefix, $file) ); $ver = "undef" unless defined $ver; # Newer MM should do this anyway push @reports, [$ver, $mod]; } else { push @reports, ["missing", $mod]; } } if ( @reports ) { my $vl = max map { length $_->[0] } @reports; my $ml = max map { length $_->[1] } @reports; splice @reports, 1, 0, ["-" x $vl, "-" x $ml]; diag "Prerequisite Report:\n", map {sprintf(" %*s %*s\n",$vl,$_->[0],-$ml,$_->[1])} @reports; } pass; # vim: ts=2 sts=2 sw=2 et: CPAN-Reporter-1.2010/t/15_option_validation.t0000644000175000017500000000352212132015716017253 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::Frontend; use t::Helper; use IO::CaptureOutput qw/capture/; use File::Spec; my @cases = ( { label => "skipfile (exists)", option => "cc_skipfile", input => File::Spec->rel2abs("Changes"), output => File::Spec->rel2abs("Changes"), }, { label => "skipfile (missing)", option => "cc_skipfile", input => "afdadfasdfasdf", output => undef, }, { label => "command_timeout (positive)", option => "command_timeout", input => 10, output => 10, }, { label => "command_timeout (negative)", option => "command_timeout", input => -10, output => undef, }, { label => "command_timeout (zero)", option => "command_timeout", input => 0, output => 0, }, { label => "command_timeout (empty)", option => "command_timeout", input => q{}, output => undef, }, { label => "command_timeout (undef)", option => "command_timeout", input => undef, output => undef, }, { label => "command_timeout (alpha)", option => "command_timeout", input => "abcd", output => undef, }, ); plan tests => 1 + 1 * @cases; #--------------------------------------------------------------------------# # Begin tests #--------------------------------------------------------------------------# require_ok( "CPAN::Reporter::Config" ); for my $c ( @cases ) { my ($got); $got = CPAN::Reporter::Config::_validate( $c->{option}, $c->{input} ); is( $got, $c->{output}, $c->{label} ); } CPAN-Reporter-1.2010/t/55_test_report_discard.t0000644000175000017500000000544612132015716017607 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Frontend; use t::Helper; my @test_distros = ( { name => 't-PrereqMiss', prereq => { 'Bogus::Module::Doesnt::Exist' => 0 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite missing", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite missing", }, { name => 't-NoTestsButPrereqMiss', prereq => { 'Bogus::Module::Doesnt::Exist' => 0 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite missing", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite missing", }, { name => 'test.pl-PrereqMiss', prereq => { 'Bogus::Module::Doesnt::Exist' => 0 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite missing", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite missing", }, { name => 't-PrereqFail', prereq => { 'File::Spec' => 99999.9 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite version too low", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite version too low", }, { name => 'test.pl-PrereqFail', prereq => { 'File::Spec' => 99999.9 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite version too low", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite version too low", }, { name => 't-Harness-Fail', prereq => {}, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Test harness failure", mb_success => 0, mb_grade => "discard", mb_msg => "Test harness failure", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => $case->{prereq}, author_id => "JOHNQP", author_fullname => "John Q. Public", ); test_grade_test( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/11_env_config.t0000644000175000017500000000606412132015716015646 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; # protect CPAN::Reporter from itself local %ENV = %ENV; delete $ENV{PERL5OPT}; # Entries bracketed with "/" are taken to be a regex; otherwise literal my @env_vars= qw( /PERL/ /LC_/ LANG LANGUAGE PATH SHELL COMSPEC TERM AUTOMATED_TESTING AUTHOR_TESTING INCLUDE LIB LD_LIBRARY_PATH PROCESSOR_IDENTIFIER NUMBER_OF_PROCESSORS ); my @env_vars_found; for my $var ( @env_vars ) { if ( $var =~ m{^/(.+)/$} ) { push @env_vars_found, grep { /$1/ } keys %ENV; } else { push @env_vars_found, $var if exists $ENV{$var}; } } my %special_vars = ( '$^X' => $^X, '$UID/$EUID' => "$< / $>", '$GID' => "$(", '$EGID' => "$)", ); if ( $^O eq 'MSWin32' && eval "require Win32" ) { my @getosversion = Win32::GetOSVersion(); my $getosversion = join(", ", @getosversion); $special_vars{"Win32::GetOSName"} = Win32::GetOSName(); $special_vars{"Win32::GetOSVersion"} = $getosversion; $special_vars{"Win32::IsAdminUser"} = Win32::IsAdminUser(); } my @toolchain_modules = qw( CPAN Module::Build ExtUtils::MakeMaker version ); # paths # * cwd # * compiler # * $Config{make} # special handling # * umask # * locale -- how do I determine this? # * compiler tools versions plan tests => 1 + test_fake_config_plan() + 2 * @env_vars_found + 2* keys %special_vars; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my ($got, $expect); #--------------------------------------------------------------------------# # Begin tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); #--------------------------------------------------------------------------# # ENV testing #--------------------------------------------------------------------------# $got = CPAN::Reporter::_env_report(); { for my $var ( sort @env_vars_found ) { my ($name, $value) = ( $got =~ m{^ +(\Q$var\E) = ([^\n]*?)$}ms ); is( $name, $var, "found \$ENV{$var}" ); is( defined $value ? $value : '', defined $ENV{$var} ? $ENV{$var} : '', "value of \$ENV{$var} is correct" ); } } #--------------------------------------------------------------------------# # Special Vars #--------------------------------------------------------------------------# $got = CPAN::Reporter::_special_vars_report(); for my $var ( sort keys %special_vars ) { my ($name, $value) = ( $got =~ m{ +(\Q$var\E) += +([^\n]*?)$}ms ); is( $name, $var, "found special variable $var" ); is( defined $value ? $value : '', defined $special_vars{$var} ? $special_vars{$var} : '', "value of $var is correct" ); } CPAN-Reporter-1.2010/t/66_have_tested.t0000644000175000017500000001227012132015716016032 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use Test::More; use Config; use File::Copy::Recursive qw/fcopy/; use File::Path qw/mkpath/; use File::Spec::Functions qw/catdir catfile rel2abs/; use File::Temp qw/tempdir/; use t::Frontend; use t::MockHomeDir; #plan 'no_plan'; plan tests => 21; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $config_dir = catdir( t::MockHomeDir::home_dir, ".cpanreporter" ); my $config_file = catfile( $config_dir, "config.ini" ); my $history_file = catfile( $config_dir, "reports-sent.db" ); my $sample_history_file = catfile(qw/t history reports-sent-longer.db/); my @fake_results = ( { dist_name => 'Baz-Bam-3.14', phase => 'test', grade => 'pass' }, { dist_name => 'Foo-Bar-1.23', phase => 'PL', grade => 'fail' }, { dist_name => 'Foo-Bar-1.23', phase => 'test', grade => 'fail' }, { dist_name => 'Foo-Bar-1.23', phase => 'test', grade => 'pass' }, { dist_name => 'Wibble-42', phase => 'test', grade => 'pass' }, { dist_name => 'Wobble-23', phase => 'PL', grade => 'na' }, { dist_name => 'Inline-0.44', phase => 'test', grade => 'pass' }, { dist_name => 'Crappy-0.01', phase => 'PL', grade => 'discard' }, ); #--------------------------------------------------------------------------## # begin testing #--------------------------------------------------------------------------# my @aoh; mkpath( $config_dir ); ok( -d $config_dir, "temporary config dir created" ); # If old history exists, convert it fcopy( $sample_history_file, $history_file); ok( -f $history_file, "copied sample old history file to config directory"); # make it writeable chmod 0644, $history_file; ok( -w $history_file, "history file is writeable" ); # load CPAN::Reporter::History and import have_tested for convenience require_ok( 'CPAN::Reporter::History' ); CPAN::Reporter::History->import( 'have_tested' ); # put in some data for current perl/arch/osname CPAN::Reporter::History::_record_history($_) for @fake_results; # one parameter should die eval { have_tested( 'Wibble-42' ) }; ok ( $@, "have_tested() dies with odd number of arguments" ); # unknown parameter shoudl die eval { have_tested( distname => 'Wibble-42' ) }; ok ( $@, "have_tested() dies with unknown parameter" ); # have_tested without any parameters should return everything on this platform @aoh = have_tested(); is( scalar @aoh, scalar @fake_results, "have_tested() with no args gives everything on this platform" ); # have_tested a dist that was only tested once - return AoH with only one hash @aoh = have_tested( dist => 'Wibble-42'); is( scalar @aoh, 1, "asking for a unique dist" ); is( ref $aoh[0], 'HASH', "returned an AoH" ); is_deeply( $aoh[0], { phase => 'test', grade => 'PASS', dist => 'Wibble-42', perl => CPAN::Reporter::History::_format_perl_version(), archname => $Config{archname}, osvers => $Config{osvers}, }, "hash fields as expected" ); # just dist returns all reports for that dist on current platform @aoh = have_tested( dist => 'Foo-Bar-1.23' ); is( scalar @aoh, 3, "asking for multiple dist reports (only on this platform)" ); # just dist doesn't return reports from other platforms @aoh = have_tested( dist => 'ExtUtils-ParseXS-2.18' ); is( scalar @aoh, 0, "asking for multiple dist reports (with none on this platform)" ); # just phase returns all reports for that dist on current platform @aoh = have_tested( phase => 'test' ); is( scalar @aoh, 5, "asking for all test phase reports (defaults to this platform)" ); # just grade returns all reports of that grade on current platform @aoh = have_tested( grade => 'na' ); is( scalar @aoh, 1, "asking for all na grade reports (defaults to this platform)" ); # just grade returns all reports of that grade on current platform @aoh = have_tested( grade => 'NA' ); is( scalar @aoh, 1, "asking for all NA grade reports (defaults to this platform)" ); # just grade returns all reports of that grade on current platform @aoh = have_tested( grade => 'DISCARD' ); is( scalar @aoh, 1, "asking for all DISCARD grade reports (defaults to this platform)" ); # restrict to just a particular dist and phase @aoh = have_tested( dist => 'Foo-Bar-1.23', phase => 'test' ); is( scalar @aoh, 2, "asking for dist in test phase (defaults to this platform)" ); # dist reports on any platform @aoh = have_tested( dist => 'Inline-0.44', perl => q{}, archname => q{}, osvers => q{} ); is( scalar @aoh, 2, "asking for dist across any perl/archname/osvers" ); # restrict to a platform @aoh = have_tested( archname => 'not-a-real-archname', perl => q{}, osvers => q{} ); is( scalar @aoh, 12, "asking for all results from an archname" ); # restrict to a perl @aoh = have_tested( perl => '9.10.0', archname => q{}, osvers => q{} ); is( scalar @aoh, 9, "asking for all results from a perl version" ); # restrict to an osver @aoh = have_tested( perl => q{}, archname => q{}, osvers => q{another-fake-version} ); is( scalar @aoh, 3, "asking for all results from an OS version" ); CPAN-Reporter-1.2010/t/perl5lib/0000775000175000017500000000000012132015716014555 5ustar garugaruCPAN-Reporter-1.2010/t/perl5lib/Bogus/0000775000175000017500000000000012132015716015634 5ustar garugaruCPAN-Reporter-1.2010/t/perl5lib/Bogus/GT.pm0000644000175000017500000000006312132015716016501 0ustar garugarupackage Bogus::GT; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/Broken.pm0000644000175000017500000000012412132015716017405 0ustar garugarupackage Bogus::Broken; $VERSION = 3.14; use strict; use FuddleDuddleCantFindMe; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/LT.pm0000644000175000017500000000006312132015716016506 0ustar garugarupackage Bogus::LT; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/GTE.pm0000644000175000017500000000006412132015716016607 0ustar garugarupackage Bogus::GTE; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/LTE.pm0000644000175000017500000000006412132015716016614 0ustar garugarupackage Bogus::LTE; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/NoVersion.pm0000644000175000017500000000005112132015716020106 0ustar garugarupackage Bogus::NoVersion; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/TooOld.pm0000644000175000017500000000006712132015716017373 0ustar garugarupackage Bogus::TooOld; $VERSION = 0.01; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/Complex.pm0000644000175000017500000000007012132015716017574 0ustar garugarupackage Bogus::Complex; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/Shadow.pm0000644000175000017500000000006712132015716017420 0ustar garugarupackage Bogus::Shadow; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/Found.pm0000644000175000017500000000006612132015716017245 0ustar garugarupackage Bogus::Found; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/perl5lib/Bogus/Conflict.pm0000644000175000017500000000007112132015716017727 0ustar garugarupackage Bogus::Conflict; $VERSION = 3.14; use strict; 1; CPAN-Reporter-1.2010/t/Frontend.pm0000644000175000017500000000122512132015716015152 0ustar garugarupackage t::Frontend; use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use ExtUtils::MakeMaker (); BEGIN { $INC{"CPAN.pm"} = 1; #fake load $INC{"Test/Reporter/Transport/Metabase.pm"} = 1; #fake load $CPAN::VERSION = 999; $Test::Reporter::Transport::Metabase::VERSION = 999; $CPAN::Reporter::VERSION ||= 999; $CPAN::Reporter::History::VERSION ||= 999; } package CPAN::Shell; sub myprint { shift; print @_; } sub mywarn { shift; print @_; } sub colorable_makemaker_prompt { goto \&ExtUtils::MakeMaker::prompt; } package CPAN; $CPAN::Frontend = $CPAN::Frontend = "CPAN::Shell"; 1; CPAN-Reporter-1.2010/t/00-compile.t0000644000175000017500000000310012132015716015061 0ustar garugaru#!perl use strict; use warnings; use Test::More; use File::Find; use File::Temp qw{ tempdir }; my @modules; find( sub { return if $File::Find::name !~ /\.pm\z/; my $found = $File::Find::name; $found =~ s{^lib/}{}; $found =~ s{[/\\]}{::}g; $found =~ s/\.pm$//; # nothing to skip push @modules, $found; }, 'lib', ); sub _find_scripts { my $dir = shift @_; my @found_scripts = (); find( sub { return unless -f; my $found = $File::Find::name; # nothing to skip open my $FH, '<', $_ or do { note( "Unable to open $found in ( $! ), skipping" ); return; }; my $shebang = <$FH>; return unless $shebang =~ /^#!.*?\bperl\b\s*$/; push @found_scripts, $found; }, $dir, ); return @found_scripts; } my @scripts; do { push @scripts, _find_scripts($_) if -d $_ } for qw{ bin script scripts }; my $plan = scalar(@modules) + scalar(@scripts); $plan ? (plan tests => $plan) : (plan skip_all => "no tests to run"); { # fake home for cpan-testers local $ENV{HOME} = tempdir( CLEANUP => 1 ); like( qx{ $^X -Ilib -e "require $_; print '$_ ok'" }, qr/^\s*$_ ok/s, "$_ loaded ok" ) for sort @modules; SKIP: { eval "use Test::Script 1.05; 1;"; skip "Test::Script needed to test script compilation", scalar(@scripts) if $@; foreach my $file ( @scripts ) { my $script = $file; $script =~ s!.*/!!; script_compiles( $file, "$script script compiles" ); } } } CPAN-Reporter-1.2010/t/52_test_report_unknown.t0000644000175000017500000000274612132015716017672 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; my @test_distros = ( # unknown { name => 'NoTestDir', eumm_success => 1, eumm_grade => "unknown", eumm_msg => "No tests provided", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests provided", }, { name => 'NoTestFiles', eumm_success => 1, eumm_grade => "unknown", eumm_msg => "No tests were run", mb_success => 1, mb_grade => "unknown", mb_msg => "No tests provided", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_test_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { test_grade_test( $case, $mock_dist ); } CPAN-Reporter-1.2010/t/02_config_env_vars.t0000644000175000017500000000547412132015716016705 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use Test::More; use Config::Tiny; use IO::CaptureOutput qw/capture/; use File::Basename qw/basename/; use File::Spec; use File::Temp qw/tempdir/; use t::Frontend; use t::MockHomeDir; plan tests => 10; #plan 'no_plan'; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# # File::HomeDir will be mocked to return these my $default_home_dir = t::MockHomeDir::home_dir; my $default_config_dir = File::Spec->catdir( $default_home_dir, ".cpanreporter" ); my $default_config_file = File::Spec->catfile( $default_config_dir, "config.ini" ); # These will be tested via ENV vars my $alt_home = tempdir( "CPAN-Reporter-testhome-XXXXXXXX", TMPDIR => 1, CLEANUP => 1 ) or die "Couldn't create a temporary config directory: $!\nIs your temp drive full?"; my $alt_home_dir = File::Spec->rel2abs( $alt_home ); my $alt_config_dir = File::Spec->catdir( $alt_home_dir, ".cpanreporter" ); my $alt_config_file = File::Spec->catfile( $alt_config_dir, "config.ini" ); # Secondary config files to check setting config file but config dir my $default_dir_alt_file = File::Spec->catfile( $default_config_dir, "altconfig.ini" ); my $alt_dir_alt_file = File::Spec->catfile( $alt_config_dir, "altconfig.ini" ); #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); require_ok('CPAN::Reporter::Config'); is( CPAN::Reporter::Config::_get_config_dir(), $default_config_dir, "default config dir path" ); is( CPAN::Reporter::Config::_get_config_file(), $default_config_file, "default config file path" ); # override config file { local $ENV{PERL_CPAN_REPORTER_CONFIG} = $default_dir_alt_file; is( CPAN::Reporter::Config::_get_config_dir(), $default_config_dir, "PERL_CPAN_REPORTER_CONFIG: default config dir path" ); is( CPAN::Reporter::Config::_get_config_file(), $default_dir_alt_file, "PERL_CPAN_REPORTER_CONFIG: alt config file path" ); } # override config dir { local $ENV{PERL_CPAN_REPORTER_DIR} = $alt_config_dir; is( CPAN::Reporter::Config::_get_config_dir(), $alt_config_dir, "PERL_CPAN_REPORTER_DIR: default config dir path" ); is( CPAN::Reporter::Config::_get_config_file(), $alt_config_file, "PERL_CPAN_REPORTER_DIR: alt config file path" ); } # override config dir and config file { local $ENV{PERL_CPAN_REPORTER_DIR} = $alt_config_dir; local $ENV{PERL_CPAN_REPORTER_CONFIG} = $alt_dir_alt_file; is( CPAN::Reporter::Config::_get_config_dir(), $alt_config_dir, "DIR + CONFIG: alt config dir path" ); is( CPAN::Reporter::Config::_get_config_file(), $alt_dir_alt_file, "DIR + CONFIG: alt config file path" ); } CPAN-Reporter-1.2010/t/57_hang_interrupt.t0000644000175000017500000000520012132015716016563 0ustar garugaruuse strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Config; use Probe::Perl; use File::Temp; #--------------------------------------------------------------------------# # Skip on Win32 except for release testing #--------------------------------------------------------------------------# if ( $^O eq "MSWin32" ) { plan skip_all => "\$ENV{RELEASE_TESTING} required for Win32 timeout testing", unless $ENV{RELEASE_TESTING}; eval "use Win32::Job ()"; plan skip_all => "Can't interrupt hung processes without Win32::Job" if $@; } #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $make = $Config{make}; my $perl = Probe::Perl->find_perl_interpreter(); my %mock_dist_options = ( prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my @cases = ( { label => "t-Pass", pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", name => "t-Pass", version => 1.23, grade => "pass", phase => "test", command => "$make test", will_send => 1, }, { label => "t-Fail", pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$make test", will_send => 1, }, { label => "PL-Hang", pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", name => "PL-Hang", version => 1.23, grade => "discard", phase => "PL", command => "$perl Makefile.PL", will_send => 0, }, { label => "t-Hang", pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", name => "t-Hang", version => 1.23, grade => "discard", phase => "test", command => "$make test", will_send => 0, }, ); plan tests => 1 + @cases * (test_fake_config_plan() + test_dispatch_plan()); #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); # test send_skipfile for my $case ( @cases ) { $case->{dist} = t::MockCPANDist->new( pretty_id => $case->{pretty_id}, %mock_dist_options, ); test_fake_config( command_timeout => 3 ); test_dispatch( $case, will_send => $case->{will_send}, ); } CPAN-Reporter-1.2010/t/05_prompting.t0000644000175000017500000000263012132015716015546 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::Helper; use t::Frontend; use IO::CaptureOutput qw/capture/; my @cases = ( "default:yes", "default:no", "default:ask/yes", "default:ask/no", "default:ask/no fail:ask/yes na:yes unknown:no", ); plan tests => 1 + 4 * @cases; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $option_name = "edit_report"; my ($got); #--------------------------------------------------------------------------# # Begin tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); local $ENV{PERL_MM_USE_DEFAULT} = 1; for my $c ( @cases ) { my $config = { $option_name => $c }; my $parsed = CPAN::Reporter::Config::_validate_grade_action_pair( $option_name, $c ); for my $grade ( qw/pass fail na unknown/ ) { capture { $got = CPAN::Reporter::_prompt( $config, $option_name, $grade ); }; my $expected = $parsed->{$grade} || $parsed->{default}; # convert ask/* to * $expected =~ s{ask/?}{}; $expected = "no" if not length $expected; is( $got, $expected , "'$c' for '$grade'" ); } } CPAN-Reporter-1.2010/t/62_duplicate_reports.t0000644000175000017500000001551312132015716017266 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Helper; use t::Frontend; use Probe::Perl; #--------------------------------------------------------------------------# # We need Config to be writeable, so modify the tied hash #--------------------------------------------------------------------------# use Config; BEGIN { BEGIN { if (not $] < 5.006 ) { warnings->unimport('redefine') } } *Config::STORE = sub { $_[0]->{$_[1]} = $_[2] } } #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# my $make = $Config{make}; my $perl = Probe::Perl->find_perl_interpreter(); my %mock_dist_info = ( prereq_pm => { 'File::Spec' => 0, }, author_id => "JOHNQP", author_fullname => "John Q. Public", ); my @cases = ( { label => "first PL failure", name => "PL-Fail", version => 1.23, grade => "unknown", phase => "PL", command => "$perl Makefile.PL", send_dup => "no", is_dup => 0, }, { label => "second PL failure", name => "PL-Fail", version => 1.23, grade => "unknown", phase => "PL", command => "$perl Makefile.PL", send_dup => "no", is_dup => 1, }, { label => "first PL unsupported", name => "PL-NoSupport", version => 1.23, grade => "na", phase => "PL", command => "$perl Makefile.PL", send_dup => "no", is_dup => 0, }, { label => "first make failure", name => "make-Fail", version => 1.23, grade => "unknown", phase => "make", command => "$make", send_dup => "no", is_dup => 0, }, { label => "second make failure", name => "make-Fail", version => 1.23, grade => "unknown", phase => "make", command => "$make", send_dup => "no", is_dup => 1, }, { label => "first test unknown", name => "NoTestFiles", version => 1.23, grade => "unknown", phase => "test", command => "$make test", send_dup => "no", is_dup => 0, }, { label => "first test failure", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$make test", send_dup => "no", is_dup => 0, }, { label => "second test failure (but send dup)", name => "t-Fail", version => 1.23, grade => "fail", phase => "test", command => "$make test", send_dup => "yes", is_dup => 1, }, { label => "first discard", name => 't-PrereqMiss', version => 9.11, prereq => { 'Bogus::Module::Doesnt::Exist' => 0 }, grade => "discard", phase => "test", command => "$make test", send_dup => "no", is_dup => 0, }, { label => "third test failure (new version)", name => "t-Fail", version => 1.24, grade => "fail", phase => "test", command => "$make test", send_dup => "no", is_dup => 0, }, { label => "second discard", name => 't-PrereqMiss', version => 9.11, prereq => { 'Bogus::Module::Doesnt::Exist' => 0 }, grade => "discard", phase => "test", command => "$make test", send_dup => "no", is_dup => 1, }, ); my $expected_history_lines = 1; # opening comment line for my $c ( @cases ) { $expected_history_lines++ if not $c->{is_dup} } plan tests => 5 + $expected_history_lines + @cases * ( 3 + test_fake_config_plan() + test_dispatch_plan() ); #--------------------------------------------------------------------------# # subs #--------------------------------------------------------------------------# sub history_format { my ($case) = @_; my ($phase, $grade, $dist) = @{$case}{qw/phase grade dist/}; $grade = uc $grade; my $perl_ver = "perl-" . CPAN::Reporter::History::_perl_version(); $perl_ver .= " patch $Config{perl_patchlevel}" if $Config{perl_patchlevel}; my $arch = "$Config{archname} $Config{osvers}"; my $dist_name = $dist->base_id; return "$phase $grade $dist_name ($perl_ver) $arch\n"; } #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); require_ok('CPAN::Reporter::History'); my @results; for my $case ( @cases ) { # localize Config in same scope if there is a patchlevel local $Config{perl_patchlevel} = $case->{patch} if $case->{patch}; # and set it once localized test_fake_config( send_duplicates => $case->{send_dup} ); $case->{dist} = t::MockCPANDist->new( %mock_dist_info, pretty_id => "JOHNQP/Bogus-Module-$case->{version}.tar.gz", ); $case->{dist}{prereq_pm} = $case->{prereq} if $case->{prereq}; test_dispatch( $case, will_send => ($case->{grade} ne 'discard') && (! $case->{is_dup}) || ( $case->{send_dup} eq 'yes' ) ); if ( not $case->{is_dup} ) { push @results, history_format($case); } my @found; ok( @found = CPAN::Reporter::History::have_tested( dist => $case->{dist}->base_id ), "$case->{label}: have_tested( base_id ) is true" ); is( ref($found[0]), 'HASH', "$case->{label}: have_tested returns AoH" ); is( $found[0]{dist}, $case->{dist}->base_id, "$case->{label}: have_tested struct has dist name" ); } #--------------------------------------------------------------------------# # have_tested fails #--------------------------------------------------------------------------# ok( ! CPAN::Reporter::History::have_tested( dist => "AADFASDFADSFASD" ), "have_tested() returns false if not found" ); #--------------------------------------------------------------------------# # Check history file format #--------------------------------------------------------------------------# my $history_fh = CPAN::Reporter::History::_open_history_file('<'); ok( $history_fh, "found history file" ); my @history = <$history_fh>; is( scalar @history, $expected_history_lines, "history file length is $expected_history_lines" ); is( shift @history, "# Generated by CPAN::Reporter $CPAN::Reporter::History::VERSION\n", "history starts with version comment" ); for my $i ( 0 .. $#results ) { is( $history[$i], $results[$i], "history matched results[$i]" ); } CPAN-Reporter-1.2010/t/41_make_report_discard.t0000644000175000017500000000316312132015716017532 0ustar garugaru#!perl use strict; BEGIN{ if (not $] < 5.006) { require warnings; warnings->import } } select(STDERR); $|=1; select(STDOUT); $|=1; use Test::More; use t::MockCPANDist; use t::Frontend; use t::Helper; my @test_distros = ( # discards { name => 'make-PrereqMiss', prereq => { 'Unavailable::Module' => 0 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite missing", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite missing", }, { name => 'make-PrereqFail', prereq => { 'File::Spec' => 99999.9 }, eumm_success => 0, eumm_grade => "discard", eumm_msg => "Prerequisite version too low", mb_success => 0, mb_grade => "discard", mb_msg => "Prerequisite version too low", }, ); plan tests => 1 + test_fake_config_plan() + test_grade_make_plan() * @test_distros; #--------------------------------------------------------------------------# # Fixtures #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # tests #--------------------------------------------------------------------------# require_ok('CPAN::Reporter'); test_fake_config(); for my $case ( @test_distros ) { my $mock_dist = t::MockCPANDist->new( pretty_id => "JOHNQP/Bogus-Module-1.23.tar.gz", prereq_pm => $case->{prereq}, author_id => "JOHNQP", author_fullname => "John Q. Public", ); test_grade_make( $case, $mock_dist ); } CPAN-Reporter-1.2010/examples/0000775000175000017500000000000012132015716014412 5ustar garugaruCPAN-Reporter-1.2010/examples/config.ini0000644000175000017500000000045012132015716016355 0ustar garugaru# example config.ini file cc_author=default:yes pass/na:no edit_report=default:ask/no pass/na:no email_from=DAGOLDEN send_duplicates=no send_report=default:ask/yes pass/na:yes # specify an internal mail server if direct mail sending is blocked smtp_server=mail.speakeasy.net CPAN-Reporter-1.2010/Makefile.PL0000644000175000017500000000431112132015716014543 0ustar garugaru use strict; use warnings; use 5.006; use ExtUtils::MakeMaker 6.30; my %WriteMakefileArgs = ( "ABSTRACT" => "Adds CPAN Testers reporting to CPAN.pm", "AUTHOR" => "David Golden ", "BUILD_REQUIRES" => {}, "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => "6.30" }, "DISTNAME" => "CPAN-Reporter", "EXE_FILES" => [], "LICENSE" => "apache", "NAME" => "CPAN::Reporter", "PREREQ_PM" => { "CPAN" => "1.9301", "CPAN::Version" => 0, "Capture::Tiny" => 0, "Carp" => 0, "Config" => 0, "Config::Tiny" => "2.08", "Devel::Autoflush" => "0.04", "Exporter" => 0, "ExtUtils::MakeMaker" => "6.36", "Fcntl" => 0, "File::Basename" => 0, "File::Find" => 0, "File::Glob" => 0, "File::HomeDir" => "0.58", "File::Path" => 0, "File::Spec" => "3.19", "File::Temp" => "0.16", "IO::File" => 0, "IPC::Cmd" => "0.76", "Parse::CPAN::Meta" => 0, "Probe::Perl" => 0, "Test::Reporter" => "1.54", "constant" => 0, "strict" => 0, "vars" => 0 }, "TEST_REQUIRES" => { "Archive::Tar" => "1.54", "File::Copy::Recursive" => "0.35", "File::Spec::Functions" => 0, "File::pushd" => "0.32", "IO::CaptureOutput" => "1.03", "List::Util" => 0, "Test::Harness" => 0, "Test::More" => "0.62", "warnings" => 0 }, "VERSION" => "1.2010", "test" => { "TESTS" => "t/*.t" } ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { my $tr = delete $WriteMakefileArgs{TEST_REQUIRES}; my $br = $WriteMakefileArgs{BUILD_REQUIRES}; for my $mod ( keys %$tr ) { if ( exists $br->{$mod} ) { $br->{$mod} = $tr->{$mod} if $tr->{$mod} > $br->{$mod}; } else { $br->{$mod} = $tr->{$mod}; } } } unless ( eval { ExtUtils::MakeMaker->VERSION(6.56) } ) { my $br = delete $WriteMakefileArgs{BUILD_REQUIRES}; my $pp = $WriteMakefileArgs{PREREQ_PM}; for my $mod ( keys %$br ) { if ( exists $pp->{$mod} ) { $pp->{$mod} = $br->{$mod} if $br->{$mod} > $pp->{$mod}; } else { $pp->{$mod} = $br->{$mod}; } } } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); CPAN-Reporter-1.2010/dist.ini0000644000175000017500000000113212132015716014233 0ustar garugaruname = CPAN-Reporter author = David Golden license = Apache_2_0 copyright_holder = David Golden copyright_year = 2006 [@DAGOLDEN] :version = 0.026 stopwords = HTTPS stopwords = IRC stopwords = ISP's stopwords = MSWin stopwords = Modulino stopwords = SMTP stopwords = SSL stopwords = Skipfile stopwords = cpan stopwords = cpanreporter stopwords = exe stopwords = ini stopwords = metabase stopwords = Metabase stopwords = modulino stopwords = na stopwords = uri stopwords = wiki stopwords = Wiki [RemovePrereqs] remove = FuddleDuddleCantFindMe CPAN-Reporter-1.2010/MANIFEST0000644000175000017500000000356312132015716013732 0ustar garugaruChanges LICENSE MANIFEST MANIFEST.SKIP META.json META.yml Makefile.PL README README.PATCHING Todo dist.ini examples/config.ini lib/CPAN/Reporter.pm lib/CPAN/Reporter/API.pm lib/CPAN/Reporter/Config.pm lib/CPAN/Reporter/FAQ.pm lib/CPAN/Reporter/History.pm lib/CPAN/Reporter/PrereqCheck.pm perlcritic.rc t/00-compile.t t/00-report-prereqs.t t/01_CPAN_Reporter.t t/02_config_env_vars.t t/03_config_file.t t/04_option_parsing.t t/05_prompting.t t/06_prompt_text.t t/10_prereq_pm.t t/11_env_config.t t/12_toolchain_versions.t t/13_record_command.t t/14_command_timeout.t t/15_option_validation.t t/20_report_output.t t/30_PL_report.t t/31_PL_report_discard.t t/40_make_report.t t/41_make_report_discard.t t/50_test_report_pass.t t/51_test_report_fail.t t/52_test_report_unknown.t t/53_test_report_na.t t/54_test_report_split.t t/55_test_report_discard.t t/56_test_report_by_harness.t t/57_hang_interrupt.t t/60_discard_triggers.t t/61_bad_dist_names.t t/62_duplicate_reports.t t/63_config_send_report.t t/64_transport.t t/65_skipfile.t t/66_have_tested.t t/67_distfile.t t/68_is_make.t t/70_darwin_move_config.t t/71_missing_config.t t/72_rename_history.t t/73_autoflush.t t/Frontend.pm t/Helper.pm t/MockCPANDist.pm t/MockHomeDir.pm t/bin/Build.PL t/bin/Makefile.PL t/bin/NotBuild.PL t/bin/NotMakefile.PL t/dist.tgz t/history/history.db t/history/reports-sent-longer.db t/history/reports-sent.db t/perl5lib-shadow/Bogus/Shadow.pm t/perl5lib/Bogus/Broken.pm t/perl5lib/Bogus/Complex.pm t/perl5lib/Bogus/Conflict.pm t/perl5lib/Bogus/Found.pm t/perl5lib/Bogus/GT.pm t/perl5lib/Bogus/GTE.pm t/perl5lib/Bogus/LT.pm t/perl5lib/Bogus/LTE.pm t/perl5lib/Bogus/NoVersion.pm t/perl5lib/Bogus/Shadow.pm t/perl5lib/Bogus/TooOld.pm xt/author/critic.t xt/author/pod-spell.t xt/release/distmeta.t xt/release/minimum-version.t xt/release/pod-coverage.t xt/release/pod-syntax.t xt/release/portability.t xt/release/test-version.t CPAN-Reporter-1.2010/META.yml0000644000175000017500000000406012132015716014043 0ustar garugaru--- abstract: 'Adds CPAN Testers reporting to CPAN.pm' author: - 'David Golden ' build_requires: Archive::Tar: 1.54 File::Copy::Recursive: 0.35 File::Spec::Functions: 0 File::pushd: 0.32 IO::CaptureOutput: 1.03 List::Util: 0 Test::Harness: 0 Test::More: 0.62 warnings: 0 configure_requires: ExtUtils::MakeMaker: 6.30 dynamic_config: 0 generated_by: 'Dist::Zilla version 4.300033, CPAN::Meta::Converter version 2.120921' license: apache meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: CPAN-Reporter no_index: directory: - t - xt - examples - corpus package: - DB provides: CPAN::Reporter: file: lib/CPAN/Reporter.pm version: 1.2010 CPAN::Reporter::API: file: lib/CPAN/Reporter/API.pm version: 1.2010 CPAN::Reporter::Config: file: lib/CPAN/Reporter/Config.pm version: 1.2010 CPAN::Reporter::FAQ: file: lib/CPAN/Reporter/FAQ.pm version: 1.2010 CPAN::Reporter::History: file: lib/CPAN/Reporter/History.pm version: 1.2010 CPAN::Reporter::PrereqCheck: file: lib/CPAN/Reporter/PrereqCheck.pm version: 1.2010 requires: CPAN: 1.9301 CPAN::Version: 0 Capture::Tiny: 0 Carp: 0 Config: 0 Config::Tiny: 2.08 Devel::Autoflush: 0.04 Exporter: 0 ExtUtils::MakeMaker: 6.36 Fcntl: 0 File::Basename: 0 File::Find: 0 File::Glob: 0 File::HomeDir: 0.58 File::Path: 0 File::Spec: 3.19 File::Temp: 0.16 IO::File: 0 IPC::Cmd: 0.76 Parse::CPAN::Meta: 0 Probe::Perl: 0 Test::Reporter: 1.54 constant: 0 perl: 5.006 strict: 0 vars: 0 resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=CPAN-Reporter homepage: https://metacpan.org/release/CPAN-Reporter repository: git://github.com/dagolden/cpan-reporter.git version: 1.2010 x_contributors: - 'Alexandr Ciornii ' - 'Breno G. de Oliveira ' - 'Christian Walde ' - 'Kent Fredric ' - 'Matthew Musgrove ' CPAN-Reporter-1.2010/Todo0000644000175000017500000001075412132015716013431 0ustar garugaruTODO list for Perl module CPAN::Reporter #--------------------------------------------------------------------------# # Bugs #--------------------------------------------------------------------------# #--------------------------------------------------------------------------# # Features, etc #--------------------------------------------------------------------------# # NOW NOW NOW NOW NOW - Add support for CPAN::Reporter singleton for CPANPLUS refactoring - Look for .cpanreporter in a known place for Strawberry preconfig (e.g. in @INC where CPAN/Reporter.pm is found?) # High priority - Add utility sub to invoke a test (for C::R::S and PoCo::C::R) - Add Oslo Accords environment variables - Add datestamps to history (ISO 8601: YYYY-MM-DD HH:MM:SS) - my @t=localtime; $t[4]++; $t[5]+=1900; my $iso = sprintf("%4d-%02d-%02d %02d:%02d:%02d", reverse @t[0..5]); - For failure in PL stage -- in report, show configure_requires and an error message that other requirements aren't available if PL fails - change report truncation to take first 25K and last 25K (summary) (?!) - check for working signals regardless of platform and skip if not working -- maybe during *.PL (write a signaling file) # Medium priority - search for recursive Makefile.PL only at depth 1 - list installed versions of any modules in requires/recommends/etc - list path of requires/recommends/etc/ - add support for a "comment.txt" file in the config directory to use in place of the default comment - 'force_prompt' config to locally unset PERL_MM_USE_DEFAULT (Rezic) - add results back to CPAN::Distribution object - Create a discards file that shows missing prerequisites for each discarded report. Could be interesting data to find highly requested. Or, perhaps track *all* prerequisites for all files tested. Very interesting data I suspect. Probably not something that should be on by default # Low priority - document Windows ErrorMode registry hack to stop segfault dialog - add earlier, successful phases to output in reverse order. Probably have to bump up the test-length cutoff, though, to deal with lengthy make output - Test phase output - make phase output - PL phase output - refactor t/Helper.pm - add warnings::compat to toolchain or else add config to allow local modules to be added to toolchain report - SAPER: Hmm... ok. The fact is that warnings::compat isn't listed in Sys::Syslog prereqs, but it should in order to make it work under 5.5. So I guess that Slaven manually installed it in his 5.5.5 smoker in order to ease the process, but in that case, it becomes (in a sense) part of the toolchain, because it masks a potentially missing prereq (this is what happened here). warnings::compat is a little special because it provides a way to make a core module available on old Perls. So maybe CPAN::Reporter should allow one to add locally installed modules in the toolchain section. - SREZIC: To add my 0.02EUR: maybe warnings::compat could/should be shown only if 5.5.x is used. - switch from a single flat file for history. e.g. - SDBM_File for history (key on subject line, with phase as value? Or key on distro name/perl with result and phase as value? ) -- but does it scale well? (See MJD's article) - Or use sorted file with Search::Dict(?) -- (prefer this option, keeps search for non-existant line fast; insertion is a just a few block writes and a rename.) If we do this, need to put distro name first to make "have_tested()" easier to write - Use filesystem to index -- one file per distname? hash with directories to keep number of files/directory down? - Or flat file per perl/archname/osver (usually constant) - use File::ReadBackwards for searches on flat file - Add interactive config for editor? - Improve test coverage for utility subs and error handling - Check email addresses for validity (cf. Email::Valid, etc.) - Add other Config items like 'make' to report context - heuristics for missing library files --> discard report ?? - figure out how to support color output from Test::Harness 3.0 -- probably set an environment variable to get them to pass color strings to the pipe and then strip color escape codes from the teed file. # Probably won't implement - add timeout to EU::MM prompts (RT#28034) - remove File::Temp as a build_requires dependency - send duplicate report if using "report" (?) or "force" (?)