Team Foundation Server’s build system serves as the “heartbeat” for your development lifecycle.  It automatically creates relationships between code changes, work items, reports, and test plans.

But once in a while I’m asked, “What if we don’t use TFS Build for building our application, but we still want to have builds in TFS so we can track and associate work?”  Besides the biased question of “Why NOT use TFS Build, then?!”, there is sometimes the need to leverage the benefit of having empty/fake builds in TFS that don’t do anything more than create a build number/entry in TFS.

There are a couple scenarios where this makes some sense, but the most common one I hear is this:

Without builds in TFS, it’s near impossible (or at least very inconvenient) to tie test plans (accurately) to the rest of the lifecycle.

Luckily, TFS 2010’s build system is incredibly flexible: flexible enough to allow us to “fake” builds without actually performing build actions (get source, compile, label, etc.).  It’s surprisingly simple, actually; and it doesn’t require writing any code.

In my example (which I’ll detail below), I define a build which doesn’t do much more than craft a build number and spit out some basic information to the build log.

First, create a new build process template, based on the default process template, using the steps described in this MSDN article.

Once you have the process template created and registered in TFS, open the new template (.xaml file) in Visual Studio.  It will look (collapsed) something like this:

Collapsed default build process template

Here’s where it gets fun.  Inside the outermost sequence, delete every sequence or activity except for “Get the Build”.

Drag an UpdateBuildNumber activity from the toolbox into the sequence, after “Get the Build”.

(optional) Rename “Get the build” to “Get Build Details” so there’s no implication that an actual build will take place".

Now expand the Arguments section (at the bottom of the XAML Designer window).  Delete all arguments except for BuildNumberFormat, Metadata, and SupportedReasons.

At the bottom of the now-shorter list, use “Create Argument” and create the following arguments:

Name Direction Argument type Default value
MajorBuildName In String  
MinorBuildName In String  
Comment In String  
IncludeBuildDetails In Boolean True

MajorBuildName” and “MinorBuildName” will be used to help manually name each build.  “Comment” will be used to capture any notes or comments the builder wants to include for a given build.  “IncludeBuildDetails” will be used to determine if additional summary information about the build will be written to the build log.

To provide users with means to set values to these arguments, create parameters in Metadata.  Click the ellipsis (…) in the Default value column for Metadata.  This will bring up the Process Parameters Metadata editor dialog.  Add each of the following parameters:

Parameter Name Display Name Category Required View this parameter when
MajorBuildName Major Build Name Manual Build Details Checked Always show the parameter
MinorBuildName Minor Build Name Manual Build Details Unchecked Only when queuing a build
Comment Comment Manual Build Details Unchecked Only when queuing a build
IncludeBuildDetails Include Build Details Summary Manual Build Details Unchecked Always show the parameter

Process Parameter Metadata editorA couple notes about setting the above parameters:

  • The “parameter name” should match the name of the like-named argument.
  • Use the exact same category name for each parameter, unless you want to see different groupings.  Also, check for any leading or trailing whitespace, as the category field is not trimmed when saved.
  • Feel free to add descriptions if you like, as they may help other users understand what to do.
  • Leave the “Editor” field blank for each parameter.

Your dialog should now look something like the one at right.

Next, open the expression editor for the Value property of the BuildNumberFormat argument and edit the value to read: “$(BuildDefinitionName)_$(Date:yyyyMMdd)_$BuildID)”. Including the BuildID will help ensure that there is always a unique build number.

Now, Click “Variables” (next to Arguments) and create a new variable named ManualBuildName of type String, scoped to the Sequence, and enter the following as the Default:

If(String.IsNullorEmpty(MinorBuildName), MajorBuildName, MajorBuidName & “.” & MinorBuildName)

This variable will be used to provide a manual build name using the supplied MajorBuildName and MinorBuildName arguments.

Now we have all the variables, arguments, and parameters all ready to go.  Let’s put them into action in the workflow!

Drag a WriteBuildMessage activity into the main sequence, before Get Build Details, with these settings:

  • Display name: “Write Build Comment”
  • Importance: Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High
  • Message: “Comment for this build: “ & Comment

Next, add an “If” activity below “Get Build Details” to evaluate when to include additional details in the build log, with the following properties:

  • Display name: “Include Build Details If Chosen”
  • Condition: IncludeBuildDetails

In the “Then” side of the “If” activity, add a WriteBuildMessage activity for each piece of information you may want to include in the build log.  In my example, I included 3 activities:

Display name Importance Message
Write Team Project Name Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High “Team Project: “ & BuildDetail.TeamProject
Write Requested for Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High “Requested for: “ & BuildDetail.RequestedFor
Write Build reason Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High “Build Reason: “ & BuildDetail.Reason.ToString()

Your “If” activity will look like this:

If activity for showing build details

The last thing to do is to add an UpdateBuildNumber activity as the last element in the main sequence, with the following properties:

  • Display name: “Set Build Number”
  • BuildNumberFormat: BuildNumberFormat & “-“ & ManualBuildName

This last activity will actually create the build number which will be stored back into TFS.  Your completed workflow should look like this:

Completed fake build process

Now go back to Source Control Explorer and check this template back into TFS.

Go create a new build definition, opting to use your new template on the process tab.  You’ll notice that your options are dramatically simplified:

Process tab on build definition editor

Specify a value for Major Build Name and save your new definition. 

Queue the build and you’ll see the following on the Parameters tab:

Parameters tab while queuing a build

Enter some basic information and click “Queue” to run the (fake) build.

What you end up with is a build that completes in just a couple seconds, does pretty much nothing, but includes your specified information in the build log:

Build log after fake build

Pretty sweet!

And just to be clear, my example adds more “noise” into the build than you may find necessary, with additional build information, comments, etc.  You could streamline the build even more by removing the “Include Build Details If Chose” activity (and all its sub-activities).

Given the overall flexibility TFS 2010 has with incorporating Windows Workflow into the build system, there are undoubtedly other ways to accomplish variations of this type of build template.  But I had fun with this one and thought I should share.  I’ve posted my sample template’s xaml file on SkyDrive here:

I’m all ears for feedback!