Recently I have been working with a customer where we wanted to migrate some source code to TFS Services for source control but we had an existing Build Server setup running on-premise with Cruise Control. We did not want to change this over to any other continuous integration server so we were hoping to just point to our new TFS server in the cloud and it would all be straightforward. Unfortunately it wasn't this easy.
The core of our problem is that the CCnet plug in for Team Foundation Server (the vsts source control plugin) is implemented as a wrapper for TF.exe. TF.exe seems to only work with TFS Services when you have logged in with your Windows Live ID credentials. There are a few articles out there about automation of TFS Services but to be honest at this stage there seems to be a lot of people struggling with how to automate properly and particularly around the different security options. Also bottom line is that none of the articles I have seem discuss how to make TF.exe work with TFS Service without logging in via Windows Live ID.
Eventually I have managed to get this scenario working but it was quite painful so ill document it here to help anyone else who may be struggling. The approach I have taken refers back to the TFS Plugin on Codeplex for CCNet (http://tfsccnetplugin.codeplex.com/). This plugin doesn't seem to have been updated for ages so I'm not sure if it is still maintained now that CCnet has its own TFS provider. The key thing about the codeplex plugin though is that it uses the TFS assemblies rather than TF.exe so I'm going to modify that plugin to work with TFS Sevrice and the rest of this article will show you how to do it.
Before you start
Before we get into the details of this we will assume that you have just installed the latest version of Cruise Control.net. I have tested this with version 1.8.3 but I'm pretty sure it would work with earlier versions too.
Step 1: Getting your TFS Credentials
Before we get into the CCnet space, you will need your TFS Services credential set which will allow you to authenticate without Windows Live ID. To do this you need to use the TFS Credential Viewer Tool
The tool is available on the following page: http://blog.hinshelwood.com/tfs-service-credential-viewer/
The following video also shows you how to use the tool: http://youtu.be/Fkn6V0_zz28
Once you have used the tool to get your credentials you will have the following information:
Step 2: Modifying CCnet to work with .net 4
We will be writing a new plugin for CCnet to use TFS Service which will need to use the TFS objects which come with Visual Studio 2012, now you may be able to get away with writing this in older versions of Visual Studio but I was having issues with this so I have written the code in Visual Studio 2010 and targeted .net 4.0. Because Cruise Control is a .net 2.0 application by default I have modified it to run in the .net 4.0 runtime instead. If you need more info on this please refer to the following article: http://www.davidmoore.info/2010/12/17/running-net-2-runtime-applications-under-the-net-4-runtime/
To implement this change I have modified the following configuration files in the Cruise Control Server folder:
- ccnet.exe.config
- ccservice.exe.config
I have modified the runtime element to include the highlighted test telling .net 4 to use the legacy security policy.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NetReflector" publicKeyToken="2f4dd8b32acbcd8e" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.120" newVersion="1.1.2009.1214"/>
</dependentAssembly>
</assemblyBinding>
<NetFx40_LegacySecurityPolicy enabled="true"/>
</runtime>
I have also added the startup element to tell it to use .net 4 but to support .net 2.
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
Step 3: The CCNet Plugin
I have taken the code from the Codeplex TFS Plugin and modified it in two ways.
Firstly I have changed and parts where it used the AuthenticatedUser property of the sourceControl variable to use the AuthorizedUser property instead.
The 2nd change is to the TFS property where I have changed how the TeamFoundationServer reference is provided. It will use the SimpleWebTokenCredential so we can use the Identity we got credentials for in step 1 rather than an active directory based identity that you would have for an on-premise TFS instance. The below code snippet shows this:
var creds = new
TfsClientCredentials(new
SimpleWebTokenCredential(Username, Password));
var tfs = new
TfsTeamProjectCollection(new
Uri(this.Server), creds);
return tfs.TeamFoundationServer;
The code for this plug in is available at the following location:
https://s3.amazonaws.com/CSCBlogSamples/CCNetTfs.zip
One key point to node about the plugin is that the dll name needs to be ccnet.*.plugin.dll so that it is picked up by the reflection process used by CCnet. When I have compiled the assembly I simply copy it to the CCnet folder where the ccnet.exe file is.
Step 4: Modify the CCnet.config File
The ccnet.config file contains the definition of the project. I will need to modify the source control element to use my new plugin. The configuration for the plugin is very similar to the out of the box vsts source control plugin except that you don't need the executablePath property because we aren't using TF.exe. You would need to supply the username and password properties that you wouldn't usually supply on-premise (unless you were using a different account).
An example of this configuration is below (note I have highlighted the name of the new plugin):
<sourcecontrol type="tfsservice" autoGetSource="true" applyLabel="true">
<server>https://<yourTFSname>.visualstudio.com/DefaultCollection</server>
<project>$/<Your project path></project>
<cleanCopy>false</cleanCopy>
<deleteWorkspace>false</deleteWorkspace>
<workspace>TestWorkspace</workspace>
<workingDirectory>C:\TFS</workingDirectory>
<username>Account Service (<yourTFSname>)</username>
<password><My Password></password>
</sourcecontrol>
You are now ready to restart your ccnet windows service and the project should pick up your new plugin.
Conclusion
Although it was initially painful to figure out how to do this hopefully you can see that Cruise Control can be used to connect to TFS Service to build your code.