I'm trialling Octopus Deploy (3.4.12) and want to automatically use the build number from the MS Build name as my NuGet package name. For example, if my latest MSBuild drop name is 'MyApp Build_20161019.2' and my app name is MyApp, then I want my package to be called MyApp.20161019.2.0.nupkg
The reason for this is that the app's assembly version doesn't change (historical reasons, non-neg), so unless I manually pass the build number to OctoPack as a build parameter each time (which takes the shine off automatic packaging IMO), I cannot get the package loaded into the Octopus library.
I'm using the old-school TFS XAML build definition btw.
I should point out that I found a blog which said to create a custom build template and change the Run MSBuild item so that the params are
String.Format("/p:SkipInvalidConfigurations=true {0} /p:OctoPackPackageVersion={1}", AdvancedBuildSettings.GetValue(Of String)("MSBuildArguments", String.Empty), BuildDetail.BuildNumber.Split(CChar("_"))(1))
and followed the steps, but it fails to build and gives the following error:
Validation Error: The private implementation of activity '1: DynamicActivity' has the following validation error: Compiler error(s) encountered processing expression "String.Format("/p:SkipInvalidConfigurations=true {0} /p:OctoPackPackageVersion={1}", AdvancedBuildSettings.GetValue(Of String)("MSBuildArguments", String.Empty), BuildDetail.BuildNumber.Split(CChar("_"))(1))". 'Microsoft.TeamFoundation.Build.Client.BuildDetail' is not accessible in this context because it is 'Friend'.
OK, I found out how to do it with the help of a similar question which was related to Git builds: Add BuildNumber in GitTemplate.12.xaml
WARNING!! AFAIK you're going to need VS2013 for this. You can't do it in VS2015.
For completeness I'm listing all of the flaming hoops steps that I had to jump go through.
1st attempt:
I tried to simply set the OctoPack package number using the TF_BUILD environment variable TF_BUILD_BUILDNUMBER by providing the following MSBuild arguments
/p:RunOctoPack=true /p:OctoPackPackageVersion=”$(TF_BUILD_BUILDNUMBER)”
but TF_BUILD_BUILDNUMBER includes text (the name of the app I think) as well as the number, e.g. CIBuild_20130613.6 which caused a NuGet error as NuGet can only work with numbers. Also I really only want the 20130613.6 part anyway.
2nd attempt:
Research indicated that I had to create a customized build process template. As a starting point I downloaded a copy of the default template by editing an existing Build Process definition (which uses the default template) and clicking the download link.
Next I renamed the template to OctoPackBuild.xaml and added it into TFS. I put it into a folder called BuildProcessTemplates separate from the project I wanted to build, as this template can be used for any project.
Technically you should create a Workflow Activity Library project and add the template to the project, and then check the project into TFS, but I found this to be unnecessary. See the msdn article if you want to go the whole hog.
After the xaml file is in TFS, you need to edit it in Visual Studio to get a reference to the build number. The following steps came from the answer to this msdn question.
a) Check out the OctoPackBuild.xaml file and open it in Visual Studio 2013.
b) Click the Imports tab at the bottom of the xaml editor, and add a reference to Microsoft.TeamFoundation.Build.Activities.Extensions.
c) Click the 'Overall build process' container in the xaml editor and then click the Variables tab at the bottom. Add a variable called BuildDetail, and set its type to be IBuildDetail
d) From the Toolbox, drag a GetEnvironmentVariable activity to just after the Update Build Number activity, and set the type to be IBuildDetail. Edit the activity properties; set the Name property to WellKnownEnvironmentVariables.BuildDetail, the Display Name to 'Get Build Details' (or whatever floats your boat), and the Result to BuildDetail <- this is the name of the variable you created.
e) Now that you have access to the BuildDetail object, you can pass the BuildNumber property to MSBuild. Do this by editing the CommandLineArguments property of the 'Run MSBuild' activity and setting the value to
String.Format("/p:SkipInvalidConfigurations=true {0} /p:OctoPackPackageVersion={1}", AdvancedBuildSettings.GetValue(Of String)("MSBuildArguments", String.Empty), BuildDetail.BuildNumber.Split(CChar("_"))(1))
You should note that BuildDetail is now referring to your variable, and not to 'Microsoft.TeamFoundation.Build.Client.BuildDetail'.
Also, it is important to understand that there is the assumption that the BuildNumber is in the format of [text]_[numbers]. So the Split function is removing the text part and only passing the numbers to OctoPack. If you didn't split the BuildNumber you would cause the NuGet problem which I referred to in my 1st attempt. This also means that if you put an extra underscore in your build name then you'll have to select element #2, not #1.
f) Check your customized build template (OctoPackBuild.xaml) back into TFS.
g) Next, you need to edit your Build Process to use the custom template instead of the default one.
The reason that you cannot use VS2015 for this exercise is that the UI will not allow you to select the xaml file from TFS. It looks like MS ran out of budget and that part of the UI is busted.
VS2010 also doesn't work as it cannot work with the TFS 2013 template.
The only way that I got it to work was to use VS2013 and edit the Build Process from there. VS2013 will allow you to specify a New template and navigate in TFS to find your OctoPackBuild.xaml file.
h) Then all you have to do in your Build Process is add /p:RunOctoPack=true to the MSBuild arguments and you're done.
Hope this helps someone!