From 7e3bee05bb1abcae98b2a715edc6ea49c1dae9f6 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 4 Feb 2011 17:55:13 -0800 Subject: The start of factoring out a runner from a builder --- lib/jitterbug/Builder.pm | 183 ++++++++++++++--------------------------------- lib/jitterbug/Runner.pm | 165 ++++++++++++++++++++++++++++++++++++++++++ scripts/builder.pl | 9 --- scripts/runner.pl | 8 +++ t/005_builder.t | 37 +++------- t/006_runner.t | 24 +++++++ 6 files changed, 260 insertions(+), 166 deletions(-) create mode 100644 lib/jitterbug/Runner.pm delete mode 100644 scripts/builder.pl create mode 100644 scripts/runner.pl create mode 100644 t/006_runner.t diff --git a/lib/jitterbug/Builder.pm b/lib/jitterbug/Builder.pm index 6441c0d..15d94ec 100644 --- a/lib/jitterbug/Builder.pm +++ b/lib/jitterbug/Builder.pm @@ -11,6 +11,7 @@ use Getopt::Long qw/:config no_ignore_case/; use File::Basename; use Git::Repository; use jitterbug::Schema; +use Cwd; #use Data::Dumper; local $| = 1; @@ -19,144 +20,66 @@ 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'}; + $self->{'conf'} = LoadFile(shift); 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; + my ($self, $conf) = @_; + my ($builddir, $report_path, $perlbrew); + + print "Creating report_path=$report_path\n"; + system("mkdir -p $report_path"); + + die "Couldn't create $builddir !" unless -e $builddir; + my $cwd = getcwd; + chdir $builddir; + + if ($perlbrew) { + my $source_perlbrew = "source $ENV{HOME}/perl5/perlbrew/etc/bashrc"; + for my $perl ( glob "$ENV{HOME}/perl5/perlbrew/perls/perl-5.*" ) { + my $logfile = "$report_path/$perl.txt"; + system("$source_perlbrew && perlbrew switch $perl"); + $self->actually_build($logfile); } - - $self->{'cron'} and return 0; - - $self->sleep(5); + } else { + my $perl = $^V; + my $logfile = "$report_path/$perl.txt"; + $self->actually_build($logfile); } - - return 1; + chdir $cwd; } -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 = "Build failed"; - my $sha = $desc->{'id'}; - my $on_failure = - $conf->{'jitterbug'}{'build_process'}{'on_failure'}; - my $failure_cmd = "$on_failure $commiter $message $output $sha"; - debug("Running failure command: $failure_cmd"); - `$failure_cmd`; - } - $desc->{'build'}{'version'}{$name} = $result; - close $fh; +sub actually_build () { + my ($self, $logfile) = @_; + if ( -e 'dist.ini' ) { + print "Found dist.ini, using Dist::Zilla\n"; + my $cmd = <> $logfile 2>&1 +CMD + system $cmd; + } elsif ( -e 'Build.PL' ) { + print "Found Build.PL, using Build.PL\n"; + my $cmd = <> $logfile 2>&1 +CMD + system $cmd; + } elsif ( -e 'Makefile.PL') { + print "Hoping to find Makefile.PL\n"; + my $cmd = <> $logfile 2>&1 +CMD + system($cmd); + } else { + die "Don't know how to build or test this!"; } - - $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/Runner.pm b/lib/jitterbug/Runner.pm new file mode 100644 index 0000000..25e6850 --- /dev/null +++ b/lib/jitterbug/Runner.pm @@ -0,0 +1,165 @@ +package jitterbug::Runner; + +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'}; + + my $builder_command = "$builder $build_dir $report_path $perlbrew"; + + debug("Going to run builder : $builder_command"); + my $res = `$builder_command`; + debug($res); + my $runner = jitterbug::Runner->new($conf); + + $runner->build; + + $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'}; + my $failure_cmd = "$on_failure $commiter $message $output $sha"; + debug("Running failure command: $failure_cmd"); + `$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/scripts/builder.pl b/scripts/builder.pl deleted file mode 100644 index 8b7ee2c..0000000 --- a/scripts/builder.pl +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use jitterbug::Builder; - -exit jitterbug::Builder->new->run; - diff --git a/scripts/runner.pl b/scripts/runner.pl new file mode 100644 index 0000000..4354672 --- /dev/null +++ b/scripts/runner.pl @@ -0,0 +1,8 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use jitterbug::Runner; + +exit jitterbug::Runner->new->run; diff --git a/t/005_builder.t b/t/005_builder.t index 15795d6..24f1e13 100644 --- a/t/005_builder.t +++ b/t/005_builder.t @@ -1,44 +1,27 @@ use strict; use warnings; -use Test::Most tests => 7; +use Test::Most tests => 2; use Data::Dumper; -use jitterbug::Builder; +use jitterbug::Runner; { - local @ARGV = qw(-c t/data/test.yml -C); - my $b = jitterbug::Builder->new(); + local @ARGV = qw(-c t/data/test.yml); + my $r = jitterbug::Runner->new(); + isa_ok($r, 'jitterbug::Runner'); + warn Dumper [ $r ]; + is($r->{'configfile'}, 't/data/test.yml'); - isa_ok($b,'jitterbug::Builder'); - can_ok($b,qw/run build run_task sleep/); + system("$^X scripts/deploy_schema t/data/test.yml"); - is($b->{'configfile'}, 't/data/test.yml'); - is($b->{'cron'}, 1 ); -} - -{ - local @ARGV = qw(-c blarg.yml -C); + is($r->run, 0, '->run returns 0 in cron mode'); - 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'); - #warn Dumper [ $b ]; - - is($b->run, 0, '->run returns 0 in cron mode'); - cmp_deeply($b->{'conf'}, { + cmp_deeply($r->{'conf'}, { 'configfile' => 't/data/test.yml', 'cron' => 1, 'sleep' => undef }); - } diff --git a/t/006_runner.t b/t/006_runner.t new file mode 100644 index 0000000..b95abb2 --- /dev/null +++ b/t/006_runner.t @@ -0,0 +1,24 @@ + +use strict; +use warnings; +use Test::Most tests => 3; +use Data::Dumper; + +use jitterbug::Runner; + +{ + local @ARGV = qw(-c t/data/test.yml); + my $b = jitterbug::Runner->new(); + + isa_ok($b,'jitterbug::Runner'); + can_ok($b,qw/new run run_task sleep/); + +} + +{ + local @ARGV = qw(-c blarg.yml); + throws_ok (sub { + my $b = jitterbug::Runner->new('blarg.yml'); + }, qr/Does not exist/i, 'nonexistent yaml file throws error'); +} + -- cgit 1.4.1