Creating a NuGet Package from a TeamCity build

Posts in this series:

In a previous post I talked about how it was possible to set up .Net dependency management in TeamCity using NuGet. In this post I will cover the steps required to create a NuGet package as part of a TeamCity build, and publish it to TeamCity’s own NuGet package source server.

It is not uncommon to want to reuse a .Net project in another solution, maybe some common data access code. This would mean a bit of a maintenance headache when trying to keep things up to date and versioned correctly. NuGet and TeamCity have now made things very easy. Create a Nuget package for the project when it is built in TeamCity and publish it to TeamCity’s own Nuget package server. This package can then be picked up and used in any other project as a dependency like you would use an external package from the NuGet official package source.

Turn on TeamCity’s NuGet server

Since version 7, TeamCity has been able to host its own Nuget package feed. To enable it, head over to TeamCity’s Administration page and select NuGet Settings.

You will be presented with the URL’s for the NuGet feed. The feed URL will be added in Visual Studio and TeamCity as a package source to allow you to use the packages you create. If you want to turn on the public feed you will need to enable Guest login for TeamCity.

Create a package from a .csproj file

It is possible to create a NuGet package directly from a .csproj file in TeamCity. However if the project from which you wish to create the package has NuGet packages itself you will encounter a couple of errors after setting up a build step and attempting to run the build.

The first will probably be this one:

The imported project "C:\Program Files (x86)\TeamCity\buildAgent\work\c4ce4cf3674f70b0\ExampleProject\ExampleProject\.nuget\nuget.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk. C:\Program Files (x86)\TeamCity\buildAgent\work\c4ce4cf3674f70b0\ExampleProject\trunk\DataAccess\DataAccess.csproj

This problem is caused by some changes made by NuGet to the .csproj file resulting in TeamCity’s build agent not being able to resolve the path correctly.  A solution to this problem is outlined here. However once the fix has been applied you may well find that you encounter another error:

nuget pack: Specifying SolutionDir in properties gives Exception: An item with the same key has already been added.

This looks like it is a Nuget error. An issue has been raised here but at the  time of writing it has not been actioned. If anyone has a solution I would be very interested to hear it.

Don’t despair at this setback. Even if this approach worked correctly it is a bit of a blunt tool. Much better is to use a .nuspec manifest to describe the package we want to build.

Create a package from a .nuspec manifest

A .nuspec manifest is an XML document that defines the content of a NuGet package. A lot of effort has gone into the NuGet documentation on .nuspec files so I am not going to recreate all of it here. Instead I will just show you .nuspec file I used and talk about a few interesting parts. First of all, create a file next to the .csproj of the project you want to package. I want to package my DataAccess project so I created a file called DataAccess.nuspec.  Here is the content:

<?xml version="1.0"?>
<package xmlns="">
    <authors>James Heppinstall</authors>
    <owners>James Heppinstall</owners>
    <copyright>Copyright James Heppinstall 2012</copyright>
        <dependency id="PetaPoco.Core" version="4.0.3" />
    <file src="ExampleProject\trunk\DataAccess\bin\Release\DataAccess.dll" target="lib\DataAccess.dll" />

Most of it is straight forward and is covered in the NuGet documentation. It doesn’t matter what the version number you put in. It will be replaced by the build number from the TeamCity build. The dependencies section should contain a list of the NuGet packages for the project. If you are unsure which packages your project uses the best thing to do is to look in the project’s packages.config for the correct name and version.

The files section is where you list the files to be included. I have just included the single .dll as an example. You can also target specific framework versions in the same package using a convention. If I wanted to target only .Net4.0 I would have used

<file src="ExampleProject\trunk\DataAccess\bin\Release\DataAccess.dll" target="lib\net40\DataAccess.dll" />

Remember that a  NuGet package is not just limited to dependencies. It is possible to create a package that contains an entire project structure with code and configuration, including scripts to perform data transformations along the way. So you could create a template package for your organisation’s web site development.

Now we have the .nuspec file the next step is to create a new build step for the TeamCity Project.

Simply select a Runner Type of NuGet Pack, add the path to your .nuspec file and you are good to go. I have selected to publish the package to the build artifacts. This can be useful for audit-ability.

Run the build and check that the Package is created in the build artifacts. If all is good the package is ready to be used in Visual Studio. From Tools | Library Package Manager | Package Manager Settings and select package sources. Add the TeamCity feed URL you wish to use, either authenticated or guest (I have added both for illustration purposes). Of course you should use the correct server name as you will probably not be running TeamCity on your development machine.

Now when you go to Manage Nuget Packages for a project you will be able to select the TeamCity package feed and see the Package you have just created, ready to be added to a new project.

And that’s all there is to it. NuGet and TeamCity make dependency management for your .Net code base very simple.

2 Responses to Creating a NuGet Package from a TeamCity build

  1. Pingback: Dependency Management in .Net with NuGet and TeamCity « James Heppinstall: On Development

  2. flurbygrass says:

    Nice information. Thanks for sharing.

Leave a Reply

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

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

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: