TFS Builds for Octopus Deploys

Posted by on

I have been playing around with Octopus Deploy lately and I have setup our TFS build server to automatically create releases and deploy to a Dev environment.

Here is how you can setup a TFS build server to create NuGet packages ready for deployment through Octopus. Building off my previous post TFS to private NuGet.

Lets start with the build script:

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

    <PropertyGroup>
        <VersionMajor>0</VersionMajor>
        <VersionMinor>8</VersionMinor>
        <VersionPatch>1</VersionPatch>
        <BuildOutputDirectory>C:\Builds\Temp\SiriuswareUtil</BuildOutputDirectory>
    </PropertyGroup>

    <Target Name="Build">
        <MSBuild Projects="SiriuswareUtil/SiriuswareUtil.csproj" Targets="Build"
			      Properties="Configuration=Release;WebProjectOutputDir=$(BuildOutputDirectory);" />
        <TfsVersion TfsLibraryLocation="C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0"
		    LocalPath="$(MSBuildProjectDirectory)..\">
			<Output TaskParameter="Changeset" PropertyName="ChangesetNumber"/>
        </TfsVersion>
        <Copy SourceFiles="$(BuildOutputDirectory)\SiriuswareUtil.nuspec" DestinationFolder="$(BuildOutputDirectory)" />
        <Exec Command='"C:\NuGet\NuGet.exe" pack "$(BuildOutputDirectory)\SiriuswareUtil.nuspec" -OutputDirectory "\\grp-dev02\f$\Websites\Ardent.NuGet\Packages"  -basePath "$(BuildOutputDirectory)" -Version "$(VersionMajor).$(VersionMinor).$(VersionPatch)$(ChangesetNumber)" -NoPackageAnalysis' />
        <Exec Command='"C:\Octopus\Octo.exe" create-release --server=http://octopus.ardentleisure.com/api --project=SiriuswareUtil --deployto=Dev --apikey=YOUR_KEY_HERE' />
	</Target>
</Project>

Now lets have a look at what each part does:

<PropertyGroup>
    <VersionMajor>0</VersionMajor>
    <VersionMinor>8</VersionMinor>
    <VersionPatch>1</VersionPatch>
    <BuildOutputDirectory>C:\Builds\Temp\SiriuswareUtil</BuildOutputDirectory>
</PropertyGroup>

The PropertyGroup element defines a few variables for later use. Starting at the top there are 3 properties for the version number, these let us set the version of the package (later on we also append the TFS changeset). The BuildOutputDirectory is a temporary path to build the project to so we can generate the NuGet package from the output.

<MSBuild Projects="SiriuswareUtil/SiriuswareUtil.csproj" Targets="Build"
	Properties="Configuration=Release;WebProjectOutputDir=$(BuildOutputDirectory);" />

Next we need to build the project, this part is pretty straight forward, set the path to the project file and the output directory. This project is a web project so I'm using the WebProjectOutputDir property on the build which publishs the project to the set path.

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

Now we want to check what the TFS changeset is so we can append it to the package version. For this we need the MSBuild Community Tasks with the import at the top of the build script. This function takes a few parameters such as the TFS binary location and outputs to a set variable (in this instance its "ChangesetNumber").

<Copy SourceFiles="$(BuildOutputDirectory)\SiriuswareUtil.nuspec" DestinationFolder="$(BuildOutputDirectory)" />

The next element ensures the nuspec file is copied to the output directory, instead of having to include it as content and it getting deployed to our servers.

<Exec Command='"C:\NuGet\NuGet.exe" pack "$(BuildOutputDirectory)\SiriuswareUtil.nuspec" -OutputDirectory "\\grp-dev02\f$\Websites\Ardent.NuGet\Packages"  -basePath "$(BuildOutputDirectory)" -Version "$(VersionMajor).$(VersionMinor).$(VersionPatch)$(ChangesetNumber)" -NoPackageAnalysis' />

Now we call the NuGet command line to create the package, pointing it at our nuspec file and setting to the output to where ever out nuget server is. This is where we also set the version of the package using our set properties and the tfs changeset number (-Version "$(VersionMajor).$(VersionMinor).$(VersionPatch)$(ChangesetNumber)").

<Exec Command='"C:\Octopus\Octo.exe" create-release --server=http://octopus.ardentleisure.com/api --project=SiriuswareUtil --deployto=Dev --apikey=YOUR_KEY_HERE' />

Lastly we want to use Octopus-Tools octo.exe to create a release in Octopus and schedule a deploy for our Dev environment. Octo.exe is a command line interface for the octopus server api, we just need to set a few variables for it to use such as the server address, project we want to create the release for and an API key that can be obtained through the web interface.

So the process for code changes is now:

  • Developer checks in code to TFS
  • CI Build server picks up code change fires off a build of the custom script
  • NuGet package is created in repo
  • New release is created and deployed to Dev environment via Octopus

And now I know exactly what code is running on all my servers and can easily deploy new versions.

Octopus Dash