TFS – XSLT to transform VSSConverter to Project Creation Settings File
For the last few weeks I’ve been spending a decent portion of my time (jointly) planning and testing my team’s migration from VSS to TFS. While I’m a big fan of Microsoft’s development platform I’ve been pleasantly surprised at the simplicity of the migration process. Visual Studio 2010 brings with it a command line application called VSSConverter which takes an XML file and completes transfer of code and history with almost no input…almost! The file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<SourceControlConverter>
<ConverterSpecificSetting>
<Source name="VSS">
<VSSDatabase name="C:\TFSMigration\vss_database"></VSSDatabase>
<UserMap name="c:\UserMap.xml"></UserMap>
</Source>
<ProjectMap>
<Project Source="$/BillingProject/BillingProject/Client" Destination="$/BillingProject/Client"></Project>
<Project Source="$/BillingProject/BillingProject/Server" Destination="$/BillingProject/Server"></Project>
</ProjectMap>
</ConverterSpecificSetting>
<Settings>
<TeamFoundationServer name="myserver.mydomain.com" port="8080" protocol="http" collection="tfs/MyProjectCollection">
</TeamFoundationServer>
</Settings>
</SourceControlConverter>
One frustration I have with the tool is that, while you must define your VSS-to-TFS project mapping, TFS projects are not automatically created – they must be created one-by-one using Visual Studio prior to migration. If you have a large number of projects (which we do) this can be quite frustrating (increasing exponentially with every test iteration run).
Fortunately, TFS’s powertools provide a mechanism to create projects based on a setting file. The command is as follows:
TFPT createteamproject /settingsfile:1.xml
Unfortunately a) it cannot use the existing information in the TFS conversion scripts and b) a separate setting file is required for each project to be created.
To save some time I wrote the following XSLT file. Applied to a VSS-to-TFS conversion file it will output an individual xml file for each project defined therein (filenames are incremented – 1.xml, 2.xml, etc.). Obviously some settings (TFS server/process template/etc.) are hard-coded and may need to be modified.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="ProjectMap">
<xsl:for-each select="Project">
<xsl:variable name="filename" select="concat('output/',position(),'.xml')" />
<xsl:value-of select="$filename" />
<xsl:result-document href="{$filename}">
<Project xmlns="ProjectCreationSettingsFileSchema.xsd">
<TFSName>http://mytfsserver:8080/tfs/myprojectcollection</TFSName>
<LogFolder>c:\temp</LogFolder>
<ProjectName><xsl:value-of select="substring-before(substring-after(@Destination,'$/'),'/')"/></ProjectName>
<ProjectSiteEnabled>true</ProjectSiteEnabled>
<ProjectSiteTitle><xsl:value-of select="@Destination"/></ProjectSiteTitle>
<ProjectSiteDescription></ProjectSiteDescription>
<SccCreateType>New</SccCreateType>
<SccBranchFromPath></SccBranchFromPath>
<ProcessTemplateName>MSF for Agile Software Development v5.0</ProcessTemplateName>
</Project>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I personally use Saxon to transform my conversion file – both because it is quick and easy and because, unlike MSXSL it supports XSL 2.0). Afterwards I can use the TFPT createteamproject command to create my projects. The commands used are as follows:
Saxon\Transform.exe -s:conversion.xml -xsl:transformer.xslt
TFPT createteamproject /settingsfile:1.xml
TFPT createteamproject /settingsfile:2.xml
On a side, it should be straightforward to create a batch/powershell script to loop through the XML files and invoke the TFPT createteamproject command, but I’ll leave that to you, dear readers. Let me know if this is useful or if there is a quicker and easier way to achieve the same goal. Until next time…
Comments
Also, I wish they were more clear on how the user mapping works. From different sources online it seems that I either can or can't just map the deleted user John.Doe to john.doe and have it work... That's my next test once I get the projects created.