DEV Community

Chris Reddington for Cloud with Chris

Posted on • Edited on • Originally published at cloudwithchris.com

Using Azure DevOps REST APIs to automatically create Team Iterations

Cloud with Chris Logo

This post was originally published on Sun, Jun 16, 2019 at cloudwithchris.com.

Consider this scenario. You are managing a software project using Azure DevOps, and you have multiple teams working towards a common cadence. Perhaps that cadence is managed by a central team. To gain the most value from your sprint planning, you would need to associate the iterations from the project level with each individual team.

This is a scenario that I have for my fictitious Theatreers project, but also a scenario I encountered recently with a colleague. I have been helping them setup an Azure DevOps project to track the development of IP and collateral, so that they can more accurately forecast what they expect to land and show the value being delivered by the team.

As we continue planning for the project to be piloted, I realise that the iterations at the project level have not yet been associated with the individual teams. Furthermore, at this point, I also realise that this is something that would need to be setup across all of those teams.

This project has about 18 teams, and started with about 6 iterations. I could have manually added the iterations one-by-one for each team, but where's the fun in that? Instead, I opted for a scripted approach.

You can find a Gist below showing the example script.

# Variables required for the script
$orgUrl = "https://dev.azure.com/organisationname"
$personalToken = "personalaccesstoken"
$projectId = "projectname"
# Pass the required authorization ifo using PAT token
Write-Host "Initialize authentication context" -ForegroundColor Yellow
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalToken)"))
$header = @{authorization = "Basic $token"}
#Set the overall URL to be used
$tfsBaseUrl = $orgUrl
$projectiterations = ''
# Let's start by getting all of the classification nodes at the project level.
$projectclassificationnodesUrl = "$($tfsBaseUrl)/$($projectId)/_apis/wit/classificationnodes?`$`depth=2&api-version=5.1-preview"
$projectclassificationnodes = Invoke-RestMethod -Uri $projectclassificationnodesUrl -Method Get -ContentType "application/json" -Headers $header
# We don't care about area path, so let's just get the set of iterations that are children of root
$projectclassificationnodes.value | ForEach-Object {
if ($_.structureType -eq "iteration"){
$projectiterations = $_.children
}
}
# Query the API for all teams in our project
$projectteamsurl = "$($tfsBaseUrl)/_apis/projects/$($projectId)/teams?api-version=5.0"
$projectteams = Invoke-RestMethod -Uri $projectteamsurl -Method Get -ContentType "application/json" -Headers $header
# Iterate over those teams
$projectteams.value | ForEach-Object {
# Display the team name
Write-Host "+ $($_.name)"
# Query for the iterations inside of this team
$iterationsinteamurl = "$($tfsBaseUrl)/$($projectId)/$($_.id)/_apis/work/teamsettings/iterations?api-version=5.0"
$iterationsinteam = Invoke-RestMethod -Uri $iterationsinteamurl -Method Get -ContentType "application/json" -Headers $header
# Iterate over the project level iterations
# Check if the project level iteration exists in the context of this team
# If it does not exist, send a post to the API
# If it exists, output that the iteration exists
$projectiterations | ForEach-Object {
$value = $iterationsinteam.value | Where-Object -Property name -Contains -Value $_.name
if ($value -eq $null){
Write-Host "-- $($_.name) needs to be added" -ForegroundColor Yellow
$idToPost = $_.identifier
$hash = @{id="$idToPost";}
$json = $hash | convertTo-Json
Invoke-WebRequest -Uri $iterationsinteamurl -Method POST -Body $json -ContentType "application/json" -Headers $header
} else {
Write-Host "== $($_.name) exists" -ForegroundColor Green
}
}
}

I realise that the above can of course be improved further, such as more robust error checking, looking through multiple depths of iterations in the project configuration, etc. However, This solves my immediate need. Why over-engineer if it solves my problem? Re-architect as the need arises.

That being said, if you think this script could be useful but needs some modifications, please do contribute to it. I have a 'permanent' copy of the script available in my Useful Scripts GitHub Repository.

Neon image

Serverless Postgres in 300ms (❗️)

10 free databases with autoscaling, scale-to-zero, and read replicas. Start building without infrastructure headaches. No credit card needed.

Try for Free →

Top comments (0)

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay