From TFS to Private NuGet

Posted by on

Let me start by saying this: I love NuGet, its straight up awesome!

This post is about how I created a TFS CI Build to create NuGet packages and push them to a private NuGet server hosted on site.

I have been playing around with the TFS Build server, mainly for a Continuous Integration (CI) build on some of our projects and I wanted a way for me to be able to update a core library and have it propagated to all of the projects that use that library without them all needing to be in the same solution.

The answer was a private NuGet server with a CI build that automatically packaged my library.

I started by setting up a private NuGet server, reading Phil Haack’s post about hosting a simple package feed. Once that was done I could start pumping out packages!

Now that I have my NuGet server I need to setup the build. I created an Ardent.CommonBuild.proj for my build config and tasks. I found its easier to manage as a separate file to the actual project file, this file has to be a .sln or .*proj file for the TFS Build server to be able to run it.

image

Now I also wanted to control the version numbers of the packages being pushed out (both manually and automatic). So I set a major and minor version property at the top.

<PropertyGroup>
    <VersionMajor>0</VersionMajor>
    <VersionMinor>1</VersionMinor>
</PropertyGroup>

I then wanted to include the TFS Changeset number as the 3rd part of the version. So I kicked off a TfsVersion task which outputs the changeset number of a specific path (Set this to the project root to get all changes).

<TfsVersion
  TfsLibraryLocation="C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0"
  LocalPath="$(MSBuildProjectDirectory)">
  <Output TaskParameter="Changeset" PropertyName="ChangesetNumber"/>
</TfsVersion>

From there I build the Project, normally the TFS build outputs the dlls to a binaries folder in the build output folder, but I decided to skip the nuspec file step but pointing NuGet at the project file directly. However you could create a nuspec file and point that to the built dlls, your choice. I also set the version number here for the build.

<MSBuild Projects="$(MSBuildProjectDirectory)\Ardent.Common\Ardent.Common.csproj"
    Targets="Build"
    Properties="Configuration=Debug;
      OutDir=$(MSBuildProjectDirectory)\Ardent.Common\Bin\Debug\;
    ApplicationVersion=$(VersionMajor).$(VersionMinor).$(ChangesetNumber)" />

So now we have built our project and we have the version we want so lets create the package. Using the Exec function I then run the NuGet.exe pack command on my project file using the –Version flag to set the version of the package. I also cheated a bit here by setting the –OutputDirectory flag and pointing that to the packages folder on the NuGet server I created. This will populate the feed now with the new package.

<Exec Command="C:\NuGet\NuGet.exe pack $(MSBuildProjectDirectory)\Ardent.Common\Ardent.Common.csproj -Version $(VersionMajor).$(VersionMinor).$(ChangesetNumber) -OutputDirectory \\grp-dev02\f$\Websites\Ardent.NuGet\Packages"></Exec>

The only thing left to do is create a TFS build definition under that points to my Ardent.CommonBuild.proj file in source control set the definition to CI mode. Done!

image

Now for every check-in to that project in TFS I get a new package created with the updated code then NuGet handles the updates in all of my other projects.

image

Life is good…