Internal debugging improvements.
[test-reporter.git] / lib / Test / Reporter.pm
blob8ef6b5e9d0669e7560e6e6991eb38746a786d064
1 # Test::Reporter - sends test results to cpan-testers@perl.org
2 # Copyright (c) 2003 Adam J. Foxson. All rights reserved.
4 # This program is free software; you can redistribute it and/or modify
5 # it under the same terms as Perl itself.
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 package Test::Reporter;
13 use strict;
14 use Cwd;
15 use Config;
16 use Carp;
17 use Net::SMTP;
18 use FileHandle;
19 use File::Temp;
20 use Sys::Hostname;
21 use Time::Local ();
22 use vars qw($VERSION $AUTOLOAD $Tempfile $Report $DNS $Domain $Send);
23 use constant FAKE_NO_NET_DNS => 0; # for debugging only
24 use constant FAKE_NO_NET_DOMAIN => 0; # for debugging only
25 use constant FAKE_NO_MAIL_SEND => 0; # for debugging only
27 $VERSION = '1.32';
29 local $^W = 1;
31 sub new {
32 my $type = shift;
33 my $class = ref($type) || $type;
34 my $self = {
35 '_mx' => ['mx.develooper.com'],
36 '_address' => 'cpan-testers@perl.org',
37 '_grade' => undef,
38 '_distribution' => undef,
39 '_report' => undef,
40 '_subject' => undef,
41 '_from' => undef,
42 '_comments' => '',
43 '_errstr' => '',
44 '_via' => '',
45 '_mail_send_args' => '',
46 '_timeout' => 120,
47 '_debug' => 0,
48 '_dir' => '',
49 '_subject_lock' => 0,
50 '_report_lock' => 0,
51 '_perl_version' => {
52 '_archname' => $Config{archname},
53 '_osvers' => $Config{osvers},
54 '_myconfig' => Config::myconfig(),
58 bless $self, $class;
60 $self->{_attr} = {
61 map {$_ => 1} qw(
62 _address _distribution _comments _errstr _via _timeout _debug _dir
66 warn __PACKAGE__, ": new\n" if $self->debug();
67 croak __PACKAGE__, ": new: even number of named arguments required"
68 unless scalar @_ % 2 == 0;
70 $self->_process_params(@_) if @_;
71 $self->_get_mx(@_) if $self->_have_net_dns();
73 return $self;
76 sub _get_mx {
77 my $self = shift;
78 warn __PACKAGE__, ": _get_mx\n" if $self->debug();
80 my %params = @_;
82 return if exists $params{'mx'};
84 my $dom = $params{'address'} || $self->address();
85 my @mx;
87 $dom =~ s/^.+\@//;
89 for my $mx (sort {$a->preference() <=> $b->preference()} Net::DNS::mx($dom)) {
90 push @mx, $mx->exchange();
93 if (not @mx) {
94 warn __PACKAGE__,
95 ": _get_mx: unable to find MX's for $dom, using defaults\n" if
96 $self->debug();
97 return;
100 $self->mx(\@mx);
103 sub _process_params {
104 my $self = shift;
105 warn __PACKAGE__, ": _process_params\n" if $self->debug();
107 my %params = @_;
108 my @defaults = qw(
109 mx address grade distribution from comments via timeout debug dir perl_version);
110 my %defaults = map {$_ => 1} @defaults;
112 for my $param (keys %params) {
113 croak __PACKAGE__, ": new: parameter '$param' is invalid." unless
114 exists $defaults{$param};
117 for my $param (keys %params) {
118 $self->$param($params{$param});
122 sub subject {
123 my $self = shift;
124 warn __PACKAGE__, ": subject\n" if $self->debug();
125 croak __PACKAGE__, ": subject: grade and distribution must first be set"
126 if not defined $self->{_grade} or not defined $self->{_distribution};
128 return $self->{_subject} if $self->{_subject_lock};
130 my $subject = uc($self->{_grade}) . ' ' . $self->{_distribution} .
131 " $self->{_perl_version}->{_archname} $self->{_perl_version}->{_osvers}";
133 return $self->{_subject} = $subject;
136 sub report {
137 my $self = shift;
138 warn __PACKAGE__, ": report\n" if $self->debug();
140 return $self->{_report} if $self->{_report_lock};
142 my $report;
143 $report .= "This distribution has been tested as part of the cpan-testers\n";
144 $report .= "effort to test as many new uploads to CPAN as possible. See\n";
145 $report .= "http://testers.cpan.org/\n\n";
146 $report .= "Please cc any replies to cpan-testers\@perl.org to keep other\n";
147 $report .= "test volunteers informed and to prevent any duplicate effort.\n";
149 if (not $self->{_comments}) {
150 $report .= "\n\n--\n\n";
152 else {
153 $report .= "\n--\n" . $self->{_comments} . "\n--\n\n";
156 $report .= $self->{_perl_version}->{_myconfig};
158 chomp $report;
159 chomp $report;
161 return $self->{_report} = $report;
164 sub grade {
165 my ($self, $grade) = @_;
166 warn __PACKAGE__, ": grade\n" if $self->debug();
168 my %grades = (
169 'pass' => "all tests passed",
170 'fail' => "one or more tests failed",
171 'na' => "distribution will not work on this platform",
172 'unknown' => "distribution did not include tests",
175 return $self->{_grade} if scalar @_ == 1;
177 croak __PACKAGE__, ":grade: '$grade' is invalid, choose from: " .
178 join ' ', keys %grades unless $grades{$grade};
180 return $self->{_grade} = $grade;
183 sub edit_comments {
184 my($self, %args) = @_;
185 warn __PACKAGE__, ": edit_comments\n" if $self->debug();
187 my %tempfile_args = (
188 UNLINK => 1,
189 SUFFIX => '.txt',
192 if (exists $args{'suffix'} && defined $args{'suffix'} && length $args{'suffix'}) {
193 $tempfile_args{SUFFIX} = $args{'suffix'};
194 # prefix the extension with a period, if the user didn't.
195 $tempfile_args{SUFFIX} =~ s/^(?!\.)(?=.)/./;
198 ($Tempfile, $Report) = File::Temp::tempfile(%tempfile_args);
200 print $Tempfile $self->{_comments};
202 $self->_start_editor();
204 my $comments;
206 local $/;
207 open FH, $Report or die __PACKAGE__, ": Can't open comment file '$Report': $!";
208 $comments = <FH>;
209 close FH or die __PACKAGE__, ": Can't close comment file '$Report': $!";
212 chomp $comments;
214 $self->{_comments} = $comments;
216 return;
219 sub send {
220 my ($self, @recipients) = @_;
221 warn __PACKAGE__, ": send\n" if $self->debug();
223 $self->from();
224 $self->report();
225 $self->subject();
227 return unless $self->_verify();
229 if ($self->_is_a_perl_release($self->distribution())) {
230 $self->errstr(__PACKAGE__ . ": use perlbug for reporting test " .
231 "results against perl itself");
232 return;
235 # Addresses #9831: Usage of Mail::Mailer is broken on Win32
236 if ($^O !~ /^(?:cygwin|MSWin32)$/ && $self->_have_mail_send()) {
237 return $self->_mail_send(@recipients);
239 else {
240 return $self->_send_smtp(@recipients);
244 sub write {
245 my $self = shift;
246 warn __PACKAGE__, ": write\n" if $self->debug();
248 my $from = $self->from();
249 my $report = $self->report();
250 my $subject = $self->subject();
251 my $distribution = $self->distribution();
252 my $grade = $self->grade();
253 my $dir = $self->dir() || cwd;
255 return unless $self->_verify();
257 $distribution =~ s/[^A-Za-z0-9\.\-]+//g;
259 my($fh, $file); unless ($fh = $_[0]) {
260 $file = "$dir/$grade.$distribution.$self->{_perl_version}->{_archname}.$self->{_perl_version}->{_osvers}.${\(time)}.$$.rpt";
261 warn $file if $self->debug();
262 $fh = FileHandle->new();
263 open $fh, ">$file" or die __PACKAGE__, ": Can't open report file '$file': $!";
265 print $fh "From: $from\n";
266 print $fh "Subject: $subject\n";
267 print $fh "Report: $report";
268 unless ($_[0]) {
269 close $fh or die __PACKAGE__, ": Can't close report file '$file': $!";
270 warn $file if $self->debug();
271 return $file;
272 } else {
273 return $fh;
277 sub read {
278 my ($self, $file) = @_;
279 warn __PACKAGE__, ": read\n" if $self->debug();
281 my $buffer;
284 local $/;
285 open REPORT, $file or die __PACKAGE__, ": Can't open report file '$file': $!";
286 $buffer = <REPORT>;
287 close REPORT or die __PACKAGE__, ": Can't close report file '$file': $!";
290 if (my ($from, $subject, $report) = $buffer =~ /^From:\s(.+)Subject:\s(.+)Report:\s(.+)$/s) {
291 my ($grade, $distribution) = (split /\s/, $subject)[0,1];
292 $self->from($from) unless $self->from();
293 $self->{_subject} = $subject;
294 $self->{_report} = $report;
295 $self->{_grade} = lc $grade;
296 $self->{_distribution} = $distribution;
297 $self->{_subject_lock} = 1;
298 $self->{_report_lock} = 1;
299 } else {
300 die __PACKAGE__, ": Failed to parse report file '$file'\n";
303 return $self;
306 sub _verify {
307 my $self = shift;
308 warn __PACKAGE__, ": _verify\n" if $self->debug();
310 my @undefined;
312 for my $key (keys %{$self}) {
313 push @undefined, $key unless defined $self->{$key};
316 $self->errstr(__PACKAGE__ . ": Missing values for: " .
317 join ', ', map {$_ =~ /^_(.+)$/} @undefined) if
318 scalar @undefined > 0;
319 return $self->errstr() ? return 0 : return 1;
322 sub _mail_send {
323 my $self = shift;
324 warn __PACKAGE__, ": _mail_send\n" if $self->debug();
326 my $fh;
327 my $recipients;
328 my @recipients = @_;
329 my $via = $self->via();
330 my $msg = Mail::Send->new();
332 if (@recipients) {
333 $recipients = join ', ', @recipients;
334 chomp $recipients;
335 chomp $recipients;
338 $via = ', via ' . $via if $via;
340 $msg->to($self->address());
341 $msg->set('From', $self->from());
342 $msg->subject($self->subject());
343 $msg->add('X-Reported-Via', "Test::Reporter ${VERSION}$via");
344 $msg->add('Cc', $recipients) if @_;
346 if ($self->mail_send_args() and ref $self->mail_send_args() eq 'ARRAY') {
347 $fh = $msg->open(@{$self->mail_send_args()});
349 else {
350 $fh = $msg->open();
353 print $fh $self->report();
355 $fh->close();
358 sub _send_smtp {
359 my $self = shift;
360 warn __PACKAGE__, ": _send_smtp\n" if $self->debug();
362 my $helo = $self->_maildomain();
363 my $from = $self->from();
364 my $via = $self->via();
365 my $debug = $self->debug();
366 my @recipients = @_;
367 my @tmprecipients = ();
368 my @bad = ();
369 my $success = 0;
370 my $fail = 0;
371 my $recipients;
372 my $smtp;
374 my $mx;
375 for my $server (@{$self->{_mx}}) {
376 $smtp = Net::SMTP->new($server, Hello => $helo,
377 Timeout => $self->{_timeout}, Debug => $debug);
379 if (defined $smtp) {
380 $mx = $server;
381 last;
383 else {
384 warn __PACKAGE__, ": Unable to connect to MX '$server'\n" if $self->debug();
385 $fail++;
389 unless ($mx && $smtp) {
390 $self->errstr(__PACKAGE__ . ': Unable to connect to any MX\'s');
391 return 0;
394 if (@recipients) {
395 if ($mx =~ /(?:^|\.)(?:perl|cpan)\.org$/) {
396 for my $recipient (sort @recipients) {
397 if ($recipient =~ /(?:@|\.)(?:perl|cpan)\.org$/) {
398 push @tmprecipients, $recipient;
399 } else {
400 push @bad, $recipient;
404 if (@bad) {
405 warn __PACKAGE__, ": Will not attempt to cc the following recipients since perl.org MX's will not relay for them. Either install Mail::Send, use other MX's, or only cc address ending in cpan.org or perl.org: ${\(join ', ', @bad)}.\n";
408 @recipients = @tmprecipients;
411 $recipients = join ', ', @recipients;
412 chomp $recipients;
413 chomp $recipients;
416 $via = ', via ' . $via if $via;
418 my $envelope_sender = $from;
419 $envelope_sender =~ s/\s\([^)]+\)$//; # email only; no name
421 $success += $smtp->mail($envelope_sender);
422 $success += $smtp->to($self->{_address});
423 $success += $smtp->cc(@recipients) if @recipients;
424 $success += $smtp->data();
425 $success += $smtp->datasend("Date: ", $self->_format_date, "\n");
426 $success += $smtp->datasend("Subject: ", $self->subject(), "\n");
427 $success += $smtp->datasend("From: $from\n");
428 $success += $smtp->datasend("To: ", $self->{_address}, "\n");
429 $success += $smtp->datasend("Cc: $recipients\n") if @recipients && $success == 8;
430 $success += $smtp->datasend("Message-ID: ", $self->message_id(), "\n");
431 $success +=
432 $smtp->datasend("X-Reported-Via: Test::Reporter ${VERSION}$via\n");
433 $success += $smtp->datasend("\n");
434 $success += $smtp->datasend($self->report());
435 $success += $smtp->dataend();
436 $success += $smtp->quit;
438 if (@recipients) {
439 $self->errstr(__PACKAGE__ .
440 ": Unable to send test report to one or more recipients\n") if $success != 15;
442 else {
443 $self->errstr(__PACKAGE__ . ": Unable to send test report\n") if $success != 13;
446 return $self->errstr() ? 0 : 1;
449 # Courtesy of Email::MessageID
450 sub message_id {
451 my $self = shift;
452 warn __PACKAGE__, ": message_id\n" if $self->debug();
454 my $unique_value = 0;
455 my @CHARS = ('A'..'F','a'..'f',0..9);
456 my $length = 3;
458 $length = rand(8) until $length > 3;
460 my $pseudo_random = join '', (map $CHARS[rand $#CHARS], 0 .. $length), $unique_value++;
461 my $user = join '.', time, $pseudo_random, $$;
463 return '<' . $user . '@' . Sys::Hostname::hostname() . '>';
466 sub from {
467 my $self = shift;
468 warn __PACKAGE__, ": from\n" if $self->debug();
470 if (@_) {
471 $self->{_from} = shift;
472 return $self->{_from};
474 else {
475 return $self->{_from} if defined $self->{_from} and $self->{_from};
476 $self->{_from} = $self->_mailaddress();
477 return $self->{_from};
482 sub mx {
483 my $self = shift;
484 warn __PACKAGE__, ": mx\n" if $self->debug();
486 if (@_) {
487 my $mx = shift;
488 croak __PACKAGE__,
489 ": mx: array reference required" if ref $mx ne 'ARRAY';
490 $self->{_mx} = $mx;
493 return $self->{_mx};
496 sub mail_send_args {
497 my $self = shift;
498 warn __PACKAGE__, ": mail_send_args\n" if $self->debug();
499 croak __PACKAGE__, ": mail_send_args cannot be called unless Mail::Send is installed\n" unless $self->_have_mail_send();
501 if (@_) {
502 my $mail_send_args = shift;
503 croak __PACKAGE__, ": mail_send_args: array reference required" if
504 ref $mail_send_args ne 'ARRAY';
505 $self->{_mail_send_args} = $mail_send_args;
508 return $self->{_mail_send_args};
511 sub perl_version {
512 my $self = shift;
513 warn __PACKAGE__, ": perl_version\n" if $self->debug();
515 if( @_) {
516 my $perl = shift;
517 my $q = ( ($^O eq "MSWin32") || ($^O eq 'VMS') ) ? '"' : "'"; # quote for command-line perl
518 my $magick = int(rand(1000)); # just to check that we get a valid result back
519 my $conf = `$perl -MConfig -e$q print qq{$magick\n\$Config{archname}\n\$Config{osvers}\n},Config::myconfig();$q`;
520 my %conf;
521 ( @conf{ qw( magick _archname _osvers _myconfig) } ) = split( /\n/, $conf, 4);
522 croak __PACKAGE__, ": cannot get perl version info from $perl: $conf" if( $conf{magick} ne $magick);
523 delete $conf{magick};
524 $self->{_perl_version} = \%conf;
526 return $self->{_perl_version};
529 sub AUTOLOAD {
530 my $self = $_[0];
531 my ($package, $method) = ($AUTOLOAD =~ /(.*)::(.*)/);
533 return if $method =~ /^DESTROY$/;
535 unless ($self->{_attr}->{"_$method"}) {
536 croak __PACKAGE__, ": No such method: $method; aborting";
539 my $code = q{
540 sub {
541 my $self = shift;
542 warn __PACKAGE__, ": METHOD\n" if $self->{_debug};
543 $self->{_METHOD} = shift if @_;
544 return $self->{_METHOD};
548 $code =~ s/METHOD/$method/g;
551 no strict 'refs';
552 *$AUTOLOAD = eval $code;
555 goto &$AUTOLOAD;
558 sub _have_net_dns {
559 my $self = shift;
560 warn __PACKAGE__, ": _have_net_dns\n" if $self->debug();
562 return $DNS if defined $DNS;
563 return 0 if FAKE_NO_NET_DNS;
565 $DNS = eval {require Net::DNS};
568 sub _have_net_domain {
569 my $self = shift;
570 warn __PACKAGE__, ": _have_net_domain\n" if $self->debug();
572 return $Domain if defined $Domain;
573 return 0 if FAKE_NO_NET_DOMAIN;
575 $Domain = eval {require Net::Domain};
578 sub _have_mail_send {
579 my $self = shift;
580 warn __PACKAGE__, ": _have_mail_send\n" if $self->debug();
582 return $Send if defined $Send;
583 return 0 if FAKE_NO_MAIL_SEND;
585 $Send = eval {require Mail::Send};
588 sub _start_editor {
589 my $self = shift;
590 warn __PACKAGE__, ": _start_editor\n" if $self->debug();
592 my $editor = $ENV{VISUAL} || $ENV{EDITOR} || $ENV{EDIT}
593 || ($^O eq 'VMS' and "edit/tpu")
594 || ($^O eq 'MSWin32' and "notepad")
595 || 'vi';
597 $editor = $self->_prompt('Editor', $editor);
599 die __PACKAGE__, ": The editor `$editor' could not be run" if system "$editor $Report";
600 die __PACKAGE__, ": Report has disappeared; terminated" unless -e $Report;
601 die __PACKAGE__, ": Empty report; terminated" unless -s $Report > 2;
604 sub _prompt {
605 my $self = shift;
606 warn __PACKAGE__, ": _prompt\n" if $self->debug();
608 my ($label, $default) = @_;
610 printf "$label%s", (" [$default]: ");
611 my $input = scalar <STDIN>;
612 chomp $input;
614 return (length $input) ? $input : $default;
617 # From Mail::Util 1.74 (c) 1995-2001 Graham Barr (c) 2002-2005 Mark Overmeer
618 sub _maildomain {
619 my $self = shift;
620 warn __PACKAGE__, ": _maildomain\n" if $self->debug();
622 my $domain = $ENV{MAILDOMAIN};
624 return $domain if defined $domain;
626 local *CF;
627 local $_;
629 my @sendmailcf = qw(
630 /etc /etc/sendmail /etc/ucblib /etc/mail /usr/lib /var/adm/sendmail
633 my $config = (grep(-r, map("$_/sendmail.cf", @sendmailcf)))[0];
635 if (defined $config && open(CF, $config)) {
636 my %var;
637 while (<CF>) {
638 if (my ($v, $arg) = /^D([a-zA-Z])([\w.\$\-]+)/) {
639 $arg =~ s/\$([a-zA-Z])/exists $var{$1} ? $var{$1} : '$'.$1/eg;
640 $var{$v} = $arg;
643 close(CF) || die $!;
644 $domain = $var{j} if defined $var{j};
645 $domain = $var{M} if defined $var{M};
647 $domain = $1
648 if ($domain && $domain =~ m/([A-Za-z0-9](?:[\.\-A-Za-z0-9]+))/);
650 undef $domain if $^O eq 'darwin' && $domain =~ /\.local$/;
652 return $domain if (defined $domain && $domain !~ /\$/);
655 if (open(CF, "/usr/lib/smail/config")) {
656 while (<CF>) {
657 if (/\A\s*hostnames?\s*=\s*(\S+)/) {
658 $domain = (split(/:/,$1))[0];
659 undef $domain if $^O eq 'darwin' && $domain =~ /\.local$/;
660 last if defined $domain and $domain;
663 close(CF) || die $!;
665 return $domain if defined $domain;
668 if (eval {require Net::SMTP}) {
669 my $host;
671 for $host (qw(mailhost localhost)) {
672 my $smtp = eval {Net::SMTP->new($host)};
674 if (defined $smtp) {
675 $domain = $smtp->domain;
676 $smtp->quit;
677 undef $domain if $^O eq 'darwin' && $domain =~ /\.local$/;
678 last if defined $domain and $domain;
683 unless (defined $domain) {
684 if ($self->_have_net_domain()) {
685 ###################################################################
686 # The below statement might possibly exhibit intermittent blocking
687 # behavior. Be advised!
688 ###################################################################
689 $domain = Net::Domain::domainname();
690 undef $domain if $^O eq 'darwin' && $domain =~ /\.local$/;
694 $domain = "localhost" unless defined $domain;
696 return $domain;
699 # From Mail::Util 1.74 (c) 1995-2001 Graham Barr (c) 2002-2005 Mark Overmeer
700 sub _mailaddress {
701 my $self = shift;
702 warn __PACKAGE__, ": _mailaddress\n" if $self->debug();
704 my $mailaddress = $ENV{MAILADDRESS};
705 $mailaddress ||= $ENV{USER} ||
706 $ENV{LOGNAME} ||
707 eval {getpwuid($>)} ||
708 "postmaster";
709 $mailaddress .= '@' . $self->_maildomain() unless $mailaddress =~ /\@/;
710 $mailaddress =~ s/(^.*<|>.*$)//g;
712 my $realname = $self->_realname();
713 if ($realname) {
714 $mailaddress = "$mailaddress ($realname)";
717 return $mailaddress;
720 sub _realname {
721 my $self = shift;
722 warn __PACKAGE__, ": _realname\n" if $self->debug();
724 my $realname = '';
726 $realname =
727 eval {(split /,/, (getpwuid($>))[6])[0]} ||
728 $ENV{QMAILNAME} ||
729 $ENV{REALNAME} ||
730 $ENV{USER};
732 return $realname;
735 sub _is_a_perl_release {
736 my $self = shift;
737 warn __PACKAGE__, ": _is_a_perl_release\n" if $self->debug();
739 my $perl = shift;
741 return $perl =~ /^perl-?\d\.\d/;
745 # Next two subs courtesy of Casey West, Ricardo SIGNES, and Email::Date
746 # Visit the Perl Email Project at: http://emailproject.perl.org/
747 sub _tz_diff {
748 my $self = shift;
749 warn __PACKAGE__, ": _tz_diff\n" if $self->debug();
751 my ($time) = @_;
753 my $diff = Time::Local::timegm(localtime $time)
754 - Time::Local::timegm(gmtime $time);
756 my $direc = $diff < 0 ? '-' : '+';
757 $diff = abs $diff;
758 my $tz_hr = int( $diff / 3600 );
759 my $tz_mi = int( $diff / 60 - $tz_hr * 60 );
761 return ($direc, $tz_hr, $tz_mi);
764 sub _format_date {
765 my $self = shift;
766 warn __PACKAGE__, ": _format_date\n" if $self->debug();
768 my ($time) = @_;
769 $time = time unless defined $time;
771 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = (localtime $time);
772 my $day = (qw[Sun Mon Tue Wed Thu Fri Sat])[$wday];
773 my $month = (qw[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec])[$mon];
774 $year += 1900;
776 my ($direc, $tz_hr, $tz_mi) = $self->_tz_diff($time);
778 sprintf "%s, %d %s %d %02d:%02d:%02d %s%02d%02d",
779 $day, $mday, $month, $year, $hour, $min, $sec, $direc, $tz_hr, $tz_mi;
782 =head1 NAME
784 Test::Reporter - sends test results to cpan-testers@perl.org
786 =head1 SYNOPSIS
788 use Test::Reporter;
790 my $reporter = Test::Reporter->new();
792 $reporter->grade('pass');
793 $reporter->distribution('Mail-Freshmeat-1.20');
794 $reporter->send() || die $reporter->errstr();
796 # or
798 my $reporter = Test::Reporter->new();
800 $reporter->grade('fail');
801 $reporter->distribution('Mail-Freshmeat-1.20');
802 $reporter->comments('output of a failed make test goes here...');
803 $reporter->edit_comments(); # if you want to edit comments in an editor
804 $reporter->send('afoxson@cpan.org') || die $reporter->errstr();
806 # or
808 my $reporter = Test::Reporter->new(
809 grade => 'fail',
810 distribution => 'Mail-Freshmeat-1.20',
811 from => 'whoever@wherever.net (Whoever Wherever)',
812 comments => 'output of a failed make test goes here...',
813 via => 'CPANPLUS X.Y.Z',
815 $reporter->send() || die $reporter->errstr();
817 =head1 DESCRIPTION
819 Test::Reporter reports the test results of any given distribution to the CPAN
820 testing service. Test::Reporter has wide support for various perl5's and
821 platforms. For further information visit the below links:
823 =over 4
825 =item * L<http://cpantesters.perl.org/>
827 CPAN Testers reports (new site)
829 =item * L<http://testers.cpan.org/>
831 CPAN Testers reports (old site)
833 =item * L<http://cpantest.grango.org/>
835 The new CPAN Testers Wiki (thanks Barbie!)
837 =back
839 Test::Reporter itself--as a project--also has several links for your visiting
840 enjoyment:
842 =over 4
844 =item * L<http://code.google.com/p/test-reporter/>
846 Test::Reporter's master project page
848 =item * L<http://groups.google.com/group/test-reporter>
850 Discussion group for Test::Reporter
852 =item * L<http://code.google.com/p/test-reporter/w/list>
854 The Wiki for Test::Reporter
856 =item * L<http://repo.or.cz/w/test-reporter.git>
858 Test::Reporter's public git source code repository.
860 =item * L<http://search.cpan.org/dist/Test-Reporter/>
862 Test::Reporter on CPAN
864 =item * L<http://code.google.com/p/test-reporter/issues/list>
866 UNFORTUNATELY, WE ARE UNABLE TO ACCEPT TICKETS FILED WITH RT.
868 Please file all bug reports and enhancement requests at our Google Code issue
869 tracker. Thank you for your support and understanding.
871 =item * L<http://backpan.cpan.org/authors/id/F/FO/FOX/>
873 =item * L<http://backpan.cpan.org/authors/id/A/AF/AFOXSON/>
875 If you happen to--for some strange reason--be looking for primordial versions
876 of Test::Reporter, you can almost certainly find them at the above 2 links.
878 =back
880 =head1 METHODS
882 =over 4
884 =item * B<address>
886 Optional. Gets or sets the e-mail address that the reports will be
887 sent to. By default, this is set to cpan-testers@perl.org. You shouldn't
888 need this unless the CPAN Tester's change the e-mail address to send
889 report's to.
891 =item * B<comments>
893 Optional. Gets or sets the comments on the test report. This is most
894 commonly used for distributions that did not pass a 'make test'.
896 =item * B<debug>
898 Optional. Gets or sets the value that will turn debugging on or off.
899 Debug messages are sent to STDERR. 1 for on, 0 for off. Debugging
900 generates very verbose output and is useful mainly for finding bugs
901 in Test::Reporter itself.
903 =item * B<dir>
905 Optional. Defaults to the current working directory. This method specifies
906 the directory that write() writes test report files to.
908 =item * B<distribution>
910 Gets or sets the name of the distribution you're working on, for example
911 Foo-Bar-0.01. There are no restrictions on what can be put here.
913 =item * B<edit_comments>
915 Optional. Allows one to interactively edit the comments within a text
916 editor. comments() doesn't have to be first specified, but it will work
917 properly if it was. Accepts an optional hash of arguments:
919 =over 4
921 =item * B<suffix>
923 Optional. Allows one to specify the suffix ("extension") of the temp
924 file used by B<edit_comments>. Defaults to '.txt'.
926 =back
928 =item * B<errstr>
930 Returns an error message describing why something failed. You must check
931 errstr() on a send() in order to be guaranteed delivery. This is optional
932 if you don't intend to use Test::Reporter to send reports via e-mail,
933 see 'send' below for more information.
935 =item * B<from>
937 Optional. Gets or sets the e-mail address of the individual submitting
938 the test report, i.e. "afoxson@pobox.com (Adam Foxson)". This is
939 mostly of use to testers running under Windows, since Test::Reporter
940 will usually figure this out automatically. Alternatively, you can use
941 the MAILADDRESS environmental variable to accomplish the same.
943 =item * B<grade>
945 Gets or sets the success or failure of the distributions's 'make test'
946 result. This must be one of:
948 grade meaning
949 ----- -------
950 pass all tests passed
951 fail one or more tests failed
952 na distribution will not work on this platform
953 unknown distribution did not include tests
955 =item * B<mail_send_args>
957 Optional. If you have MailTools installed and you want to have it
958 behave in a non-default manner, parameters that you give this
959 method will be passed directly to the constructor of
960 Mail::Mailer. See L<Mail::Mailer> and L<Mail::Send> for details.
962 =item * B<message_id>
964 Returns an automatically generated Message ID. This Message ID will later
965 be included as an outgoing mail header in the test report e-mail. This was
966 included to conform to local mail policies at perl.org. This method courtesy
967 of Email::MessageID.
969 =item * B<mx>
971 Optional. Gets or sets the mail exchangers that will be used to send
972 the test reports. If you override the default values make sure you
973 pass in a reference to an array. By default, this contains the MX's
974 known at the time of release for perl.org. If you do not have
975 Mail::Send installed (thus using the Net::SMTP interface) and do have
976 Net::DNS installed it will dynamically retrieve the latest MX's. You
977 really shouldn't need to use this unless the hardcoded MX's have
978 become wrong and you don't have Net::DNS installed.
980 =item * B<new>
982 This constructor returns a Test::Reporter object. It will optionally accept
983 named parameters for: mx, address, grade, distribution, from, comments,
984 via, timeout, debug and dir.
986 =item * B<perl_version>
988 Returns a hashref containing _archname, _osvers, and _myconfig based upon the
989 perl that you are using. Alternatively, you may supply a different perl (path
990 to the binary) as an argument, in which case the supplied perl will be used as
991 the basis of the above data.
993 =item * B<report>
995 Returns the actual content of a report, i.e.
996 "This distribution has been tested as part of the cpan-testers...".
997 'comments' must first be specified before calling this method, if you have
998 comments to make and expect them to be included in the report.
1000 =item * B<send>
1002 Sends the test report to cpan-testers@perl.org and cc's the e-mail to the
1003 specified recipients, if any. If you do specify recipients to be cc'd and
1004 you do not have Mail::Send installed be sure that you use the author's
1005 @cpan.org address otherwise they will not be delivered. You must check
1006 errstr() on a send() in order to be guaranteed delivery. Technically, this
1007 is optional, as you may use Test::Reporter to only obtain the 'subject' and
1008 'report' without sending an e-mail at all, although that would be unusual.
1010 =item * B<subject>
1012 Returns the subject line of a report, i.e.
1013 "PASS Mail-Freshmeat-1.20 Darwin 6.0". 'grade' and 'distribution' must
1014 first be specified before calling this method.
1016 =item * B<timeout>
1018 Optional. Gets or sets the timeout value for the submission of test
1019 reports. Default is 120 seconds.
1021 =item * B<via>
1023 Optional. Gets or sets the value that will be appended to
1024 X-Reported-Via, generally this is useful for distributions that use
1025 Test::Reporter to report test results. This would be something
1026 like "CPANPLUS 0.036".
1028 =item * B<write and read>
1030 These methods are used in situations where you test on a machine that has
1031 port 25 blocked and there is no local MTA. You use write() on the machine
1032 that you are testing from, transfer the written test reports from the
1033 testing machine to the sending machine, and use read() on the machine that
1034 you actually want to submit the reports from. write() will write a file in
1035 an internal format that contains 'From', 'Subject', and the content of the
1036 report. The filename will be represented as:
1037 grade.distribution.archname.osvers.seconds_since_epoch.pid.rpt. write()
1038 uses the value of dir() if it was specified, else the cwd.
1040 On the machine you are testing from:
1042 my $reporter = Test::Reporter->new
1044 grade => 'pass',
1045 distribution => 'Test-Reporter-1.16',
1046 )->write();
1048 On the machine you are submitting from:
1050 my $reporter;
1051 $reporter = Test::Reporter->new()->read('pass.Test-Reporter-1.16.i686-linux.2.2.16.1046685296.14961.rpt')->send() || die $reporter->errstr(); # wrap in an opendir if you've a lot to submit
1053 write() also accepts an optional filehandle argument:
1055 my $fh; open $fh, '>-'; # create a STDOUT filehandle object
1056 $reporter->write($fh); # prints the report to STDOUT
1058 =back
1060 =head1 CAVEATS
1062 If you specify recipients to be cc'd while using send() (and you do not have
1063 Mail::Send installed) be sure that you use the author's @cpan.org address
1064 otherwise they may not be delivered, since the perl.org MX's are unlikely
1065 to relay for anything other than perl.org and cpan.org.
1067 =head1 COPYRIGHT
1069 Copyright (c) 2007 Adam J. Foxson. All rights reserved.
1071 =head1 LICENSE
1073 This program is free software; you may redistribute it
1074 and/or modify it under the same terms as Perl itself.
1076 =head1 SEE ALSO
1078 =over 4
1080 =item * L<perl>
1082 =item * L<Config>
1084 =item * L<Net::SMTP>
1086 =item * L<File::Spec>
1088 =item * L<File::Temp>
1090 =item * L<Net::Domain>
1092 This is optional. If it's installed Test::Reporter will try even
1093 harder at guessing your mail domain.
1095 =item * L<Net::DNS>
1097 This is optional. If it's installed Test::Reporter will dynamically
1098 retrieve the mail exchangers for perl.org, instead of relying on the
1099 MX's known at the time of this release.
1101 =item * L<Mail::Send>
1103 This is optional. If it's installed Test::Reporter will use Mail::Send
1104 instead of Net::SMTP.
1106 =back
1108 =head1 AUTHOR
1110 Adam J. Foxson E<lt>F<afoxson@pobox.com>E<gt> and
1111 Richard Soderberg E<lt>F<rsod@cpan.org>E<gt>, with much deserved credit to
1112 Kirrily "Skud" Robert E<lt>F<skud@cpan.org>E<gt>, and
1113 Kurt Starsinic E<lt>F<Kurt.Starsinic@isinet.com>E<gt> for predecessor versions
1114 (CPAN::Test::Reporter, and cpantest respectively).
1116 =cut