Test::Smoke::Mailer - Wrapper to send the report.


Test-Smoke documentation Contained in the Test-Smoke distribution.

Index


Code Index:

NAME

Top

Test::Smoke::Mailer - Wrapper to send the report.

SYNOPSIS

Top

    use Test::Smoke::Mailer;

    my %args = ( mhowto => 'smtp', mserver => 'smtp.your.domain' );
    my $mailer = Test::Smoke::Mailer->new( $ddir, %args );

    $mailer->mail or die "Problem in mailing: " . $mailer->error;

DESCRIPTION

Top

This little wrapper still allows you to use the sendmail, mail or mailx programs, but prefers to use the Mail::Sendmail module (which comes with this distribution) to send the reports.

METHODS

Top

Test::Smoke::Mailer->new( $mailer[, %args] )

Can we provide sensible defaults for the mail stuff?

    mhowto  => [Module::Name|sendmail|mail|mailx]
    mserver => an SMTP server || localhost
    mbin    => the full path to the mail binary
    mto     => list of addresses (comma separated!)
    mfrom   => single address
    mcc     => list of addresses (coma separated!)

$mailer->fetch_report( )

fetch_report() reads mktest.rpt from {ddir} and return the subject line for the mail-message.

$mailer->error( )

error() returns the value of $mailer->{error}.

$self->_get_cc( $subject )

_get_cc() implements the --ccp5p_onfail option. It looks at the subject to see if the smoke FAILed and then adds the perl5-porters mailing-list to the Cc: field unless it is already part of To: or Cc:.

The new behaviour is to only return Cc: on fail. This is determined by the new global regex kept in $Test::Smoke::Mailer::NOCC_RE.

Test::Smoke::Mailer->config( $key[, $value] )

config() is an interface to the package lexical %CONFIG, which holds all the default values for the new() arguments.

With the special key all_defaults this returns a reference to a hash holding all the default values.

Test::Smoke::Mailer::Sendmail

Top

This handles sending the message by piping it to the sendmail program.

Test::Smoke::Mailer::Sendmail->new( %args )

Keys for %args:

  * ddir
  * sendmailbin
  * to
  * from
  * cc
  * v

$mailer->mail( )

mail() sets up a header and body and pipes them to the sendmail program.

Test::Smoke::Mailer::Mail_X

Top

This handles sending the message with either the mail or mailx program.

Test::Smoke::Mailer::Mail_X->new( %args )

Keys for %args:

  * ddir
  * mailbin/mailxbin
  * to
  * cc
  * v

$mailer->mail( )

mail() sets up the commandline and body and pipes it to either the mail or the mailx program.

Test::Smoke::Mailer::Mail_Sendmail

Top

This handles sending the message using the Mail::Sendmail module.

Test::Smoke::Mailer::Mail_Sendmail->new( %args )

Keys for %args:

  * ddir
  * mserver
  * to
  * from
  * cc
  * v

$mailer->mail( )

mail() sets up the message to be send by Mail::Sendmail.

Test::Smoke::Mailer::MIME_Lite

Top

This handles sending the message using the MIME::Lite module.

Test::Smoke::Mailer::MIME_Lite->new( %args )

Keys for %args:

  * ddir
  * mserver
  * to
  * from
  * cc
  * v

$mailer->mail( )

mail() sets up the message to be send by MIME::Lite.

COPYRIGHT

Top


Test-Smoke documentation Contained in the Test-Smoke distribution.
package Test::Smoke::Mailer;
use strict;

# $Id: Mailer.pm 1044 2007-04-06 22:01:03Z abeltje $
use vars qw( $VERSION $P5P $NOCC_RE);
$VERSION = '0.014';

use Test::Smoke::Util qw( parse_report_Config );

$P5P       = 'perl5-porters@perl.org';
$NOCC_RE   = ' (?:PASS\b|FAIL\(X\))';
my %CONFIG = (
    df_mailer        => 'Mail::Sendmail',
    df_ddir          => undef,
    df_v             => 0,
    df_rptfile       => 'mktest.rpt',
    df_to            => 'daily-build-reports@perl.org',
    df_from          => '',
    df_cc            => '',
    df_swcc          => '-c',
    df_swbcc         => '-b',
    df_bcc           => '',
    df_ccp5p_onfail  => 0,
    df_mserver       => 'localhost',

    df_mailbin       => 'mail',
    mail             => [qw( bcc cc mailbin )],
    df_mailxbin      => 'mailx',
    mailx            => [qw( bcc cc mailxbin swcc swbcc )],
    df_sendmailbin   => 'sendmail',
    sendmail         => [qw( from bcc cc sendmailbin )],
    'Mail::Sendmail' => [qw( from bcc cc mserver )],
    'MIME::Lite'     => [qw( from bcc cc mserver )],

    valid_mailer => { sendmail => 1, mail => 1, mailx => 1,
                      'Mail::Sendmail' => 1, 'MIME::Lite' => 1, },
);

sub  new {
    my $proto = shift;
    my $class = ref $proto || $proto;

    my $mailer = shift || $CONFIG{df_mailer};

    unless ( exists $CONFIG{valid_mailer}->{ $mailer } ) {
        require Carp;
        Carp::croak( "Invalid mailer '$mailer'" );
    };

    my %args_raw = @_ ? UNIVERSAL::isa( $_[0], 'HASH' ) ? %{ $_[0] } : @_ : ();

    my %args = map {
        ( my $key = $_ ) =~ s/^-?(.+)$/lc $1/e;
        ( $key => $args_raw{ $_ } );
    } keys %args_raw;

    my %fields = map {
        my $value = exists $args{$_} ? $args{ $_ } : $CONFIG{ "df_$_" };
        ( $_ => $value )
    } ( rptfile => v => ddir => to => ccp5p_onfail => @{ $CONFIG{ $mailer } } );
    $fields{ddir} = File::Spec->rel2abs( $fields{ddir} );

    DO_NEW: {
        local $_ = $mailer;

        /^sendmail$/  && return Test::Smoke::Mailer::Sendmail->new( %fields );
        /^mailx?$/ && return Test::Smoke::Mailer::Mail_X->new( %fields );
        /^Mail::Sendmail$/ && 
            return Test::Smoke::Mailer::Mail_Sendmail->new( %fields );
        /^MIME::Lite$/ && 
            return Test::Smoke::Mailer::MIME_Lite->new( %fields );
    }

}

sub fetch_report {
    my $self = shift;

    my $report_file = File::Spec->catfile( $self->{ddir}, $self->{rptfile} );

    local *REPORT;
    if ( open REPORT, "< $report_file" ) {
        $self->{body} = do { local $/; <REPORT> };
        close REPORT;
    } else {
        require Carp;
        Carp::croak( "Cannot read '$report_file': $!" );
    }

    my @config = parse_report_Config( $self->{body} );

    return sprintf "Smoke [%s] %s %s %s %s (%s)", @config[0, 1, 5, 2, 3, 4];
}

sub error {
    my $self = shift;

    return $self->{error} || '';
}

sub _get_cc {
    my( $self, $subject ) = @_;
    return "" if $subject =~ m/$NOCC_RE/;

    return $self->{cc} || "" unless $self->{ccp5p_onfail};

    my $p5p = $Test::Smoke::Mailer::P5P or return $self->{cc};
    my @cc = $self->{cc} ? $self->{cc} : ();

    push @cc, $p5p unless $self->{to} =~ /\Q$p5p\E/ || 
                          $self->{cc} =~ /\Q$p5p\E/;
    return join ", ", @cc;
}

sub config {
    my $dummy = shift;

    my $key = lc shift;

    if ( $key eq 'all_defaults' ) {
        my %default = map {
            my( $pass_key ) = $_ =~ /^df_(.+)/;
            ( $pass_key => $CONFIG{ $_ } );
        } grep /^df_/ => keys %CONFIG;
        return \%default;
    }

    return undef unless exists $CONFIG{ "df_$key" };

    $CONFIG{ "df_$key" } = shift if @_;

    return $CONFIG{ "df_$key" };
}

1;

package Test::Smoke::Mailer::Sendmail;

@Test::Smoke::Mailer::Sendmail::ISA = qw( Test::Smoke::Mailer );

sub new {
    my $proto = shift;
    my $class = ref $proto || $proto;

    return bless { @_ }, $class;
}

sub mail {
    my $self = shift;

    my $subject   = $self->fetch_report();
    my $cc = $self->_get_cc( $subject );
    my $header = "To: $self->{to}\n";
    $header   .= "From: $self->{from}\n" 
        if exists $self->{from} && $self->{from};
    $header   .= "Cc: $cc\n" if $cc;
    $header   .= "Bcc: $self->{bcc}\n" if $self->{bcc};
    $header   .= "Subject: $subject\n\n";

    $self->{v} > 1 and print "[$self->{sendmailbin} -i -t]\n";
    $self->{v} and print "Sending report to $self->{to} ";
    local *MAILER;
    if ( open MAILER, "| $self->{sendmailbin} -i -t " ) {
        print MAILER $header, $self->{body};
        close MAILER or
            $self->{error} = "Error in pipe to sendmail: $! (" . $?>>8 . ")";
    } else {
        $self->{error} = "Cannot fork ($self->{sendmailbin}): $!";
    }
    $self->{v} and print $self->{error} ? "not OK\n" : "OK\n";

    return ! $self->{error};
}

package Test::Smoke::Mailer::Mail_X;

@Test::Smoke::Mailer::Mail_X::ISA = qw( Test::Smoke::Mailer );

sub new {
    my $proto = shift;
    my $class = ref $proto || $proto;

    return bless { @_ }, $class;
}

sub mail {
    my $self = shift;

    my $mailer = $self->{mailbin} || $self->{mailxbin};

    my $subject = $self->fetch_report();
    my $cc = $self->_get_cc( $subject );

    my $cmdline = qq|$mailer -s '$subject'|;
    $self->{swcc}  ||= '-c', $cmdline   .= qq| $self->{swcc} '$cc'| if $cc;
    $self->{swbcc} ||= '-b', $cmdline   .= qq| $self->{swbcc} '$self->{bcc}'|
        if $self->{bcc};
    $cmdline   .= qq| $self->{to}|;

    $self->{v} > 1 and print "[$cmdline]\n";
    $self->{v} and print "Sending report to $self->{to} ";
    local *MAILER;
    if ( open MAILER, "| $cmdline " ) {
        print MAILER $self->{body};
        close MAILER or 
            $self->{error} = "Error in pipe to '$mailer': $! (" . $?>>8 . ")";
    } else {
	$self->{error} = "Cannot fork '$mailer': $!";
    }
    $self->{v} and print $self->{error} ? "not OK\n" : "OK\n";

    return ! $self->{error};
}

package Test::Smoke::Mailer::Mail_Sendmail;

@Test::Smoke::Mailer::Mail_Sendmail::ISA =  qw( Test::Smoke::Mailer );

sub new {
    my $proto = shift;
    my $class = ref $proto || $proto;

    bless { @_ }, $class;
}

sub mail {
    my $self = shift;

    eval { require Mail::Sendmail; };

    $self->{error} = $@ and return undef;

    my $subject = $self->fetch_report();
    my $cc = $self->_get_cc( $subject );

    my %message = (
        To      => $self->{to},
        Subject => $subject,
        Body    => $self->{body},
    );
    $message{cc}   = $cc if $cc;
    $message{bcc}   = $self->{bcc} if $self->{bcc};
    $message{from} = $self->{from} if $self->{from};
    $message{smtp} = $self->{mserver} if $self->{mserver};

    $message{ 'Content-type' } = qq!text/plain; charset="UTF8"!
        if exists $ENV{LANG} && $ENV{LANG} =~ /utf-?8$/i;

    $self->{v} > 1 and print "[Mail::Sendmail]\n";
    $self->{v} and print "Sending report to $self->{to} ";

    Mail::Sendmail::sendmail( %message ) or
        $self->{error} = $Mail::Sendmail::error;

    $self->{v} and print $self->{error} ? "not OK\n" : "OK\n";

    return ! $self->{error};
}

package Test::Smoke::Mailer::MIME_Lite;

@Test::Smoke::Mailer::MIME_Lite::ISA =  qw( Test::Smoke::Mailer );

sub new {
    my $proto = shift;
    my $class = ref $proto || $proto;

    bless { @_ }, $class;
}

sub mail {
    my $self = shift;

    eval { require MIME::Lite; };

    $self->{error} = $@ and return undef;

    my $subject = $self->fetch_report();
    my $cc = $self->_get_cc( $subject );

    my %message = (
        To      => $self->{to},
        Subject => $subject,
        Type    => "TEXT",
        Data    => $self->{body},
    );
    $message{Cc}   = $cc  if $cc;
    $message{Bcc}   = $self->{bcc} if $self->{bcc};
    $message{From} = $self->{from} if $self->{from};

    MIME::Lite->send( smtp => $self->{mserver}, Debug => ( $self->{v} > 1 ) )
        if $self->{mserver};

    my $ml_msg = MIME::Lite->new( %message );
    $ml_msg->attr( 'content-type.charset' => 'UTF8' )
        if exists $ENV{LANG} && $ENV{LANG} =~ /utf-?8$/i;

    $self->{v} > 1 and print "[MIME::Lite]\n";
    $self->{v} and print "Sending report to $self->{to} ";

    $ml_msg->send or $self->{error} = "Problem sending mail";

    $self->{v} and print $self->{error} ? "not OK\n" : "OK\n";

    return ! $self->{error};
}