I was starting up a new hobby project the other night and thought I’d try using Rake to script my build (instead of pure MSBuild, Nant, or just plain VS). Now Ruby and I generally don’t get on too well, so I was really surprised with how easy I found it to setup, and even more surprised with how much I enjoyed it. :)
Prerequisites
Um, Ruby. The installer I used gave me Ruby with Rake included. We’ll also need a simple .NET solution. I created one with a structure that looked a bit like this:
The SLN file contains two projects, DaveSquared.SampleProject.Tests
and .Web
. The .Tests
project references the .Web
project, as well as the NUnit framework buried somewhere in the tools/NUnit
directory. Both projects where configured to build to the build/output
directory (so .Tests
will build to build/output/DaveSquared.SampleProject.Tests
).
We can now setup our rakefile.rb
, which I’ve plonked into the build
directory. We’ll run the build from this directory, so we can specify all our paths relative to this build file.
Basic build and test run
After reading Dave Laribee’s post on OMG Rake!, and Mark Guzman’s excellent post on Building .NET projects with rake, I then proceeded to ruin all their good work by patching bits and pieces of their posts together and got this:
require 'rake/clean' DOT_NET_PATH = "#{ENV["SystemRoot"]}\\Microsoft.NET\\Framework\\v3.5" NUNIT_EXE = "../tools/Nunit/bin/nunit-console.exe" SOURCE_PATH = "../src" OUTPUT_PATH = "output" CONFIG = "Debug" CLEAN.include(OUTPUT_PATH) task :default => ["clean", "build:all"] namespace :build do task :all => [:compile, :test] desc "Build solutions using MSBuild" task :compile do solutions = FileList["#{SOURCE_PATH}/**/*.sln"] solutions.each do |solution| sh "#{DOT_NET_PATH}/msbuild.exe /p:Configuration=#{CONFIG} #{solution}" end end desc "Runs tests with NUnit" task :test => [:compile] do tests = FileList["#{OUTPUT_PATH}/**/*.Tests.dll"].exclude(/obj\//) sh "#{NUNIT_EXE} #{tests} /nologo /xml=#{OUTPUT_PATH}/TestResults.xml" end end
Now the good thing about this is that I don’t think you need to know much (any? I know virtually none) Ruby to understand what is going on here, or even to make basic modifications to the tasks (although it might be a struggle if you haven’t used build tools like make
or nant before). But you can bring the full power of the language to bear when you need it. Let’s have a quick step through the main parts of the file.
The first line imports rake/clean
, which lets us use CLEAN.include(OUTPUT_PATH)
to tidy up for us. We’ve then got loads of constants to specify various paths: the location of .NET tools like msbuild
, and the relative paths to NUnit, our source, and our output. Our :default
task is set to run clean
, then build:all
(the => syntax translates to depends on in make
terms, so to run the default task rake will make sure its dependencies are run).
If we drop into the :build
namespace, we have :all
, :compile
and :test
tasks defined. To :compile
, we use the wonderful FileList
class built into rake to get all *.sln
files in our source directory, then shell out to msbuild
to take care of the hardwork of compiling everything. The :test
task relies on convention, by finding all *.Tests.dll
files and running them through NUnit. We also make sure that :test
won’t run until :compile
has run by setting :compile
as a dependency.
Finally, our :all
task compiles and tests the build.
Running our rake build
By dropping into our build directory from the command line, just typing rake
will pickup our rakefile.rb
and execute our default task, which will clean, compile and test our build. We can also run a task at a time, say rake clean
, or rake build:test
(the :test
task is prefixed by build
because of its namespace).
There’s obviously tonnes we could do to make this nicer (like using Mark’s .NET tasks, and/or removing the hard-coded Debug configuration), but hopefully this gives people a quick way to start getting into rake and ruby for building .NET projects.