Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 3

This is the third part of my documentation of how I have put up a Continuous integration (CI) flow with TeamCity, Rake, Albacore, GitHub and NUnit for a .Net project.

What do I want to achieve?

In the previous part I prepared my solution to be built from TeamCity; by using Albacore to orchestra a bunch of rake tasks. In this part, I will set up a project in our TeamCity installation, and let it checkout the code from our GitHub repository and execute our rake tasks to build, test and package the binaries as a ZIP- and a NuGet package.

Upgrade TeamCity

First, there has come an upgrade of TeamCity, and since I still have a very clean TeamCity environment on my CI server I decided to upgrade it by doing a reinstall. More information about the recommended process of how to upgrade, could be found here: http://confluence.jetbrains.net/display/TCD65/Upgrade#Upgrade-win

Let the CI server manage build numbers

In my previous article I wanted my Albacore tasks to manage as much as possible, and I used version bumper and a VERSION file to bump the versions. This has been replaced and is now controlled by the CI server instead. This is something I have done so that I only need read access to my GitHub repository from my CI server.

Create a folder sturcture for the project

At the CI server I’ve decided to have some control of where files and folders are created. For this purpose I’ve created the following directories:

Builds: This is where the result of each individual build for the PineCone project will end up.
Checkout: This is where the files checked out from the GitHub repository will end up.
VCSRoot: Contains files/folders for managing the integration with GitHub.

Note! Checkout and VCSRoot is maintained by TeamCity and is nothing you need to maintain, just now that it’s there.

Create a project in TeamCity

I hope the screenshots talk for themselves. If not comment the article and I will insert explanations (if I can).


Log in


Create project


Name it


Add VCS Root


Create new VCS Root


Configure VCS Root
Note here that I’m using readonly and anonymous access which is feasible, since it’s a public project and I don’t want the CI server to push anything to my repository. This is probably something that I will change in the future, when I wan’t labels etc. created by the CI server.



Back to General tab


Create new build configuration


General settings
Since I have removed the version bumper and the VERSION file I know let the CI server handle the generation of build numbers. This is later on passed in to our rake tasks.


I have also specified a specific Checkout directory, just for the sake of having some control of the files needed for building the PineCone project.


Create new build step
Since my Rakefile lies in a directory named Build, which lies in the checkout directory, I need to specify the path. And since my Rakefile is designed in a manner where it’s supposed to be executed in the Build directory, where it lives, I also need to specify a working directory.


Since I have installed Ruby with registration of it’s bins in the environmentpath and I don’t want to specify a specific version, I’m satisfied with Use default Ruby.

Since I don’t need any of the attached reporters. If you select Test::Unit you need to install the gem test-unit.


Add Environment parameters
The Rakefile has been updated so that the environment parameters are now injected by the build step. To accomplish this, we need to specify Build parameters.


Naming
If the variable is called env_buildversion in our Rakefile, it should be named env.env_buildversion in TeamCity. This makes it an environment variable which is exactly what we want.


All environment parameters


Add Build feature for parsing the NUnit report
If we don’t supply a XML report processing build feature, we will not get any detailed information about the unit tests being executed.


Build it

As of now we have no automated process and as of now, this is left for future articles. But you could put up a trigger or make use of GitHub’s service hook against TeamCity.

If you trigger a build, you will get:

The updated Rakefile

As I said. The Rakefile has been updated, to not use version bumper and to not be responsible for generating project full names etc.

#--------------------------------------
# Dependencies
#--------------------------------------
require 'albacore'
#--------------------------------------
# Debug
#--------------------------------------
#ENV.each {|key, value| puts "#{key} = #{value}" }
#--------------------------------------
# My environment vars
#--------------------------------------
@env_projectname = ENV['env_projectname']
@env_buildconfigname = ENV['env_buildconfigname']
@env_buildversion = ENV['env_buildversion']
@env_projectfullname = ENV['env_projectfullname']
@env_buildfolderpath = ENV['env_buildfolderpath']
@env_unitTestXmlResultsPath = ENV['env_unitTestXmlResultsPath']
@env_solutionfolderpath = "../Solution/"
#--------------------------------------
# Albacore flow controlling tasks
#--------------------------------------
desc "Fixes version, compiles the solution, executes tests and deploys."
task :default => [:buildIt, :testIt, :deployIt]

desc "Fixes version and compiles."
task :buildIt => [:versionIt, :compileIt, :copyBinaries]

desc "Executes all tests."
task :testIt => [:runUnitTests]

desc "Creates ZIP and NuGet packages."
task :deployIt => [:createZipPackage, :createNuGetPackage]
#--------------------------------------
# Albacore tasks
#--------------------------------------
desc "Updates version info."
assemblyinfo :versionIt do |asm|
  sharedAssemblyInfoPath = "#{@env_solutionfolderpath}SharedAssemblyInfo.cs"
  
  asm.input_file = sharedAssemblyInfoPath
  asm.output_file = sharedAssemblyInfoPath
  asm.version = @env_buildversion
  asm.file_version = @env_buildversion  
end

desc "Creates clean build folder structure."
task :createCleanBuildFolder do
  FileUtils.rm_rf(@env_buildfolderpath)
  FileUtils.mkdir_p("#{@env_buildfolderpath}Binaries")
end

desc "Clean and build the solution."
msbuild :compileIt => :createCleanBuildFolder do |msb|
  msb.properties :configuration => @env_buildconfigname
  msb.targets :Clean, :Build
  msb.solution = "#{@env_solutionfolderpath}#{@env_projectname}.sln"
end

desc "Copy binaries to output."
task :copyBinaries do
  FileUtils.cp_r(FileList["#{@env_solutionfolderpath}Source/#{@env_projectname}/bin/#{@env_buildconfigname}/*.*"], "#{@env_buildfolderpath}Binaries/")
end

desc "Run unit tests."
nunit :runUnitTests do |nunit|
  nunit.command = "#{@env_solutionfolderpath}packages/NUnit.2.5.10.11092/tools/nunit-console.exe"
  nunit.options "/framework=v4.0.30319","/xml=#{@env_unitTestXmlResultsPath}"
  nunit.assemblies = FileList["#{@env_solutionfolderpath}Tests/**/#{@env_buildconfigname}/*.UnitTests.dll"].exclude(/obj\//)
end

desc "Creates ZIPs package of binaries folder."
zip :createZipPackage do |zip|
     zip.directories_to_zip "#{@env_buildfolderpath}Binaries/"
     zip.output_file = "#{@env_projectfullname}.zip"
	 zip.output_path = @env_buildfolderpath
end

desc "Creates NuGet package"
exec :createNuGetPackage do |cmd|
  cmd.command = "NuGet.exe"
  cmd.parameters = "pack #{@env_projectname}.nuspec -version #{@env_buildversion} -nodefaultexcludes -outputdirectory #{@env_buildfolderpath} -basepath #{@env_buildfolderpath}Binaries"
end

What’s next?

Well of course we need to automate our build and perhaps add features like labelling, reporting, code-coverage etc. But that’s left for a future article.

//Daniel

8 thoughts on “Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 3

  1. Pingback: Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 1 « Daniel Wertheim

  2. Very helpful, thanks for sharing. I’m in the process of building something similar and found your article so this gives me a good starting point. How are you handling deployments? I was planning on using albacore + powershell to do a capistrano-esque one click deployment.

    • Thanks,

      The project will be published as a NuGet package, which as of now is created but not published, but there’s a task for that in Albacore.

      //Daniel

      • There’s of course also the possibility of using a msbuild task for publish. Interested to hear the way you will chose to go.

        //Daniel

      • Thanks for the link to dolphin. I’ll play around with it and see if it works. The author has a disclaimer not to use in production yet 😛

        But in the meantime i ended up using the exec task to issue remote powershell commands and robocopying files over. I then mimic what capistrano does on the app server by creating a symlink to a release folder for IIS to point to. Seems to work but i need to test it further.

  3. Pingback: Continuous integration using TeamCity, Rake, Albacore, GitHub and NUnit for .Net – Part 2 « Daniel Wertheim

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s