Posted by Daniel Wertheim

Some Git commands I have come to use

Create remote tag

Syntax: git tag -a [name] -m '[comment]'
E.g:	git tag -a v0.7.1 -m 'v0.7.1'

Delete local tag

Syntax: git tag -d [tagname]
E.g:	git tag -d v0.7.1

Delete remote tag

Syntax: git push origin :refs/tags/[name]
E.g:	git push origin :refs/tags/v0.7.1

Force new tag

Syntax: git tag -f -a [existingname] -m '[comment]'
E.g:	git tag -f -a v0.7.1 -m 'v0.7.1'

Reset to a commit

git reset --hard a6b4c974

Existing repo

git clone
(No need to create directory)

Create remote branch

git checkout -b develop
git push -u origin develop

Delete remote branch

Syntax: git push origin :[remotename]
E.g:	git push origin :mybranch

Stash – save to not get changes in other branches

Syntax:	git stash save '[comment]'

Apply stash

Syntax:	git stash apply

Remove stash

Syntax:	git stash clear

Example when setting up new GitHub Repo

Global setup:
 Download and install Git
  git config --global user.name "Daniel Danielsson"
  git config --global user.email daniel@not-a-valid-domain.com

Next steps:
  mkdir PROJ
  cd PROJ
  git init
  touch README
  git add README
  git commit -m 'first commit'
  git remote add origin git@github.com:username/PROJ.git
  git push -u origin master

Existing Git Repo:
  cd existing_git_repo
  git remote add origin git@github.com:username/PROJ.git
  git push -u origin master

Ensure.That – a simple guard clause project

Yes I know there’s a bunch of these projects out there already and that there’s built in support for using code-contracts in .Net, but even so we found a need for a custom API, hence Ensure.That was created. Also, I think Microsoft’s Code-contracts fails on the part of having to install an add-on to VS2010 to actually put the Code-contract requirements to use. Until it’s a first class citizen of VS, it’s not useful in my eyes. Enough about that.

Why

Easy, to provide a clean API for validating arguments and a solution that throws natural argument exceptions with informative exception messages.

NuGet

It’s distributed using NuGet. You could consume it as a normal lib or as a source distribution. The later gives you the possibility of incorporating it into any existing “common core lib” that you already use for these kind of utils.

Some code

The API is continuously evolving and it hasn’t reached v1.0 yet, hence there might be braking changes, but that’s not very likely. There will probably only be new stuff added.

Without parametername

Will throw ArgumentNullException or ArgumentException without ParameterName.

public void MyMethod(string myString, int myInt, Guid myGuid)
{
    Ensure.That(myString).IsNotNullOrEmpty();
    Ensure.That(myInt).IsInRange(10, 20);
    Ensure.That(myGuid).IsNotEmpty();
}

Using Lambdas

Note, that since the value also is extracted via the Lambda there’s a compile of it, hence the other overloads or more performant.

public void MyMethod(string myString, int myInt, Guid myGuid)
{
    Ensure.That(() => myString).IsNotNullOrEmpty();
    Ensure.That(() => myInt).IsInRange(10, 20);
    Ensure.That(() => myGuid).IsNotEmpty();
}

Providing parameter name explicitly

Will work as the first example with the difference of including the parameter name in the exception’s _ParameterName _property.

public void MyMethod(string myString, int myInt, Guid myGuid)
{
    Ensure.That(myString, "myString").IsNotNullOrEmpty();
    Ensure.That(myInt, "myInt").IsInRange(10, 20);
    Ensure.That(myGuid, "myGuid").IsNotEmpty();
}

More information and sourcecode is available on the GitHub site.

//Daniel

Tagged , ,

When will we ever see something like this in MSTest?

Perhaps I haven’t looked enough but I really miss Assert.Throws in MSTest. Or does it exist? I’ve seen more people look for it…. For me, I just put together something real quick.

[DebuggerStepThrough()]
public static T Throws<T>(Action action) where T : Exception
{
    try
    {
        action.Invoke();
    }
    catch (T ex)
    {
        return ex;
    }
    catch (Exception ex)
    {
        throw new AssertFailedException(
            string.Format("Expected exception was not thrown! Got other exception: '{0}'.", ex.GetType())
            ,ex);
    }

    throw new AssertFailedException("Expected exception was not thrown! None was thrown.");
}

//Daniel

Tagged ,

Tip: Install missing NuGet packages using Albacorebuild and Rake

UPDATED!

See comments below, and you will learn that Albacore uses deferred execution, hence not all packages.config will be treated. The corrected code looks like this:

task :installNuGetPackages do
  FileList["Solution/**/packages.config"].each { |filepath|
    sh "NuGet.exe i #{filepath} -o Solution/packages"
  }
end

Which also removes the dependency on Albacore.

End update

As I’m using Albacorebuild and Rake together with TeamCity and GitHub to setup a continuous integration (CI) flow I’m about to stop checking in NuGet packages in my source code repository at GitHub. What I do want, is a simple way for the developer and the CI server to use rake to install any missing NuGet packages. The NuGet.exe tool allready supports this, but per project: read more at NuGet.org. If you have a look at the link you will also see that they give an example of using a Pre-build event for each project. Not fun. Lets have a look at another solution.

The solution using Albacorebuild and Rake

Create a rakefile and define a task that uses NuGet.exe and use the command parameters defined at the link above, but do it for each packages.config file located under the solution directory.

setup.rb

require 'albacore'
#--------------------------------------
task :default => [:installNuGetPackages]
#--------------------------------------
desc "Install missing NuGet packages."
exec :installNuGetPackages do |cmd|
  FileList["Solution/**/packages.config"].each { |filepath|
    cmd.command = "NuGet.exe"
    cmd.parameters = "i #{filepath} -o Solution/packages"
  }
end

So given this structure:

One can simply use rake to install any missing packages:

Summary

Even if it was a simplified rakefile I showed here, you could easily incorporate the task in your normal rakefile and let the CI server execute it, as well as perhaps just have a simple bat-file for devs to setup their local environment.

//Daniel

Tagged , ,

Why the ExpectedExceptionAttribute sucks!

Today I was reading a book which showed an example of an unit test. And even if it was just there to show unit testing as a concept when doing ASP.Net MVC development, I really think you never, ever, ever, ever, ever…..(n)….ever should use that ugly attribute. Why, well follow along.

BTW, the example tests below is not as they were in the book and they are just created for showing you the fragility of ExpectedExceptionAttribute

Test 1: Place a bid When no bids exists Then the bid gets added

You should be able to place a bid when no other bid exists, then there should be one bid registrered and that is the one you placed.

Test

[Test]
public void PlaceBid_WhenNoBidsExists_BidIsAdded()
{
    const int artefactId = 1;
    const decimal bid = 100m;

    var auction = new Auction();
    auction.PlaceBid(artefactId, bid);

    var bids = auction.GetBids(artefactId);
    Assert.AreEqual(bid, bids.Single());
}

Implementation

public class Auction
{
    private readonly Dictionary<int, List<decimal>> _bids
         = new Dictionary<int, List<decimal>>();

    public void PlaceBid(int artefactId, decimal bid)
    {
        _bids.Add(artefactId, new List<decimal> { bid });
    }

    public IEnumerable<decimal> GetBids(int artefactId)
    {
        if (!_bids.ContainsKey(artefactId))
            return Enumerable.Empty<decimal>();

        return _bids[artefactId];
    }
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

1 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Ok, nothing complicated here, lets move on to the next test.

Test 2: Place a bid When a higher bid exists Then it throws an InvalidOperationException

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 10m);
    auction.PlaceBid(artefactId, 5m);
}

Implementation

public void PlaceBid(int artefactId, decimal bid)
{
    var hasExistingExceedingBid = GetBids(artefactId)
        .Any(existingBid => existingBid >= bid);

    if (hasExistingExceedingBid)
        throw new InvalidOperationException(
            "The bid is to low. Existing bids with same or higher value exists.");

    _bids.Add(artefactId, new List<decimal> { bid });
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

2 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Ok, everything works and the ExpectedException is thrown and the second test passes. Lets continue and add yet another test to meet a new requirement.

Test 3: Place a bid When the bid is lower than five Then it throws an InvalidOperationException

Just by readint the test spec there should be an alarm bell going of here. I will give you a small hint: … Then it throws an InvalidOperationException. Two tests for different requirements throws the same exception. What could go wrong? Lets see. Lets continue our journey.

Test

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PlaceBid_WhenBidIsLowerThan5_ThrowsInvalidOperationException()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 4m);
}

Implementation

public void PlaceBid(int artefactId, decimal bid)
{
    if (bid < 5)
        throw new InvalidOperationException(
            "The bid is to low. A bid must be greater than 5.");

    var hasExistingExceedingBid = GetBids(artefactId)
        .Any(existingBid => existingBid >= bid);

    if (hasExistingExceedingBid)
        throw new InvalidOperationException(
            "The bid is to low. Existing bids with same or higher value exists.");

    _bids.Add(artefactId, new List<decimal> { bid });
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

3 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Ok, still everything works out fine, or does it?

A change of the requirements – instead of check against bid lower than five, ten should be used

Piece of cake. Just update the test PlaceBid_WhenBidIsLowerThan5_ThrowsInvalidOperationException and make it fail and correct the implementation so that we get a green test for the new requirement.

Test

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PlaceBid_WhenBidIsLowerThan10_ThrowsInvalidOperationException()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 9m); //UPDATED
}

Implementation

public void PlaceBid(int artefactId, decimal bid)
{
    if (bid < 10) //UPDATED
        throw new InvalidOperationException(
            "The bid is to low. A bid must be greater than 10."); //UPDATED

    var hasExistingExceedingBid = GetBids(artefactId)
        .Any(existingBid => existingBid >= bid);

    if (hasExistingExceedingBid)
        throw new InvalidOperationException(
            "The bid is to low. Existing bids with same or higher value exists.");

    _bids.Add(artefactId, new List<decimal> { bid });
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

3 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Three tests passes. How about that! Nothing wrong there is it? Of course. Lets tweak the test that checks if there’s any existing bids that are higher.

Updated test #1

[Test]
[ExpectedException(
    typeof(InvalidOperationException),
    ExpectedMessage = "The bid is to low. Existing bids with same or higher value exists.")]
public void PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better1()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 10m);
    auction.PlaceBid(artefactId, 5m);
}

I have now put an expectation on the message, now lets see what happens.

------ Test started: Assembly: ClassLibrary1.dll ------

Test 'ClassLibrary1.AuctionTests.PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better1' failed: The exception message text was incorrect
Expected: The bid is to low. Existing bids with same or higher value exists.
 but was: The bid is to low. A bid must be greater than 10.
	BidTests.cs(80,0): at ClassLibrary1.Auction.PlaceBid(Int32 artefactId, Decimal bid)
	BidTests.cs(56,0): at ClassLibrary1.AuctionTests.PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better1()

3 passed, 1 failed, 0 skipped, took 0,20 seconds (NUnit 2.5.5).

The exception message text was incorrect
Expected: The bid is to low. Existing bids with same or higher value exists.
but was: The bid is to low. A bid must be greater than 10.

How about that! The exception was thrown at the wrong place. Of course this situation could have been avoided with some specific business exception or even an ArgumentOutOfRangeException; but again. This is a simplified, fictive scenario which still isn’t making me happy, since the ugly ExpectedExceptionAttribute still is present. Lets fix that.

Assert.Throws

Moste testing frameworks (NOT MSTest) has some sort of ability to pass a delegate to a method and the lets you specify that you expect that delegate to throw an exception of a certain type. If the exception isn’t thrown, the test fails.

For you MSTest users, you can of course write this test util on your own.

Updated test #2

[Test]
public void PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better2()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 10m);

    var ex = Assert.Throws<InvalidOperationException>(
        () => auction.PlaceBid(artefactId, 5m));

    Assert.AreEqual(
        "The bid is to low. Existing bids with same or higher value exists.",
        ex.Message);
}

I hope you get the point, and that you stop using the not so nifty ExpectedExceptionAttribute

//Daniel

Tagged ,

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

Tagged , , , , , ,

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

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

What do I want to achieve?

In this part I will prepare my solution to be built from TeamCity; and to do this I will use Rake via Albacore. More specifically, I will show how to accomplish the following:

  • Manage the assembly version
  • Do a clean release build
  • Execute our NUnit tests
  • Create a ZIP package for deployment
  • Create a NuGet package for deployment

We will not look at the integration with TeamCity in this article, that’s for the future. However, after this article you will have a build, test and deploy process that you can trigger via the command prompt. And with just adding one additional NuGet publish task, you could as well publish the generated NuGet package.

As of now, I have decided to go with a solution where as much logic of my building process is kept in the source code. Whit this I mean, that I, using Albacore, will try to create Rake tasks that takes care of this instead of putting this responsibility on the continuous integration (CI) server. By doing this I hope to get a simpler CI server configuration, and for me as a developer, I like to find the specs for the build with the source code instead of in a CI server. Lets hope I can stick to this when looking closer at TeamCity in future articles.

Install Ruby, Rake, Albacore & Version bumper

First we need to install Ruby and then the necessary gems: Rake gem, Albacore gem and the Version bumper gem. This is something I will do on both my client as well as on my server where TeamCity is installed, since this is where the builds will be executed.

I used the installer from: http://rubyinstaller.org/downloads/ and at the time of this writing the latest version was: Ruby 1.9.2-p180.

During the installation I explicitly selected the two checkboxes to add it to the Path environment variable and to associate it with Ruby files.

Install the required gems

Since I chosen to register ruby in my environment path, to install the required gems is a real breeze. After the installation was finished I just fired up the command prompt and typed:

gem install rake
gem install albacore
gem install version_bumper

Meet Albacore

Just to provide you with a quick insight in what Albacore is, I have pasted some lines from the Albacore Wiki, below:

Albacore is intended to be a professional quality suite of Rake tasks to help automate the process of building a .NET based system. – https://github.com/derickbailey/albacore/wiki

Albacore is a build system that is based on Ruby’s Rake. Within it, you can use several different build ‘tasks’ that help you forge the build of your choice. – https://github.com/derickbailey/Albacore/wiki/Getting-Started

The Rakefile

A rakefile is a collection of tasks – work to be performed. A rakefile is also a valid ruby script, meaning you can write any executable ruby code that you wish to use with your tasks, in this file. – https://github.com/derickbailey/Albacore/wiki/Getting-Started

The Rakefile shoud be named: “Rakefile.rb“; and it is case-insensitive. According to the documentation it should reside in the “project root”. The project I will use for this guide is a rather simple one, and it’s named “PineCone” (GitHub site) and the folderstructure looks like this:

As you can see I have chosen to put my Rakefile and my NuSpec in a folder called Build and not directly in the root. In the Build folder, I have created tasks so that there will be a Builds folder created. This folder is with advantage excluded from Git using the .gitignore file. In the Builds folder there will be a folder created for each build, with a naming convention: [ProjectName]-v[Version]-[BuildConfigName]. In that folder the binaries, testresult and ZIP-package as well as the NuGet-package will be created.

A few words about the solution and its layout

To keep the complexity down, I’ve deliberately selected this, as of now, fairly simple project:

I will be adding more projects to this solution in the future but then I would like to share the versioning info as well as copyrights etc. For this I have selected to have a SharedAssemblyInfo added as a linked file. This shared assembly info file is the one we will use in our Albacore AssemblyInfoTask later on in the article.

SharedAssemblyInfo.cs

using System.Reflection;

#if DEBUG
[assembly: AssemblyProduct("PineCone (Debug)")]
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyProduct("PineCone (Release)")]
[assembly: AssemblyConfiguration("Release")]
#endif

[assembly: AssemblyDescription("Library used for managing primitive value members in object-graphs as key-values.")]
[assembly: AssemblyCompany("Daniel Wertheim")]
[assembly: AssemblyCopyright("Copyright © Daniel Wertheim")]
[assembly: AssemblyTrademark("")]

[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]

With Albacore you could set each of the attributes above, but I will only affect versioning. Why? As of now it would be more natural for me to look in AssemblyInfo or SharedAssemblyInfo for these kind of attributes, and then look for versioning info in the build definitions.

I have two build configurations:

  • Debug
  • Release

Both configurations builds all projects, so the binaries being deployed are the same being tested by our test project; hence I don’t have a build configuration like “Deploy” that only compiles the the actual project and not the tests.

XML Documentation file

In Release mode the XML Documentation file is generated. To get rid of all warnings about not having a XML comment for all public members, I have added a Suppressed warning for this.

The complete Rakefile

Before having a look at the Rakefile, remember this is my first writings of Ruby code. Now, lets have a look at the complete and finished Rakefile and then break it down.

#--------------------------------------
# Dependencies
#--------------------------------------
require 'albacore'
require 'version_bumper'
#--------------------------------------
# My environment vars
#--------------------------------------
@env_solutionfolderpath = "../Solution/"
@env_projectname = "PineCone"
@env_buildconfigname = "Release"

def env_buildversion
  bumper_version.to_s
end

def env_projectfullname
  "#{@env_projectname}-v#{env_buildversion}-#{@env_buildconfigname}"
end

def env_buildfolderpath
  "Builds/#{env_projectfullname}/"
end
#--------------------------------------
# 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 "Bumpes new version."
task :bumpVersion do
  bumper_version.bump_build
  bumper_version.write('VERSION')
end

desc "Updates version info."
assemblyinfo :versionIt => :bumpVersion 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_buildfolderpath}/NUnit-results-#{@env_projectname}-UnitTests.xml"
  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"
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

Rakefile – “Dependencies”

We know that there’s a dependency on the albacore library, hence we need to define it using the require keyword. I’m also making use of version bumper, so we need to include that as well. I’m using version bumper to bump the versions of each build, as well as persist this information in the VERSION file, located in the Build folder.

require 'albacore'
require 'version_bumper'

Rakefile – “My environment vars”

As of now, before integrating with TeamCity, I have identified some few things I wan’t to define as some sort of shared configurations between my task. E.g the version to use for my project(s) and the path of the solution folder as well as the buildconfiguration name.

@env_solutionfolderpath = "../Solution/"
@env_projectname = "PineCone"
@env_buildconfigname = "Release"

def env_buildversion
  bumper_version.to_s
end

def env_projectfullname
  "#{@env_projectname}-v#{env_buildversion}-#{@env_buildconfigname}"
end

def env_buildfolderpath
  "Builds/#{env_projectfullname}/"
end

If you like you can also provide some shared configuration variables to Albacore, e.g. defining the NUnit test runner in one place.

Rakefile – “Albacore flow controlling tasks”

I like to see them as compositions of tasks with the purpose of controlling the flow in the build process. You could of course skip a lot of these, and instead “chain” the tasks directly, as I have done in the assemblyinfo task versionIt, where I state that before executing this task, the bumpVersion task needs to have been executed.

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]

I have selected to create the tasks below, so that I can execute just the build step or just the test step, …., etc. This can be achieved by passing the taskname to rake at the command prompt.

rake buildIt

this will only execute the tasks: versionIt, createCleanBuildFolder and compileIt.

Define a default task

If you don’t want to specify each task to be executed at the command prompt, you need to create a default task in the rakefile. If not you will be promted with a message stating:

Don’t know how to build task ‘default’.

In our case our default task is composed by three other tasks: buildIt, testI and deployIt. If you do have a look at the testIt task you will see that you can point on other tasks that in turn points to other tasks. So the testIt task could in turn have pointed to our runUnitTests task as well as a MSpec test task.

Rakefile – “Albacore tasks”

Now, it’s time to have a look at our actual worker task, the tasks that actually does something. There are a bunch of pre made tasks and you can create your own custom task etc.

Tasks: versionIt & bumpVersion

As stated above, I will only affect the version attribute in the SharedAssemblyInfo file and nothing else. The task used is the AssemblyInfoTask, which lets you set values to your assemblyinfo attributes. Note that I have specified a value for the input_file attribute on the task. If not, only the attributes being assigned a value on the Albacore task would be represented in the output_file and the rest would have been removed. In my case I have chosen to use a SharedAssemblyInfo file that acts as a template for all my projects in the solution. The only attributes I’m setting via Albacore and Rake is the version attributes.

desc "Updates version info."
assemblyinfo :versionIt => :bumpVersion 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

This task is dependent on the bumpVersion task which uses version bumper to read the current version string from the VERSION-file and then increment the build number by one. The version string from the version bumper is accessed via the property env_buildversion, defined under My environment vars.

desc "Bumpes new version."
task :bumpVersion do
  bumper_version.bump_build
  bumper_version.write('VERSION')
end

Tasks: compileIt, createCleanBuildFolder & copyBinaries

After the version has been set, it’s time for compilation so that we have something to test and deploy. It is the compileIt task that is being executed, but it states that before compileIt can execute, createCleanBuildFolder needs to have been executed; which in turn just creates a clean build folder. The copyBinaries task just copies the binaries to a folder named Binaries located in the build folder. This simplifies the creation of the ZIP- and NuGet packages.

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

Read more about the MSBuild task.

Task: unitTests

As of now, this solution has no integration tests. Just simple unit tests that needs to be executed. By convention I have determined that all my pure unit test assemblies should end with UnitTests, hence I only extract those assemblies and pass them to the NUnit test runner.

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_buildfolderpath}/NUnit-results-#{@env_projectname}-UnitTests.xml"
  nunit.assemblies = FileList["#{@env_solutionfolderpath}Tests/**/#{@env_buildconfigname}/*.UnitTests.dll"].exclude(/obj\//)
end

In your scenario, you will probably have more test assemblies and might not want to have the NUnit-Console as a dependency to every project. Perhaps there should be a tool repository or something instead? Since I’m using the NuGet NUnit package in my unit test project, I get the tools placed in the packages repository for my solution which I then use. Learn more about the NUnit task.

The task I have defined also makes use of NUnit console runner switches. I have used two options:

  • nunit.options '/framework=v4.0.30319': tells the testrunner to use the .Net framework 4.0 to execute the tests.
  • nunit.options '/xml=#{env_buildfolderpath}/NUnit-results-#{@env_projectname}-UnitTests.xml': specifies the name and path of the resulting XML-file.

Note! It says: nunit.options, plural and not singular. If you provide two lines with different values for nunit.options, then last in wins.

I have used the Rake FileList helper to resolve all the unit test assemblies to be executed. It also takes some of My environment vars into account, so that I don’t have to hard code and manage the assemblies to treat as unit tests by hand.

Task: createZipPackage

Not much to say here. Just ZIP the Binaries folder under the Build folder using the ZIP task.

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

Task: createNuGetPackage

There’s actually specific tasks for managing NuGet specifications and packages. I have decided to keep my NuSpec file and not generate it using either NuGet.exe from the projectfile, nor via the Albacore NuSpec task. I tried the NuGetPack task but couldn’t get it to use the NuGet.exe switch version, which I wan’t, since I would like to inject the build version into the package. Instead I relied on the simple Exec task, to call NuGet.exe with the switches I want.

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 have we accomplished?

Just use the command prompt and type:

rake

and you will get tested and packaged binaries, in versioned build folders:

Note that files are getting updated

When executing the version tasks, two files will get updated. The VERSION-file that contains the current version number as well as the SharedAssemblyInfo.cs file.

What’s next?

In the next part, Part 3, I will integrate GitHub and TeamCity so that our buildserver can get something to build.

//Daniel

Tagged , , , , , ,

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

This is simply going to be my documentation of how I have put up a Continuous integration flow with TeamCity, Rake, Albacore, GitHub and NUnit for a .Net project.

Environment

The environment for this article is a live environment, NOT a test on a Windows 7 machine, but I’m instead setting this up on a VPS with Windows Server 2008 R2 hosted at the excellent providers Tilaa. The TeamCity installation will be accessible via a public URL: http://ci.foo.com. To achieve this we will make use of IIS 7 Reverse proxying. Why? Felt simpler and I will probably make use of the site to provide reports etc. via e.g http://ci.fool.com/reports

Install TeamCity

Start by downloading the installation media from: http://www.jetbrains.com/teamcity/ This article will use v6.5.1 and the Proffesional edition. The installation is fairly simple and is documented using the following screenshots.

Make TeamCity public accessible

As of right now our TeamCity webserver is only accessible from the server where we installed it on. To make it public accessible, using the URL: http://ci.foo.com (we installed it on http://ci.foo.com:8080) we will use the IIS 7 Application Request Routing module but we will NOT setup a webfarm as other articles do; but instead setup a Reverse proxy on a normal IIS-site.

Install Application Request Routing module

I will install this module using Microsoft’s Web platform installer. Fire it up an locate the URL rewriting module (Products –> Server). Install it and let it include the modules it depends on.

NOTE! I have already installed the URL Rewriting module, hence it’s not selected as a dependency. It’s also worth noting that it’s not enough with the URL Rewriting module to setup a Reverse proxy.

What’s left?

That’s it for now. Part 2 will be written soon, and then we will look at using Rake and Albacore for building our Visual Studio solution and running our unit tests.

//Daniel

Tagged , , , , , ,

NancyFx – Part 1 – Getting ready to use it

I have been aiming at trying out a micro web framework for a while and have been choosing between: JessicaFx and NancyFx; but I’ve never gotten the time, until now. My choice fell on Nancy, despite Tom Bell’s (creator of JessicaFx) article, in which he thinks that Nancy has taken steps away from being a micro web framework by not just extending the Asp.Net stack. I kind of like that Nancy offers other hosting capabilities and that they strive to not being dependent on the Asp.Net web stack, but who knows, in the end I might use JessicaFX instead. Don’t you just love OSS? Instead of a complex solution from Microsoft, targeting a multitude of scenarios, you get multitude of OSS projects solving a smaller problem domain for one of these scenarios.

This is not an ending story

This is part 1 of me exploring Nancy, and in this part I will only describe my way of getting good to go, to start working with Nancy.

Not a Ruby guy….yet

I also never have gotten the time to look at Ruby. And not being a Ruby guy at all, I thought “Hey, why not use Rake to build Nancy and that way start to get a little bit closer to Ruby by at least installing it and installing some gems.” I know that I could have settled with downloading the binaries or even simpler using NuGet but as I’m looking at using Rake myself, why not download the source of NancyFx and use Rake and Albacore to build it.

Get your hands on Ruby

Google it and you’ll find: http://www.ruby-lang.org/en/downloads/. Well there, and since I’m a Windows guy, I used the recommended way of heading over to: http://rubyinstaller.org/downloads/ and at the time of this writing the latest version was: Ruby 1.9.2-p180.

IronRuby

Nice to know for .Net people needing to extend their every day static language writing with some dynamic Ruby: http://www.ironruby.net/.

Disclaimer

Just so that you know. I haven’t investigated any best practices whatsoever in the context of installing Ruby and Gems.

Install…

During the installation I explicitly selected the two checkboxes to add it to the Path environment variable and to associate it with Ruby files.

After the installation was finnished I just fired up the command prompt and typed:

gem install rake
gem install albacore

Now I see where NuGet has been ripped from has gotten the inspiration from.

Get your hands on Nancy

Just head over to their GitHub page via http://nancyfx.org. Download the source and unzip it locally. After that just fire up the command window and navigate to the path where the “rakefile.rb” is located and type:

rake

That’s it. You now have yourself a set of compiled assemblies located under build\binaries, all tested and compiled on your machine. That’s it for this part. Next time, will actually open up our favourite choice of IDE, Visual Studio 2010???

//Daniel

Tagged , , , , , ,

PineCone project

PineCone (https://github.com/danielwertheim/PineCone) is a new open source project I just created. As of now it’s just a component that is a result of things I have used in one of my other open source projects SisoDb http://sisodb.com. I’m intending to use PineCone in a third project coming soon.

PineCone lets you take a C# class and then builds a schema for this class. This schema contains cached members that via IL Emit extracts all simple values from the object graph. All values are turned into a StructureIndex, which is contained by a Structure. Each StructureIndex holds a Guid pointing back to the structure so that you easily can navigate to the structure again.

You can also provide an implementation of ISerializer https://github.com/danielwertheim/PineCone/blob/master/Solution/Source/PineCone/Serialization/ISerializer.cs on the StructureBuilder, which then will be called for each item being converted to a structure. The result of the serializer will be put in the IStructure.Data property.

Model

Example of model with nested complex and enumerable of complex items.

public class X
{
    public Guid StructureId { get; set; }

    [Unique(UniqueModes.PerType)]
    public int X1 { get; set; }

    public int[] X2 { get; set; }

    public Y X3 { get; set; }

    public IList<Y> X4 { get; set; }
}

public class Y
{
    public string Y1 { get; set; }

    public int Y2 { get; set; }

    public IList<Z> Y3 { get; set; }
}

public class Z
{
    public DateTime Z1 { get; set; }

    public decimal Z2 { get; set; }
}

Build structures

The process is simple. Get a schema from the Schemas (keep the Schemas-collection alive to keep schemas cached). Use the schema to build structures using the builder.

var pineConizer = new PineConizer();

var schema = pineConizer.Schemas.GetSchema(typeof(X));
            
var structures = pineConizer.Builder.CreateStructures(items, schema);

Access structures and indexes

As of now you have a structure with indexes.

var p = structures.SelectMany(s => s.Indexes).Where(i => i.Path.StartsWith("X3") || i.Value is string);

IStructure

https://github.com/danielwertheim/PineCone/blob/master/Solution/Source/PineCone/Structures/IStructure.cs

public interface IStructure
{
    Guid Id { get; }

    string Name { get; }

    dynamic Data { get; set; }
        
    ISet<IStructureIndex> Indexes { get; }

    ISet<IStructureIndex> Uniques { get; }
}

IStructureIndex

https://github.com/danielwertheim/PineCone/blob/master/Solution/Source/PineCone/Structures/IStructureIndex.cs

public interface IStructureIndex : IEquatable<IStructureIndex>
{
    Guid StructureId { get;  }

    string Path { get;  }
        
    object Value { get; }

    bool IsUnique { get; }

    StructureIndexType IndexType { get; }
}

Serializer

Implement ISerialzer

https://github.com/danielwertheim/PineCone/blob/master/Solution/Source/PineCone/Serialization/ISerializer.cs

public interface ISerializer
{
    dynamic Serialize<T>(T item);
}

To get the serializer into play, you need to assign it to the builder.

pineConizer.Builder.Serializer = mySerializer;

After this your structures will have their Data prop filled with the serialized content. For JSON I highly recommend https://github.com/ServiceStack/ServiceStack.Text as it is the most performant I know: http://daniel.wertheim.se/2011/02/07/json-net-vs-servicestack/

The end. Will get back with examples of use-cases.

//Daniel

Tagged
Follow

Get every new post delivered to your Inbox.