Mixing TFVC and Git

· by giulio · Read in about 3 min · (577 Words)

It all started because I needed using files coming from a Git repository and additional files stored in classic Team Foundation Version Control (TFVC), all toghether in the same build.

The Options

You have three options: the REST API, the tf.exe vc command or … we will see.

Option 1 – REST API

My first attempt relied on a Powershell script to download the files from TFVC using REST API. It worked but performance is not that great as you have to download a file at a time in a loop.

Here is some sample code for it

$tempFile = "$env:BUILD_SOURCESDIRECTORY\all.json"
$authHeader = @{ Authorization=( "Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(":${env:PAT}")) ) }

Invoke-RestMethod -Uri "${env:TfsProjectUrl}/_apis/tfvc/items?scopePath=${env:TfvcPath}&recursionLevel=Full&api-version=1.0" -headers $authHeader -Method Get -OutFile $tempFile

$headers = $authHeader + @{ Accept= 'application/octet-stream' }
$baseTfvcPath = Split-Path $tfvcPath -Leaf
(Get-Content $tempFile | ConvertFrom-Json).value | foreach {
    $f = $_.path.Replace( $tfvcPath + '/', '' )
    if ($_.isFolder) {
        New-Item (Join-Path $baseTfvcPath -ChildPath $f) -Force -ItemType Directory >$null
    } else {
        Write-Host "Downloading ${f}"
        Invoke-RestMethod -Uri $_.url -headers $headers -Method Get -OutFile $baseTfvcPath/$f

The script uses three variables specifing the connection and authentication data in the form of a Personal Access Token (PAT).

Variable Sample value
TfsProjectUrl https://tfsaggregator.visualstudio.com/ProjectName
TfvcPath $/ProjectName/References
PAT 3wvu….sk7a

Option 2 – tf vc

A second option would be to use tf.exe. In order to do so, you need to define a workspace including the mapping: a very boring and detailed process with no less that the following four commands.

tf vc workspace /new 
tf vc workfold
tf vc get $/YourProject
tf vc workspace /delete

Using this approach is not something I would recommend lightly, in particoular handling errors correctly is non trivial. Furthermore, you have to put authentication data in variables.

Option 3 – Chain two build!

But wait, both Visual Studio Team Services (VSTS) and Team Foundation Server (TFS) can use TFVC as a version control source, so why not simply add all downloaded files as resulting build artifacts? The build using Git picks the artifacts from another build using TFVC.

Let’s see how it works in details.

TFVC dummy build (Upstream Producer)

Get the files from TFVC

Get from TFVC

and publish them all as artifacts

Publish Artifacts

I activated the new Build Editor, so if you are still using the old editor, the screenshots will look different.

Git Build (Downstream Consumer)

First you need to search the Marketplace for Fetch Build Artifacts Extension

'Fetch Build Artifacts' Extension in Marketplace

and install it onto your system

Extension Installed

Add the extension Task to your Build Definition

Fetch Build Artifacts Task

The Build Definition Id can be found in the Process Variables of the TFVC dummy build

Process Variables of TFVC dummy build

Note: the Extension requires access to the OAuth token as shown in the below screenshot.

Access to OAuth token

Pros & Cons

Some side benefits:

  1. The scenario went down from three minutes to less than 30 seconds compared to the REST APIs;
  2. You need one less Task and three less Variables;
  3. You don’t need to manage a PAT

On the other hand, the downstream Git build is using a snapshot defined by the upstream TFVC which can be a good or a bad thing.

The build chaining fits quite well my scenario, where I need some additional references and I could not stored them in the Git repository. Also, the DLLs are quite static and do not change much.

Do not forget to mark the upstream build as retained if you need to keep a specific version around.

This technique is in use at our open source project TFS Aggregator.

Happy Building!