Lorna Watson
Posted on February 25, 2021
I've been working on a side project 'DevOps API Tool' where I am essentially combining Bitbucket API, Octopus Deploy API and Teamcity API to get the most useful and common 'things' out of it into a simplified couple of webpages. As well as a number of reasons including having more knowledge about their processes, but also to get rid of the noise. I found it super fun and quick to get started using Postman to test the APIs to get all sorts of wonderful data from basic info about a project to detailed test results and so on... The backend project is using Node.js but this post is not specific to that but more an intended general reference guide for using the Teamcity API, I hope you find this useful. โจ
โน For more info visit Teamcity REST API documentation. โน
Useful bits ๐
- Authenticate your request via bearer token in the header
- Locators - filter string in URL (more info in the link above ^)
- Response format - set in the HTTP
Accept
header for either plain text, JSON or XML. The default format is XML - By default the max. list amount response will be 100
$long โญโญโญโญโญ
This is extremely useful to know and it essentially returns all fields from a chosen resource. The official documentation recommends not to use $long for actual requests but more of a check to see what fields you might need.
For example, let's say I want to get a specific build:
My go-to default is a request URL like this:
GET http://teamcity:8111/app/rest/builds/id:308
But now I want to see only the test info from this build, so my first step would be to check for all fields to see what I needed like so:
GET http://teamcity:8111/app/rest/builds?locator=id:308&fields=build($long)
From the response I was able to manually refine down the fields I needed and adjusted the URL:
http://teamcity:8111/app/rest/builds?locator=id:308&fields=build(testOccurrences(count,passed,ignored))
and this response would look like this:
{
"build": [
{
"testOccurrences": {
"count": 201,
"passed": 199,
"ignored": 2
}
}
]
}
Interestingly... The response is different between /app/rest/builds/id:308
and /app/rest/builds/locator=id:308
where the 1st has more detail. I'm going to look into this more. ๐ค
Example Requests
Presenting a selection of useful requests - not every single one, and please note for readability purposes (and less page noise) I've reduced some of the responses but tried including the 'main' bits if that makes sense! The following examples assumes the base URL is http://teamcity:8111/app/rest
for simplicity.
Builds ๐จ
Get build
GET http://teamcity:8111/app/rest/builds?locator=id:308&fields=count,build(id,buildTypeId,number,status,state,branchName,webUrl)
{
"count": 1,
"build": [
{
"id": 308,
"buildTypeId": "projectA_Release",
"number": "7.5.0.6352",
"status": "SUCCESS",
"state": "finished",
"branchName": "branchA",
"webUrl": "http://teamcity:8111/viewLog.html?buildId=308&buildTypeId=projectA_Release"
}
]
}
Get build related issues
GET http://teamcity:8111/app/rest/builds/id:308/relatedIssues
{
"href": "/app/rest/builds/id:308/relatedIssues",
"issueUsage": [
{
"changes": {
"change": [
{
"id": 26019,
"version": "b300f534a2733530c623d41ddcf59690053e580d",
"username": "lorna.watson",
"date": "20210210T142232+0000",
"href": "/app/rest/changes/id:26019",
"webUrl": "http://teamcity:8111/viewModification.html?modId=26019&personal=false"
}
],
"count": 1
},
"issue": {
"url": "http://jira:8111/browse/feature-98",
"id": "feature-98"
}
}
],
"count": 1
}
Get build queue
GET http://teamcity:8111/app/rest/buildQueue
{
"count": 0,
"href": "/app/rest/buildQueue",
"build": []
}
Get build types
GET http://teamcity:8111/app/rest/buildTypes?locator=affectedProject:(id:projectA)&fields=buildType(id,name,projectName,projectId,webUrl,steps(count))
{
"buildType": [
{
"id": "projectA_Release",
"name": "Project A Release",
"projectName": "Project A",
"projectId": "projectA",
"webUrl": "http://teamcity:8111/viewType.html?buildTypeId=projectA_Release",
"steps": {
"count": 6
}
}
}
Get list of build types in a project with the status of the last finished build for each build configuration
GET http://teamcity:8111/app/rest/buildTypes?locator=affectedProject:(id:projectA)&fields=buildType(id,name,builds($locator(running:false,count:1),build(number,status,statusText,finishDate)))
{
"buildType": [
{
"id": "projectA_Release",
"name": "Project A Release",
"builds": {
"build": [
{
"number": "35",
"status": "FAILURE",
"statusText": "Tests passed: 199, ignored: 2; unable to create or deploy release. Please check the build log for details on the error. (new)",
"finishDate": "20210209T102244+0000"
}
]
}
}
]
}
Changes ๐
Get the list of all changes included into the build
GET http://teamcity:8111/app/rest/changes?locator=build:(id:buildId)
{
"change": [
{
"id": 26,
"username": "lorna.watson",
"date": "20210210T142232+0000",
"webUrl": "http://teamcity:8111/viewModification.html?modId=260191&personal=false"
},
{
"id": 27,
"username": "lorna.watson",
"date": "20210210T142219+0000",
"webUrl": "http://teamcity:8111/viewModification.html?modId=260190&personal=false"
}
],
"count": 2
}
Get details of an individual change
GET http://teamcity:8111/app/rest/changes/id:changeId
{
"id": 26,
"username": "lorna.watson",
"date": "20210210T142232+0000",
"webUrl": "http://teamcity:8111/viewModification.html?modId=260191&personal=false",
"comment": "Merge branch into master",
"user": {
"username": "hello@lorna.dev",
"name": "Lorna Watson",
"id": 1,
},
"files": {
"count": 0,
"file": []
}
}
Get all changes for a project
GET http://teamcity:8111/app/rest/changes?locator=project:projectA&fields=change(id,username,date,webUrl)
{
"change": [
{
"id": 27,
"username": "lorna.watson",
"date": "20210225T142606+0000",
"webUrl": "http://teamcity:8111/viewModification.html?modId=270391&personal=false"
},
{
"id": 28,
"username": "bill.smith",
"date": "20210225T135430+0000",
"webUrl": "http://teamcity:8111/viewModification.html?modId=270344&personal=false"
},
{
"id": 29,
"username": "bill.smith",
"date": "20210225T120351+0000",
"webUrl": "http://teamcity:8111/viewModification.html?modId=270343&personal=false"
}
],
"count": 3
}
Projects ๐งพ
Get list of projects
GET http://teamcity:8111/app/rest/projects
{
"count": 2,
"href": "/app/rest/projects",
"project": [
{
"id": "_Root",
"name": "<Root project>",
"description": "Contains all other projects",
"href": "/app/rest/projects/id:_Root",
"webUrl": "http://teamcity:8111/project.html?projectId=_Root"
},
{
"id": "projectA",
"name": "Project A",
"parentProjectId": "_Root",
"href": "/app/rest/projects/id:projectA",
"webUrl": "http://teamcity:8111/project.html?projectId=projectA"
}
]
}
Servers โ
Get server version
GET http://teamcity:8111/app/rest/version
85899
Agents ๐
Get list of agents
GET http://teamcity:8111/app/rest/agents
Get agent details
GET http://teamcity:8111/app/rest/agents/id:5109
Summary
You can really do so much with the well-documented Teamcity API and whilst I've touched base on some parts i.e. project and build requests, you can explore other areas such as: investigations, branches, problems, users, agents and so on. Please see the link at the top of this post for more details. I need to play around more with locators but so far really loving the filtering! I've tried to keep the detail to minimum but also informative, didn't want to blag the whole page with JSON responses ๐ . I hope this has been useful and clear to follow, thanks!! ๐
Posted on February 25, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.