summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan "Duke" Leto <jonathan@leto.net>2011-01-19 13:04:42 -0800
committerJonathan "Duke" Leto <jonathan@leto.net>2011-01-19 13:04:42 -0800
commit05c0a17eabb8cb52535ca1ae30fcf8ce0906f5c3 (patch)
tree7a782c216051e366c215ad902571d34cf2939a17
parentAttempt to fix the mangled build failure email bug (diff)
parentFix a jitterbug::Emailer test (diff)
downloadjitterbug-05c0a17eabb8cb52535ca1ae30fcf8ce0906f5c3.tar.gz
Merge branch 'refactor_builder'
Conflicts: config.yml lib/jitterbug/Builder.pm scripts/build-failed.sh
Diffstat (limited to '')
-rw-r--r--Build.PL2
-rw-r--r--config.yml8
-rw-r--r--lib/jitterbug/Builder.pm20
-rw-r--r--lib/jitterbug/Emailer.pm78
-rwxr-xr-xscripts/build-failed.sh17
-rwxr-xr-xscripts/capsule.sh69
-rw-r--r--t/005_builder.t42
-rw-r--r--t/006_emailer.t153
8 files changed, 348 insertions, 41 deletions
diff --git a/Build.PL b/Build.PL
index 7218a16..063b3de 100644
--- a/Build.PL
+++ b/Build.PL
@@ -11,6 +11,7 @@ my $builder = Module::Build->new(
include_dirs => '',
build_requires => {
'Test::Most' => 0,
+ 'Test::MockObject'=> 0,
},
requires => {
'YAML' => 0,
@@ -27,6 +28,7 @@ my $builder = Module::Build->new(
'Digest::MD5' => 0,
'App::perlbrew' => 0,
'Dist::Zilla' => 0,
+ 'Email::Stuff' => 0,
},
add_to_cleanup => [ 'jitterbug-' ],
create_makefile_pl => 'traditional',
diff --git a/config.yml b/config.yml
index c9c4b4b..bf9bd23 100644
--- a/config.yml
+++ b/config.yml
@@ -18,7 +18,13 @@ jitterbug:
build_process:
builder: ./scripts/capsule.sh
on_failure: ./scripts/build-failed.sh
- on_failure_email: alice@example.com
+ on_failure_cc_email: alice@example.com
+ on_failure_from_email: donotreply@example.com
+ on_failure_subject_prefix: "[jitterbug] FAIL "
+ on_failure_header:
+ on_failure_footer:
+ options:
+ perlbrew: 1
plugins:
DBIC:
diff --git a/lib/jitterbug/Builder.pm b/lib/jitterbug/Builder.pm
index 32bc51c..a836f70 100644
--- a/lib/jitterbug/Builder.pm
+++ b/lib/jitterbug/Builder.pm
@@ -113,7 +113,9 @@ sub run_task {
my $builder = $conf->{'jitterbug'}{'build_process'}{'builder'};
- my $builder_command = "$builder $build_dir $report_path";
+ my $perlbrew = $conf->{'options'}{'perlbrew'} || 1;
+
+ my $builder_command = "$builder $build_dir $report_path $perlbrew";
debug("Going to run builder : $builder_command");
my $res = `$builder_command`;
@@ -136,15 +138,23 @@ sub run_task {
$result = "FAIL";
my $message = $desc->{'message'};
my $commiter = $desc->{'author'}{'email'};
- my $output = "Build failed";
+ my $output = $lines;
my $sha = $desc->{'id'};
my $on_failure = $conf->{'jitterbug'}{'build_process'}{'on_failure'};
- my $on_failure_email = $conf->{'jitterbug'}{'build_process'}{'on_failure_email'};
+ my $on_failure_cc_email = $conf->{'jitterbug'}{'build_process'}{'on_failure_email'};
$message =~ s/'/\\'/g; $commiter =~ s/'/\\'/g; $output =~ s/'/\\'/g;
- my $failure_cmd = qq{$on_failure '$commiter' '$message' '$output' $sha $on_failure_email};
+ my $failure_cmd = sprintf("%s '%s' %s '%s' '%s' %s %s", $on_failure, $commiter, $task->project->name, $message, $output, $sha, $on_failure_cc_email);
debug("Running failure command: $failure_cmd");
- `$failure_cmd`;
+
+ # does it look like a module name?
+ if ($on_failure =~ /::/) {
+ # we should do some error checking here
+ eval "require $on_failure";
+ $on_failure->new($conf,$task,$output)->run;
+ } else {
+ system($failure_cmd);
+ }
}
$desc->{'build'}{'version'}{$name} = $result;
close $fh;
diff --git a/lib/jitterbug/Emailer.pm b/lib/jitterbug/Emailer.pm
new file mode 100644
index 0000000..d21028f
--- /dev/null
+++ b/lib/jitterbug/Emailer.pm
@@ -0,0 +1,78 @@
+package jitterbug::Emailer;
+
+use strict;
+use warnings;
+use Email::Stuff;
+use JSON;
+
+sub new {
+ my $self = bless {} => shift;
+ my ($conf,$task,$tap_output) = @_;
+ # smelly
+ $self->{'conf'} = $conf;
+ $self->{'task'} = $task;
+ $self->{'tap_output'} = $tap_output;
+
+ return $self;
+}
+
+sub _make_body {
+ my ($header, $message, $tap, $footer) = @_;
+
+ no warnings 'uninitialized';
+ return <<BODY;
+$header
+Commit Message:
+$message
+
+TAP Output:
+$tap
+$footer
+BODY
+
+}
+sub run {
+ my $self = shift;
+ my $task = $self->{'task'};
+ my $buildconf = $self->{'conf'}->{'jitterbug'}{'build_process'};
+ my $project = $task->project->name;
+ my $tap = $self->{'tap_output'};
+ my $sha1 = $task->commit->sha256;
+ my $shortsha1 = substr($sha1, 0, 8);
+ my $desc = JSON::decode_json( $task->commit->content );
+ my $email = $desc->{'author'}{'email'};
+ my $message = $desc->{'message'};
+ my $header = $buildconf->{'on_failure_header'};
+ my $footer = $buildconf->{'on_failure_footer'};
+ my $body = _make_body($header,$message, $tap, $footer);
+ my $summary = '';
+
+ if ( $tap =~ m/^(Test Summary Report.*)/ms ) {
+ $summary = $1;
+ }
+
+ # Expand placeholders in our failure email
+ $body =~ s/%%PROJECT%%/$project/g;
+ $body =~ s/%%SHA1%%/$sha1/g;
+ $body =~ s/%%SUMMARY%%/$summary/g;
+
+
+ my $stuff = Email::Stuff->from($buildconf->{'on_failure_from_email'})
+ # bug in Email::Stuff brakes chaining if $email is empty
+ ->to($email || " ")
+ ->cc($buildconf->{'on_failure_cc_email'})
+ ->text_body($body)
+ ->subject(
+ $buildconf->{'on_failure_subject_prefix'} . "$project @ $shortsha1 $message"
+ );
+ # Should we attach a build log for convenience?
+ # ->attach(io('dead_bunbun_faked.gif')->all,
+ # filename => 'dead_bunbun_proof.gif')
+ $self->{'last_email_sent'} = $stuff;
+
+ $stuff->send;
+
+ return $self;
+}
+
+1;
diff --git a/scripts/build-failed.sh b/scripts/build-failed.sh
index 1be5cd2..ebd098a 100755
--- a/scripts/build-failed.sh
+++ b/scripts/build-failed.sh
@@ -1,7 +1,14 @@
COMMITER=$1
-MESSAGE=$2
-OUTPUT=$3
-SHA=$4
-CC_EMAIL=$5
+PROJECT=$2
+MESSAGE=$3
+OUTPUT=$4
+SHA=$5
+CC_EMAIL=$6
-echo "Message:\n$MESSAGE\nTest Output:\n$OUTPUT\n" | mail -c "$CC_EMAIL" -s "[jitterbug] BUILD FAILED $SHA" $COMMITER
+echo "
+Message:
+$MESSAGE
+
+Test Output:
+$OUTPUT
+" | mail -c "$CC_EMAIL" -s "[jitterbug] FAIL $PROJECT @ $SHA" $COMMITER
diff --git a/scripts/capsule.sh b/scripts/capsule.sh
index 7411639..abc632d 100755
--- a/scripts/capsule.sh
+++ b/scripts/capsule.sh
@@ -3,27 +3,7 @@
# first arg: build_dir
# second arg: report path
-builddir=$1
-report_path=$2
-
-echo "Creating report_path=$report_path"
-mkdir -p $report_path
-
-cd $builddir
-
-source $HOME/perl5/perlbrew/etc/bashrc
-
-for perl in $HOME/perl5/perlbrew/perls/perl-5.*
-do
- theperl="$(basename $perl)"
-
- echo ">perlbrew switch $theperl"
- perlbrew switch $theperl
- # TODO: check error condition
-
- perlversion=$(perl -v)
- logfile="$report_path/$theperl.txt"
-
+function jitterbug_build () {
if [ -f 'dist.ini' ]; then
echo "Found dist.ini, using Dist::Zilla"
dzil authordeps | cpanm
@@ -35,11 +15,50 @@ do
# ./Build installdeps is not available in older Module::Build's
cpanm --installdeps .
HARNESS_VERBOSE=1 ./Build test --verbose >> $logfile 2>&1
- else
- echo "Hoping to find Makefile.PL"
+ elif [ -f 'Makefile.PL' ]; then
+ echo "Found Makefile.PL"
perl Makefile.PL
cpanm --installdeps .
- make
+ HARNESS_VERBOSE=1 make test >> $logfile 2>&1
+ elif [ -f 'setup.pir' ]; then
+ echo "Found setup.pir"
+ HARNESS_VERBOSE=1 parrot setup.pir test >> $logfile 2>&1
+ elif [ -f 'setup.nqp' ]; then
+ echo "Found setup.nqp"
+ HARNESS_VERBOSE=1 parrot-nqp setup.nqp test >> $logfile 2>&1
+ elif [ -f 'Configure.pl' ]; then
+ echo "Found Configure.pl"
+ perl Configure.pl
+ cpanm --installdeps .
HARNESS_VERBOSE=1 make test >> $logfile 2>&1
fi
-done
+}
+
+# this is getting smelly
+builddir=$1
+report_path=$2
+perlbrew=$3
+
+echo "Creating report_path=$report_path"
+mkdir -p $report_path
+
+cd $builddir
+
+if [ $use_perlbrew ]; then
+ source $HOME/perl5/perlbrew/etc/bashrc
+ for perl in $HOME/perl5/perlbrew/perls/perl-5.*
+ do
+ theperl=$(perl -e 'print $^V')
+ logfile="$report_path/perl-$theperl.txt"
+
+ echo ">perlbrew switch $theperl"
+ perlbrew switch $theperl
+ # TODO: check error condition
+
+ jitterbug_build
+ done
+else
+ theperl=$(perl -e 'print $^V')
+ logfile="$report_path/perl-$theperl.txt"
+ jitterbug_build
+fi
diff --git a/t/005_builder.t b/t/005_builder.t
index 15795d6..84e13ef 100644
--- a/t/005_builder.t
+++ b/t/005_builder.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use Test::Most tests => 7;
+use Test::Most tests => 9;
use Data::Dumper;
use jitterbug::Builder;
@@ -30,13 +30,45 @@ use jitterbug::Builder;
my $b = jitterbug::Builder->new();
isa_ok($b, 'jitterbug::Builder');
is($b->{'configfile'}, 't/data/test.yml');
- #warn Dumper [ $b ];
is($b->run, 0, '->run returns 0 in cron mode');
cmp_deeply($b->{'conf'}, {
- 'configfile' => 't/data/test.yml',
- 'cron' => 1,
- 'sleep' => undef
+ 'engines' => {
+ 'xslate' => {
+ 'type' => 'text',
+ 'path' => '/',
+ 'cache' => '0'
+ }
+ },
+ 'plugins' => {
+ 'DBIC' => {
+ 'schema' => {
+ 'connect_info' => [
+ 'dbi:SQLite:dbname=jitterbug.db'
+ ],
+ 'pckg' => 'jitterbug::Schema',
+ 'skip_automake' => '1'
+ }
+ }
+ },
+ 'jitterbug' => {
+ 'build_process' => {
+ 'on_failure' => './scripts/build-failed.sh',
+ 'builder' => './scripts/capsule.sh'
+ },
+ 'builder' => {},
+ 'reports' => {
+ 'dir' => '/tmp/jitterbug'
+ },
+ 'build' => {
+ 'dir' => '/tmp/build'
+ }
+ },
+ 'template' => 'xslate',
+ 'appname' => 'jitterbug',
+ 'layout' => 'main',
+ 'logger' => 'file',
+ 'builds_per_feed' => '5'
});
diff --git a/t/006_emailer.t b/t/006_emailer.t
new file mode 100644
index 0000000..44dd328
--- /dev/null
+++ b/t/006_emailer.t
@@ -0,0 +1,153 @@
+use strict;
+use warnings;
+use Test::Most tests => 9;
+use Data::Dumper;
+use Test::MockObject;
+
+use_ok "jitterbug::Emailer";
+
+sub setup {
+ my $buildconf = {
+ on_failure_from_email => 'bob@example.com',
+ on_failure_cc_email => 'steve@example.com',
+ on_failure_subject_prefix => 'BLARG ',
+ on_failure_header => "Summary:\n%%SUMMARY%%",
+ on_failure_footer => "FOOT",
+ };
+
+ my $conf = { jitterbug => { build_process => $buildconf } };
+ my $commit = Test::MockObject->new;
+ my $project = Test::MockObject->new;
+ my $task = Test::MockObject->new;
+
+ $project->mock('name', sub { 'ponie' });
+
+ $commit->mock('sha256', sub { 'c0decafe' });
+ $commit->mock('content', sub { '{ "message" : "blargly blarg" }' } );
+
+ $task->mock('commit', sub { $commit });
+ $task->mock('project', sub { $project });
+ return ($conf, $commit, $project, $task);
+}
+
+{
+ my ($conf, $commit, $project, $task) = setup();
+ my $tap = "THIS IS TAP";
+ my $e = jitterbug::Emailer->new($conf, $task, $tap);
+
+ isa_ok($e,'jitterbug::Emailer');
+ can_ok($e,qw/new run/);
+
+ $e->run;
+ my $email = $e->{'last_email_sent'}{'email'};
+ like($email->body, qr/THIS IS TAP/, 'email body looks right');
+
+ my $header = $email->{'header'};
+ isa_ok($header, 'Email::MIME::Header');
+
+ is($header->header_raw('cc'), 'steve@example.com', 'cc header');
+ like($header->header_raw('subject'), qr/BLARG ponie @ c0decafe blargly blarg/, 'subject header');
+ is($header->header_raw('from'), 'bob@example.com', 'from header');
+}
+
+{
+ my ($conf, $commit, $project, $task) = setup();
+ my $tap = <<TAP;
+Copying lib/Math/Primality/AKS.pm -> blib/lib/Math/Primality/AKS.pm
+Copying lib/Math/Primality/BigPolynomial.pm -> blib/lib/Math/Primality/BigPolynomial.pm
+Copying lib/Math/Primality.pm -> blib/lib/Math/Primality.pm
+Copying bin/primes.pl -> blib/script/primes.pl
+Copying bin/strong_psuedoprimes.pl -> blib/script/strong_psuedoprimes.pl
+# Testing Math::Primality 0.0401, Perl 5.010001, /usr/bin/perl
+t/00-load.t ......................
+1..1
+ok 1 - use Math::Primality;
+ok
+# Failed test '-1 is not prime'
+# at t/is_prime.t line 16.
+# Looks like you failed 1 test of 573.
+t/is_prime.t .....................
+1..6
+ok 1 - is_prime should handle Math::GMPz objects, three is prime
+ok 2 - 2 is prime
+ok 3 - 1 is not prime
+ok 4 - 0 is not prime
+not ok 5 - -1 is not prime
+ok 6 - blarg
+t/boilerplate.t ..................
+1..3
+ok 1 - README contains no boilerplate text
+ok 2 - Changes contains no boilerplate text
+ok 3 - lib/Math/Primality.pm contains no boilerplate text
+ok
+Test Summary Report
+-------------------
+t/is_prime.t (Wstat: 256 Tests: 573 Failed: 1)
+Failed test: 5
+Non-zero exit status: 1
+Failed 1/11 test programs. 1/2498 subtests failed.
+Files=11, Tests=2498, 3 wallclock secs ( 0.20 usr 0.04 sys + 2.99 cusr 0.18 csys = 3.41 CPU)
+Result: FAIL
+TAP
+ my $e = jitterbug::Emailer->new($conf, $task, $tap);
+ $e->run;
+ my $email = $e->{'last_email_sent'}{'email'};
+ my $body = <<EMAIL;
+Summary:
+Test Summary Report
+-------------------
+t/is_prime.t (Wstat: 256 Tests: 573 Failed: 1)
+Failed test: 5
+Non-zero exit status: 1
+Failed 1/11 test programs. 1/2498 subtests failed.
+Files=11, Tests=2498, 3 wallclock secs ( 0.20 usr 0.04 sys + 2.99 cusr 0.18 csys = 3.41 CPU)
+Result: FAIL
+
+Commit Message:
+blargly blarg
+
+TAP Output:
+Copying lib/Math/Primality/AKS.pm -> blib/lib/Math/Primality/AKS.pm
+Copying lib/Math/Primality/BigPolynomial.pm -> blib/lib/Math/Primality/BigPolynomial.pm
+Copying lib/Math/Primality.pm -> blib/lib/Math/Primality.pm
+Copying bin/primes.pl -> blib/script/primes.pl
+Copying bin/strong_psuedoprimes.pl -> blib/script/strong_psuedoprimes.pl
+# Testing Math::Primality 0.0401, Perl 5.010001, /usr/bin/perl
+t/00-load.t ......................
+1..1
+ok 1 - use Math::Primality;
+ok
+# Failed test '-1 is not prime'
+# at t/is_prime.t line 16.
+# Looks like you failed 1 test of 573.
+t/is_prime.t .....................
+1..6
+ok 1 - is_prime should handle Math::GMPz objects, three is prime
+ok 2 - 2 is prime
+ok 3 - 1 is not prime
+ok 4 - 0 is not prime
+not ok 5 - -1 is not prime
+ok 6 - blarg
+t/boilerplate.t ..................
+1..3
+ok 1 - README contains no boilerplate text
+ok 2 - Changes contains no boilerplate text
+ok 3 - lib/Math/Primality.pm contains no boilerplate text
+ok
+Test Summary Report
+-------------------
+t/is_prime.t (Wstat: 256 Tests: 573 Failed: 1)
+Failed test: 5
+Non-zero exit status: 1
+Failed 1/11 test programs. 1/2498 subtests failed.
+Files=11, Tests=2498, 3 wallclock secs ( 0.20 usr 0.04 sys + 2.99 cusr 0.18 csys = 3.41 CPU)
+Result: FAIL
+
+FOOT
+EMAIL
+
+ my $ebody = $email->body;
+ $ebody =~ s/\r\n/\n/g;
+ eq_or_diff($ebody, $body, 'email body has failure summary');
+
+}