Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / continuous-build

Fiddling around with the TeamCity REST API

5.00/5 (1 vote)
6 Mar 2018CPOL2 min read 12.5K  
Automating package downloads with a PowerShell script and the TeamCity REST API

Image 1

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:

PowerShell
"?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:

PowerShell
"&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:

PowerShell
# A PowerShell script to get the status of the last build in a TeamCity project
# If there is a new build, download the artifacts as a .zip file.

$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 !"
#Start-Sleep -s 10

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

  • V 1.0

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)