VSTS tricks. Как изменить 100500 Build Definitions за один ра

Вопрос

Допустим Вы хотите изменить какой-то общий параметр сразу во всех Build Definitions. Например, путь для выгрузки артефактов.

Build_old.jpg

Как это сделать? Ни экспорта/импорта, ни PowerShell модулей в 2016 году для VSTS не существует. Но зато есть REST API.

Ответ

И так, чтобы получить доступ к API необходимо сгенерировать Personal access token.
Переходим в VSTS в раздел Account -> Security -> Personal access tokens -> Add

create PAT.jpg

Задаём название, срок действия, нажимаем Create Token.

PAT.jpg

Теперь приступаем к скрипту на PowerShel.
Сначала зададим основные параметры.

$User = "Script"
$PAT = "PUT YOUR PERSONAL ACCESS TOKEN HERE"
$base64authinfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User, $PAT)))
$Instance = "PUT VSTS ADDRESS HERE"
$Project = "PUT YOUR PROJECT NAME HERE"
$Version = "2.0"
$OutputDir = $env:TEMP
  • $PAT - Только что сгенерированный токен
  • $Instance, $Project - URL Вашего VSTS и название проекта, подробнее здесь.
  • $Version - Актуальная версия API

Далее сформируем HTTP запрос для получения списка ID всех Build Definitions.

$BuildDefinitionsListUrl = "$instance/DefaultCollection/$Project/_apis/build/definitions?api-version=$Version"
$BuildDefinitionsList = Invoke-RestMethod -Uri $BuildDefinitionsListUrl -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Method Get -ContentType application/json

В ответ мы получим JSON с которым довольно удобно работать в PowerShell.
Так можно получить все ID.

$BuildDefinitionsIDs = $BuildDefinitionsList.value.id 

Далее сделаем цикл, который будет проходить по всем Build Definitions, выгружать описание в JSON и заменять необходимые параметры.
Тут логично ограничиться работой с JSON, но в моём случае старый адрес \\​KR-VSOBUILD01 присутствует в самых разных шагах билда. Поэтому мне проще сохранить его описание в файл, произвести замену при помощи -Replace и потом прочитать из файла.

foreach ( $_ in $BuildDefinitionsIDs) { 
$url = "$instance/DefaultCollection/$Project/_apis/build/definitions/"+$_+"?api-version=$Version"
$BuildDefinition = Invoke-RestMethod -Uri $url -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Method Get -ContentType application/json -OutFile $OutputDir\$_ -Verbose
$BuildDefinitionReplaced = ((Get-Content $File) | Foreach-Object {$_ -replace 'KR-VSOBUILD01','KR-TFS'})
$BuildDefinitionReplaced = Get-Content $OutputDir\$_
Invoke-RestMethod -Uri $url -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Method Put -ContentType application/json -Body $BuildDefinitionReplaced -Verbose
}

В выводе скрипта - результат для каждой Build Definitions

Log.jpg

Скрипт целиком

$User = "Script"
$PAT = "PUT YOUR PERSONAL ACCESS TOKEN HERE"
$base64authinfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User, $PAT)))
$Instance = "PUT VSTS ADDRESS HERE"
$Project = "PUT YOUR PROJECT NAME HERE"
$Version = "2.0"
$OutputDir = $env:TEMP

$BuildDefinitionsListUrl = "$instance/DefaultCollection/$Project/_apis/build/definitions?api-version=$Version"
$BuildDefinitionsList = Invoke-RestMethod -Uri $BuildDefinitionsListUrl -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Method Get -ContentType application/json
$BuildDefinitionsIDs = $BuildDefinitionsList.value.id

foreach ( $_ in $BuildDefinitionsIDs) { 
$url = "$instance/DefaultCollection/$Project/_apis/build/definitions/"+$_+"?api-version=$Version"
$File = "$OutputDir\$_"
$BuildDefinition = Invoke-RestMethod -Uri $url -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Method Get -ContentType application/json -OutFile $OutputDir\$_ -Verbose
$BuildDefinitionReplaced = ((Get-Content $File) | Foreach-Object {$_ -replace 'KR-VSOBUILD01\\\\AutoBuildsDrop','KR-TFS\\AutoBuildsDrop'}) 
$BuildDefinitionReplaced = Get-Content $OutputDir\$_
Invoke-RestMethod -Uri $url -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Method Put -ContentType application/json -Body $BuildDefinitionReplaced -Verbose
}