Basic .NET builds using Rake

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:

  • DaveSquared.SampleProject
    • build
      • rakefile.rb
    • src
      • DaveSquared.SampleProject.Tests
      • DaveSquared.SampleProject.Web
      • DaveSquared.SampleProject.sln
    • tools
      • NUnit

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.

Comments