diff options
author | Jonathan "Duke" Leto <jonathan@leto.net> | 2011-01-19 13:04:42 -0800 |
---|---|---|
committer | Jonathan "Duke" Leto <jonathan@leto.net> | 2011-01-19 13:04:42 -0800 |
commit | 05c0a17eabb8cb52535ca1ae30fcf8ce0906f5c3 (patch) | |
tree | 7a782c216051e366c215ad902571d34cf2939a17 | |
parent | Attempt to fix the mangled build failure email bug (diff) | |
parent | Fix a jitterbug::Emailer test (diff) | |
download | jitterbug-05c0a17eabb8cb52535ca1ae30fcf8ce0906f5c3.tar.gz |
Merge branch 'refactor_builder'
Conflicts: config.yml lib/jitterbug/Builder.pm scripts/build-failed.sh
-rw-r--r-- | Build.PL | 2 | ||||
-rw-r--r-- | config.yml | 8 | ||||
-rw-r--r-- | lib/jitterbug/Builder.pm | 20 | ||||
-rw-r--r-- | lib/jitterbug/Emailer.pm | 78 | ||||
-rwxr-xr-x | scripts/build-failed.sh | 17 | ||||
-rwxr-xr-x | scripts/capsule.sh | 69 | ||||
-rw-r--r-- | t/005_builder.t | 42 | ||||
-rw-r--r-- | t/006_emailer.t | 153 |
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'); + +} |