I wanted to create NuGet packages for some internal libraries that I use. I came across this post that describes how to create a NuGet package with MSBuild, which got me the majority of the way. I did have to make a few modifications to make it fit in nicely with my TeamCity CI server.
To begin, I installed the MSBuild Community Tasks to my build server.
After that, I grabbed the NuGet.MSBuild assembly from their CI server and copied it to the C:Program Files (x86)MSBuildNuGet folder.
Following Mark’s instructions, I created a NuGet folder for my project. In that folder, I’m able to put my nuspec file and any transforms. With current versions of NuGet, you need to make sure that you have proper namespaces added to the package and metadata elements:
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
I then added the following MSBuild file to my project:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)MSBuildCommunityTasksMSBuild.Community.Tasks.Targets"/> <UsingTask AssemblyFile="$(MSBuildExtensionsPath)NuGetNuGet.MSBuild.dll" TaskName="NuGet.MSBuild.NuGet" /> <PropertyGroup> <AssemblyName>BiaCreations</AssemblyName> <PackagePath>C:Packages</PackagePath> <BuildConfiguration Condition="'$(teamcity_version)' == ''">Debug</BuildConfiguration> <BuildConfiguration Condition="'$(teamcity_version)' != ''">Release</BuildConfiguration> <build_number Condition="'$(teamcity_version)' == ''">18.104.22.168</build_number> </PropertyGroup> <Target Name="CreatePackage"> <PropertyGroup> <PackageBuildPath Condition="'$(teamcity_version)' == ''">buildNuGet</PackageBuildPath> <PackageBuildPath Condition="'$(teamcity_version)' != ''">$(teamcity_build_tempDir)buildNuGet</PackageBuildPath> <PackageSourcePath>NuGet</PackageSourcePath> </PropertyGroup> <ItemGroup> <PackageSourceFiles Include="$(PackageSourcePath)**" /> <PackageLibFiles Include="bin$(BuildConfiguration)$(AssemblyName).dll;bin$(BuildConfiguration)$(AssemblyName).pdb" /> <OldDestinationFiles Include="$(PackagePath)$(AssemblyName).1.*.nupkg" Exclude="$(PackagePath)$(AssemblyName).$(build_number).nupkg" /> </ItemGroup> <RemoveDir Directories="$(PackageBuildPath)" ContinueOnError="true" /> <Message Text="Setting up the $(PackageBuildPath) directory will all the necessary files to create our package"/> <Copy SourceFiles="@(PackageSourceFiles)" DestinationFiles="@(PackageSourceFiles->'$(PackageBuildPath)%(RecursiveDir)%(Filename)%(Extension)')" /> <Copy SourceFiles="@(PackageLibFiles)" DestinationFiles="@(PackageLibFiles->'$(PackageBuildPath)lib%(RecursiveDir)%(Filename)%(Extension)')" /> <FileUpdate Files="$(PackageBuildPath)package.nuspec" Regex="version>([^"<]*)</version" ReplacementText="version>$(build_number)</version" /> <Message Text="Creating the package"/> <NuGet PackageDir="$(PackagePath)" SpecFile="$(PackageBuildPath)package.nuspec" /> <Message Text="Deleting previous package"/> <Delete Files="@(OldDestinationFiles->'$(PackagePath)%(Filename)%(Extension)')" ContinueOnError="true" /> </Target> </Project>
There are some conditions added to some of the properties so that I can run the build file locally (for testing) and so that it works as I want when TeamCity runs it. Additionally, I am only copying the project assemblies from the bin folder, rather than all files, since I handle any dependencies via the nuspec file.
Next, I upgraded my Team City installation to version 6 so that I could take advantage of the multiple build runner feature. I use the Visual Studio build runner to build my solution and just created a MSBuild runner that will create the NuGet package:
This pretty much sums up the changes I needed to make to have TeamCity produce a NuGet package every time it builds my library. I’m fairly happy with this solution and so far it seems to be working well. I want to thank Mark for his post on building NuGet files via MSBuild. I hope this post helps those of you who want to incorporate this process with TeamCity.