summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore15
-rw-r--r--Build.PL43
-rw-r--r--MANIFEST42
-rw-r--r--MANIFEST.SKIP20
-rw-r--r--Makefile.PL31
-rw-r--r--README43
-rw-r--r--config.yml7
-rw-r--r--lib/jitterbug/Builder.pm172
-rw-r--r--lib/jitterbug/Emailer.pm78
-rwxr-xr-xscripts/build-failed.sh11
-rw-r--r--scripts/builder.pl77
-rwxr-xr-xscripts/capsule.sh69
-rw-r--r--t/001_base.t3
-rw-r--r--t/002_index_route.t1
-rw-r--r--t/005_builder.t76
-rw-r--r--t/006_emailer.t153
-rw-r--r--t/data/test.yml30
17 files changed, 740 insertions, 131 deletions
diff --git a/.gitignore b/.gitignore
index 7eb4e9c..afad8f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,15 @@
logs/*
-*.db \ No newline at end of file
+*.db
+*.sql
+blib/*
+pm_to_blib
+Makefile
+Makefile.old
+_build
+META.yml
+MYMETA.yml
+*.bak
+*.sw?
+Makefile.PL
+Build
+jitterbug.db
diff --git a/Build.PL b/Build.PL
new file mode 100644
index 0000000..063b3de
--- /dev/null
+++ b/Build.PL
@@ -0,0 +1,43 @@
+use strict;
+use warnings;
+use Module::Build;
+
+my $builder = Module::Build->new(
+ module_name => 'jitterbug',
+ license => 'perl',
+ dist_author => 'franck cuny <franck@lumberjaph.net>',
+ dist_abstract => 'Perl smoker that uses Dancer and git',
+ dist_version_from => 'lib/jitterbug.pm',
+ include_dirs => '',
+ build_requires => {
+ 'Test::Most' => 0,
+ 'Test::MockObject'=> 0,
+ },
+ requires => {
+ 'YAML' => 0,
+ 'Dancer' => 1.1810,
+ 'XML::Feed' => 0,
+ 'DateTime' => 0,
+ 'JSON' => 0,
+ 'Git::Repository' => 0,
+ 'YAML' => 0,
+ 'Dancer::Template::Xslate' => 0,
+ 'Dancer::Plugin::DBIC' => 0,
+ 'DBIx::Class' => 0,
+ 'SQL::Translator' => 0,
+ 'Digest::MD5' => 0,
+ 'App::perlbrew' => 0,
+ 'Dist::Zilla' => 0,
+ 'Email::Stuff' => 0,
+ },
+ add_to_cleanup => [ 'jitterbug-' ],
+ create_makefile_pl => 'traditional',
+ meta_merge => {
+ resources => {
+ repository => 'http://github.com/franckcuny/jitterbug/tree/master'
+ },
+ },
+);
+
+$builder->create_build_script();
+print "Have a great day!\n";
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..268d204
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,42 @@
+Build.PL
+config.yml
+eg/post_hook.t
+environments/development.yml
+environments/production.yml
+jitterbug.pl
+lib/jitterbug.pm
+lib/jitterbug/Hook.pm
+lib/jitterbug/Plugin/Template.pm
+lib/jitterbug/Project.pm
+lib/jitterbug/Schema.pm
+lib/jitterbug/Schema/Result/Commit.pm
+lib/jitterbug/Schema/Result/Project.pm
+lib/jitterbug/Schema/Result/Task.pm
+lib/jitterbug/Task.pm
+lib/jitterbug/WebService.pm
+Makefile
+MANIFEST This list of files
+MANIFEST.SKIP
+public/404.html
+public/500.html
+public/dispatch.cgi
+public/dispatch.fcgi
+public/favicon.ico
+public/images/feed.png
+public/images/perldancer-bg.jpg
+public/images/perldancer.jpg
+README
+scripts/builder.pl
+scripts/deploy_schema
+scripts/migrate_from_redis.pl
+t/001_base.t
+t/002_index_route.t
+t/003_hook_route.t
+t/004_project.t
+t/data/export_jitterbug.yml
+t/data/test.yaml
+TODO
+views/index.tt
+views/layouts/main.tt
+views/project/index.tt
+views/task/index.tt
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
new file mode 100644
index 0000000..7b521b7
--- /dev/null
+++ b/MANIFEST.SKIP
@@ -0,0 +1,20 @@
+\.git*
+tmp.*
+.*\.o
+\..*sw?
+\.bak
+_build
+^Build$
+blib/*
+.*\.data
+.*core
+foo*
+.*\.gz
+^tags
+jitterbug-\d+\..*
+.prove
+^MYMETA.yml$
+jitterbug.db
+logs/
+META.yml
+Makefile.PL
diff --git a/Makefile.PL b/Makefile.PL
deleted file mode 100644
index 880131b..0000000
--- a/Makefile.PL
+++ /dev/null
@@ -1,31 +0,0 @@
-use strict;
-use warnings;
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
- NAME => 'jitterbug',
- AUTHOR => q{franck cuny <franck@lumberjaph.net>},
- VERSION_FROM => 'lib/jitterbug.pm',
- ABSTRACT => 'perl/github smoker',
- ( $ExtUtils::MakeMaker::VERSION >= 6.3002
- ? ( 'LICENSE' => 'perl' )
- : () ),
- PL_FILES => {},
- PREREQ_PM => {
- 'Test::More' => 0,
- 'YAML' => 0,
- 'Dancer' => 1.1810,
- 'XML::Feed' => 0,
- 'DateTime' => 0,
- 'JSON' => 0,
- 'Git::Repository' => 0,
- 'YAML' => 0,
- 'Dancer::Template::Xslate' => 0,
- 'Dancer::Plugin::DBIC' => 0,
- 'DBIx::Class' => 0,
- 'SQL::Translator' => 0,
- 'Digest::MD5' => 0,
- },
- dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
- clean => { FILES => 'jitterbug-*' },
-);
diff --git a/README b/README
new file mode 100644
index 0000000..7139479
--- /dev/null
+++ b/README
@@ -0,0 +1,43 @@
+Jitterbug : A continuous integration system built on Dancer and git hooks
+
+Jitterbug is written in Perl 5 and depends on various CPAN modules, such
+as Dancer, DBIx::Class and Git::Repository.
+
+Installing Jitterbug
+===================
+
+perl Build.PL
+
+# You can also use Makefile.PL, but you will then have to manually
+# install dependencies
+# perl Makefile.PL
+
+# install missing dependencies
+./Build installdeps
+
+# start the jitterbug Dancer app, which by default binds to port 3000
+perl jitterbug.pl
+
+# If you need to start it on a different port use -p
+# perl jitterbug.pl -p 3001
+
+In another terminal, deploy a DBIx::Class schema ( which is SQLite by default,
+change the values in config.yml to tweak) :
+
+perl scripts/deploy_schema config.yml
+
+Now add a post-receive hook to your github project that hits the /hook/ URL
+on the server that the jitterbug Dancer app is running on, i.e.
+
+ http://example.com:3001/hook/
+
+Now you must start the builder, which actually clones a new git repo for
+each task (this could be network-intensive) and actually runs the build
+and test commands for each project.
+
+ perl scripts/builder.pl -c config.yml
+
+Now, when you commit to a project that has a Jitterbug post-receive hook,
+the builder check every 30 seconds for a new task and build and test your
+projects!
+
diff --git a/config.yml b/config.yml
index e4144c3..bf9bd23 100644
--- a/config.yml
+++ b/config.yml
@@ -18,6 +18,13 @@ jitterbug:
build_process:
builder: ./scripts/capsule.sh
on_failure: ./scripts/build-failed.sh
+ 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
new file mode 100644
index 0000000..a836f70
--- /dev/null
+++ b/lib/jitterbug/Builder.pm
@@ -0,0 +1,172 @@
+package jitterbug::Builder;
+
+use strict;
+use warnings;
+
+use YAML qw/LoadFile Dump/;
+use JSON;
+use File::Path qw/rmtree/;
+use Path::Class;
+use Getopt::Long qw/:config no_ignore_case/;
+use File::Basename;
+use Git::Repository;
+use jitterbug::Schema;
+#use Data::Dumper;
+
+local $| = 1;
+use constant DEBUG => 1;
+
+sub new {
+ my $self = bless {} => shift;
+
+ GetOptions(
+ 'C|cron' => \$self->{'cron'},
+ 'c|configfile=s' => \$self->{'configfile'},
+ 's|sleep=i' => \$self->{'sleep'},
+ ) or die "Cannot get options\n";
+
+ $self->{'configfile'}
+ or die qq{missing config.yml, use "-c config.yml" to help us find it\n};
+
+ die "Does not exist!: " . $self->{'configfile'} unless -e $self->{'configfile'};
+
+ return $self;
+}
+
+sub debug {
+ warn @_ if DEBUG;
+}
+
+sub run {
+ my $self = shift || die "Must call run() from object\n";
+ my $conf = $self->{'conf'} = LoadFile( $self->{'configfile'} );
+ my $dbix_conf = $conf->{'plugins'}{'DBIC'}{'schema'};
+
+ debug("Loaded config file: " . $self->{'configfile'});
+ debug("Connection Info: " . join ':', @{ $dbix_conf->{'connect_info'} });
+
+ $self->{'schema'} = jitterbug::Schema->connect( @{ $dbix_conf->{'connect_info'} } );
+ $self->{'interval'} = $self->{'sleep'} ||
+ $conf->{'jitterbug'}{'builder'}{'sleep'} ||
+ 30;
+
+ return $self->build;
+}
+
+sub build {
+ my $self = shift;
+
+ while (1) {
+ my @tasks = $self->{'schema'}->resultset('Task')->all();
+ debug("Found " . scalar(@tasks) . " tasks");
+
+ foreach my $task (@tasks) {
+ $task ? $self->run_task($task) : $self->sleep;
+ }
+
+ $self->{'cron'} and return 0;
+
+ $self->sleep(5);
+ }
+
+ return 1;
+}
+
+sub sleep {
+ my ($self, $interval) = @_;
+ $interval ||= $self->{'interval'};
+ debug("sleeping for $interval seconds\n");
+ sleep $interval;
+}
+
+sub run_task {
+ my $self = shift;
+ my ($task) = @_;
+ my $desc = JSON::decode_json( $task->commit->content );
+ my $conf = $self->{'conf'};
+
+ $desc->{'build'}{'start_time'} = time();
+ debug("Build Start");
+
+ my $report_path = dir(
+ $conf->{'jitterbug'}{'reports'}{'dir'},
+ $task->project->name,
+ $task->commit->sha256,
+ );
+
+ my $build_dir = dir(
+ $conf->{'jitterbug'}{'build'}{'dir'},
+ $task->project->name,
+ );
+
+ debug("Removing $build_dir");
+ rmtree($build_dir, { error => \my $err } );
+ warn @$err if @$err;
+
+ $self->sleep(1); # avoid race conditions
+
+ my $repo = $task->project->url . '.git';
+ my $r = Git::Repository->create( clone => $repo => $build_dir );
+
+ debug("Checking out " . $task->commit->sha256 . " from $repo into $build_dir\n");
+ $r->run( 'checkout', $task->commit->sha256 );
+
+ my $builder = $conf->{'jitterbug'}{'build_process'}{'builder'};
+
+ 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`;
+ debug($res);
+
+ $desc->{'build'}{'end_time'} = time();
+
+ my @versions = glob( $report_path . '/*' );
+ foreach my $version (@versions) {
+ open my $fh, '<', $version;
+ my ($result, $lines);
+ while (<$fh>){
+ $lines .= $_;
+ }
+ ($result) = $lines =~ /Result:\s(\w+)/;
+ my ( $name, ) = basename($version);
+ $name =~ s/\.txt//;
+ if ( !$result || ($result && $result !~ /PASS/ )) {
+ # mail author of the commit
+ $result = "FAIL";
+ my $message = $desc->{'message'};
+ my $commiter = $desc->{'author'}{'email'};
+ my $output = $lines;
+ my $sha = $desc->{'id'};
+ my $on_failure = $conf->{'jitterbug'}{'build_process'}{'on_failure'};
+ my $on_failure_cc_email = $conf->{'jitterbug'}{'build_process'}{'on_failure_email'};
+
+ $message =~ s/'/\\'/g; $commiter =~ s/'/\\'/g; $output =~ s/'/\\'/g;
+ 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");
+
+ # 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;
+ }
+
+ $task->commit->update( {
+ content => JSON::encode_json($desc),
+ } );
+ debug("Task completed for " . $task->commit->sha256 . "\n");
+
+ $task->delete();
+
+ debug("Task removed from " . $task->project->name . "\n");
+}
+
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 bddf4d0..ebd098a 100755
--- a/scripts/build-failed.sh
+++ b/scripts/build-failed.sh
@@ -1,11 +1,14 @@
COMMITER=$1
-MESSAGE=$2
-OUTPUT=$3
-SHA=$4
+PROJECT=$2
+MESSAGE=$3
+OUTPUT=$4
+SHA=$5
+CC_EMAIL=$6
echo "
Message:
$MESSAGE
+Test Output:
$OUTPUT
-" | mail -s "[jitterbug] BUILD FAILED $SHA" --to $COMMITER
+" | mail -c "$CC_EMAIL" -s "[jitterbug] FAIL $PROJECT @ $SHA" $COMMITER
diff --git a/scripts/builder.pl b/scripts/builder.pl
index fba8147..8b7ee2c 100644
--- a/scripts/builder.pl
+++ b/scripts/builder.pl
@@ -1,80 +1,9 @@
-#!/usr/bin/env perl
+#!/usr/bin/perl
use strict;
use warnings;
-use JSON;
-use YAML qw/LoadFile Dump/;
-use File::Spec;
-use File::Path qw/rmtree/;
-use File::Basename;
-use Git::Repository;
-use jitterbug::Schema;
+use jitterbug::Builder;
-$|++;
+exit jitterbug::Builder->new->run;
-my $conf_file = shift || die "config.yml is missing";
-my $conf = LoadFile($conf_file);
-my $dbix_conf = $conf->{plugins}->{DBIC}->{schema};
-my $schema = jitterbug::Schema->connect( @{ $dbix_conf->{connect_info} } );
-my $interval = $conf->{jitterbug}->{builder}->{sleep} || 30;
-
-while (1) {
- my $task = $schema->resultset('Task')->search()->single();
-
- unless ($task) {
- sleep $interval;
- next;
- }
-
- my $desc = JSON::decode_json($task->commit->content);
- $desc->{build}->{start_time} = time();
-
- my $report_path = File::Spec->catdir( $conf->{jitterbug}->{reports}->{dir},
- $task->project->name, $task->commit->sha256 );
- my $build_dir = File::Spec->catdir( $conf->{jitterbug}->{build}->{dir},
- $task->project->name );
-
- my $repo = $task->project->url . '.git';
- my $r = Git::Repository->create( clone => $repo => $build_dir );
- $r->run( 'checkout', $task->commit->sha256 );
-
- my $builder = $conf->{jitterbug}->{build_process}->{builder};
- my $res = `$builder $build_dir $report_path`;
-
- rmtree($build_dir);
-
- $desc->{build}->{end_time} = time();
-
- my @versions = glob( $report_path . '/*' );
- foreach my $version (@versions) {
- open my $fh, '<', $version;
- my ($result, $lines);
- while (<$fh>){
- $lines .= $_;
- }
- ($result) = $lines =~ /Result:\s(\w+)/;
- my ( $name, ) = basename($version);
- $name =~ s/\.txt//;
- if ( !$result || ($result && $result !~ /PASS/ )) {
- # mail author of the commit
- $result = "FAIL";
- my $message = $desc->{message};
- my $commiter = $desc->{author}->{email};
- my $output = "Build failed";
- my $sha = $desc->{id};
- my $on_failure =
- $conf->{jitterbug}->{build_process}->{on_failure};
- `$on_failure $commiter $message $output $sha`;
- }
- $desc->{build}->{version}->{$name} = $result;
- close $fh;
- }
-
- $task->commit->update({
- content => JSON::encode_json($desc),
- });
- $task->delete();
- warn "done\n";
- sleep 5;
-}
diff --git a/scripts/capsule.sh b/scripts/capsule.sh
index 1977313..abc632d 100755
--- a/scripts/capsule.sh
+++ b/scripts/capsule.sh
@@ -3,31 +3,62 @@
# first arg: build_dir
# second arg: report path
+function jitterbug_build () {
+ if [ -f 'dist.ini' ]; then
+ echo "Found dist.ini, using Dist::Zilla"
+ dzil authordeps | cpanm
+ cpanm --installdeps .
+ HARNESS_VERBOSE=1 dzil test >> $logfile 2>&1
+ elif [ -f 'Build.PL' ]; then
+ echo "Found Build.PL, using Build.PL"
+ perl Build.PL
+ # ./Build installdeps is not available in older Module::Build's
+ cpanm --installdeps .
+ HARNESS_VERBOSE=1 ./Build test --verbose >> $logfile 2>&1
+ elif [ -f 'Makefile.PL' ]; then
+ echo "Found Makefile.PL"
+ perl Makefile.PL
+ cpanm --installdeps .
+ 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
+}
+
+# this is getting smelly
builddir=$1
report_path=$2
+perlbrew=$3
+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)"
- perlbrew switch $theperl
+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"
- perlversion=$(perl -v)
- logfile="$report_path/$theperl.txt"
+ echo ">perlbrew switch $theperl"
+ perlbrew switch $theperl
+ # TODO: check error condition
- if [ -f 'dist.ini' ]; then
- dzil authordeps | cpanm
- cpanm --installdeps .
- HARNESS_VERBOSE=1 dzil test >> $logfile 2>&1
- else
- perl Makefile.PL
- cpanm --installdeps .
- make
- HARNESS_VERBOSE=1 make test >> $logfile 2>&1
- fi
-done
+ jitterbug_build
+ done
+else
+ theperl=$(perl -e 'print $^V')
+ logfile="$report_path/perl-$theperl.txt"
+ jitterbug_build
+fi
diff --git a/t/001_base.t b/t/001_base.t
index 936ffff..43163e6 100644
--- a/t/001_base.t
+++ b/t/001_base.t
@@ -1,5 +1,6 @@
-use Test::More tests => 1;
+use Test::More tests => 2;
use strict;
use warnings;
use_ok 'jitterbug';
+use_ok 'jitterbug::Builder';
diff --git a/t/002_index_route.t b/t/002_index_route.t
index 5c02d85..f6fe11b 100644
--- a/t/002_index_route.t
+++ b/t/002_index_route.t
@@ -3,7 +3,6 @@ use strict;
use warnings;
ok 1;
-ok 2;
# the order is important
#use jitterbug;
#use Dancer::Test;
diff --git a/t/005_builder.t b/t/005_builder.t
new file mode 100644
index 0000000..84e13ef
--- /dev/null
+++ b/t/005_builder.t
@@ -0,0 +1,76 @@
+
+use strict;
+use warnings;
+use Test::Most tests => 9;
+use Data::Dumper;
+
+use jitterbug::Builder;
+
+{
+ local @ARGV = qw(-c t/data/test.yml -C);
+ my $b = jitterbug::Builder->new();
+
+ isa_ok($b,'jitterbug::Builder');
+ can_ok($b,qw/run build run_task sleep/);
+
+ is($b->{'configfile'}, 't/data/test.yml');
+ is($b->{'cron'}, 1 );
+}
+
+{
+ local @ARGV = qw(-c blarg.yml -C);
+
+ throws_ok (sub {
+ my $b = jitterbug::Builder->new();
+ }, qr/Does not exist/i, 'nonexistent yaml file throws error');
+}
+
+{
+ local @ARGV = qw(-c t/data/test.yml -C);
+ my $b = jitterbug::Builder->new();
+ isa_ok($b, 'jitterbug::Builder');
+ is($b->{'configfile'}, 't/data/test.yml');
+
+ is($b->run, 0, '->run returns 0 in cron mode');
+ cmp_deeply($b->{'conf'}, {
+ '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');
+
+}
diff --git a/t/data/test.yml b/t/data/test.yml
new file mode 100644
index 0000000..e4144c3
--- /dev/null
+++ b/t/data/test.yml
@@ -0,0 +1,30 @@
+layout: "main"
+logger: "file"
+appname: "jitterbug"
+
+builds_per_feed: 5
+template: "xslate"
+engines:
+ xslate:
+ path: /
+ type: text
+ cache: 0
+
+jitterbug:
+ reports:
+ dir: /tmp/jitterbug
+ build:
+ dir: /tmp/build
+ build_process:
+ builder: ./scripts/capsule.sh
+ on_failure: ./scripts/build-failed.sh
+
+plugins:
+ DBIC:
+ schema:
+ skip_automake: 1
+ pckg: "jitterbug::Schema"
+ connect_info:
+ - dbi:SQLite:dbname=jitterbug.db
+
+