How to customize TFS Build project

A couple days ago, I presented a session called “Continuous Integration throughout the Entire Development Lifecycle” at an Application Lifecycle Management (ALM) event held at Auditorium East, Level 29, Microsoft Malaysia’s office. As promised I will blog about my findings and what I’d demo at my session. I’ll be explaining how to customize your TFS Build project so that you could override an existing target with a custom task.

 

TFS Build is essentially built on top of the foundation provided by MSBuild. Having said that, you could customize TFS Build just like how you would customize your MSBuild script. To find out what are the customizable Team Foundation Build targets, there is a good article on MSDN that explains it well. I’m not exactly adept at creating my own custom tasks, so to my delight I found the MSBuild Extension pack which you could download from Codeplex.

 

After installing the MSBuild Extension pack, the next thing to do is to edit the TFSBuild.proj file which can be found under the default source control folder named TeamBuildTypes. You may have a number of Team Build types already defined. Each Team Build type corresponds to a build definition. Take note that this is the file that you had set along with its version control folder in the Build definition wizard as shown in the following screen clipping:

image

In the following task, I am editing the TFSBuild.proj that corresponds to my build definition called “ALM111908Build”.

image

Check out to edit the TFSBuild.proj file. Open up the file in the Visual Studio editor. I’ll be customizing the Team Foundation Build target, BeforeDropBuild, with a task I am borrowing from the MSBuild extension pack called MSBuild.ExtensionPack.Communication.Email. The definition of the BeforeDropBuild target is:

BeforeDropBuild
Called before saving the built binaries, build log files, and test results to the build-drop directory on the release server. Insert your task into this target to run custom tasks before the built files are saved to the drop-directory.

This task I’m borrowing may be similar to the “A build completes” in the Project Alerts in TFS as illustrated in the following screen clipping.

image

However I have more control over how the notification email is composed such as including attachments, recipients, subject and body of the email. And I could also decide when to send an email notification at any stage along the TFS Build process, not just when a build completes.

At the end of the TFSBuild.proj file, right before the </Project> closing element, I add the following:

<UsingTask AssemblyFile="$(MSBuildExtensionsPath)\\ExtensionPack\\MSBuild.ExtensionPack.dll" TaskName="MSBuild.ExtensionPack.Communication.Email"/>

<Target Name="BeforeDropBuild">
  <ItemGroup>
    <!-- Specify some attachments -->
    <Attachment Include="C:\demo.txt"/>
    <!-- Specify some recipients -->
    <Recipient Include="darren@tfs.local"/>
  </ItemGroup>
  <MSBuild.ExtensionPack.Communication.Email TaskAction="Send" Subject="Email After Build 5pm" SmtpServer="tfsrtm08" MailFrom="tfsbuild@tfs.local" MailTo="@(Recipient)" Body="This email is sent after ALM Build" Attachments="@(Attachment)"/>
</Target>

Be sure to check in the TFSBuild.proj into the source control. Otherwise, your current build definition will not be able to invoke the overriden TFS Build target. If you have set up continuous integration, which in other words each check-in will trigger a TFS Build, you will realize that checking in TFSBuild.proj will not trigger any build. This is an expected behavior because only files within your solution will trigger a build. So if you want to see that the customized email task for the BeforeDropBuild target is successfully performed, you can just queue a new build in the Team Explorer Build menu. You can then check out the BuildLog.txt file, and search for BeforeDropBuild. The first thing you see if the following:

Overriding target "BeforeDropBuild" in project "C:\Program Files\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" with target "BeforeDropBuild" from project "C:\Documents and Settings\TFSBUILD\Local Settings\Temp\Demo\ALM111808Build\BuildType\TFSBuild.proj".

 

This means that TFS Build understands that you are overriding the the “BeforeDropBuild” with a custom task. Subsequently when you search for another occurrence of the target, you will see the following:

Target "BeforeDropBuild" in file "C:\Documents and Settings\TFSBUILD\Local Settings\Temp\Demo\ALM111808Build\BuildType\TFSBuild.proj" from project "C:\Documents and Settings\TFSBUILD\Local Settings\Temp\Demo\ALM111808Build\BuildType\TFSBuild.proj":
Using "MSBuild.ExtensionPack.Communication.Email" task from assembly "C:\Program Files\MSBuild\\ExtensionPack\\MSBuild.ExtensionPack.dll".
Task "MSBuild.ExtensionPack.Communication.Email"
  Sending email: Email After Build 5pm
  Adding recipient: darren@tfs.local
  Adding attachment: C:\demo.txt
Done executing task "MSBuild.ExtensionPack.Communication.Email".
Done building target "BeforeDropBuild" in project "TFSBuild.proj".

The final check before you shout VOILA is when you see this email in your inbox:

image

Just remember that there are plenty of other tasks you could borrow from the MSBuild Extension Pack. For instance I can compress the assemblies after the build, deploy my web app to IIS 7, create an event log in Windows, and basically anything you have in mind that you want to associate to your TFS Build.