#!/usr/bin/env perl
#
# ** Send queued test reports **
#
# I like to use CPAN::Reporter, but the default behavior of sending the
# reports during my cpan runs is very slow.
#
# Fortunately, you can configure CPAN::Reporter to write the reports to
# a directory, and later send them all in a batch.
#
# First you need to configure your CPAN::Reporter. Create a
# $HOME/.cpanreporter/ directory and place a config.ini file inside with
# the following content:
#
# ---- 8< ------
# email_from = melo@simplicidade.org
# edit_report = no
#
# transport=File $QUEUE_DIR
# ---- 8< ------
#
# Adjust the email_from field to use your email, and adjust the
# $QUEUE_DIR directory path in the last line.
#
# I use `/Users/melo/.cpan/reports` as my $QUEUE_DIR, for example.
#
# **Make sure the directory exists**
#
# $ mkdir -p /Users/melo/.cpan/reports
#
# Then make sure your cpan command is configured to use CPAN::Reporter. The easiest way is:
#
# $ cpan
# cpan> o conf test_report 1
# cpan> o conf commit
# cpan> quit
#
# Done! You can now install your modules and a report will be created in
# the $QUEUE_DIR directory
#
# After you create your reports, you can send them later with this script. Just run:
#
# $ x-perl-send-test-reports $QUEUE_DIR
#
# Reports will be renamed to .done after they are send. You can run the
# script with --clean to remove those files.
#
use strict;
use warnings;
use 5.10.0;
use Test::Reporter;
use Getopt::Long;
use Path::Class qw( dir );
my $opt_clean;
my $opt_from;
my $opt_server;
my $opt_transport;
my @queues = parse_arguments();
scan_all_queues(@queues);
sub send_report {
my ($file) = @_;
my $tr = Test::Reporter->new;
$tr->from($opt_from);
$tr->mx([ $opt_server ]);
$tr->transport(split(/\s+/, $opt_transport));
$tr->via( 'x-perl-send-test-reports v0.1');
return if $tr->read($file)->send;
return $tr->errstr;
}
sub send_reports_in_queue {
my $q = shift;
scan_queue($q, qr{[.]rpt$}, sub {
my ($file) = @_;
local $| = 1;
my $subject = find_subject($file);
next unless $subject;
print "Sending report for '$subject'... ";
if (my $error = send_report($file)) {
print "FAIL\n>> Error: $error\n";
}
else {
if (rename($file, "$file.done")) {
print "done!\n";
}
else {
print "FAIL\n>>> Could not mark '$subject' as DONE, will be resent.\n";
}
}
});
}
sub scan_all_queues {
for my $q (@_) {
send_reports_in_queue($q);
clean_reports_in_queue($q) if $opt_clean;
}
}
sub clean_reports_in_queue {
my ($q) = @_;
scan_queue($q, qr{[.]done$}, sub {
$_->remove && print "Cleaned up '$_'\n";
});
}
sub scan_queue {
my ($q, $regexp, $cb) = @_;
ITEM: while (my $item = $q->next) {
next ITEM unless -f $item;
local $_ = $item;
$cb->($item) if $item =~ /$regexp/;
}
}
sub find_subject {
my ($rpt) = @_;
my $subject;
my $fh = $rpt->openr;
for (1..5) {
my $line = <$fh>;
last unless $line;
$subject = $1 if $line =~ m/^Subject:\s*(.+)/;
last if $subject;
}
$fh->close;
return $subject;
}
sub parse_arguments {
GetOptions(
"from=s" => \$opt_from,
"server=s" => \$opt_server,
"transport=s" => \$opt_transport,
"clean" => \$opt_clean,
) || usage();
usage('missing queue directory') unless @ARGV;
usage('parameter --from is required') unless $opt_from;
usage('parameter --server is required') unless $opt_server;
for my $q (@ARGV) {
usage("queue '$q' is not a directory") unless -d $q;
$q = dir($q);
}
return @ARGV;
}
sub usage {
my $mesg = join('', @_);
print <<'USAGE';
Send test reports created with CPAN::Reporter.
Usage: x-perl-send-test-reports options queue1 ...
Options:
--from Email FROM address
--server SMTP server to use
--transport Tweak transport to use
--clean Remove reports that where sent sucessfully
Example: to send test reports via the GMail server:
x-perl-send-test-reports --from your@email --server smtp.gmail.com \
--transport "Net::SMTP::TLS User your@email Password your_gmail_password Port 587" \
~/.cpan/reports
USAGE
print "\nFATAL: $mesg\n" if $mesg;
exit(1);
}