TFS 2017 copy build definition template between team projects

By Mirek on (tags: build definition, Powershell, tfs, vNext, VSO, categories: tools, infrastructure)

Over a year ago I’ve presented a solution to copy build definitions between team projects in new Team Foundation Server 2015. That was a workaround for missing functionality in TFS, so there was no standard way to save the build definition as a template and reuse it outside the scope of current team project. Well, in TFS 2017 it hasn’t change yet…

There is still no way to reuse build definitions between team projects directly from the web portal of TFS. However thanks to its rich REST api this is quite easy to do it programatically, for instance with use of Powershell scripting facilities. The TFS REST api is well documented here.

I use the build rest api which allows to get, put and delete build definitions as well as build templates for all team projects. The powershell script looks like this

function Clone-TFSBuildDefinitionTemplate
{
    [CmdletBinding()]
    param(
       [Parameter(Mandatory=$true)][string]$TfsUrl,
       [Parameter(Mandatory=$true)][string]$sourceProjectName,
       [Parameter(Mandatory=$true)][string]$targetProjectName,
       [Parameter(Mandatory=$true)][string]$buildTemplateId,
       [PSCredential]$Credential = (Get-Credential)
    )
 
    $buildTemplatesURL = "{0}/DefaultCollection/{1}/_apis/build/definitions/templates/{2}?api-version=2.0"
 
    #get build definition as JSON
    $headers = @{ "Accept" = "application/json; api-version=2.0"; "Content-Type" = "application/json" }
 
    #http://{TFS_URL}/DefaultCollection/{TeamProject_Name}/_apis/build/definitions/templates?api-version=3.0
    $url = ($buildTemplatesURL -f $TfsUrl, $sourceProjectName, $buildTemplateId)  
    Write-Host "Receiving build definition template at $url"
 
    $buildTemplateDef = Invoke-RestMethod -Uri $url -Credential $Credential -Headers $headers -Method Get 
 
    #clear unnecessary stuff
    $buildTemplateDef.template.PSObject.Properties.Remove("metrics")
    $buildTemplateDef.template.PSObject.Properties.Remove("_links")
    $buildTemplateDef.template.PSObject.Properties.Remove("repository")
    $buildTemplateDef.template.PSObject.Properties.Remove("defaultBranch")
    $buildTemplateDef.template.PSObject.Properties.Remove("queue")
    $buildTemplateDef.template.PSObject.Properties.Remove("project")
    $buildTemplateDef.template.PSObject.Properties.Remove("name")
    $buildTemplateDef.template.PSObject.Properties.Remove("url")
    $buildTemplateDef.template.PSObject.Properties.Remove("uri")
    $buildTemplateDef.template.PSObject.Properties.Remove("id")
    $buildTemplateDef.template.PSObject.Properties.Remove("revision")
    $buildTemplateDef.template.PSObject.Properties.Remove("path")
    $buildTemplateDef.template.PSObject.Properties.Remove("type")
    $buildTemplateDef.template.PSObject.Properties.Remove("properties")
    $buildTemplateDef.template.PSObject.Properties.Remove("authoredBy")
 
    $buildTemplateDefJSON = $buildTemplateDef | ConvertTo-Json -Depth 100
 
    #replace all occurences of source project name
    $buildTemplateDefJSON = $buildTemplateDefJSON -replace $sourceProjectName, $targetProjectName;
 
    #Store build definition template in new project
    $url = ($buildTemplatesURL -f $TfsUrl, $targetProjectName, $buildTemplateId)  
    Write-Host "Storing build definition template to $url"
    $buildTemplateDef = Invoke-RestMethod -Uri $url -Credential $Credential -Headers $headers -Method Put -Body $buildTemplateDefJSON  
 
   }

Assumming we have a team project “MyProject” and a build definition template in it called “dev” and we have a team project “SecondProject”, we can easily copy the build definition template using above function. We do it like this:

Clone-TFSBuildDefinitionTemplate “http://my-tfs” "MyProject" "SecondProject" "dev"

We will be asked for the credentials with a visual prompt. As you can see the script removes some of the unnecessary project specific data from the template, so it better fits to the new team projects. It also searches for all team project name strings and replaces them with the new one. After that we should already see the build definition template available in “SecondProject” when creating a new build definition

image