Pull to refresh

Использование переменных в пайплайнах Azure DevOps

Reading time4 min
Views5.9K
Продолжаем обзор замечательной тулы для разработки под Windows и не только, Azure DevOps. На этот раз, намучавшись с переменными окружения, я решил вынести весь опыт в одну статью.

Начиная от того, что для каждой среды исполнения у них разный синтаксис, оканчивая отсутствием стандартной возможности переноса переменных из одной стадии пайплайна в другую.

Оговорюсь, что основные примеры будут на Release Pipelines, потому, что YAML туда еще не доехал, а мне нужна функциональность множества этапов и множества артефактов. Это, вроде, стало доступно в обычных Pipelines, что практически уровняло их по функциональности. В Pipelines YAML допилили и добавили к текстовому представлению, небольшую графическую подсказку с параметрами, которые можно задать. Очень удобно, не надо лезть в документацию по каждому модулю. Но это буду описывать в следующей статье, а пока вот картинка самого нововведения.



Хранение и использование


Начнем с того, что в системе у нас есть переменные по умолчанию. Они начинаются, в зависимости от происхождения, со слов Release, System, etc. Полный список (как оказалось, нет), доступен в документации. Всю шизофрению с синтаксисом иллюстрирует пример из документации ниже. У одной и той же переменной есть три представления, в зависимости от того, где мы ее вызываем.

steps:
 - bash: echo This script could use $SYSTEM_ACCESSTOKEN
    env:
      SYSTEM_ACCESSTOKEN: $(System.AccessToken)
  - powershell: Write-Host "This is a script that could use $env:SYSTEM_ACCESSTOKEN"
    env:
      SYSTEM_ACCESSTOKEN: $(System.AccessToken)

Если вы задаете переменную на агенте, котором исполняется таск, это $(System.AccessToken). Если вы хотите использовать ее внутри powershell скрипта на том же агенте, это уже будет $env:SYSTEM_ACCESSTOKEN. Если вы, упаси бог, хотите использовать эту переменную на каком то удаленном хосте, используя таск PowerShell on target machines, вам нужно передать это через аргумент к скрипту, используя param. С bash попроще, можно просто прокидывать внутрь используя аргумент и синтаксис $SYSTEM_ACCESSTOKEN.

Те же законы не распростроняются на ваши собственные переменные, тут уже вы несете ответственность за синтаксис. Задать переменные можно локально в каждой задаче.



Или глобально в хранилище переменных, а потом линковать их из хранилища. Очень удобно.



Бонусом к этому, если переменные шибко секретные, их можно хранить в облаке Azure в хранилище под названием Azure Vault, залинковать Vault к проекту можно в Library.



В целом с переменными все понятно, в pipelines их еще можно задавать в ручную на каждый запуск, в release такой функциональности нет. Посмотреть что вы передаете в пайплайн можно еще раз в логах инициализации агента, но учтите, они там уже в преобразованном виде.



Динамические переменные


Самое интересное начинается, когда мы хотим получить некоторое значение в одном этапе и передать его в следующий.



Такой функциональности нам не завезли. Но наши руки не для скуки и при помощи гугла было найдено решение. Слава богу, у Azure DevOps есть API, который нам позволяет сделать чуть больше, чем нарисовали в интерфейсе.

Итак, нам понадобится вызов по обновлению глобальных переменных, который мы будем делать прямо изнутри пайплайна. Адрес берется из переменных окружения, тех самых о которых нет ни слова в документации, как упоминалось ранее. Вы можете их самостоятельно задать или, что уж там, захардкодить, если лавочку прикроют.

$releaseurl = ('{0}{1}/_apis/release/releases/{2}?api-version=5.0' -f $($env:SYSTEM_TEAMFOUNDATIONSERVERURI), $($env:SYSTEM_TEAMPROJECTID), $($env:RELEASE_RELEASEID)  )

Задаем пустое значение переменной, которую мы хотим передать, ставим Scope — Release



Для примера делаем некоторый рандомный генератор значений. Обратите внимание на синтаксис объявления переменной внутри этого этапа, такой функционал завезли.



В следующем этапе мы передаем переменную скрипту, да да, напрямую нельзя, надо через аргумент.



Скрипт под спойлером

PowerShell
#Script requires stageVar variable in release variables set to Release scope

param ( [string] $expVar )
#region variables
$ReleaseVariableName = 'StageVar'
$releaseurl = ('{0}{1}/_apis/release/releases/{2}?api-version=5.0' -f $($env:SYSTEM_TEAMFOUNDATIONSERVERURI), $($env:SYSTEM_TEAMPROJECTID), $($env:RELEASE_RELEASEID)  )
#endregion


#region Get Release Definition
Write-Host "URL: $releaseurl"
$Release = Invoke-RestMethod -Uri $releaseurl -Headers @{
    Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
#endregion

#region Output current Release Pipeline
Write-Output ('Release Pipeline variables output: {0}' -f $($Release.variables | ConvertTo-Json -Depth 10))
#endregion


#region Update StageVar with new value
$release.variables.($ReleaseVariableName).value = "$expVar"
#endregion

#region update release pipeline
Write-Output ('Updating Release Definition')
$json = @($release) | ConvertTo-Json -Depth 99
Invoke-RestMethod -Uri $releaseurl -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
#endregion

#region Get updated Release Definition
Write-Output ('Get updated Release Definition')
Write-Host "URL: $releaseurl"
$Release = Invoke-RestMethod -Uri $releaseurl -Headers @{
    Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
#endregion

#region Output Updated Release Pipeline
Write-Output ('Updated Release Pipeline variables output: {0}' -f $($Release.variables | ConvertTo-Json -Depth 10))
#endregion


Или

Bash
INPUT_VAR=$1
RELEASE_VAR=$2

echo Test ID: ${INPUT_VAR}

RELEASE_URL="${SYSTEM_TEAMFOUNDATIONSERVERURI}${SYSTEM_TEAMPROJECTID}/_apis/release/releases/${RELEASE_RELEASEID}?api-version=5.0"

echo release url: $RELEASE_URL

RELEASE_JSON=$(curl -H "Authorization: Bearer $SYSTEM_ACCESSTOKEN" $RELEASE_URL)

OUTPUT=`jq ''.variables.${RELEASE_VAR}.value' = '\"${INPUT_VAR}\"'' <<< $RELEASE_JSON`

curl -H "Authorization: Bearer $SYSTEM_ACCESSTOKEN" -H "Content-Type: application/json" -X PUT -d "$OUTPUT" $RELEASE_URL


В двух словах, наш скрипт берет на входе переменную myVar и используя API кладет значение этой переменной в stageVar. В следующем этапе, используя синтаксис системных переменных, мы можем ее посмотреть.



Пример довольно простой, но функционал открывает нам хорошие возможности, в сумме с моей прошлой статьей, когда мы можем создать виртуальную машину на первом этапе тестирования, проделать с ней какие-то манипуляции дальше, причем параллельно несколько. И финальным этапом ее уничтожить. Сейчас у нас гоняются автотесты продукта каждый раз на свежих виртуалках. Учитывая, что живут они минут 10, стоит это копейки.

В следующей статье, если будет необходимость, расскажу о YAML пайплайнах, там довольно много интересных нововведений последнее время.
Tags:
Hubs:
+11
Comments0

Articles

Change theme settings