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

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

Archive for the ‘Microsoft’ Category

Автоматизация изменения состояния родительских рабочих элементов Azure DevOps при изменении дочерних через Azure Logic App

Posted by Shamrai Alexander на 8 января, 2020

Автоматизация изменений объектов Azure DevOps может выполняться различными методами. Один из них – это проект Visual Studio с использованием соответствующий nuget пакет, который работает через данный Rest Api. Пример его использования приводился здесь: Автоматизация изменений состояний рабочих элементов Azure DevOps на основе состояний дочерних элементов. Однако использование данного метода требует наличия навыков в программировании. В данной статье мы рассмотрим возможности автоматизации объектов Azure DevOps через Azure Logic App, который позволяет проектировать взаимодействие с Azure DevOps через визуальный редактор без наличия навыков программирования. Кроме этого, нет необходимости искать дополнительное место для развертывания веб-сервисов или консольных задач.

Рассматриваться будут два примера:

  1. Активирование родителя, если любой дочерний элемент перешел в состояние Активно.
  2. Закрытие родителя, если все дочерние задачи закрыты.

Логика обработки будет простая:

  1. Создать триггер, который будет отслеживать изменение рабочих элементов:
    1. Задачи, которые перешли в состояние Активно.
    2. Задачи, которые были закрыты.
  2. Проанализировать необходимость изменения родителя:
    1. Родительский элемент находится в состоянии Новый.
    2. Родительский элемент еще не закрыт и все дочерние задачи закрыты.
  3. Выполнить обновление родительского рабочего элемента.

Активирование родителя, если любой дочерний элемент перешел в состояние Активно

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

  • Создать свое приложение Logic App:

Рисунок 1. Создание приложения Logic App

  • Использовать пустой шаблон

Рисунок 2. Пустой шаблон

  • Найти триггеры для DevOps сервисов

Рисунок 3. Поиск триггеров Azure DevOps

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

Рисунок 4. Триггер на изменение рабочего элемента

  • Войти в необходимую подписку Azure DevOps:

Рисунок 5. Вход в подписку Azure DevOps

  • После регистрации в подписке, нужно указать параметры для триггера (такие как, организация подписки, имя командного проекта и отслеживаемый тип рабочего элемента):

Рисунок 6. Триггер на изменение задач

  • Добавить новый шаг:

Рисунок 7. Добавление нового шага

  • И выбрать категорию переменных

Рисунок 8. Категория для переменных

  • Выбрать инициализацию переменных:

Рисунок 9. Инициализация переменной

  • Указать наименование и тип переменной. В данном случае будет переменная для хранения ссылки на родительский элемент.

Рисунок 10. Переменная для хранения ссылки на родительский рабочий элемент

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

Рисунок 11. Переменная массив

  • Триггер для отслеживания рабочих элементов возвращает последние значения для рабочих элементов, но какие поля изменились не видно. В этом случае мы не знаем изменилось ли поле состояния. Поэтому необходимо получить предыдущую версию рабочего элемента, для которого сработал триггер. Но такого метода нет в текущем наборе активностей, поэтому можно использовать универсальный метод Send a HTTP request to Azure DevOps, который отправит следующий запрос: Revisions – Get.

Рисунок 12. Метод Send a HTTP request to Azure DevOps

  • Наименование шага можно сразу поменять:

Рисунок 13. Переименование шага

  • Вставить шаблон запроса в задачу (_apis/wit/workItems/{id}/revisions/{revisionNumber}?api-version=5.1):

Рисунок 14. Относительный путь для вызова Rest Api — получение ревизии рабочего элемента

  • Вместо {id} указать идентификатор рабочего элемента из триггера:

Рисунок 15. Определение идентификатора

  • Вместо {revisionNumber} вычисляем предыдущий номер версии рабочего элемента через формулу add(triggerBody()?[‘fields’]?[‘System_Rev’],-1):

Рисунок 16. Определение номера ревизии

  • В результате шаг будет выглядеть следующим образом:

Рисунок 17. Команда получения ревизии рабочего элемента

  • Добавить шаг для разбора json ответа от сервиса:

Рисунок 18. Разбор JSON

  • В поле Content вставить тело из запроса получения предыдущей версии:

Рисунок 19. Содержимое для разбора JSON

  • В поле Schema вставить следующее содержимое для извлечения поля состояние:
{

«properties»: {

«_links»: {

«type»: «object»

},

«fields»: {

«properties»: {

«System.State»: {

«type»: «string»

}

},

«type»: «object»

},

«id»: {

«type»: «integer»

},

«rev»: {

«type»: «integer»

},

«url»: {

«type»: «string»

}

},

«type»: «object»

}

Рисунок 20. Схема для разбора ответа

  • Сравнить текущее состояние с предыдущим. Для этого следующим шаге нужно добавить условие из категории Control:

Рисунок 21. Шаг — условие

  • Указать, что предыдущее состояние должно быть New, а текущее Active.

Рисунок 22. Выбор состояния в предыдущей ревизии

Рисунок 23. Выбор состояния для текущей версии

Рисунок 24. Сравнение состояний в условии

  • Далее необходимо получить ссылку на родителя нашей задачи. Для этого используем метод Send a HTTP request to Azure DevOps и ссылку Work Items — Get Work Item, в которой идентификатор используем из триггера.

Рисунок 25. Относительный путь с идентификатором для вызова Rest Api — получение связей рабочего элемента

  • Результат запроса также нужно разобрать c использованием следующей схемы, которая позволит получить только связи:
{

«properties»: {

«_links»: {

«type»: «object»

},

«fields»: {

«type»: «object»

},

«id»: {

«type»: «integer»

},

«relations»: {

«items»: {

«properties»: {

«attributes»: {

«properties»: {

«isLocked»: {

«type»: «boolean»

},

«name»: {

«type»: «string»

}

},

«type»: «object»

},

«rel»: {

«type»: «string»

},

«url»: {

«type»: «string»

}

},

«required»: [

«rel»,

«url»,

«attributes»

],

«type»: «object»

},

«type»: «array»

},

«rev»: {

«type»: «integer»

},

«url»: {

«type»: «string»

}

},

«type»: «object»

}

Рисунок 26. Разбор ответа

  • Далее необходимо перебрать ссылки и вычислить родителя. Для этого необходимо добавить цикл For each.

Рисунок 27. Цикл для перебора связей

  • Как входной параметр для шага указываем relations из предыдущего шага. Каждый элемент этого массива будет перебираться в цикле

Рисунок 28. Выбор источника для цикла

  • Далее необходимо добавить условия сравнения текущего объекта цикла и его свойства rel (через выражение items(‘For_each’)?[‘rel’]) со значением System.LinkTypes.Hierarchy-Reverse.

Рисунок 29. Выбор поля наименования связи

Рисунок 30. Сравнение с родительским типом связи

  • В блок If true добавить шаг копирования ссылки родительского рабочего элемента через действие Set variable в переменную ParentUrl из текущего элемента через выражение items(‘For_each’)?[‘url’]:

Рисунок 31. Шаг для установки значения переменной

Рисунок 32. Копирование значения ссылка на родительский рабочий элемент

  • После перебора всех связей добавим еще одно условие, которое проверит был ли родитель через проверку значения в переменной ParentUrl. Если оно не пустое, то мы можем пробовать обновлять родительский рабочий элемент.

Рисунок 33. Сравнение значения в ParentUrl

  • Если ParentUrl содержит значение, то создаем новый шаг для получения информации о родителе:

Рисунок 34. Шаг получения детальной информации о рабочем элементе

  • В нашем случае, мы ожидаем, что будет рабочий элемент с типом User Story. Идентификатор мы можем извлечь из ссылки на рабочий элемент через выражение: split(variables(‘Parent Url’), ‘_apis/wit/workItems/’)[1].

Рисунок 35. Получить детальную информацию о рабочем элементе

  • Далее необходимо проверить, что рабочий элемент до сих пор находится в состоянии New через шаг Condition:

Рисунок 36. Выбор поля для сравнения

Рисунок 37. Сравнение состояния

  • В блок If true добавляем шаг обновления рабочего элемента:

Рисунок 38. Выбор шага обновления рабочего элемента

  • Указать, что мы хотим обновить состояние рабочего элемента:

Рисунок 39. Обновление состояния рабочего элемента

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

Рисунок 40. Журнал выполнения правила

Закрытие родителя, если все дочерние задачи закрыты

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

  1. Сначала клонируем предыдущую задачу:

Рисунок 41. Клонирование приложения

  1. Начнем редактирование действий. Сначала добавим дополнительную переменную, которая будет говорить о необходимости обновления родителя.

Рисунок 42. Вставка действия в существующую последовательность

  1. Укажем наименование и значение по умолчанию:

Рисунок 43. Наименование и значение по умолчанию.

  1. Изменим первое условие на следующую логику: предыдущее состояние не равно текущему (т.е. состояние изменилось), текущее состояние равно Closed:

Рисунок 44. Проверка, что задача была закрыта

  1. Удаляем последнюю задачу обновления рабочего элемента:

Рисунок 45. Удаление задачи

  1. И вставляем новую для получения дочерних рабочих элементов:

Рисунок 46. Действие для получения дочерних рабочих элементов

  1. В качестве идентификатора используем соответствующее свойство из шага Get work item details и указываем тип дочерних элементов Task:

Рисунок 47. Получение дочерних рабочих элементов

  1. Добавляем новый цикл For each, которые переберет все наши полученные дочерние элементы из шага Get work item children:

Рисунок 48. Цикл анализа дочерних элементов

  1. И вставляем новую проверку для анализа состояния каждого элемента. Доступ к элементу выполняется через выражение items(‘For_each_2’)?[‘System.State’]:

Рисунок 49. Выражение для поиска состояния текущего элемента в цикле

Или его можно выбрать через поиск состояния в динамическом содержимом:

Рисунок 50. Вставка состояния текущего элемента через динамическое содержимое

  1. Далее ищем незакрытый элемент и, если его находим, то в блоке If true присваиваем значение переменной UpdateState значение false.

Рисунок 51. Анализ необходимости обновления состояния

  1. Далее после шага Check Parent State, вставляем новый блок проверки условия. В нем проверяем переменную UpdateState. Если она истинна, то обновляем наш родительский рабочий элемент.

Рисунок 52. Обновление родительского рабочего элемента

Итого

В итоге мы получили сервис, который:

  1. Создан относительно быстро без необходимости развертывания каких-то сторонних сервисов, плагинов и т.д.
  2. Создан в графическом мастере без необходимости кодинга, компиляции и развертывания результатов сборки.
  3. Расширяем. На текущий момент еще немного существует встроенных действий, но вызов Send a HTTP request to Azure DevOps довольно универсален и покрывает основные потребности.
  4. Позволяет использовать стандартные возможности Azure для мониторинга работы сервиса, возможных ошибок, аудита истории и т.д.

Рисунок 53. Просмотр истории выполнения

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

Автоматизированное создание GIT запросов на включение кода через сборки Azure DevOps

Posted by Shamrai Alexander на 27 декабря, 2019

Часто командам разработки на основе типовых моделей ветвлений необходимо выполнять рутинные слияния изменений из общего интеграционного потока (master) в свои командные ветви для того, чтобы получить изменения от других команд и понять их влияние на текущую работу. Выполнять это лучше чаще, чтоб раньше узнать о возможных проблемах. Выполнять это можно вручную, что довольно часто игнорируется. А можно этот шаг автоматизировать с помощью вызовов Rest API через PowerShell. При этом достаточно создать один запрос на включение изменений, и он будет периодически пополняться новыми изменениями при каждом новом комите в общий интеграционный поток. Создавать запрос на включение изменений через сборки Azure DevOps можно несколькими путями:

  1. Периодически на основе расписания запуска сборки.
  2. На основе непрерывной интеграции, т.е. каждый новый комит в общий интеграционный поток создает новый запрос на включение изменений в поток разработки команды.

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

  • Проверить, что пользователь выполнения сборок имеет доступ для создания запросов на изменение через разрешение Contribute to pull requests.

Рисунок 1. Разрешение на работу с запросами на включение изменений

  • Создать новое определение сборки. В моем случае, через классический редактор.

Рисунок 2. Выбор классического редактора

  • Указать репозиторий и ветвь, в которую будут создаваться запросы на включение кода из master.

Рисунок 3. Указание репозитория и ветви

  • Выбрать пустой набор шагов:

Рисунок 4. Определение сборки без шагов

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

Рисунок 5. Отключение скачивания кода

  • Дать возможность заданиям сборки получать ключ доступа к сервису.

Рисунок 6. Разрешение для получения ключа доступа

  • Указать необходимый период выполнения задания.

Рисунок 7. Установка расписания выполнения

  • Добавить только один шаг PowerShell с типом Inline.

Рисунок 8. Задача PowerShell

Сам же скрипт будет выполнять следующие шаги:

  • Зафиксировать необходимые параметры из предопределенных переменных сборки (ключ доступа, адрес организации, имя проекта, имя репозитория и ветви для запроса на включение изменений). Источником изменений будет master.

$token = «$(System.AccessToken)«

$branchTarget = «$(Build.SourceBranch)«

$branchSource = «refs/heads/master»

$branchTragetPath = $branchTarget -replace «refs/heads/», «»

$teamProject = «$(System.TeamProject)«

$repoName = «$(Build.Repository.Name)«

$orgUrl = «$(System.CollectionUri)«

  • Проверка, есть ли новые комиты в мастере через запрос Stats – Get, результат которого содержит свойство behindCount.

$uriBranchStatus = «$orgUrl/$teamProject/_apis/git/repositories/$repoName/stats/branches?name=$branchTragetPath&api-version=5.1″

resultStatus = Invoke-RestMethod -Uri $uriBranchStatus -Method Get -ContentType «application/json» -Headers @{Authorization=(«Basic {0}» -f $base64AuthInfo)}

if ($resultStatus.behindCount -eq 0)

{

    Write-Host «Current branch contains last changes from master»

    Return

}

  • Проверка, существует ли уже активный запрос на включение изменений через метод Pull Requests — Get Pull Requests. Метод возвращает массив соответствующих поисковому запросу запросов на включение кода. Если массив пустой, то и нет запросов на включение кода.

$uriCheckActivePR = «$orgUrl/$teamProject/_apis/git/repositories/$repoName/pullrequests?searchCriteria.targetRefName=$branchTarget&searchCriteria.sourceRefName=$branchSource&api-version=5.1″

$resultActivePR = Invoke-RestMethod -Uri $uriCheckActivePR -Method Get -ContentType «application/json» -Headers @{Authorization=(«Basic {0}» -f $base64AuthInfo)}

if ($resultActivePR.count -gt 0)

{

    Write-Host «PR exists already»

    Return

}

  • Создать запрос на включение изменений через метод Pull Requests – Create, в тело которого передается информация о источнике и цели запроса на включение кода.

$uriCreatePR = «$orgUrl/$teamProject/_apis/git/repositories/$repoName/pullrequests?api-version=5.1″

$bodyCreatePR = «{sourceRefName:’$branchSource‘,targetRefName:’$branchTarget‘,title:’Sync changes from $branchSource‘}»

result = Invoke-RestMethod -Uri $uriCreatePR -Method Post -ContentType «application/json» -Headers @{Authorization=(«Basic {0}» -f $base64AuthInfo)} -Body $bodyCreatePR

Write-Host «Created PR» $result.pullRequestId

Результирующий шаг в сборке:

Рисунок 9. Скрипт в сборке

Содержимое скрипта можно посмотреть здесь: https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/CustomPSTasks/CreatePRBuildTask.ps1

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

Автоматическое обновление целевой даты исправления ошибки на основе Azure DevOps CLI

Posted by Shamrai Alexander на 12 ноября, 2019

Часто в проектах возникает потребность устанавливать определенные сроки для исправления ошибок определенного приоритета. Т.к. в процессах Azure DevOps отсутствует возможность использовать вычисляемые поля, то решать данную задачу приходится с помощью не-коробочных возможностей (например, Excel или отдельно разработать утилиту на основе Rest API). Однако использование Azure DevOps CLI позволяет значительно сэкономить время, необходимое на решение подобного вопроса.

Попробуем реализовать схожую задачу. Для этого нам понадобится следующее:

  1. PowerShell
  2. Azure DevOps CLI
  3. Personal Access Token
  4. Адрес организации Azure DevOps и наименование проекта
  5. Подготовленный запрос на основе WIQL, которые отберет необходимые рабочие элементы и поля, на основе которых будет выполнять вычисление. Например, можно сразу отбирать дату создания и на ее основе устанавливать целевую дату.

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

  • Установить значения по умолчанию для адреса организации Azure DevOps и наименования проекта. Это позволит не использовать эти параметры в каждой следующей команде:

az devops configure -d organization=$azdOrg project=$azdProject

  • Выполнить подготовленный ранее запрос. Команда вернет ответ в json формате, поэтому результат нужно конвертировать:

$workItems = (az boards query —wiql «$queryWiql« | ConvertFrom-Json)

  • Обновить необходимое поле для обнаруженный рабочих элементов:

az boards work-item update —id $workItem.id —fields «Microsoft.VSTS.Scheduling.DueDate=$targetDateStr» —discussion «Updated by CLI»

Вот и все. Полный пример можно посмотреть здесь: https://github.com/ashamrai/AzureDevOpsExtensions/blob/master/CustomPSTasks/UpdateBugTargetDate.ps1

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

Azure DevOps Rest Api. 21. Создание и просмотр запросов на включение кода

Posted by Shamrai Alexander на 8 июля, 2019

Для взаимодействия с объектами версионного контроля GIT используется клиент GitHttpClient. В рамках данной статьи мы рассмотрим методы:

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

Просмотра текущих или закрытых запросов на включение кода

Для поиска запросов на включение кода используется метод GetPullRequestsAsync, который принимает основные параметры: имя командного проекта и наименование репозитория. Кроме этого, условия поиска можно детализировать, указав класс GitPullRequestSearchCriteria как дополнительный параметр, в котором можно определить:

  • CreatorId – идентификатор пользователя, создавшего запрос
  • ReviewerId — идентификатор ревьювера, который присутствует в запрос
  • SourceRefName – наименование ветви источника изменений
  • Status – состояние запроса. Перечень статусов можно найти в перечислении PullRequestStatus.
  • TargetRefName – наименование целевой ветви.

Пример выполнения метода, следующий:

var pullRequests = (CompletedPRs)?
GitClient.GetPullRequestsAsync(TeamProjectName, GitRepo, new GitPullRequestSearchCriteria { Status = PullRequestStatus.Completed, TargetRefName = TargetRef }, top: 10).Result :

GitClient.GetPullRequestsAsync(TeamProjectName, GitRepo, null ).Result;

В данном примере мы получаем 10 закрытых запросов на включение кода для определенной ветви или список активных запросов на включение кода. Каждый запрос на включение кода содержит следующие важные свойства:

  • PullRequestId – идентификатор запроса
  • Title – наименование запроса
  • CreatedBy – пользователь, который создал запрос
  • Status – состояние запроса
  • SourceRefName – ветвь источник изменений
  • TargetRefName – ветвь приемник изменений
  • Description – описание запроса

Также мы можем получить список комментариев запроса на включение кода через метод GetThreadsAsync, который принимает основные три параметра: имя командного проекта, наименование репозитория и идентификатор запроса на включение изменений. В ответ мы получаем список поток обсуждений GitPullRequestCommentThread. Поток обсуждений содержит список объектов Comment. Первый элемент Comment всегда является темой обсуждения, а каждый последующий ответами. Пример получения комментариев к запросу:

var pullTheads = GitClient.GetThreadsAsync(TeamProjectName, GitRepo, pullRequest.PullRequestId).Result;

Рабочие элементы, которые связаны с запросом на включение кода, можно получить через метод GetPullRequestWorkItemRefsAsync, который также получает только три основных параметра: имя командного проекта, наименование репозитория и идентификатор запроса на включение изменений. Результатом является список объектов ResourceRef, который содержит идентификатор рабочего элемента. Как получить детали рабочего элемента описано здесь: Получение рабочих элементов. Пример получения списка рабочих элементов:

var workItemRefs = GitClient.GetPullRequestWorkItemRefsAsync(TeamProjectName, GitRepo, pullRequest.PullRequestId).Result;

Комиты, которые вошли в запрос на включение кода, можно получить через метод GetPullRequestCommitsAsync, который все еще получает только три основных параметра: имя командного проекта, наименование репозитория и идентификатор запроса на включение изменений. Результатом является список объектов GitCommitRef, который включает в себя: идентификатор комита CommitId и его комментарий Comment. Пример получения списка комитов:

var commits = GitClient.GetPullRequestCommitsAsync(TeamProjectName, GitRepo, pullRequest.PullRequestId).Result;

Создание запроса на включение кода

Запрос на включение кода создается через метод CreatePullRequestAsync, который принимает три основных параметра:

  • gitPullRequestToCreate – объект GitPullRequest, который содержит характеристики нового запроса на включение.
  • Project – наименование командного проекта.
  • repositoryId – наименование репозитрия

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

  • Title – наименование запроса
  • Description – описание запроса
  • SourceRefName – путь к исходной ветви
  • TargetRefName – путь к целевой ветви
  • (опционально) WorkItemRefs – массив объектов ResourceRef, в который присваивается идентификатор рабочего элемента Id и его ссылка Url.

Пример создания запроса на включение кода:

GitPullRequest pr = new GitPullRequest();
pr.Title = pr.Description = String.Format(«PR from {0} into {1} «, SourceRef, TargetRef);

pr.SourceRefName = SourceRef;

pr.TargetRefName = TargetRef;

var newPr = GitClient.CreatePullRequestAsync(pr, TeamProjectName, RepoName).Result;

Создание рабочих элементов, связанных с запросом на включение кода

Примеры создания и связывания рабочих элементов рассматривались здесь: Создание и редактирование рабочих элементов и Добавление и редактирование связей между рабочими элементами. Отличием связывания рабочего элемента с запросом на включение кода является объект описания связи:

  • тип связи — ArtifactLink
  • ссылка на объект формируется по формату: vstfs:///Git/PullRequestId/{0}%2F{1}%2F{2}, где:
    • {0} – идентификатор командного проекта.
    • {1} – идентификатор репозитория.
    • {2} – идентификатор запроса на включение кода.
  • Наименование связи — Pull Request

Пример создания объекта для описания связи с запросом на включение кода:

const string ArtigactLinkName = «ArtifactLink»;
const string PRUrlTemplate = «vstfs:///Git/PullRequestId/{0}%2F{1}%2F{2}»;

const string PRLinkName = «Pull Request»;

static object CreateNewLinkObject(string RelName, string RelUrl, string Name, string Comment)

{

    return new {

        rel = RelName,

        url = RelUrl,

        attributes = new {

            name = Name,

            comment = Comment

        }

    };

}

FiledValue = CreateNewLinkObject(ArtigactLinkName, String.Format(PRUrlTemplate, TeamProject.Id, TeamRepo.Id, pr.PullRequestId), PRLinkName, «Review this PR»);

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

https://github.com/ashamrai/TFRestApi/tree/master/21.TFRestApiAppCreateAndViewPullRequests

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

Azure DevOps Rest Api. 20. Просмотр определений сборки для командного проекта

Posted by Shamrai Alexander на 10 июня, 2019

Для управление сборками используется клиент BuildHttpClient. В рамках данный статьи мы рассмотрим методы для получения всех определений сборок и просмотра их последних запусков.

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

  • Id – идентификатор определения сборки
  • Name – наименование определения сборки
  • Path – путь, по которому храниться определение сборки
  • Revision– версия определения сборки
  • Queue – очередь, в которую поставлена сборка
  • QueueStatus – состояние сборки в очереди

Пример получения списка определений сборки:

List<BuildDefinitionReference> buildDefs = BuildClient.GetDefinitionsAsync(TeamProjectName).Result;

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

  • Id – идентификатор сборки
  • BuildNumber – номер сборки
  • Status – состояние сборки
  • StartTime – время старта процесса сборки
  • FinishTime – время завершения процесса сборки

Пример получения списка сборок для конкретного определения сборки:

List<Build> builds = BuildClient.GetBuildsAsync(TeamProjectName, new List<int> { buildDef.Id }).Result;

Дополнительно для каждой сборки можно получить список комитов, которые были основой для ее создания, через метод GetBuildChangesAsync:

var changes = BuildClient. GetBuildChangesAsync(TeamProjectName, builds[i].Id).Result;

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

https://github.com/ashamrai/TFRestApi/tree/master/20.TFRestApiAppExploreBuildDefinitions

Posted in azure, devops, Microsoft, Team Foundation Server, Visual Studio, visual studio team services | Отмечено: , | Leave a Comment »

Azure DevOps Rest Api. 14. Создание и добавление тестовых сценариев

Posted by Shamrai Alexander на 11 мая, 2019

<< Перейти в радел «Azure DevOps Services (TFS/VSTS) Rest Api»

Примечание: На основе Microsoft.TeamFoundationServer.Client 16.150.0-preview

Создание тестового сценария

Примечание: На момент написания статьи не существовало официальных задокументированных возможностей для создания тестовых сценариев через Rest Api. Ниже описанное о тестовых шагах получено опытным путем.

Клиент TestPlanHttpClient не содержит каких-либо методов для создания тестовых сценариев. Тестовые сценарии создаются как обычные рабочие элементы через клиент WorkItemTrackingHttpClient (см. Создание и редактирование рабочих элементов). Особенностью является формирование шагов тестирования и параметров для них.

Структура содержимого шагов тестирования в сценарии

Шаги тестирования содержатся в поле Microsoft.VSTS.TCM.Steps в следующем формате:

<steps id=»0″ last=»{LAST_STEP_ID}»>

<step type=»ActionStep» id=»{STEP_ID}»>

<parameterizedString isformatted=»true»>{ACTION_DESCRIPTION}</parameterizedString>

<parameterizedString isformatted=»true»></parameterizedString>

</step>

<step type=»ValidateStep» id=»{STEP_ID}»>

<parameterizedString isformatted=»true»>{ ACTION _DESCRIPTION}</parameterizedString>

<parameterizedString isformatted=»true»>{VALIDATION_DESCRIPTION}</parameterizedString>

</step>

</steps>

Тут можно выделить следующие атрибуты:

  1. {LAST_STEP_ID} – идентификатор последнего шага.
  2. type – тип шага. Если установлено значение ActionStep, то заполняется только содержимое для первой строки шага(parameterizedString), содержимое второй строки остается пустым. Если же установлено ValidateStep, то обе строки заполняются.
  3. {STEP_ID} – порядковый номер шага. Отсчет начинается с 2.
  4. {ACTION_DESCRIPTION} – описание действий в шаге.
  5. {VALIDATION_DESCRIPTION} – описание проверок правильного выполнения шага.

Структура содержимого параметров шагов тестирования

Если тестовый сценарий не использует локальные параметры, то этот пункт можно упустить. Описание параметров разделяется на две части:

  1. Описание набора параметров.
  2. Описание значений параметров.

Описание набора параметров

Набор параметров содержится в поле Microsoft.VSTS.TCM.Parameters в следующем виде:

<parameters>

<param name=»param1″ bind=»default»/>

<param name=»param2″ bind=»default»/>

</parameters>

Т.е. для каждого параметра в блоке parameters описывается строка <param name=»ИМЯ_ПАРАМЕТРА» bind=»default»/>.

Описание значений параметров

Набор параметров содержится в поле Microsoft.VSTS.TCM.LocalDataSource в следующем виде:

<NewDataSet>

<xs:schema id=’NewDataSet’ xmlns:xs=’http://www.w3.org/2001/XMLSchema&#8217; xmlns:msdata=’urn:schemas-microsoft-com:xml-msdata’>

    <xs:element name=’NewDataSet’ msdata:IsDataSet=’true’ msdata:Locale=»>

        <xs:complexType>

<xs:choice minOccurs=’0′ maxOccurs = ‘unbounded’>

            <xs:element name=’Table1′>

<xs:complexType>

                <xs:sequence>

                    <xs:element name=’param1′ type=’xs:string’ minOccurs=’0′ />

                    <xs:element name=’param2′ type=’xs:string’ minOccurs=’0′ />

                </xs:sequence>

            </xs:complexType>

        </xs:element>

    </xs:choice>

</xs:complexType>

</xs:element>

</xs:schema>

<Table1><param1>value1</ param1>< param2>value2</ param2></Table1>

<Table1>< param1>value3</ param1>< param2>value4</ param2></Table1>

</NewDataSet>

Т.е. это описание набора данных с его содержимым. Для каждого нового параметра необходимо в разделе <xs:sequence> добавить новую строку с описанием параметра: <xs:element name=’ИМЯ_ПАРАМЕТРА’ type=’xs:string’ minOccurs=’0′ /> .

Далее внизу в таблице <Table1> прописываются значения для каждого из параметров. Сколько новых строк будет в таблице – столько итераций тестирования будет запускать мастер выполнения тестовых сценариев.

Пример генерирования содержимого тестовых шагов и параметров находится в файле в TestStepsHelper.cs тестового решения ниже.

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

Dictionary<string, object> fields = new Dictionary<string, object>();
LocalStepsDefinition stepsDefinition = new LocalStepsDefinition();
stepsDefinition.AddStep(«Run Application»);

stepsDefinition.AddStep(«Enter creds @user_name @user_password»);

stepsDefinition.AddStep(«Check available functions», «Functions for: @user_role»);

LocalTestParams testParams = new LocalTestParams();

testParams.AddParam(«user_name», new string[] { «admin», «user», «manager» });

testParams.AddParam(«user_password», new string[] { «admin_pswrd», «user_pswrd», «manager_pswrd» });

testParams.AddParam(«user_role», new string[] { «Administrator», «Local User», «Shop Manager» });

fields.Add(«Title», «new test case»);

fields.Add(FieldSteps, stepsDefinition.StepsDefinitionStr);

fields.Add(FieldParameters, testParams.ParamDefinitionStr);

fields.Add(FieldDataSource, testParams.ParamDataSetStr);

CreateWorkItem(TeamProjectName, «Test Case», fields);

А выполнение шагов будет отображаться так:

Рисунок 1. Выполнение теста

Добавление тестового сценария в существующий набор тестов

Тестовые сценарии могут быть добавлены только в статический набор тестов или набор тестов для требования. Для добавления используется метод AddTestCasesToSuiteAsync клиента TestPlanHttpClient с параметрами: список экземпляров класса SuiteTestCaseCreateUpdateParameters, который описывает ссылку на рабочий элемент теста; наименование командного проекта; идентификатор плана тестирования для новых тестовых сценариев и идентификатор набора тестов. Класс SuiteTestCaseCreateUpdateParameters содержит два атрибута (workItem и PointAssignments), мы будем использовать только атрибут workItem для создания ссылки на рабочий элемент. Пример:

TestSuite testSuite = TestPlanClient.GetTestSuiteByIdAsync(TeamProjectName, TestPlanId, testSuiteId).Result;
if (testSuite.SuiteType == TestSuiteType.StaticTestSuite || testSuite.SuiteType == TestSuiteType.DynamicTestSuite)
{

List<SuiteTestCaseCreateUpdateParameters> suiteTestCaseCreateUpdate = new List<SuiteTestCaseCreateUpdateParameters>();


foreach (int testCaseId in TestCasesIds)

suiteTestCaseCreateUpdate.Add(new SuiteTestCaseCreateUpdateParameters()

{

workItem = new Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.WorkItem()

{

Id = testCaseId

}

});

TestPlanClient.AddTestCasesToSuiteAsync(suiteTestCaseCreateUpdate, TeamProjectName, TestPlanId, testSuiteId).Wait();

}

else

Console.WriteLine(«The Test Suite ‘» + StaticSuitePath + «‘ is not static or requirement»);

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

https://github.com/ashamrai/TFRestApi/tree/master/14.TFRestApiAppCreateAndAddTestCase

Posted in azure, devops, Microsoft, Team Foundation Server, Visual Studio, visual studio team services | Отмечено: , | Leave a Comment »

Azure DevOps Rest Api. 13. Создание плана тестирования и наборов тестов

Posted by Shamrai Alexander на 11 мая, 2019

<< Перейти в радел «Azure DevOps Services (TFS/VSTS) Rest Api»

Примечание: На основе Microsoft.TeamFoundationServer.Client 16.150.0-preview

Создание плана тестирования

План тестирования создается с помощью метода CreateTestPlanAsync из клиента TestPlanHttpClient. Данный метод принимает только два параметра:

  • Объект класса TestPlanCreateParams, который описывает основные параметры плана тестирования.
  • И имя командного проекта.

Класс TestPlanCreateParams включает следующие атрибуты, которые интересуют нас при создании на данном этапе:

  • Name – наименование нового плана тестирования
  • StartDate – дата начала плана тестирования в виде строки
  • EndDate – дата окончания плана тестирования в виде строки
  • AreaPath – путь области
  • Iteration – путь итерации

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

TestPlanCreateParams newPlanDef = new TestPlanCreateParams()
{

Name = TestPlanName,

StartDate = StartDate,

EndDate = FinishDate,

AreaPath = AreaPath,

Iteration = IterationPath

};

return TestPlanClient.CreateTestPlanAsync(newPlanDef, TeamProjectName).Wait();

Создание тестового набора

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

  1. SuiteType – тип набор тестирования, который может быть одним из значений перечисления TestSuiteType:
    1. StaticTestSuite – статический набор тестов, который может включать дочерние наборы тестов и тестовые сценарии.
    2. DynamicTestSuite – динамический набор тестов, который содержит тесты, отобранные его запросом через атрибут queryString.
    3. RequirementTestSuite – набор тестов, который ассоциируется с рабочим элементов группы требований и может содержать только тестовые сценарии.
  2. Name – наименование нового набора тестов.
  3. QueryString – WIQL запрос для отбора тестов для динамического набора тестов.
  4. RequirementId – идентификатор рабочего элемента группы требований, для которого будет создан тестовый набор с типом RequirementTestSuite.
  5. ParentSuite – родительский набор тестов, который описывается экземпляром класса TestSuiteReference. Класс TestSuiteReference содержит атрибут Id, которому присваивается идентификатор родительского набора тестов.

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

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

Прим создания набора тестов:

TestSuiteCreateParams newSuite = new TestSuiteCreateParams()
{

Name = TestSuiteName,

SuiteType = SuiteType,

QueryString = SuiteQuery,

RequirementId = RequirementId,

ParentSuite = new TestSuiteReference() { Id = parentsuiteId }

};

TestSuite testSuite = TestPlanClient.CreateTestSuiteAsync(newSuite, TeamProjectName, TestPlanId).Result;

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

https://github.com/ashamrai/TFRestApi/tree/master/13.TFRestApiAppCreateTestPlanAndSuites

Posted in Microsoft, Team Foundation Server, Team Foundation Server FAQ, Visual Studio, visual studio team services | Отмечено: , | Leave a Comment »

Azure DevOps Rest Api. 12. Просмотр содержимого плана тестирования

Posted by Shamrai Alexander на 23 апреля, 2019

<< Перейти в радел «Azure DevOps Services (TFS/VSTS) Rest Api»

Примечание: На основе Microsoft.TeamFoundationServer.Client 16.150.0-preview

Для работы с объектами тестирования используется клиент TestPlanHttpClient (пространство имен Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi). В рамках планирования тестирования используются следующие основные объекты:

  1. План тестирования – класс TestPlan. Он содержит в основном информацию о названии, планируемых датах тестирования и т.д.
  2. Набор тестов – класс TestSuite. Содержит дочерние наборы, а также сценарии тестирования. Наборы тестов могут быть статическими, наборам для требований (т.е. ссылаются на конкретное требование) и динамическими (на основе запроса по рабочим элементам).
  3. Тестовый сценарий – класс TestCase. Содержит информацию о рабочем элементе тестового сценария, тестировщике и конфигурации для тестирования.

Для того, чтобы получить информацию о всех объектах тестирования, необходимо:

  1. Получить план тестирования.
  2. Получить дерево наборов тестов плана тестирования.
  3. Получить содержимое набора тестов, т.е. тестовые сценарии.

Для получения тестового сценария используется метод GetTestPlanByIdAsync с использованием имени командного проекта и идентификатора. Идентификатор можно увидеть через интерфейс:

Рисунок 1. Редактирование плана тестирование

Рисунок 2. Идентификатор плана тестирования

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

Пример получения плана тестирования и его свойств:

TestPlan testPlan = TestPlanClient.GetTestPlanByIdAsync(TeamProjectName, TestPlanId).Result;

Console.WriteLine(«================================================================»);

Console.WriteLine(«Test Plan : {0} : {1} : {2}», testPlan.Id, testPlan.State, testPlan.Name);

Console.WriteLine(«Area Path : {0} : Iteration Path : {1}», testPlan.AreaPath, testPlan.Iteration);

Console.WriteLine(«Plan Dates : {0} — {1}»,

(testPlan.StartDate.HasValue) ? testPlan.StartDate.Value.ToShortDateString() : «none»,

(testPlan.EndDate.HasValue) ? testPlan.EndDate.Value.ToShortDateString() : «none»);

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

List<TestSuite> suitesDetail = TestPlanClient.GetTestSuitesForPlanAsync(TeamProjectName, TestPlanId, asTreeView: true).Result;

ExploreTestSuiteTree(TeamProjectName, TestPlanId, suitesDetail, «»);

static
void ExploreTestSuiteTree(string TeamProjectName, int TestPlanId, List<TestSuite> SuitesSubTree, string ParentPath)

{

foreach (TestSuite testSuite in SuitesSubTree)

{

PrintSuiteInfo(testSuite, ParentPath);

if (testSuite.HasChildren) ExploreTestSuiteTree(TeamProjectName, TestPlanId, testSuite.Children, ParentPath + «\\» + testSuite.Name);

}

}

static
void PrintSuiteInfo(TestSuite Suite, string ParentPath)

{

Console.WriteLine(«================================================================»);

Console.WriteLine(«Test Suite : {0} : {1}», Suite.Id, Suite.Name);

Console.WriteLine(«Suite Type : {0} : {1}», Suite.SuiteType,

(Suite.SuiteType == TestSuiteType.StaticTestSuite) ? «» :

(Suite.SuiteType == TestSuiteType.DynamicTestSuite) ? «\nQuery: « + Suite.QueryString : «Requirement ID « + Suite.RequirementId.ToString());


if (Suite.ParentSuite == null) Console.WriteLine(«This is a root suite»);


else Console.WriteLine(«Parent Path: « + ParentPath);

Console.WriteLine(«—————————————————————-«);

}

Список тестов в наборе тестов можно получить через метод GetTestCaseListAsync, который использует наименование проекта, идентификатор плана тестирования и идентификатор набора тестирования. Кроме этого, тестовый сценарий содержит идентификатор рабочего элемента и его поля. Пример получения списка тестов и свойств рабочих элементов:

List<TestCase> testCases = TestPlanClient.GetTestCaseListAsync(TeamProjectName, TestPlanId, testSuite.Id).Result;

if (testCases.Count > 0)

{

foreach (TestCase testCase in testCases)

{

Console.WriteLine(«Test: {0} — {1}», testCase.workItem.Id, testCase.workItem.Name);

var wiFields = GetWorkItemFields(testCase.workItem.WorkItemFields);

if (wiFields.ContainsKey(«System.State»))

Console.WriteLine(«Test Case State: {0}», wiFields[«System.State»].ToString());


foreach (var config in testCase.PointAssignments)

Console.WriteLine(«Run for: {0} : {1}», config.Tester.DisplayName, config.ConfigurationName);

}

}

private
static Dictionary<string, object> GetWorkItemFields(List<object> WorkItemFieldsList)

{

Dictionary<string, object> wiFields = new Dictionary<string, object>();


foreach (object wiField in WorkItemFieldsList)

{

Dictionary<string, object> fld = JsonConvert.DeserializeObject<Dictionary<string, object>>(wiField.ToString());

wiFields.Add(fld.Keys.ElementAt(0), fld[fld.Keys.ElementAt(0)]);

}

return wiFields;

}

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

https://github.com/ashamrai/TFRestApi/tree/master/12.TFRestApiAppTestPlanDelails

Posted in Microsoft, Team Foundation Server, Team Foundation Server FAQ, Visual Studio, visual studio team services | Отмечено: , , , | Leave a Comment »

Azure DevOps Rest Api. 19. Выполнение сборки и получение результатов

Posted by Shamrai Alexander на 22 апреля, 2019

Для управление сборками используется клиент BuildHttpClient.

Выполнение сборки

Для запуска сборки используется метод QueueBuildAsync, который принимает экземпляр класса Build на вход. Для создания нового объекта класса Build используются два основных параметра:

  • Definition – определение сборки, которые мы получаем через метод GetDefinitionAsync.
  • Project – командные проект, который мы получаем через метод GetProject клиента ProjectHttpClient.

Пример:

var buildDefinition = BuildClient.GetDefinitionAsync(TeamProjectName, BuildDefId).Result;

var teamProject = ProjectClient.GetProject(TeamProjectName).Result;

BuildClient.QueueBuildAsync(new Build() { Definition = buildDefinition, Project = teamProject }).Wait();

Собственно, это все, что нужно для запуска сборки. Метод QueueBuildAsync возвращает экземпляр класса Build, который содержит идентификатор сборки для дальнейших операций с ней. Например, для получения текущей информации о сборке можно использовать метод GetBuildAsync, который вернет все тот же класс Build со следующими полезными атрибутами:

  • Id – идентификатор сборки
  • BuildNumber – номер сборки
  • Status – состояние сборки
  • Definition – определение сборки

Просмотр задач сборки

Если есть необходимость просмотреть состав задач и детализацию их выполнения, то для этого можно воспользоваться методом GetBuildTimelineAsync с параметрами имя проекта и идентификатор сборки. Метод вернет экземпляр класса Timeline со списком TimelineRecord, который включает в себя следующие атрибуты:

  • RecordType – тип записи. Нас интересует значение Task.
  • Name – имя задачи.
  • StartTime – дата и время запуска задачи.
  • FinishTime – дата и время завершения задачи.
  • Result – результат выполнения задачи. Список значений доступен в перечисленииTaskResult.

Пример:

var timeline = BuildClient.GetBuildTimelineAsync(TeamProjectName, BuildId).Result;

if (timeline.Records.Count > 0)

{

     Console.WriteLine(«Task Name——————————Start Time—Finish Time—Result»);

     foreach(var record in timeline.Records)

          if (record.RecordType == «Task»)

               Console.WriteLine(«{0, -35} | {1, -10} | {2, -10} | {3}»,

               (record.Name.Length < 35) ? record.Name : record.Name.Substring(0, 35),

               (record.StartTime.HasValue) ? record.StartTime.Value.ToLongTimeString() : «»,

               (record.FinishTime.HasValue) ? record.FinishTime.Value.ToLongTimeString() : «»,

               (record.Result.HasValue) ? record.Result.Value.ToString() : «»);

}

Скачивание результатов сборки

Когда нужно получить результаты сборки в виде определенного артефакта, то для этого можно воспользоваться следующими методами:

  • GetArtifactAsync – получить информацию об артефакте со следующими полезными атрибутами:
    • BuildNumber – номер сборки.
    • Resource.DownloadUrl – ссылка для скачивания результатов.
  • GetArtifactContentZipAsync – возвращает поток архива артефакта.

При этом оба метода принимают два параметра: идентификатор сборки и имя артефакта, которое обычно имеет значение drop.

Пример:

BuildArtifact drop = BuildClient.GetArtifactAsync(StartedBuild.Id, ArtifactName).Result;

string dropFileName = String.Format(«{0}_{1}.zip», StartedBuild.Definition.Name, StartedBuild.BuildNumber);

Stream zipStream = BuildClient.GetArtifactContentZipAsync(StartedBuild.Id, ArtifactName).Result;

using (FileStream zipFile = new FileStream(dropFileName, FileMode.Create))

zipStream.CopyTo(zipFile);

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

https://github.com/ashamrai/TFRestApi/tree/master/19.TFRestApiAppQueueBuild

Posted in Microsoft, Team Foundation Server, Team Foundation Server FAQ, Visual Studio, visual studio team services | Отмечено: , , , , | Leave a Comment »

Azure DevOps Services Rest Api. 18. Создание и клонирование определения сборки

Posted by Shamrai Alexander на 9 апреля, 2019

В рамках данной статьи мы рассмотрим созданием и клонирование определений сборки для yaml формата и графического мастера. В общем их структура одинаковая, но они отличаются только параметром, который характеризует шаги выполнения сборки. В yaml формате это ссылка на соответствующий файл в версионном контроле, а для графического мастера – детальное определение фаз и шагов выполнения. Основным хранилищем версионного контроля будет выступать внутренний GIT. Для управления сборками используется клиент BuildHttpClient.

Создание определения сборки

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

  1. Открыть на редактирование существующее определение сборки.
  2. Выбрать фазу выполнения на агенте и нажать на ссылку View YAML:

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

  • Path – путь или каталог, в котором будет храниться определение сборки.
  • Name – наименование определения сборки.
  • Queue – пул через который будет запускаться новая сборка. Определяется через класс AgentPoolQueue, в котором указывается наименование пула.
  • Process – описание процесса выполнения шагов. Для yaml формата используется класс YamlProcess, в котором через атрибут YamlFilename указывается путь к yaml файлу в версионном хранилище.
  • Repository – описывает используемое хранилище исходного кода. Описывается классом BuildRepository, который включает в себя:
    • Url – url для клонирования репозитория. Посмотреть его можно на основе следующих шагов: Clone the repo to your computer
    • Name – имя репозитория
    • Type – тип репозитория, который описывается через статический класс RepositoryTypes.
  • Variables – переменные, которыми определяем путь к решению, конфигурацию и платформу сборки.

Далее запускается метод CreateDefinitionAsync, в который передается наименование командного проекта и сформированное определение сборки. Пример создания:

BuildDefinition newBuild = new BuildDefinition();
newBuild.Path = BuildPath;

newBuild.Name = BuildName;

newBuild.Queue = new AgentPoolQueue() { Name = «Hosted VS2017» };

YamlProcess yamlProcess = new YamlProcess();

yamlProcess.YamlFilename = «<yaml file>»;

newBuild.Process = yamlProcess;

newBuild.Repository = new BuildRepository();

newBuild.Repository.Url = new Uri(String.Format(GitRepoFormat, TeamProjectName, GitRepoName));

newBuild.Repository.Name = GitRepoName;

newBuild.Repository.DefaultBranch = RepoBranch;

newBuild.Repository.Type = RepositoryTypes.TfsGit;

newBuild.Variables.Add(«BuildConfiguration», new BuildDefinitionVariable { AllowOverride = false, IsSecret = false, Value = «Debug» });

newBuild.Variables.Add(«BuildPlatform», new BuildDefinitionVariable { AllowOverride = false, IsSecret = false, Value = «Any CPU» });

newBuild.Variables.Add(«Parameters.solution», new BuildDefinitionVariable { AllowOverride = false, IsSecret = false, Value = SlnPath });

newBuild = BuildClient.CreateDefinitionAsync(newBuild, TeamProjectName).Result;

Клонирование определения сборки

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

  1. Получение существующего определения сборки.
  2. Обновление необходимых параметров.
  3. Создание новой сборки.

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

Далее необходимо изменить необходимые параметры в полученной сборке, например:

  • Repository – описывает используемое хранилище исходного кода. Описывается классом BuildRepository, который включает в себя:
    • Url – url для клонирования репозитория. Посмотреть его можно на основе следующих шагов: Clone the repo to your computer
    • Name – имя репозитория
    • DefaultBranch – наименование ветви репозитория.
  • Path – путь к новому определению сборки.
  • Name – наименование нового определения сборки.

Далее вызывается метод CreateDefinitionAsync:

var bld = BuildClient.GetDefinitionAsync(TeamProjectName, SourceBuildId).Result;
var clonedBuild = bld;

clonedBuild.Repository.Url = new Uri(String.Format(GitRepoFormat, TeamProjectName, GitRepoName));

clonedBuild.Repository.Name = GitRepoName;

clonedBuild.Repository.Id = null;

if (NewBranch != null) clonedBuild.Repository.DefaultBranch = NewBranch;

clonedBuild.Path = NewPath;

clonedBuild.Name = NewName;

if (NewProjectPath != null && clonedBuild.ProcessParameters.Inputs.Count == 1)

clonedBuild.ProcessParameters.Inputs[0].DefaultValue = NewProjectPath;

clonedBuild = BuildClient.CreateDefinitionAsync(clonedBuild, TeamProjectName).Result;

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

https://github.com/ashamrai/TFRestApi/tree/master/18.TFRestApiAppCreateCloneBuild

Posted in Microsoft, Team Foundation Server, Visual Studio, visual studio team services | Отмечено: , , , , | Leave a Comment »

 
%d такие блоггеры, как: