Build bot
Another job for myself as part of the Games Project was to set up automatic building of our master repository branch whenever anyone committed new code. Unfortunately, due to our game being developed for Windows (using Visual Studio) and there being a security restriction stopping us SSH’ing into the machines, I was unable to set up building upon commit.
I eventually decided that the next best thing would be to use Scheduled Tasks to first do a pull from the remote repository, and then if there were any changes, attempt to build the solution. The task was set up so that it would run every 15 minutes and it runs even when none of the group are logged into the machine.
The next step was to write the script that would do the pull from the repository and then call the Visual Studio MSBuild tool. Here was where I ran into a number of issues. The git package (msysgit) we had set up on the machine is basically git compiled using MinGW with a small shell. Unfortunately it seemed that it doesn’t like to launch the command prompt as you would normally. For example, the following code simply leaves you at a command prompt instead of printing “pie” and returning you to the bash shell:
cmd /C echo pie
Eventually I found that you could get the desired behaviour with some quoting like so:
"cmd" "/C echo pie"
Now that I was able to launch the command prompt (and therefore batch scripts), I had to create a batch script which would first call the Visual Studio vsvars32.bat script which sets the environment variables for Visual Studio. The script then makes a call to msbuild to compile the solution and exits with the return code from msbuild.
@echo off @call "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat" msbuild "%~f1" exit %ERRORLEVEL%
Now that I could build solutions from the bash shell, all that was left was to write a perl script (msysgit includes perl) which would handle the calls to git. For the most part this was reasonably easy despite perl’s confusing syntax ($_, $? etc), but I ran into a hitch when I got to the part where I wanted to send the email. Initially I tried to use the CPAN Email::Send::Gmail module but it turns out it relies on the IO::Socket::SSL module which can’t handle timeouts due to IO::Socket::INET not supporting non-blocking sockets on Windows (see http://cpansearch.perl.org/src/SULLR/IO-Socket-SSL-1.38/README.Win32). It also turns out that although msysgit includes perl, it barely includes any modules so I was going to have to add tonnes of dependencies. Instead, I found mailsend which allowed me to easily send emails via a gmail account I set up on my domain.
#!/usr/bin/perl
use strict;
use warnings;
sub trim{
my $string = shift;
$string =~ s/^\s+|\s+$//g;
return $string;
}
# Check we're on the master branch
`git checkout -q master`;
my $gitOutput = qx(git pull);
open FILE, "<buildBot.cfg" or die $!;
if ($gitOutput eq "Already up-to-date.\n")
{
print "\nNo new commits, exiting\n";
}
else
{
print "\nNew commits, commencing automated build\n\n";
# Here we'll actually do the build attempts
my @failures = ();
my $output;
my @temp;
while (<FILE>)
{
# Only examine non-comments
if (substr($_, 0, 1) ne "#" && $_ ne "")
{
print "Now building $_\n";
$output = `"cmd" "/C buildSolution.bat ../$_"`;
for (my $i = 0; $i < 5; $i++) {
$output =~ s/.*?\n//;
}
if (($? >>=8) != 0)
{
@temp = ($_, $output);
push(@failures, [@temp]);
}
}
}
if (@failures > 0)
{
# Get the current revision from git
my $revision = trim(`git log --no-merges --format="%H" -1`);
my $author = trim(`git log --no-merges --format="%aN" -1`);
my $commitMessage = trim(`git log --format="%s" --no-merges -1`);
my $subject = "[BloodBrothers Build Bot Alert] Automated building failed at revision $revision";
my $message = "Automated building failed for revision $revision\n\nThis was probably caused by a commit by $author with log message:\n\"$commitMessage\"\n\nThe following solutions failed to build:\n";
# Build string representing failures for email
foreach my $solution (@failures)
{
$message .= @$solution[0] . "\n";
}
$message .= "\nLogs for failed solutions:\n";
foreach my $solution (@failures)
{
$message .= "------------------------------------------------------------\n" . @$solution[0] . "\n------------------------------------------------------------\n";
$message .= @$solution[1] . "\n";
}
# Call mailsend (eating it's output)
open(PIPE, "| mailsend -t \"to\@somewhere.com\" -f \"buildbot\@somewhere.com\" -smtp smtp.gmail.com -port 587 -sub \"$subject\" -from \"buildbot\@somewhere.com\" +cc +bc -starttls -auth -user \"buildbot\@somewhere.com\" -pass \"password\"");
print PIPE $message;
close(PIPE);
}
}
exit 0;
All done!
Latest tweet
- I just unlocked the "Swimmies" badge on @foursquare! Splish splash! http://t.co/6aR4sPlb
Categories


