Making a TFS Build wait

In my career I have created Automated builds for many different technologies. TFS never lets me down. The old XAML build did a good job however the new TFS 2015 Builds are awesome. First of all I love PowerShell, which makes my life much easier. I can just call out to a script sitting in source control or better yet create my own Build Task and upload it to the server.

I recently had to create a build for a development tool that generates documents from various system data. This tool has it’s own editor, version control,  release management everything. It’s kind of a closed eco system.

So how do we get the rest of the team involved in it’s builds and deployments. How do I trigger a build and have this system drop a deployable package for me, that I can deploy to different environments without having to ask the developers? Letting QA be responsible for their own environment.

After talking with an expert in this tool. It turns out, it also has an automation component. The developers can write scripts to perform builds and deployments. However we want this to be part of a larger eco system with our other applications.

It was decided that we would create a file share on the network where I could drop a file to let the other system know I wanted a new build dropped. This way TFS would still generate a build number the testers can deploy to the QA environment and reference from their test plan so we get the full end to end traceability.

So I wrote a script that would drop a file (Build.txt) in a known location on the network. Said products automation tool watches for my file and triggers a script to perform a build when it sees it and then drops that build package back for me to turn into a build artifact. I will put the build number in this file so the other system can use that as a label in it’s own Version Control system.

Then the build waits and watches for a file named BuildComplete.txt to be placed back in that working folder. When my build sees it I know the built package is there and I can create a build artifact. By the way the BuildComplete.txt either contains the word successful or an error log if something went wrong. I will pull that out and toss it up into the build console.

My build has two tasks one to Drop the file that triggers the other system and one to create a build artifact. The second one is already built into TFS “Copy and Publish Build Artifacts”. The first step is one Powershell script. See below with Comments:

The Powershell script takes two arguments The WorkingFolder and a timeout.

image

 

 

 

The comments in line explain how it works.

   1: param()
   2:  
   3: #This is how we do parameters in a custom build task 
   4: Trace-VstsEnteringInvocation $MyInvocation
   5: try {
   6:     Import-VstsLocStrings "$PSScriptRoot\Task.json" 
   7:     [int32]$timeout = Get-VstsInput -Name TimeOut
   8:     [string]$WorkingFolder = Get-VstsInput -Name WorkingFolder 
   9: } 
  10: finally 
  11: { 
  12:      Trace-VstsLeavingInvocation $MyInvocation 
  13: } 
  14:  
  15: #Start the Timer at zero
  16: $timesofar = 0
  17: #This is the file we are looking for to know the package is complete 
  18: $BuildComplete = "$WorkingFolder\BuildComplete.txt"
  19: #Clean the Working Folder
  20: Remove-Item  "$WorkingFolder\*"
  21: #Create file containing Build number to trigger the build
  22: New-Item -path "$WorkingFolder" -name 'Build.txt' -type 'file' -value "$env:BUILD_BUILDNUMBER"
  23:  
  24: Write-Host "Triggered Build"
  25: #While BuildComplete.txt does not exist and timer has not reached the timeout specified
  26: while (!(Test-Path $BuildComplete) -and !($timesofar -eq $timeout)) 
  27: { 
  28:     #Wait for 10 seconds
  29:     Start-Sleep 10 
  30:     #Add 10 seconds to the time So Far
  31:     $timesofar = $timesofar + 10
  32: }
  33:  
  34: #Either the File has been dropped by the other system or the timeout was reached
  35: if (!(Test-Path $BuildComplete)) 
  36: {
  37:     #If the file was not dropped it must be the timeout so fail the build write to the console
  38:     Write-Error "Build Timed out after $timeout seconds."
  39: }
  40: else
  41: {
  42:     #If we got here the file was dropped
  43:     #Get the content of the file
  44:     $BuildResult = Get-Content $BuildComplete -Raw
  45:  
  46:     #Check if it says successful
  47:     if ($BuildResult.StartsWith("successful"))
  48:     {
  49:         #On Success say so
  50:         Write-Host "Successful Build"
  51:         #write the contents out in case the calling system wants to tell us something
  52:         write-Host "$BuildResult"
  53:     }
  54:     else
  55:     {
  56:         #On Error Faile the build and say so 
  57:         Write-Error "Build Error"
  58:         #write the contents out so we can see why it failed
  59:         Write-Error "$BuildResult"
  60:     }
  61: }