Created
September 29, 2013 00:01
-
-
Save jstangroome/6747950 to your computer and use it in GitHub Desktop.
Serialize a TFS 2012 Build Definition as XML to be version controlled
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CmdletBinding()] | |
param ( | |
$CollectionUri, | |
$ProjectName | |
) | |
Set-StrictMode -Version Latest | |
$ErrorActionPreference = 'Stop' | |
Add-Type -AssemblyName 'Microsoft.TeamFoundation, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' | |
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' | |
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Build.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' | |
# consider scanning HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\Visual Studio v11.0 Reference Assemblies | |
#Add-Type -AssemblyName 'Microsoft.TeamFoundation.Build.Workflow, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' | |
Add-Type -Path 'C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Build.Workflow.dll' | |
$Collection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($CollectionUri) | |
$BuildServer = $Collection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer]) | |
$Definitions = $BuildServer.QueryBuildDefinitions($ProjectName) | |
$Def = $Definitions | ? { $_.queuestatus -eq 'enabled' } | select -skip 3 -First 1 | |
function Convert-BuildDefinitionToXml { | |
[CmdletBinding()] | |
param ( | |
[Microsoft.TeamFoundation.Build.Client.IBuildDefinition] | |
$Definition, | |
[string] | |
$CollectionUri | |
) | |
$x = [xml]'<BuildDefinition />' | |
# TODO build def uri, collection uri, team project name? | |
$x.DocumentElement.AppendChild($x.CreateElement('Uri')).InnerText = $Definition.Uri | |
$x.DocumentElement.AppendChild($x.CreateElement('Id')).InnerText = $Definition.Id | |
$x.DocumentElement.AppendChild($x.CreateElement('TeamProject')).InnerText = $Definition.TeamProject | |
$x.DocumentElement.AppendChild($x.CreateElement('CollectionUri')).InnerText = $CollectionUri | |
# general | |
$x.DocumentElement.AppendChild($x.CreateElement('Name')).InnerText = $Definition.Name | |
$x.DocumentElement.AppendChild($x.CreateElement('Description')).InnerText = $Definition.Description | |
$x.DocumentElement.AppendChild($x.CreateElement('QueueStatus')).InnerText = $Definition.QueueStatus | |
# trigger | |
$triggerX = $x.DocumentElement.AppendChild($x.CreateElement('Trigger')) | |
$triggerX.AppendChild($x.CreateElement('TriggerType')).InnerText = $Definition.TriggerType | |
$triggerX.AppendChild($x.CreateElement('ContinuousIntegrationType')).InnerText = $Definition.ContinuousIntegrationType | |
$triggerX.AppendChild($x.CreateElement('ContinuousIntegrationQuietPeriodMinutes')).InnerText = $Definition.ContinuousIntegrationQuietPeriod | |
$triggerX.AppendChild($x.CreateElement('BatchSize')).InnerText = $Definition.BatchSize | |
foreach ($Schedule in $Definition.Schedules) { | |
$scheduleX = $triggerX.AppendChild($x.CreateElement('Schedule')) | |
$scheduleX.AppendChild($x.CreateElement('DaysToBuild')).InnerText = $Schedule.DaysToBuild | |
$scheduleX.AppendChild($x.CreateElement('StartTimeSecondsPastMidnight')).InnerText = $Schedule.StartTime | |
$scheduleX.AppendChild($x.CreateElement('TimeZone')).InnerText = $Schedule.TimeZone | |
$scheduleX.AppendChild($x.CreateElement('Type')).InnerText = $Schedule.Type | |
# TODO serialize TimeZoneInfo as culture-invariant | |
} | |
#workspace | |
# TODO optional path translation | |
$workspaceX = $x.DocumentElement.AppendChild($x.CreateElement('Workspace')) | |
foreach ($Mapping in $Definition.Workspace.Mappings) { | |
$mappingX = $workspaceX.AppendChild($x.CreateElement('Mapping')) | |
$mappingX.AppendChild($x.CreateElement('MappingType')).InnerText = $Mapping.MappingType | |
$mappingX.AppendChild($x.CreateElement('ServerItem')).InnerText = $Mapping.ServerItem | |
$mappingX.AppendChild($x.CreateElement('LocalItem')).InnerText = $Mapping.LocalItem | |
$mappingX.AppendChild($x.CreateElement('Depth')).InnerText = $Mapping.Depth | |
} | |
#build defaults | |
$controllerX = $x.DocumentElement.AppendChild($x.CreateElement('BuildController')) | |
$controllerX.AppendChild($x.CreateElement('BuildControllerUri')).InnerText = $Definition.BuildControllerUri | |
$controllerX.AppendChild($x.CreateElement('Name')).InnerText = $Definition.BuildController.Name | |
$controllerX.AppendChild($x.CreateElement('Description')).InnerText = $Definition.BuildController.Description | |
$controllerX.AppendChild($x.CreateElement('CustomAssemblyPath')).InnerText = $Definition.BuildController.CustomAssemblyPath | |
$x.DocumentElement.AppendChild($x.CreateElement('DefaultDropLocation')).InnerText = $Definition.DefaultDropLocation | |
# process | |
$processX = $x.DocumentElement.AppendChild($x.CreateElement('Process')) | |
$processX.AppendChild($x.CreateElement('Id')).InnerText = $Definition.Process.Id | |
$processX.AppendChild($x.CreateElement('Description')).InnerText = $Definition.Process.Description | |
$processX.AppendChild($x.CreateElement('ServerPath')).InnerText = $Definition.Process.ServerPath | |
$processX.AppendChild($x.CreateElement('SupportedReasons')).InnerText = $Definition.Process.SupportedReasons | |
$processX.AppendChild($x.CreateElement('TeamProject')).InnerText = $Definition.Process.TeamProject | |
$processX.AppendChild($x.CreateElement('TemplateType')).InnerText = $Definition.Process.TemplateType | |
$processX.AppendChild($x.CreateElement('Version')).InnerText = $Definition.Process.Version | |
# TODO use WorkflowHelpers.DeserializeProcessParameters to translate paths but serialize as-is | |
$parametersX = $x.DocumentElement.AppendChild($x.CreateElement('ProcessParameters')) | |
[void]$parametersX.AppendChild( $x.CreateCDataSection( $Definition.ProcessParameters) ) # TODO escape ]] in parameters | |
<# | |
$Dictionary = [Microsoft.TeamFoundation.Build.Workflow.WorkflowHelpers]::DeserializeProcessParameters($Definition.ProcessParameters) | |
#> | |
# retention policy | |
$policyListX = $x.DocumentElement.AppendChild($x.CreateElement('RetentionPolicyList')) | |
foreach ($Policy in $Definition.RetentionPolicyList) { | |
$policyX = $policyListX.AppendChild($x.CreateElement('RetentionPolicy')) | |
$policyX.AppendChild($x.CreateElement('BuildReason')).InnerText = $Policy.BuildReason | |
$policyX.AppendChild($x.CreateElement('BuildStatus')).InnerText = $Policy.BuildStatus | |
$policyX.AppendChild($x.CreateElement('DeleteOptions')).InnerText = $Policy.DeleteOptions | |
$policyX.AppendChild($x.CreateElement('NumberToKeep')).InnerText = $Policy.NumberToKeep | |
} | |
# TODO attached properties at the various levels of the hierarchy? | |
return ,$x | |
} | |
$buildxml = Convert-BuildDefinitionToXml -Definition $Def -CollectionUri $CollectionUri | |
$buildxml.Save('c:\temp\build.xml') | |
gc 'c:\temp\build.xml' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Curious, would you expect this to work with TFS 2010 if the assemblies to load for Add-Type were changed to version '10.0.0.0' (and the -Path changed to 10.0 folder)?