Background
Our continuous integration setup is as follows:
- Windows10 Pro
- PostgreSQL
- Gitea GIT server
- TeamCity2017.1 server
Some days ago, our tester approached me with a request to automate the downloading of artifacts (packages) from TeamCity.
Of course, he could do this manually using the TeamCity webpage and by clicking 'Artifacts - download all', but he wanted to automate the process so that when a new package was available, it would be downloaded automatically.
Ok, I said, I'll see what I can do in my usual naive way.
At first, I was hopeful after finding information about the TeamCity REST API on the TeamCity website on how this could be achieved: https://confluence.jetbrains.com/display/TCD10/REST+API
There are several ways to use the TeamCity REST API, one that is usually shown on the TeamCity website is to use CURL, this has the advantage of being available on all platforms: https://curl.haxx.se/download.html.
In the comments section of the following web page however, I found a Windows PowerShell script that appealed to me more: https://confluence.jetbrains.com/display/TCD10/REST+API#RESTAPI-BuildLocator
When trying out the PowerShell script with TeamCity 2017.1, it would not work sadly, it seems the TeamCity API had been changed and the command was not available anymore.
Using Fiddler, and with the help of a seasoned colleague, I found out that the last part of the command did not work:
"?locator=project:$TcProjectId"
When this last part was removed, I saw results, but too much, so the results had to be filtered somehow.
The locator command I found that worked was:
"&locator=start:0,count:50"
But this still resulted in too much information, so some additional xml wrangling had to be done, which can be seen in the PowerShell script code below.
I also wanted to download the artifacts (produced package), so this was added to the script too using System.Net.WebClient
.
As only newer packages must be downloaded, the old build number is written to TCdownload.txt so it can be retrieved later for comparison with the newest build number.
The fruits of my labour look like this:
$username = "User"
$password = "Password"
$domain = ""
$TcProjectId="XXX_Package"
$serverAddress = "http://1.2.3.4"
$command = $serverAddress + "/httpAuth/app/rest/builds/?buildTypeId='" +
$TcProjectId + "'&locator=start:0,count:50"
$downloadUrl = "http://1.2.3.4/repository/downloadAll/XXX_Package/.lastFinished"
$downloadFile = "C:\Temp\XXXpackage"
$buildnumber = 0
If ( Test-Path -Path "TCdownload.txt" )
{
$buildnumber = Get-Content -Path "TCdownload.txt"
Write-Host "Old build number = " $buildnumber
}
function Execute-HTTPPostCommand() {
param(
[string] $target = $null
)
$request = [System.Net.WebRequest]::Create($target)
$request.PreAuthenticate = $true
$request.Method = "GET"
$request.Credentials = new-object system.net.networkcredential($username, $password)
$response = $request.GetResponse()
$sr = [Io.StreamReader]($response.GetResponseStream())
$xmlout = $sr.ReadToEnd()
return $xmlout;
}
$xml = [xml]$(Execute-HTTPPostCommand $command)
$xml2 = $xml.builds.build | where { $_.buildTypeId.equals($TcProjectId) }
Write-Host "TeamCity " $TcProjectId $xml2[0].number $xml2[0].status
If ($xml2[0].number -gt $buildnumber)
{
$downloadFile += $xml2[0].number + ".zip"
Write-Host "Downloading $downloadFile ..."
$xml2[0].number | Out-File -FilePath "TCdownload.txt"
$wc = New-Object System.Net.WebClient
$wc.Credentials = new-object System.Net.NetworkCredential($username, $password, $domain)
$wc.DownloadFile($downloadUrl, $downloadFile)
}
Write-Host "Done !"
Using the Code
The easiest way to execute the script is to right-click on it, and select 'Run with PowerShell'.
Points of Interest
When testing with Fiddler, I found the following information on authentication useful:
History