Заметки консультанта

Шамрай Александр Владимирович

Извлечение ветви триггерующей сборки Azure DevOps

Posted by Shamrai Alexander на 18 октября, 2023

Если настраивать для сборки триггер по завершению другой сборки, то настройки ветви извлечения никак не влияют на наследуемую сборку. Например:

  • Сборка B1 может иметь настройку триггера на ветки dev и qa.
  • Сборка B2 может иметь триггер на сборку B1. При этом у сборка B2 будет включать свои настройки по умолчанию для получения ветви и репозитория, например master.

Т.е. если сборка B1 будет запущена для ветки dev или qa, то B2 всегда будет использовать master. В случае если необходимо триггерится не только по завершению сборки, но и работать с веткой исходной сборки, то можно использовать команду git checkout. Однако здесь необходимо знать наименование ветви. Получить ее можно через выполнение команды Builds – Get Rest API. Для выполнения команды необходим идентификатор сборки, который можно получить из predefined variables Build.TriggeredBy.BuildId.

Пример PowerShell шага для сборки можно найти здесь: https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/CustomPSTasks/CheckoutTriggeredBuildBranch.ps1

Posted in azure, devops, Microsoft | Отмечено: , , | Leave a Comment »

Использование Checkstyle для проверки изменений java кода в запросе на включение изменений Azure DevOps GIT

Posted by Shamrai Alexander на 15 сентября, 2023

Checkstyle –это инструмент, который помогает экономить много времени для разработчиков за счет поддержания исходного кода в стандартах, которых договорилась команда. Использование единых подходов в именовании переменных, методов и других вопросов проектирования коде позволяет в дальнейшем снизить издержки, которые связанны с поддержкой давно написанного кода, передачей кода новым разработчикам и текущей разработкой. При этом важно находить проблемы с кодом еще на ранних этапах пока изменения свежие, а не проверять весь проект периодически и вспоминать назначение изменений. Запросы на включение изменений являются отличным местом для данной задачи.

Для того, чтобы выполнять данную проверку, для начала необходимо выбрать стили, которые вы будете поддерживать. Checkstyle поддерживает два стиля: Google’s Java Style и Sun’s Java Style.

Далее уже перейдем к реализации на основе сборок, т.к. их можно быстро добавить в процесс валидации запроса на включение кода. Сборка будет выполнять следующе задачи:

  1. Установка необходимой версии java через задачу JavaToolInstaller
steps:

- task: JavaToolInstaller@0

displayName: 'Use Java 17'

inputs:

versionSpec: 17

jdkArchitectureOption: x64

jdkSourceOption: PreInstalled
  1. Скачать на билд агент Checkstyle. В данном случае мы рассматриваем облачные агенты, где он не может быть предустановлен.
steps:

- script: |

curl -L https://github.com/checkstyle/checkstyle/releases/download/checkstyle-10.12.5/checkstyle-10.12.5-all.jar --output checkstyle-10.12.5-all.jar
  1. Скачать настройки стиля.
steps:

- script: |

curl https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/main/resources/google_checks.xml --output google_checks.xml
  1. Далее необходимо получить изменения, которые были выполнены в запросе на включение изменений. Для этого можно воспользоваться командой git diff:
$targetBranch = "$(system.pullRequest.targetBranch)" -replace "refs/heads/", "origin/"

$changes = git diff --name-only --relative --diff-filter AMR $targetBranch
  1. Для каждого изменения выполнить проверку стиля:
foreach($change in $changes)

{

    if($change.EndsWith(".java") -and -not $change.EndsWith("Test.java")){

        $results = java -jar checkstyle-10.12.5-all.jar -c google_checks.xml $change

    }

}
  1. В дальнейшем все изменения нужно сохранить в файл и отправить в текущий запрос на включение изменений: Add an attachment to a pull request through the Azure DevOps Rest Api

Полный пример можно посмотреть здесь: https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/yaml/pr_codestyle_report.yml

Posted in azure, devops, Microsoft | Отмечено: , , , | Leave a Comment »

Динамическое использование секретов Azure Key Vault в Azure DevOps pipelines

Posted by Shamrai Alexander на 11 августа, 2023

В общих случаях использование секретов Azure Key Vault предполагает использование секретов, имена которых известны заранее. При этом можно указать как получение всех секретов, так и отдельных. Используется для этого задача AzureKeyVault@2. Эта задача считывает секрет и сохраняет во внутреннюю переменную с наименованием $(secret_name). В дальнейшем его можно использовать в рамках текущего исполнения. Однако может понадобиться иногда использовать динамический подход. Например, использовать один yaml файл для нескольких сборок нескольких сред. В этом случае имя секрета будет отличаться в зависимости от среды и определить его точное название будет сложно в рамках одного yaml файла. В этом случае можно использовать параметры и различные подходы использования параметров и переменных во время компиляции или во время исполнения. Например, если вы используете параметр secret_name, то передать его можно в AzureKeyVault можно через выражение ${{ parameters.secret_name }}’:

- task: AzureKeyVault@2

inputs:

azureSubscription: 'your_service_connection'

KeyVaultName: 'your_akv'

SecretsFilter: '${{ parameters.secret_name }}'

RunAsPreJob: false

Далее нужно как-то использовать полученный секрет. Сделать это можно через прямую ссылку $(secret_name), на которую мы не можем сослаться, т.к. она динамическая. Также можно передать значение через переменную среды, но тут также сложность в том, что мы не знаем название переменной. Тут можно воспользоваться комбинированием подходов компиляции yaml и выполнения сборки, например:

env:

MY_MAPPED_SECRET: $(${{ parameters.secret_name }})

Полный пример можно посмотреть здесь: https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/yaml/dynamic_akv_secret.yml

Posted in azure, devops, Microsoft | Отмечено: , , | Leave a Comment »

Использование az devops invoke для работы с Azure DevOps Rest Api

Posted by Shamrai Alexander на 19 июля, 2023

Команда az devops содержит большое количество полезных подкоманд. Однако это количество подкоманд может не покрыть все необходимые потребности. Как раз для таких целей можно использовать подкоманду azure devops invoke, которая позволяет конструировать нетиповые запросы.

Команда использует следующий основной формат вызова:

az devops invoke --area restapi_area --resource restapi_mothod --route-parameters url_parameters --query-parameters method parameters

Эти параметры можно найти на странице Azure DevOps Rest API. Например, рассмотрим следующий метод:

GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/pullRequests/{pullRequestId}/commits?$top={$top}&continuationToken={continuationToken}&api-version=7.2-preview.1

В нем будут следующие параметры для az devops invoke:

  • git – это area
  • repositories – это resource
  • {project}, {repositoryId}, {pullRequestId} – это route-parameters
  • {$top}, {continuationToken} – это query-parameters

Также можно выполнить подкоманду az devops invoke —query «[?contains(area,’git’)]», чтоб проверить поддерживаемые запросы в этой области. Например, для вышеприведенного запроса будет следующий ответ:

{

"area": "git",

"id": "xxxx",

"maxVersion": 7.2,

"minVersion": 2.1,

"releasedVersion": "7.1",

"resourceName": "pullRequestCommits",

"resourceVersion": 1,

"routeTemplate": "{project}/_apis/{area}/repositories/{repositoryId}/pullRequests/{pullRequestId}/commits"

}

Если выполнить следующую команду:

az devops invoke --org https://dev.azure.com/<org> --area git --resource commits --route-parameters project=<project_name> repositoryId=<repo_name> pullRequestId=<pr_id> --query-parameters $top=1 --http-method GET -o json

То будет следующий результат:

Posted in azure, devops, Microsoft | Отмечено: , | Leave a Comment »

Azure DevOps как не выполнять сборку при завершении запроса на включение изменений

Posted by Shamrai Alexander на 15 июня, 2023

Azure DevOps имеет возможность не выполнять сборку при поставке изменений в репозитрий. Для этого нужно добавить, например, текст [skip ci] в сообщение комита: Skipping CI for individual pushes. Однако это не работает, если попробовать сделать тоже самое для запроса на включение изменений. Что отражено в документации: PR triggers.

Finally, after you merge the PR, Azure Pipelines will run the CI pipelines triggered by pushes to the target branch, even if some of the merged commits’ messages or descriptions contain [skip ci] (or any of its variants).
Но это можно реализовать на основе Rest Api. Для этого нам нужно сделать следующее:

  1. Добавить шаг, которые выполняет отмену текущей сборки
  2. Для этого шага указать условие: сообщение комита содержит тег [skip ci]

Шаг отмены текущей сборки может быть написан на основе PowerShell и использованием метода Update Build. Для этого метода необходимо получить идентификатор текущей сборки. Он находится в переменной $(Build.BuildId). Пример скрипта:

$user = ""
$token = "$(System.AccessToken)"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uri = "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)?api-version=5.1"
$json = @{status="Cancelling"} | ConvertTo-Json -Compress
$build = Invoke-RestMethod -Uri $uri -Method Patch -Headers @{Authorization = "Basic $base64AuthInfo"} -ContentType "application/json" -Body $json

Start-Sleep -Seconds 10

Условие для выполнения скрипта должно проверять присутствие текста [skip ci] в сообщении комита, например:

contains(variables['Build.SourceVersionMessage'], '[skip ci]')

При этом также необходимо дать разрешение на остановку сборки для сервиса сборки:

Полный текст определение сборки можно найти здесь: https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/yaml/skip_ci_pr_build.yml

Posted in azure, devops, Microsoft | Отмечено: , | Leave a Comment »

Ошибка при развертывании Azure Data Factory: InvalidResourceRequest: Invalid resource request. Resource type: ‘ManagedPrivateEndpoint’, Resource name: ‘name’ ‘Error: Invalid payload’.

Posted by Shamrai Alexander на 20 мая, 2023

При развертывании Azure Data Factory с использование приватных подключений возможна следующая ошибка:

InvalidResourceRequest: Invalid resource request. Resource type: ‘ManagedPrivateEndpoint’, Resource name: ‘name’ ‘Error: Invalid payload’.

Эта ошибка возможна в двух случаях:

  1. В настройках развертывания неправильно указан формат для параметра идентификатора ресурса linkname_properties_privateLinkResourceId для приватного подключения. В этом случае необходимо исправить этот параметр корректным значением и выполнить развертывание повторно.
  2. Формат параметра был указан правильно, но указывает на несуществующий ресурс. В этом случае ADF будет пытается выполнить согласование с несуществующим приватным подключением. Исправление и повторный деплой в данном случае не помогут, т.к. ADF не поддерживает изменение атрибутов опубликованных подключений. В этом случае необходимо сначала удалить созданное подключение в ADF, исправить на правильное значение и снова выполнить развертывание.

Posted in azure, devops, Microsoft | Отмечено: , , | Leave a Comment »

Как скачать файл из репозитория Azure DevOps Git через Rest Api и PowerShell

Posted by Shamrai Alexander на 6 апреля, 2023

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

Для Rest Api нам необходимо создать токен в Azure DevOps. Инструкцию создания можно найти здесь: Use personal access tokens . Для доступа к файлам можно установить уровень доступа repo. Для получение файлов можно использовать следующий вызов: Items – Get.

Пример PowerShell скрипта:

$user = ""

$token = "<pat>"

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))

$org = "<org>"
$project = "<team_project>"
$repo = "<repo_name>"

$localfilepath = "<filepath>"
$devopsfilepath = "/<path_to_repo_file>"

$fileurl = "https://dev.azure.com/$org/$project/_apis/git/repositories/$repo/items?scopePath=$devopsfilepath&download=true&api-version=7.2-preview.1"

function InvokeDownloadRequest ($GetUrl, $filepath)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -OutFile $filepath
}

InvokeDownloadRequest $fileurl $localfilepath

В скрипте:

  • $token- токен для подключения
  • $localfilepath — путь к файлу, в который будет выполнено сохранение
  • $org — имя организации Azure DevOps
  • $project — проект Azure Devops
  • $repo — название репозитория
  • $devopsfilepath — относительный путь к файлу в репозитории

Сам скрипт можно скачать здесь:

https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/CustomPSTasks/DownloadAzDvFile.ps1

Posted in azure, devops | Отмечено: , , | 2 комментария »

Azure DevOps Rest Api. 39. Управление тэгами рабочих элементов

Posted by Shamrai Alexander на 7 марта, 2023

Для работы с тэгами рабочих элементов используется клиент TaggingHttpClient. С его помощью здесь мы выполним следующие операции:

  • Создание нового тэга
  • Переименование или деактивация тега
  • Просмотр тегов в проекте
  • Удаление тега

Создание нового тэга

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

  1. Идентификатор проекта, в котором выполняется создание
  2. Наименование нового тега.

Для того, чтобы узнать идентификатор проекта, можно использовать метод GetProject клиента ProjectHttpClient.

Перед созданием тега можно попровать его получить через метод GetTagAsync. Если тега не существует, то мы получим исключение TagNotFoundException. Существующий тег включает в себя следующие свойства:

  • ID – глобальный идентификатор тега
  • Name — имя тега
  • Active – активный тег или нет
  • Url – ссылка на тег

Пример создания тэга для рабочих элементов:

var prjId = ProjectClient.GetProject(teamProject).Result.Id;

try

{

    var existingTag = TaggingClient.GetTagAsync(prjId, newTagName).Result;

    Console.WriteLine($@»Tag exists: {existingTag.Id}{existingTag.Name}«);

    return;

}

catch (Exception ex)

{

    if (ex.InnerException == null || ex.InnerException.GetType().Name != «TagNotFoundException»)

    {

        throw new Exception(«Unknow exception», ex);

    }

}

var newTag = TaggingClient.CreateTagAsync(prjId, newTagName).Result;

Console.WriteLine($@»Tag created: {newTag.Id}{newTag.Name}«);

Переименование или деактивация тега

Чтобы изменить свойства тега, можно воспользоваться методом UpdateTagAsync, который принимает следующие параметры:

  1. Идентификатора проекта
  2. Идентификатор тега
  3. Новое наименование тега. Если не нужно тег переименовывать, то указываем старое.
  4. Активность тега. Если мы не хотим, чтобы тег больше появлялся в списке предложенных тегов рабочих элементов, то устанавливаем здесь false. Но если пользователь снова внесет этот тег вручную в любой рабочий элемент, то тег снова станет активным.

Пример обновления тега:

UpdateTag(string teamProject, string tagOldName, string tagNewName, bool tagActive = true)

{

    var prjId = ProjectClient.GetProject(teamProject).Result.Id;

    var tag = (from t in TaggingClient.GetTagsAsync(prjId).Result where t.Name == tagOldName select t).FirstOrDefault();

    if (tag == null)

    {

        Console.WriteLine(«Tag does not exist: « + tagOldName);

        return;

    }

    var newTag = (tagNewName.IsNullOrEmpty()) ?

        TaggingClient.UpdateTagAsync(prjId, tag.Id, tag.Name, tagActive).Result:

        TaggingClient.UpdateTagAsync(prjId, tag.Id, tagNewName, tagActive).Result;

    Console.WriteLine($@»Tag is updated: {newTag.Id}{newTag.Name}{newTag.Active.Value}«);

}

Просмотр тегов в командном проекте

Для получения списка тегов в проекте используется метод GetTagsAsync, который принимает следующие параметры:

  • Идентификатор проекта
  • Включать ли неактивные теги. Если вы планируете удалить неактивные теги, то можно использовать этот параметр для их получения.

Пример для просмотра все тегов в организации:

var projects = ProjectClient.GetProjects().Result;

foreach (var project in projects)

{

    Console.WriteLine(project.Name);

    var tags = TaggingClient.GetTagsAsync(project.Id, true).Result;

    foreach (var tag in tags)

        Console.WriteLine($@» {tag.Id}{tag.Name}{tag.Active.Value}«);

}

Удаление тэга

Удаление тэга выполняется через метод DeleteTagAsync, который принимает следующие основные параметры:

  1. Идентификатор проекта
  2. Идентификатор тега для удаления

Пример удаления тэга:

RemoveTag(string teamProject, string tagName)

{

    var prjId = ProjectClient.GetProject(teamProject).Result.Id;

    var tag = (from t in TaggingClient.GetTagsAsync(prjId).Result where t.Name == tagName select t).FirstOrDefault();

    if (tag == null)

    {

        Console.WriteLine(«Tag does not exist: « + tagName);

        return;

     }

     TaggingClient.DeleteTagAsync(prjId, tag.Id).Wait();

     Console.WriteLine(tagName + » was removed»);

}

Пример тестового приложения можно посмотреть здесь:

https://github.com/ashamrai/TFRestApi/tree/master/39.TFRestApiAppWorkItemTags

Posted in azure, devops, Microsoft | Отмечено: , | Leave a Comment »

Ошибка 403 Azure Function App при работе с учетной записью хранения через приватные конечные точки

Posted by Shamrai Alexander на 19 февраля, 2023

Если вы переключаете существующие Azure Function App на работу через приватные подключения, то можно встретить следующую ошибку:

Failed to update web app settings: Creation of storage file share failed with: ‘The remote server returned an error: (403) Forbidden.’. Please check if the storage account is accessible.

Решается ошибка через обновление параметр Content share. Сделать это можно:

  • через командную строку az

az resource update —resource-group RESORCE_GROUP —name APP_NAME —resource-type «Microsoft.Web/sites» —set properties.vnetContentShareEnabled=true

  • или прописав напрямую переменную среды WEBSITE_CONTENTOVERVNET:

Новые Azure Function App подключаемые к защищенным хранилищам нужно создавать через arm-шаблоны, где нужно добавить переменную WEBSITE_CONTENTOVERVNET (пример тут: WEBSITE_CONTENTOVERVNET). Также в arm-шаблон можно добавить свойство vnetContentShareEnabled:

Дополнительная информация:

Posted in azure, Microsoft | Отмечено: | Leave a Comment »

Сбой скрипта PrePostDeploymentScript при развертывании ADF через Azure Pipelines

Posted by Shamrai Alexander на 24 января, 2023

Если вы используете процесс сборки и развертывания Azure Data Factory через следующий подход «Automated publishing for continuous integration and delivery» , то в какой-то момент вы можете встретить ошибку при выполнении пре и пост скриптов:

At D:\a\r1\a\{Artifaccts_dir}\PrePostDeploymentScript.ps1:470 char:74

+ … parameterType = $templateParameters.$($parameterName).value ? $templa …

+ ~

Unexpected token ‘?’ in expression or statement.

##[error]PowerShell exited with code ‘1’.

Связано это с тем, что в этих шагах используется не PowerShell Core, а PowerShell версии 5. Проверить можно это в логах выполнения релизов, например:

##[warning] The script is not compatible with your current PowerShell version 5.1.17763.2931. Use either PowerShell Core or at least PS version 7.0, otherwise the script may fail to compare the trigger payload and start the trigger(s)

До какого-то времени это могло работать, но последние версии скриптов развертывания ADF уже не поддерживают PowerShell версии 5.

Чтобы исправить ситуацию, нужно установить использование PowerShell Core в шагах запуска пре и пост скриптов в секции Advanced:

Posted in azure, devops, Microsoft | Отмечено: , , | Leave a Comment »