In my previous post I introduced TeamCity as an alternative build server to use in conjunction with Team Foundation Server. This post mainly focused on getting started with TeamCity and building sources coming from Team Foundation Server. At the end of this previous post I talked about the dependency of TFS artifacts with the TFS Build System. For example, selecting a build in Test Manager, can only be a build created with the TFS Build system. In this post I will talk about how to create a tight integration between TeamCity and TFS so that you can use the TeamCity build within Test Manager and in Work Items ….or at least fake that ..
Setting up TFS Build
As said, currently you need a build created in TFS in order to tie other artifacts to it. Of course you don’t need to tie everything together, but when you want traceability, reports or overview it is the wisest thing to do. So what we need is a build in Team Foundation Server. But….we use TeamCity. True, therefore we create a a very simple build in TFS as part of our Team Project that builds a blank solution. In the sources that you can download from github here you will find a blank solution called PlaceholderBuild.sln.
Check this file into your source Control and create a build definition for it.
I created an (old fashioned) XAML Build definition, that used the default template (later this will change), and pointed to this solution. I called the build definition [TeamCity_PlaceHolder].
Run the build and make sure it works !
Publishing the TeamCity drop to a network share
TeamCity does not use a network share as its drop location as TFS does. But when we want to integrate things we need a drop location on a network share. Fortunately TeamCity has the ability to load plugins to add additional build steps. To publish artifacts to a network location you can use the Deployer plugin. The TeamCity manual about installing a plugin is a bit unclear. To understand the plugins in TeamCity you can better read this page. Or…if you just want to install the deployer plugin..follow these steps.
- Download the deployer plugin
- Unblock the zip file
- Stop the TeamCity server by running [TeamCityInstallationDir]\bin\Runall.bat stop
- Navigate to the [TeamCityInstallationDir]\webapps\ROOT\WEB-INF\plugins directory and copy the zipfile here (do not extract!)
- Start the TeamCity server by running [TeamCityInstallationDir]\bin\Runall.bat start
If everything went well, the plugin was installed
Now we need to update our Build Configuration in Team Citty, so that it publishes to a network share. Open the build steps section in the Build Configuration and add a step.
Select the SMB Deployer and fill in the steps
- Runner type: SMB Deployer. This is the one that publishes to a network share. There are more deployers available
- Target URL: Fill in the drop location of the binaries. Note the %build.number%.. This is a variable that is replaces with the build name (e.g. ColorGallery_13)
- Artifacts path: Fill in the path of your artifacts (as defined in the first build step) and publish to / . This publishes everything in the root of the %build.number% folder. Just like TFS does
After running the build you will see something like this
Change the TFS Build Template
So now we have a TeamCity build and a TFS build. But how can we “link” those two builds together? First thing would be to align the name of the build. If you look in TeamCity or in TFS the builds are called the same. Second thing to do is aligning the drop location so that the build results in TFS open the artifacts location from Team City. In the previous step we have already made sure that TeamCity drops the binaries on a share.
When you run the build that we defined in TFS (TeamCity_PlaceHolder) you will see that the name of the build is [TeamCity_PlaceHolder_YYYYMMDD.RRR].
This name cannot be traced to the TeamCity build, so we need to change that. The drop location is the one that we configured in the build definition so we need to change that too. In order to do that we need to modify the XAML build template and use the modified template instead of the default one. On MSDN there is guidance on how to do this (found here ). But I will do a shorter version.
- Open the build definition and navigate to the [Process] Tab
- Press download under the dropdown box and download your template
- Open the XAML template in Visual Studio and add 2 parameters to the template. In my case I added
- Open the properties of the [Update build number] task and set the value of the build number to the [RoadToALM_BuildName] property
- Under the Update build number task, add a [SetBuildProperties] task from the toolbox. Set the properties to update to [DropLocation] and set the [DropLocation] property to the [RoadToALM_DropLocation] value
- Save the XAML template (I saved it as TFVCTemplate.v12.TeamCity] and add this to Source Control
- Edit the Build Definition and choose this new template as the Build Process Template to use.
Triggering the TFS Build
Now we need to trigger the TFS Build. This is not something we want to do manually, so I created a small Console Application for that (download at Github). I used the CommandLineParser NuGetPackage to get some help in parsing the command line arguments
I added a few options to my Command Line
In my code I make connection to Team Foundation Server, find the Build Definition with the name specified and queue a new build with my 2 custom parameters.
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(new Uri(options.TeamProjectCollectionUrl));
//Call Build
IBuildServer buildServer = collection.GetService<IBuildServer>();
IBuildDefinition definition = buildServer.GetBuildDefinition(options.TeamProjectName,
options.BuildDefinition);
IBuildRequest request = definition.CreateBuildRequest();
request.ProcessParameters = UpdateVersion(request.ProcessParameters, options);
request.DropLocation = options.DropLocation;
buildServer.QueueBuild(request);
private static string UpdateVersion(string processParameters, Options o)
{
IDictionary<String, Object> paramValues = WorkflowHelpers.DeserializeProcessParameters(processParameters);
paramValues[Constants.PARAMETER_BUILD_NAME] = o.NameBuild;
paramValues[Constants.PARAMETER_DROP_LOCATION] = o.DropLocation;
return WorkflowHelpers.SerializeProcessParameters(paramValues);
You can download the source of this console application on github
Connecting TFS and TeamCity
So now we have 2 builds and a console application that triggers a TFS build. Now it is time for the final step. Triggering the TFS build from Team City and adding the parameters. First you need to copy the console application executable to the TeamCity server. I copied it to a directory BuildScripts.
Then we need to go back to the build steps of our build configuration and add a command line step.
In the Custom script section add the following line
C:\<path to exe>\RoadToALM.Build.StartTFSBuild.v12.exe -n “%build.number%” -c “http://tfs:8080/tfs/DefaultCollection” –p “TeamProjectName” –b “TeamCity_PlaceHolder” -d “\\server\drops\%build.number%”
Notice the %build.number% placeholders that are filled in by TeamCity.
Running the build now triggers a TFS build. The TFS build receives the new name and droplocation and sets this on the TFS build.
In the picture above you see the name of the build in TeamCity set to the TFS Build as well. The drop location also points to the location of the TeamCity artifacts. Great thing is that TFS retention policies will just work on this drop directory because they are connected.
Summary
Team Foundation Server is complete ALM solution but if you want to use another component this is perfectly valid. By using the TFS API and extension points we can easily integrate two great products to leverage the best of both world !
Reblogged this on Dinesh Ram Kali..
Nice article. What about using visual studio online TFS? Do you planning to do an example or guide for that? Would be nice!
Hi, thanks for the comment. VSO is TFS online. So it is already integrated. What would you like to know ?
Reblogged this on Code and commented:
An interesting solution to integrating TFS (on premises) with TeamCity for tightly Application Lifecycle Management (ALM). This solution probably does need some updating for TFS’s new build model. Also, it would be nice to have an automated provisioning mechanism. Having a solution like this in place would allow gating pull requests based on whether or not they have a successful TeamCity build.