about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonathan "Duke" Leto <jonathan@leto.net>2011-05-23 20:43:43 -0700
committerJonathan "Duke" Leto <jonathan@leto.net>2011-05-23 20:43:43 -0700
commit15e96b9f945f9d58ddbe07fab0b2d41474b05118 (patch)
treef7d0349fa5e8c5987e7da0c26022d385e82a8262
parentTeach capsule about HARNESS_TIMER (diff)
parentUnbreak capsule.sh (diff)
downloadjitterbug-15e96b9f945f9d58ddbe07fab0b2d41474b05118.tar.gz
Merge branch 'git_refactor'
-rw-r--r--.gitignore1
-rw-r--r--Build.PL36
-rw-r--r--lib/jitterbug/Builder.pm176
-rwxr-xr-xscripts/capsule.sh22
-rw-r--r--t/002_index_route.t4
-rw-r--r--t/003_hook_route.t10
-rw-r--r--t/005_builder.t4
-rw-r--r--t/008_git_clone.t65
-rw-r--r--t/data/hook_data.yml11
-rw-r--r--t/data/test.yml4
-rw-r--r--t/data/testing.git/config4
-rw-r--r--t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.idxbin5188 -> 0 bytes
-rw-r--r--t/data/testing.git/packed-refs2
-rw-r--r--t/data/testing/._git_/COMMIT_EDITMSG1
-rw-r--r--t/data/testing/._git_/HEAD (renamed from t/data/testing.git/HEAD)0
-rw-r--r--t/data/testing/._git_/MERGE_RR0
-rw-r--r--t/data/testing/._git_/config10
-rw-r--r--t/data/testing/._git_/description (renamed from t/data/testing.git/description)0
-rw-r--r--t/data/testing/._git_/hooks/.exists0
-rw-r--r--t/data/testing/._git_/indexbin0 -> 728 bytes
-rw-r--r--t/data/testing/._git_/info/exclude (renamed from t/data/testing.git/info/exclude)0
-rw-r--r--t/data/testing/._git_/logs/HEAD6
-rw-r--r--t/data/testing/._git_/logs/refs/heads/master6
-rw-r--r--t/data/testing/._git_/logs/refs/remotes/origin/master5
-rw-r--r--t/data/testing/._git_/objects/07/f62ec694f139bc628bd2b74944388aa1a358d3bin0 -> 81 bytes
-rw-r--r--t/data/testing/._git_/objects/09/6664a240206996cb54d94a5e1f3fe59e2b1cfebin0 -> 81 bytes
-rw-r--r--t/data/testing/._git_/objects/0f/453aedce353b474dc70bb333b683f5165165aebin0 -> 271 bytes
-rw-r--r--t/data/testing/._git_/objects/1b/6fca8292281a9b8f651b48183dc19b4555d5b7bin0 -> 81 bytes
-rw-r--r--t/data/testing/._git_/objects/29/2fa93528b7d6004fb9a130bce53ccf32f1b1f82
-rw-r--r--t/data/testing/._git_/objects/2a/1ac6de05e4b1af148497ba65c061a9e9ceeb38bin0 -> 169 bytes
-rw-r--r--t/data/testing/._git_/objects/3a/b75b9a29e09bf027f64250b44cab19b316c1281
-rw-r--r--t/data/testing/._git_/objects/41/5c331f9c82cd6788a1b3b09e408db631b12052bin0 -> 271 bytes
-rw-r--r--t/data/testing/._git_/objects/47/0a1cd6c98340735efc3040caaf42148f7b9c44bin0 -> 81 bytes
-rw-r--r--t/data/testing/._git_/objects/48/5351a500018fe2a6ba8ecbcddd40cef09542292
-rw-r--r--t/data/testing/._git_/objects/78/f22df1fb2f50acc05ee8e8586a72c2a68b86c6bin0 -> 271 bytes
-rw-r--r--t/data/testing/._git_/objects/88/a328dfa8d6c3a6b4e21d4a5a240dcfbe06a9f6bin0 -> 271 bytes
-rw-r--r--t/data/testing/._git_/objects/8c/011a49746b5c140aa2f1a907d2fe8c9fa297673
-rw-r--r--t/data/testing/._git_/objects/98/9b9ab3305277cb255f990651eb133f0a633cadbin0 -> 271 bytes
-rw-r--r--t/data/testing/._git_/objects/99/0856953bd0a5f8284e1bbeeb09e3d238337486bin0 -> 82 bytes
-rw-r--r--t/data/testing/._git_/objects/a8/c9f5ba5a4d87755da639b85f2ca35ea5ee56b3bin0 -> 179 bytes
-rw-r--r--t/data/testing/._git_/objects/b3/ef6519ad389c2d3a892791a8f048083e786f8dbin0 -> 181 bytes
-rw-r--r--t/data/testing/._git_/objects/db/803809a0e8f808d94e83857977758a61e80ff02
-rw-r--r--t/data/testing/._git_/objects/e5/e5ab2c0d36a219a999aa5b93a0c45977e4d06f4
-rw-r--r--t/data/testing/._git_/objects/fa/4485dfa3dab8dccd72c546af735725c2deddf22
-rw-r--r--t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.idxbin0 -> 4628 bytes
-rw-r--r--t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.pack (renamed from t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.pack)bin12344 -> 10773 bytes
-rw-r--r--t/data/testing/._git_/packed-refs2
-rw-r--r--t/data/testing/._git_/refs/heads/master1
-rw-r--r--t/data/testing/._git_/refs/remotes/origin/HEAD1
-rw-r--r--t/data/testing/._git_/refs/remotes/origin/master1
-rw-r--r--t/data/testing/.gitignore4
-rw-r--r--t/data/testing/Build.PL28
-rw-r--r--t/data/testing/README3
-rw-r--r--t/data/testing/boringemptyfile2
-rw-r--r--t/data/testing/foo.txt3
-rw-r--r--t/data/testing/shart.foo1
-rw-r--r--t/data/testing/t/data/answer_to_the_universe.txt1
-rw-r--r--t/data/testing/t/test.t16
-rw-r--r--t/data/testing/xt/borkborkbork.t2
-rw-r--r--views/project/index.tt2
60 files changed, 332 insertions, 118 deletions
diff --git a/.gitignore b/.gitignore
index 819baac..01c76da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ Build
 jitterbug.db
 MYMETA.json
 t/data/jitterbug.db
+t/tmp
diff --git a/Build.PL b/Build.PL
index 52158ee..a1b2814 100644
--- a/Build.PL
+++ b/Build.PL
@@ -15,23 +15,25 @@ my $builder = Module::Build->new(
         '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,
-        'DateTime::Format::SQLite' => 0,
-        'SQL::Translator'          => 0,
-        'Digest::MD5'              => 0,
-        'App::perlbrew'            => 0,
-        'Dist::Zilla'              => 0,
-        'Email::Stuff'             => 0,
-        'Time::Elapsed'            => 0,
+        'autodie'                        => 0,
+        'IPC::System::Simple'            => 0,
+        'IPC::Cmd'                       => 0,
+        'YAML'                           => 0,
+        'Dancer'                         => 1.1810,
+        'XML::Feed'                      => 0,
+        'DateTime'                       => 0,
+        'JSON'                           => 0,
+        'YAML'                           => 0,
+        'Dancer::Template::Xslate'       => 0,
+        'Dancer::Plugin::DBIC'           => 0,
+        'DBIx::Class'                    => 0,
+        'DateTime::Format::SQLite'       => 0,
+        'SQL::Translator'                => 0,
+        'Digest::MD5'                    => 0,
+        'App::perlbrew'                  => 0,
+        'Dist::Zilla'                    => 0,
+        'Email::Stuff'                   => 0,
+        'Time::Elapsed'                  => 0,
         'DBIx::Class::DeploymentHandler' => 0,
     },
     add_to_cleanup      => [ 'jitterbug-', catfile(qw/t data jitterbug.db/) ],
diff --git a/lib/jitterbug/Builder.pm b/lib/jitterbug/Builder.pm
index 1f9bd3d..ab96251 100644
--- a/lib/jitterbug/Builder.pm
+++ b/lib/jitterbug/Builder.pm
@@ -10,7 +10,7 @@ use File::Path qw/rmtree/;
 use Path::Class;
 use Getopt::Long qw/:config no_ignore_case/;
 use File::Basename;
-use Git::Repository;
+use File::Spec::Functions;
 use jitterbug::Schema;
 use Cwd;
 #use Data::Dumper;
@@ -81,75 +81,87 @@ sub sleep {
     sleep $interval;
 }
 
-sub run_task {
-    my ($self,$task)   = @_;
+sub _clone_into {
+    my ($repo, $dir) = @_;
+    my $pwd = getcwd;
+    chdir $dir;
 
-    my $desc    = JSON::decode_json( $task->commit->content );
-    my $conf    = $self->{'conf'};
-    my $buildconf = $conf->{'jitterbug'}{'build_process'};
-    my $project = $task->project;
+    debug("cloning $repo into $dir");
+    system("git clone $repo $dir");
 
-    my $dt = DateTime->now();
-    $task->update({started_when => $dt});
-    $desc->{'build'}{'start_time'} = $dt->epoch;
-    debug("Build Start");
+    chdir $pwd;
+}
 
-    my $report_path = dir(
-        $conf->{'jitterbug'}{'reports'}{'dir'},
-        $project->name,
-        $task->commit->sha256,
-    );
-    my $dir = $conf->{'jitterbug'}{'build'}{'dir'};
-    mkdir $dir unless -d $dir;
+sub _prepare_git_repo {
+    my ($self, $task, $buildconf, $build_dir, $cached_repo_dir) = @_;
 
-    my $build_dir = dir($dir, $project->name);
+    my $repo    = $task->project->url;
+    my $name    = $task->project->name;
 
-    my $r;
-    my $repo    = $task->project->url . '.git';
+    debug("Removing $build_dir");
+    rmtree($build_dir, { error => \my $err } );
+    warn @$err if @$err;
+
+    # If we aren't reusing/caching git repos, clone from remote into the build dir
     unless ($buildconf->{reuse_repo}) {
-        debug("Removing $build_dir");
-        rmtree($build_dir, { error => \my $err } );
-        warn @$err if @$err;
-        $r       = Git::Repository->create( clone => $repo => $build_dir );
+        _clone_into($repo, $build_dir);
     } else {
-        # If this is the first time, the repo won't exist yet
+        # We are caching git repos, so we clone a new repo from our local
+        # cached git repo, then checkout the correct sha1
+
         debug("build_dir = $build_dir");
-        if( -d $build_dir ){
-            my $pwd = getcwd;
-            chdir $build_dir;
-            # TODO: Error Checking
-            debug("Cleaning git repo");
-            system("git clean -dfx");
-            debug("Fetching new commits into $repo");
-            system("git fetch");
-            debug("Checking out correct commit");
-            system("git checkout " . $task->commit->sha256 );
-            chdir $pwd;
-        } else {
-            debug("Creating new repo");
-            my $pwd = getcwd;
-            debug("pwd=$pwd");
-            chdir $build_dir;
-            system("git clone $repo $build_dir");
-            chdir $pwd;
+        mkdir $cached_repo_dir unless -d $cached_repo_dir;
+        my $cached_repo = catfile($cached_repo_dir,$name);
+
+        unless ( -d $cached_repo ) {
+            # If this is the first time, the repo won't exist yet
+            # Clone it into our cached repo directory
+            _clone_into($repo, $cached_repo);
         }
+        my $pwd = getcwd;
+
+        chdir $cached_repo;
+        # TODO: Error Checking
+
+        debug("Fetching new commits into $cached_repo");
+        system("git fetch --prune");
+
+        $self->sleep(1); # avoid race conditions
+
+        debug("Cloning from cached repo $cached_repo_dir/$name into $build_dir");
+        _clone_into(catdir($cached_repo_dir,$name), $build_dir);
+        chdir $build_dir;
+
+        $self->sleep(1); # avoid race conditions
+
+        # TODO: this may fail on non-unixy systems
+        debug("checking out " . $task->commit->sha256);
+        system("git checkout " . $task->commit->sha256 . "&>/dev/null" );
+
+        chdir $pwd;
     }
-    $self->sleep(1); # avoid race conditions
+}
 
-    debug("Checking out " . $task->commit->sha256 . " from $repo into $build_dir\n");
-    # $r->run( 'checkout', $task->commit->sha256 );
-    my $pwd = getcwd;
-    chdir $build_dir;
-    system("git checkout " . $task->commit->sha256 );
-    chdir $pwd;
+sub build_task {
+    my ($self, $conf, $project, $task, $report_path) = @_;
+
+    my $buildconf = $conf->{'jitterbug'}{'build_process'};
+    my $dir       = $conf->{'jitterbug'}{'build'}{'dir'};
+
+    mkdir $dir unless -d $dir;
+
+    my $build_dir = dir($dir, $project->name);
+    my $cached_repo_dir = dir($dir, 'cached');
+
+    mkdir $cached_repo_dir unless -d $cached_repo_dir;
+
+    $self->_prepare_git_repo($task, $buildconf, $build_dir, $cached_repo_dir);
 
     my $builder       =    $conf->{'jitterbug'}{'projects'}{$project->name}{'builder'}
                         || $conf->{'jitterbug'}{'build_process'}{'builder'};
 
     my $perlbrew      = $conf->{'jitterbug'}{'options'}{'perlbrew'};
-    my $email_on_pass = $conf->{'jitterbug'}{'options'}{'email_on_pass'};
 
-    debug("email_on_pass = $email_on_pass");
     debug("perlbrew      = $perlbrew");
 
     # If the project has custom builder variables, use those. Otherwise, use the global setting
@@ -161,9 +173,47 @@ sub run_task {
     debug("Going to run builder : $builder_command");
     my $res             = `$builder_command`;
     debug($res);
+    return $res;
+}
+
+sub run_task {
+    my ($self,$task)   = @_;
+
+    my $desc    = JSON::decode_json( $task->commit->content );
+    my $conf    = $self->{'conf'};
+    my $project = $task->project;
+    my $report_path = dir(
+        $conf->{'jitterbug'}{'reports'}{'dir'},
+        $project->name,
+        $task->commit->sha256,
+    );
+
+    my $dt = DateTime->now();
+    $task->update({started_when => $dt});
+    $desc->{'build'}{'start_time'} = $dt->epoch;
+    debug("Build Start");
+
+    $self->build_task($conf, $project, $task, $report_path);
 
     $desc->{'build'}{'end_time'} = time();
 
+    $self->_parse_results($report_path, $conf, $task, $desc);
+
+    $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");
+}
+
+sub _parse_results {
+    my ($self, $report_path, $conf, $task, $desc) = @_;
+    my $email_on_pass = $conf->{'jitterbug'}{'options'}{'email_on_pass'};
+    debug("email_on_pass = $email_on_pass");
+
     my @versions = glob( $report_path . '/*' );
     foreach my $version (@versions) {
         open my $fh, '<', $version;
@@ -193,15 +243,15 @@ sub run_task {
             my $on_failure_cc_email = $conf->{'jitterbug'}{'build_process'}{'on_failure_cc_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,'failure')->run;
             } else {
+                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");
+
                 system($failure_cmd);
             }
         } elsif ($email_on_pass) {
@@ -215,8 +265,6 @@ sub run_task {
             my $on_pass_cc_email = $conf->{'jitterbug'}{'build_process'}{'on_pass_cc_email'};
 
             $message  =~ s/'/\\'/g; $commiter =~ s/'/\\'/g; $output =~ s/'/\\'/g;
-            my $pass_cmd = sprintf("%s '%s' %s '%s' '%s' %s %s", $on_pass, $commiter, $task->project->name, $message, $output, $sha, $on_pass_cc_email);
-            debug("Running pass command: $pass_cmd");
 
             # does it look like a module name?
             if ($on_pass =~ /::/) {
@@ -224,20 +272,12 @@ sub run_task {
                 eval "require $on_pass";
                 $on_pass->new($conf,$task,$output, 'pass')->run;
             } else {
+                my $pass_cmd = sprintf("%s '%s' %s '%s' '%s' %s %s", $on_pass, $commiter, $task->project->name, $message, $output, $sha, $on_pass_cc_email);
+                debug("Running pass command: $pass_cmd");
                 system($pass_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/scripts/capsule.sh b/scripts/capsule.sh
index a47972a..548780e 100755
--- a/scripts/capsule.sh
+++ b/scripts/capsule.sh
@@ -9,14 +9,12 @@ builddir=$1
 report_path=$2
 perlbrew=$3
 
-HARNESS_OPTS="HARNESS_VERBOSE=1 HARNESS_TIMER=1"
-
 function jitterbug_build () {
     if [ -f 'dist.ini' ]; then
         echo "Found dist.ini, using Dist::Zilla"
         dzil authordeps | cpanm >> $logfile 2>&1
         cpanm --installdeps . >> $logfile 2>&1
-        $HARNESS_OPTS dzil test >> $logfile  2>&1
+        HARNESS_VERBOSE=1 HARNESS_TIMER=1 dzil test >> $logfile  2>&1
     elif [ -f 'Build.PL' ]; then
         echo "Found Build.PL, using Build.PL"
         perl Build.PL >> $logfile 2>&1
@@ -24,23 +22,23 @@ function jitterbug_build () {
         cpanm --installdeps . >> $logfile 2>&1
         # Run this again in case our Build is out of date (suboptimal)
         perl Build.PL >> $logfile 2>&1
-        $HARNESS_OPTS ./Build test --verbose >> $logfile 2>&1
+        HARNESS_VERBOSE=1 HARNESS_TIMER=1 ./Build test --verbose >> $logfile 2>&1
     elif [ -f 'Makefile.PL' ]; then
         echo "Found Makefile.PL"
         perl Makefile.PL >> $logfile 2>&1
         cpanm --installdeps . >> $logfile 2>&1
-        $HARNESS_OPTS make test >> $logfile 2>&1
+        HARNESS_VERBOSE=1 HARNESS_TIMER=1 make test >> $logfile 2>&1
     elif [ -f 'setup.pir' ]; then
         echo "Found setup.pir"
-        $HARNESS_OPTS parrot setup.pir test >> $logfile 2>&1
+        HARNESS_VERBOSE=1 HARNESS_TIMER=1 parrot setup.pir test >> $logfile 2>&1
     elif [ -f 'setup.nqp' ]; then
         echo "Found setup.nqp"
-        $HARNESS_OPTS parrot-nqp setup.nqp test >> $logfile 2>&1
+        HARNESS_VERBOSE=1 HARNESS_TIMER=1 parrot-nqp setup.nqp test >> $logfile 2>&1
     elif [ -f 'Configure.pl' ]; then
         echo "Found Configure.pl"
         perl Configure.pl >> $logfile 2>&1
         cpanm --installdeps . >> $logfile 2>&1
-        $HARNESS_OPTS make test >> $logfile 2>&1
+        HARNESS_VERBOSE=1 HARNESS_TIMER=1 make test >> $logfile 2>&1
     elif [ -f 'Makefile' ]; then
         echo "Found a Makefile"
         make test >> $logfile 2>&1
@@ -49,7 +47,6 @@ function jitterbug_build () {
     fi
 }
 
-
 echo "Creating report_path=$report_path"
 mkdir -p $report_path
 
@@ -62,6 +59,9 @@ if [ $use_perlbrew ]; then
         theperl=$(perl -e 'print $^V')
         logfile="$report_path/perl-$theperl.txt"
 
+        mkdir -p $report_path
+        touch $logfile
+
         echo ">perlbrew switch $theperl"
         perlbrew switch $theperl
         # TODO: check error condition
@@ -71,5 +71,9 @@ if [ $use_perlbrew ]; then
 else
         theperl=$(perl -e 'print $^V')
         logfile="$report_path/perl-$theperl.txt"
+
+        mkdir -p $report_path
+        touch $logfile
+
         jitterbug_build
 fi
diff --git a/t/002_index_route.t b/t/002_index_route.t
index 2a9092e..868298e 100644
--- a/t/002_index_route.t
+++ b/t/002_index_route.t
@@ -13,5 +13,5 @@ jitterbug::Test->init();
 route_exists          [ GET => '/' ], 'a route handler is defined for /';
 response_status_is    [ GET => '/' ], 200, 'response status is 200 for /';
 response_content_like [ GET => '/' ], qr/Dashboard/, 'content looks OK for /';
-response_content_like [ GET => '/' ], qr/Repositories \(0\)/, 'no repositories';
-response_content_like [ GET => '/' ], qr/Builds pending \(0\)/, 'no repositories';
+response_content_like [ GET => '/' ], qr/Repositories \(\d+\)/, 'repositories';
+response_content_like [ GET => '/' ], qr/Builds pending \(\d+\)/, 'pending builds';
diff --git a/t/003_hook_route.t b/t/003_hook_route.t
index 0361b15..6e86dfd 100644
--- a/t/003_hook_route.t
+++ b/t/003_hook_route.t
@@ -44,7 +44,7 @@ my $response;
 }
 
 {
-    my $rs = $schema->resultset('Project')->find( { name => 'Dancer' } );
+    my $rs = $schema->resultset('Project')->find( { name => 'testing' } );
     ok !defined $rs, 'no project dancer yet';
 
     $response = dancer_response(
@@ -58,11 +58,11 @@ my $response;
 
     is $response->{status}, 200, 'status OK with payload';
     is_deeply JSON::decode_json( $response->{content} ),
-      { updated => 'Dancer' }, 'response OK with payload';
+      { updated => 'testing' }, 'response OK with payload';
 
-    $rs = $schema->resultset('Project')->find( { name => 'Dancer' } );
+    $rs = $schema->resultset('Project')->find( { name => 'testing' } );
     ok $rs, 'project exists in DB';
-    is $rs->name, 'Dancer', 'project\'s name is good';
+    is $rs->name, 'testing', 'project\'s name is good';
 
     is $schema->resultset('Task')->search()->count(), 1, 'one task created';
 }
@@ -90,7 +90,7 @@ my $response;
     $schema->resultset('Task')->search()->delete();
 
     # testing with invalid global branch
-    setting jitterbug => { branches => { Dancer => ['foo'], }, };
+    setting jitterbug => { branches => { testing => ['foo'], }, };
     $content->{ref} = 'refs/heads/foo';
     $response = dancer_response(
         POST => '/hook/',
diff --git a/t/005_builder.t b/t/005_builder.t
index 603001a..7888417 100644
--- a/t/005_builder.t
+++ b/t/005_builder.t
@@ -58,7 +58,7 @@ jitterbug::Test->init();
                          },
             'jitterbug' => {
                              'build_process' => {
-                                                'on_failure' => './scripts/build-failed.sh',
+                                                'on_failure' => 'jitterbug::Emailer',
                                                 'builder' => './scripts/capsule.sh',
                                                 'builder_variables' => 'STUFF=BLAH',
                                                 'on_pass_header' => undef,
@@ -72,7 +72,7 @@ jitterbug::Test->init();
                                                 'on_pass_to_email' => undef,
                                                 'on_pass_from_email' => 'donotreply@example.com',
                                                 'on_failure_cc_email' => 'alice@example.com',
-                                                'on_pass' => './scripts/build-pass.sh',
+                                                'on_pass' => 'jitterbug::Emailer',
                                                 'on_pass_subject_prefix' => '[jitterbug] PASS '
                                               },
                              'builder' => {},
diff --git a/t/008_git_clone.t b/t/008_git_clone.t
new file mode 100644
index 0000000..6733a14
--- /dev/null
+++ b/t/008_git_clone.t
@@ -0,0 +1,65 @@
+use Test::More tests => 4;
+use Test::Exception;
+use strict;
+use warnings;
+use autodie qw/:all/;
+use IPC::Cmd qw/can_run/;
+
+use jitterbug;
+use jitterbug::Schema;
+use lib 't/lib';
+use jitterbug::Test;
+
+use JSON;
+use YAML qw/LoadFile Dump/;
+
+use File::Spec;
+use File::Temp qw/tempdir/;
+
+use Dancer::Test;
+use Dancer::Config qw/setting/;
+use File::Spec::Functions;
+use File::Copy::Recursive qw/dircopy/;
+use File::Path qw/rmtree/;
+
+my $hook_data = catfile(qw/t data hook_data.yml/);
+
+my $content = LoadFile($hook_data);
+
+my $db_dir = tempdir( CLEANUP => 1 );
+my $db_file = File::Spec->catfile( $db_dir, 'jitterbug.db' );
+my $dsn     = 'dbi:SQLite:dbname=' . $db_file;
+my $schema  = jitterbug::Schema->connect($dsn);
+$schema->deploy;
+
+setting plugins => {
+    DBIC => {
+        schema => {
+            skip_automake => 1,
+            pckg          => "jitterbug::Schema",
+            connect_info  => [$dsn]
+        }
+    }
+};
+
+rmtree(catfile(qw/t tmp build testing/));
+
+if (can_run('git')){
+
+    my $gitrepo = "t/data/testing";
+    dircopy "$gitrepo/._git_", "$gitrepo/.git" unless -e "$gitrepo/.git";
+
+    lives_ok sub { system("$^X -Ilib scripts/post_to_hook.pl") }, 'post_to_hook.pl lives';
+
+
+    lives_ok sub { $ENV{DEBUG} = 1;
+        system("$^X -Ilib scripts/builder.pl -c t/data/test.yml -C")
+    }, 'builder.pl lives';
+
+    ok(-e "t/tmp/build/testing/.git", 'found a testing git repo');
+    chdir "t/tmp/build/testing";
+    chomp( my $sha1 = qx{git rev-parse HEAD} );
+    is($sha1,"3ab75b9a29e09bf027f64250b44cab19b316c128", "got expected sha1 in repo");
+} else {
+    skip "Git not available, skipping tests", 3;
+}
diff --git a/t/data/hook_data.yml b/t/data/hook_data.yml
index da5b78f..a55d7e9 100644
--- a/t/data/hook_data.yml
+++ b/t/data/hook_data.yml
@@ -8,16 +8,15 @@ commits:
     author: 
       email: franck@lumberjaph.net
       name: franck cuny
-    #id: 8c3c1d6be0fa27ada4f03258ddea7683c967a925
-    id: ba54d9b7d82eabe4ba35ec212eb24d00869119d5
+    id: 3ab75b9a29e09bf027f64250b44cab19b316c128
     message: test
     modified: 
       - lib/Dancer.pm
     removed: []
 
     timestamp: 2010-09-23T08:04:42-07:00
-    url: https://github.com/franckcuny/Dancer/commit/22116bcdb229c1514f3069aaaf9c87e9d5455409
-compare: https://github.com/franckcuny/Dancer/compare/db8d023...22116bc
+    url: https://github.com/franckcuny/testing/commit/22116bcdb229c1514f3069aaaf9c87e9d5455409
+compare: https://github.com/franckcuny/testing/compare/db8d023...22116bc
 forced: !!perl/scalar:JSON::XS::Boolean 0
 pusher: 
   email: franck@lumberjaph.net
@@ -32,12 +31,12 @@ repository:
   has_issues: !!perl/scalar:JSON::XS::Boolean 0
   has_wiki: !!perl/scalar:JSON::XS::Boolean 1
   homepage: ''
-  name: Dancer
+  name: testing
   open_issues: 0
   owner: 
     email: franck@lumberjaph.net
     name: franckcuny
   private: !!perl/scalar:JSON::XS::Boolean 1
   pushed_at: 2010/09/23 08:04:49 -0700
-  url: ./t/data/testing.git
+  url: ./t/data/testing
   watchers: 1
diff --git a/t/data/test.yml b/t/data/test.yml
index 98f8e65..eab52c3 100644
--- a/t/data/test.yml
+++ b/t/data/test.yml
@@ -18,14 +18,14 @@ jitterbug:
   build_process:
     builder: ./scripts/capsule.sh
     builder_variables: STUFF=BLAH
-    on_failure: ./scripts/build-failed.sh
+    on_failure: "jitterbug::Emailer"
     on_failure_to_email: bob@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:
-    on_pass: ./scripts/build-pass.sh
+    on_pass: "jitterbug::Emailer"
     on_pass_to_email:
     on_pass_cc_email: alice@example.com
     on_pass_subject_prefix: "[jitterbug] PASS "
diff --git a/t/data/testing.git/config b/t/data/testing.git/config
deleted file mode 100644
index 07d359d..0000000
--- a/t/data/testing.git/config
+++ /dev/null
@@ -1,4 +0,0 @@
-[core]
-	repositoryformatversion = 0
-	filemode = true
-	bare = true
diff --git a/t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.idx b/t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.idx
deleted file mode 100644
index f03f9d2..0000000
--- a/t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.idx
+++ /dev/null
Binary files differdiff --git a/t/data/testing.git/packed-refs b/t/data/testing.git/packed-refs
deleted file mode 100644
index 4a1d788..0000000
--- a/t/data/testing.git/packed-refs
+++ /dev/null
@@ -1,2 +0,0 @@
-# pack-refs with: peeled 
-3ab75b9a29e09bf027f64250b44cab19b316c128 refs/heads/master
diff --git a/t/data/testing/._git_/COMMIT_EDITMSG b/t/data/testing/._git_/COMMIT_EDITMSG
new file mode 100644
index 0000000..333796c
--- /dev/null
+++ b/t/data/testing/._git_/COMMIT_EDITMSG
@@ -0,0 +1 @@
+WTF has left the building
diff --git a/t/data/testing.git/HEAD b/t/data/testing/._git_/HEAD
index cb089cd..cb089cd 100644
--- a/t/data/testing.git/HEAD
+++ b/t/data/testing/._git_/HEAD
diff --git a/t/data/testing/._git_/MERGE_RR b/t/data/testing/._git_/MERGE_RR
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/t/data/testing/._git_/MERGE_RR
diff --git a/t/data/testing/._git_/config b/t/data/testing/._git_/config
new file mode 100644
index 0000000..dc3e3df
--- /dev/null
+++ b/t/data/testing/._git_/config
@@ -0,0 +1,10 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = false
+[remote "origin"]
+	fetch = +refs/heads/*:refs/remotes/origin/*
+	url = git@github.com:solgenomics/testing.git
+[branch "master"]
+	remote = origin
+	merge = refs/heads/master
diff --git a/t/data/testing.git/description b/t/data/testing/._git_/description
index 498b267..498b267 100644
--- a/t/data/testing.git/description
+++ b/t/data/testing/._git_/description
diff --git a/t/data/testing/._git_/hooks/.exists b/t/data/testing/._git_/hooks/.exists
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/t/data/testing/._git_/hooks/.exists
diff --git a/t/data/testing/._git_/index b/t/data/testing/._git_/index
new file mode 100644
index 0000000..f59ebea
--- /dev/null
+++ b/t/data/testing/._git_/index
Binary files differdiff --git a/t/data/testing.git/info/exclude b/t/data/testing/._git_/info/exclude
index a5196d1..a5196d1 100644
--- a/t/data/testing.git/info/exclude
+++ b/t/data/testing/._git_/info/exclude
diff --git a/t/data/testing/._git_/logs/HEAD b/t/data/testing/._git_/logs/HEAD
new file mode 100644
index 0000000..ae4f6bf
--- /dev/null
+++ b/t/data/testing/._git_/logs/HEAD
@@ -0,0 +1,6 @@
+0000000000000000000000000000000000000000 c4a7a4eadada751c2592ace0f18742f2eeacf51e Jonathan "Duke" Leto <jonathan@leto.net> 1303416725 -0700	clone: from git://github.com/solgenomics/testing.git
+c4a7a4eadada751c2592ace0f18742f2eeacf51e e5e5ab2c0d36a219a999aa5b93a0c45977e4d06f Jonathan "Duke" Leto <jonathan@leto.net> 1303416792 -0700	commit: Faily McFailpants
+e5e5ab2c0d36a219a999aa5b93a0c45977e4d06f 485351a500018fe2a6ba8ecbcddd40cef0954229 Jonathan "Duke" Leto <jonathan@leto.net> 1303416941 -0700	commit: fail harder
+485351a500018fe2a6ba8ecbcddd40cef0954229 8c011a49746b5c140aa2f1a907d2fe8c9fa29767 Jonathan "Duke" Leto <jonathan@leto.net> 1303417074 -0700	commit: fail harderer
+8c011a49746b5c140aa2f1a907d2fe8c9fa29767 2a1ac6de05e4b1af148497ba65c061a9e9ceeb38 Jonathan "Duke" Leto <jonathan@leto.net> 1303417238 -0700	commit: fail uselessly
+2a1ac6de05e4b1af148497ba65c061a9e9ceeb38 3ab75b9a29e09bf027f64250b44cab19b316c128 Jonathan "Duke" Leto <jonathan@leto.net> 1303850277 -0700	commit: WTF has left the building
diff --git a/t/data/testing/._git_/logs/refs/heads/master b/t/data/testing/._git_/logs/refs/heads/master
new file mode 100644
index 0000000..ae4f6bf
--- /dev/null
+++ b/t/data/testing/._git_/logs/refs/heads/master
@@ -0,0 +1,6 @@
+0000000000000000000000000000000000000000 c4a7a4eadada751c2592ace0f18742f2eeacf51e Jonathan "Duke" Leto <jonathan@leto.net> 1303416725 -0700	clone: from git://github.com/solgenomics/testing.git
+c4a7a4eadada751c2592ace0f18742f2eeacf51e e5e5ab2c0d36a219a999aa5b93a0c45977e4d06f Jonathan "Duke" Leto <jonathan@leto.net> 1303416792 -0700	commit: Faily McFailpants
+e5e5ab2c0d36a219a999aa5b93a0c45977e4d06f 485351a500018fe2a6ba8ecbcddd40cef0954229 Jonathan "Duke" Leto <jonathan@leto.net> 1303416941 -0700	commit: fail harder
+485351a500018fe2a6ba8ecbcddd40cef0954229 8c011a49746b5c140aa2f1a907d2fe8c9fa29767 Jonathan "Duke" Leto <jonathan@leto.net> 1303417074 -0700	commit: fail harderer
+8c011a49746b5c140aa2f1a907d2fe8c9fa29767 2a1ac6de05e4b1af148497ba65c061a9e9ceeb38 Jonathan "Duke" Leto <jonathan@leto.net> 1303417238 -0700	commit: fail uselessly
+2a1ac6de05e4b1af148497ba65c061a9e9ceeb38 3ab75b9a29e09bf027f64250b44cab19b316c128 Jonathan "Duke" Leto <jonathan@leto.net> 1303850277 -0700	commit: WTF has left the building
diff --git a/t/data/testing/._git_/logs/refs/remotes/origin/master b/t/data/testing/._git_/logs/refs/remotes/origin/master
new file mode 100644
index 0000000..aa2dfd5
--- /dev/null
+++ b/t/data/testing/._git_/logs/refs/remotes/origin/master
@@ -0,0 +1,5 @@
+c4a7a4eadada751c2592ace0f18742f2eeacf51e e5e5ab2c0d36a219a999aa5b93a0c45977e4d06f Jonathan "Duke" Leto <jonathan@leto.net> 1303416798 -0700	update by push
+e5e5ab2c0d36a219a999aa5b93a0c45977e4d06f 485351a500018fe2a6ba8ecbcddd40cef0954229 Jonathan "Duke" Leto <jonathan@leto.net> 1303416947 -0700	update by push
+485351a500018fe2a6ba8ecbcddd40cef0954229 8c011a49746b5c140aa2f1a907d2fe8c9fa29767 Jonathan "Duke" Leto <jonathan@leto.net> 1303417078 -0700	update by push
+8c011a49746b5c140aa2f1a907d2fe8c9fa29767 2a1ac6de05e4b1af148497ba65c061a9e9ceeb38 Jonathan "Duke" Leto <jonathan@leto.net> 1303417242 -0700	update by push
+2a1ac6de05e4b1af148497ba65c061a9e9ceeb38 3ab75b9a29e09bf027f64250b44cab19b316c128 Jonathan "Duke" Leto <jonathan@leto.net> 1303850282 -0700	update by push
diff --git a/t/data/testing/._git_/objects/07/f62ec694f139bc628bd2b74944388aa1a358d3 b/t/data/testing/._git_/objects/07/f62ec694f139bc628bd2b74944388aa1a358d3
new file mode 100644
index 0000000..286b46b
--- /dev/null
+++ b/t/data/testing/._git_/objects/07/f62ec694f139bc628bd2b74944388aa1a358d3
Binary files differdiff --git a/t/data/testing/._git_/objects/09/6664a240206996cb54d94a5e1f3fe59e2b1cfe b/t/data/testing/._git_/objects/09/6664a240206996cb54d94a5e1f3fe59e2b1cfe
new file mode 100644
index 0000000..040b932
--- /dev/null
+++ b/t/data/testing/._git_/objects/09/6664a240206996cb54d94a5e1f3fe59e2b1cfe
Binary files differdiff --git a/t/data/testing/._git_/objects/0f/453aedce353b474dc70bb333b683f5165165ae b/t/data/testing/._git_/objects/0f/453aedce353b474dc70bb333b683f5165165ae
new file mode 100644
index 0000000..44e0480
--- /dev/null
+++ b/t/data/testing/._git_/objects/0f/453aedce353b474dc70bb333b683f5165165ae
Binary files differdiff --git a/t/data/testing/._git_/objects/1b/6fca8292281a9b8f651b48183dc19b4555d5b7 b/t/data/testing/._git_/objects/1b/6fca8292281a9b8f651b48183dc19b4555d5b7
new file mode 100644
index 0000000..a4c6ae2
--- /dev/null
+++ b/t/data/testing/._git_/objects/1b/6fca8292281a9b8f651b48183dc19b4555d5b7
Binary files differdiff --git a/t/data/testing/._git_/objects/29/2fa93528b7d6004fb9a130bce53ccf32f1b1f8 b/t/data/testing/._git_/objects/29/2fa93528b7d6004fb9a130bce53ccf32f1b1f8
new file mode 100644
index 0000000..119115a
--- /dev/null
+++ b/t/data/testing/._git_/objects/29/2fa93528b7d6004fb9a130bce53ccf32f1b1f8
@@ -0,0 +1,2 @@
+xMO
+0j-hl`=TVZ	DM.,2E-q4kt	m+]'Y ṗ|hc aQ>3GVF
xj٥-p!kϨR_[c{~TUgVxڐI$
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/2a/1ac6de05e4b1af148497ba65c061a9e9ceeb38 b/t/data/testing/._git_/objects/2a/1ac6de05e4b1af148497ba65c061a9e9ceeb38
new file mode 100644
index 0000000..c7c80ea
--- /dev/null
+++ b/t/data/testing/._git_/objects/2a/1ac6de05e4b1af148497ba65c061a9e9ceeb38
Binary files differdiff --git a/t/data/testing/._git_/objects/3a/b75b9a29e09bf027f64250b44cab19b316c128 b/t/data/testing/._git_/objects/3a/b75b9a29e09bf027f64250b44cab19b316c128
new file mode 100644
index 0000000..567ad5c
--- /dev/null
+++ b/t/data/testing/._git_/objects/3a/b75b9a29e09bf027f64250b44cab19b316c128
@@ -0,0 +1 @@
+xj0EW٧,J@#iq!vw0CdM,b	RH.<%AiISѳKv]3M=9٨ha^87l+oeOXv-tlCTT:0L\d`H8]?5Qr
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/41/5c331f9c82cd6788a1b3b09e408db631b12052 b/t/data/testing/._git_/objects/41/5c331f9c82cd6788a1b3b09e408db631b12052
new file mode 100644
index 0000000..fd62d13
--- /dev/null
+++ b/t/data/testing/._git_/objects/41/5c331f9c82cd6788a1b3b09e408db631b12052
Binary files differdiff --git a/t/data/testing/._git_/objects/47/0a1cd6c98340735efc3040caaf42148f7b9c44 b/t/data/testing/._git_/objects/47/0a1cd6c98340735efc3040caaf42148f7b9c44
new file mode 100644
index 0000000..7784e00
--- /dev/null
+++ b/t/data/testing/._git_/objects/47/0a1cd6c98340735efc3040caaf42148f7b9c44
Binary files differdiff --git a/t/data/testing/._git_/objects/48/5351a500018fe2a6ba8ecbcddd40cef0954229 b/t/data/testing/._git_/objects/48/5351a500018fe2a6ba8ecbcddd40cef0954229
new file mode 100644
index 0000000..409faa2
--- /dev/null
+++ b/t/data/testing/._git_/objects/48/5351a500018fe2a6ba8ecbcddd40cef0954229
@@ -0,0 +1,2 @@
+xK
+0@]{eKL)VBzEWsl<nZU>pfD\J%zfjD=J$*ҙTh (,,2`SRa썬mX*\Y 3l/CpӶY	,!yB4{e`i5oNK@
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/78/f22df1fb2f50acc05ee8e8586a72c2a68b86c6 b/t/data/testing/._git_/objects/78/f22df1fb2f50acc05ee8e8586a72c2a68b86c6
new file mode 100644
index 0000000..600a8a5
--- /dev/null
+++ b/t/data/testing/._git_/objects/78/f22df1fb2f50acc05ee8e8586a72c2a68b86c6
Binary files differdiff --git a/t/data/testing/._git_/objects/88/a328dfa8d6c3a6b4e21d4a5a240dcfbe06a9f6 b/t/data/testing/._git_/objects/88/a328dfa8d6c3a6b4e21d4a5a240dcfbe06a9f6
new file mode 100644
index 0000000..581809d
--- /dev/null
+++ b/t/data/testing/._git_/objects/88/a328dfa8d6c3a6b4e21d4a5a240dcfbe06a9f6
Binary files differdiff --git a/t/data/testing/._git_/objects/8c/011a49746b5c140aa2f1a907d2fe8c9fa29767 b/t/data/testing/._git_/objects/8c/011a49746b5c140aa2f1a907d2fe8c9fa29767
new file mode 100644
index 0000000..85b02f6
--- /dev/null
+++ b/t/data/testing/._git_/objects/8c/011a49746b5c140aa2f1a907d2fe8c9fa29767
@@ -0,0 +1,3 @@
+xK
+1]N3Aą+	~T-i4pV$ȁs
+#~myHչv(ꤏ2h)ֳ̘s[#6.N,m-ͬmk&}6a\0JZLY
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/98/9b9ab3305277cb255f990651eb133f0a633cad b/t/data/testing/._git_/objects/98/9b9ab3305277cb255f990651eb133f0a633cad
new file mode 100644
index 0000000..3d3d3dc
--- /dev/null
+++ b/t/data/testing/._git_/objects/98/9b9ab3305277cb255f990651eb133f0a633cad
Binary files differdiff --git a/t/data/testing/._git_/objects/99/0856953bd0a5f8284e1bbeeb09e3d238337486 b/t/data/testing/._git_/objects/99/0856953bd0a5f8284e1bbeeb09e3d238337486
new file mode 100644
index 0000000..ed39330
--- /dev/null
+++ b/t/data/testing/._git_/objects/99/0856953bd0a5f8284e1bbeeb09e3d238337486
Binary files differdiff --git a/t/data/testing/._git_/objects/a8/c9f5ba5a4d87755da639b85f2ca35ea5ee56b3 b/t/data/testing/._git_/objects/a8/c9f5ba5a4d87755da639b85f2ca35ea5ee56b3
new file mode 100644
index 0000000..1994521
--- /dev/null
+++ b/t/data/testing/._git_/objects/a8/c9f5ba5a4d87755da639b85f2ca35ea5ee56b3
Binary files differdiff --git a/t/data/testing/._git_/objects/b3/ef6519ad389c2d3a892791a8f048083e786f8d b/t/data/testing/._git_/objects/b3/ef6519ad389c2d3a892791a8f048083e786f8d
new file mode 100644
index 0000000..a630600
--- /dev/null
+++ b/t/data/testing/._git_/objects/b3/ef6519ad389c2d3a892791a8f048083e786f8d
Binary files differdiff --git a/t/data/testing/._git_/objects/db/803809a0e8f808d94e83857977758a61e80ff0 b/t/data/testing/._git_/objects/db/803809a0e8f808d94e83857977758a61e80ff0
new file mode 100644
index 0000000..28ad90b
--- /dev/null
+++ b/t/data/testing/._git_/objects/db/803809a0e8f808d94e83857977758a61e80ff0
@@ -0,0 +1,2 @@
+xMO
+0j4UP롂Jn$I,2C8_*C%&b5~tS	2pHrm,I=<#9-<pH i`Tm `N'uT6ÇV^0_TEؿۻ5HH
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/e5/e5ab2c0d36a219a999aa5b93a0c45977e4d06f b/t/data/testing/._git_/objects/e5/e5ab2c0d36a219a999aa5b93a0c45977e4d06f
new file mode 100644
index 0000000..e4a7843
--- /dev/null
+++ b/t/data/testing/._git_/objects/e5/e5ab2c0d36a219a999aa5b93a0c45977e4d06f
@@ -0,0 +1,4 @@
+x;
+ADL;?A@DwvYۻ7
+W
+DH +-`,9H	)6GA{J䅎cRpabcAz`UUh6ϫ4`yۈ*7sbZ Lm?tOU
O.
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/fa/4485dfa3dab8dccd72c546af735725c2deddf2 b/t/data/testing/._git_/objects/fa/4485dfa3dab8dccd72c546af735725c2deddf2
new file mode 100644
index 0000000..5c3cf2c
--- /dev/null
+++ b/t/data/testing/._git_/objects/fa/4485dfa3dab8dccd72c546af735725c2deddf2
@@ -0,0 +1,2 @@
+xMOM@켿b0
+u	ChddD{`޼y̛bTWV#g*"T\hXc$҆2U(AF=AG?sa/YK6qxy8jȥ`<\	L
6SN!)nDXM}4~_GI
\ No newline at end of file
diff --git a/t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.idx b/t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.idx
new file mode 100644
index 0000000..33bb5bc
--- /dev/null
+++ b/t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.idx
Binary files differdiff --git a/t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.pack b/t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.pack
index 6d0725c..d5b5462 100644
--- a/t/data/testing.git/objects/pack/pack-298dcfe572066343c474309f9e4bb06ea58d811d.pack
+++ b/t/data/testing/._git_/objects/pack/pack-7b6bf2b12062edba443050763835539d044a98f8.pack
Binary files differdiff --git a/t/data/testing/._git_/packed-refs b/t/data/testing/._git_/packed-refs
new file mode 100644
index 0000000..3f001b9
--- /dev/null
+++ b/t/data/testing/._git_/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled 
+c4a7a4eadada751c2592ace0f18742f2eeacf51e refs/remotes/origin/master
diff --git a/t/data/testing/._git_/refs/heads/master b/t/data/testing/._git_/refs/heads/master
new file mode 100644
index 0000000..4022448
--- /dev/null
+++ b/t/data/testing/._git_/refs/heads/master
@@ -0,0 +1 @@
+3ab75b9a29e09bf027f64250b44cab19b316c128
diff --git a/t/data/testing/._git_/refs/remotes/origin/HEAD b/t/data/testing/._git_/refs/remotes/origin/HEAD
new file mode 100644
index 0000000..6efe28f
--- /dev/null
+++ b/t/data/testing/._git_/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/t/data/testing/._git_/refs/remotes/origin/master b/t/data/testing/._git_/refs/remotes/origin/master
new file mode 100644
index 0000000..4022448
--- /dev/null
+++ b/t/data/testing/._git_/refs/remotes/origin/master
@@ -0,0 +1 @@
+3ab75b9a29e09bf027f64250b44cab19b316c128
diff --git a/t/data/testing/.gitignore b/t/data/testing/.gitignore
new file mode 100644
index 0000000..b85a126
--- /dev/null
+++ b/t/data/testing/.gitignore
@@ -0,0 +1,4 @@
+_build/
+Build
+MYMETA.yml
+*.sw?
diff --git a/t/data/testing/Build.PL b/t/data/testing/Build.PL
new file mode 100644
index 0000000..1443b82
--- /dev/null
+++ b/t/data/testing/Build.PL
@@ -0,0 +1,28 @@
+use strict;
+use warnings;
+use Module::Build;
+
+my $builder = Module::Build->new(
+    module_name         => 'testing',
+    license             => 'perl',
+    dist_author         => 'The Gods Themselves',
+    dist_abstract       => 'This universe is only a test',
+    dist_version        => 1,
+    include_dirs        => '',
+    build_requires => {
+        'Test::More'      => 0,
+    },
+    requires => {
+        'YAML'                     => 0,
+    },
+    add_to_cleanup      => [ '' ],
+    create_makefile_pl  => 'traditional',
+    meta_merge     => {
+        resources => {
+            repository  => 'http://github.com/solgenomics/testing/tree/master'
+        },
+    },
+);
+
+$builder->create_build_script();
+print "Have a great day!\n";
diff --git a/t/data/testing/README b/t/data/testing/README
new file mode 100644
index 0000000..58db14a
--- /dev/null
+++ b/t/data/testing/README
@@ -0,0 +1,3 @@
+THIS IS FOR TESTING PURPOSES : NOT TO BE USED FOR NON-TESTING PURPOSES
+
+THIS IS ONLY A TEST
diff --git a/t/data/testing/boringemptyfile b/t/data/testing/boringemptyfile
new file mode 100644
index 0000000..4e56a60
--- /dev/null
+++ b/t/data/testing/boringemptyfile
@@ -0,0 +1,2 @@
+LIES
+asdf
diff --git a/t/data/testing/foo.txt b/t/data/testing/foo.txt
new file mode 100644
index 0000000..7ee6fc0
--- /dev/null
+++ b/t/data/testing/foo.txt
@@ -0,0 +1,3 @@
+alskddjfalsdkdjfasldkffj
+blarg
+This is for realz.
diff --git a/t/data/testing/shart.foo b/t/data/testing/shart.foo
new file mode 100644
index 0000000..0d9a10b
--- /dev/null
+++ b/t/data/testing/shart.foo
@@ -0,0 +1 @@
+4242242
diff --git a/t/data/testing/t/data/answer_to_the_universe.txt b/t/data/testing/t/data/answer_to_the_universe.txt
new file mode 100644
index 0000000..d81cc07
--- /dev/null
+++ b/t/data/testing/t/data/answer_to_the_universe.txt
@@ -0,0 +1 @@
+42
diff --git a/t/data/testing/t/test.t b/t/data/testing/t/test.t
new file mode 100644
index 0000000..fa4485d
--- /dev/null
+++ b/t/data/testing/t/test.t
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+
+print "# Testing on Perl ($^X) $]\n";
+
+print "1..100\n";
+print "ok 1\n";
+print "i am not ok your not ok\n";
+print "NOT OK 42, HUT HUT\n";
+
+for (2 .. 100) {
+    print "ok $_ - stuff\n";
+}
+
+1/exp(1/0);
+exit "WTF";
diff --git a/t/data/testing/xt/borkborkbork.t b/t/data/testing/xt/borkborkbork.t
new file mode 100644
index 0000000..d1e26cf
--- /dev/null
+++ b/t/data/testing/xt/borkborkbork.t
@@ -0,0 +1,2 @@
+BORK BORK BORK
+The Internet Is Serious Business
diff --git a/views/project/index.tt b/views/project/index.tt
index f8d0ea2..92ef7a2 100644
--- a/views/project/index.tt
+++ b/views/project/index.tt
@@ -28,7 +28,7 @@
               <br />
               <div class="builds">
                 :for $commit.build.version.keys() -> $version {
-                  <a href="<: $uri_base :>/api/build/<: $project.name :>/<: $commit.id :>/<: $version :>"><: $version :></a> <span class="<: $commit.build.version[$version] :>"><: $commit.build.version[$version] :></span>
+                  <a href="/api/build/<: $project.name :>/<: $commit.id :>/<: $version :>"><: $version :></a> <span class="<: $commit.build.version[$version] :>"><: $commit.build.version[$version] :></span>
                 :}
               </div>
             </div>