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

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

Posts Tagged ‘rest api’

Azure DevOps Rest Api. 24. Просмотр определений релизов командного проекта

Posted by Shamrai Alexander на 31 марта, 2020

Для работы с релизами необходим дополнительный пакет Microsoft.VisualStudio.Services.Release.Client, который содержит клиент ReleaseHttpClient. С его помощью здесь мы выполним следующие операции:

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

Получить список определений релизов можно через метод GetReleaseDefinitionsAsync, которому по умолчанию достаточно имени проекта в качестве параметра. Если необходимо сократить количество возвращаемых определений релизов, можно указать параметры searchText (для поиска по шаблону) и path (для поиска по определенному пути). По умолчанию метод возвращает список определений релизов с базовой информаций, такой как:

  • Идентификатор
  • Наименование
  • Описание
  • Путь
  • И т.д.

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

var reldefList = ReleaseClient.GetReleaseDefinitionsAsync(teamProjectName, expand: ReleaseDefinitionExpands.Environments).Result;

foreach (var reldef in reldefList)

{

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

Console.WriteLine(«ID: {0} PATH: {1} NAME: {2}», reldef.Id, reldef.Path, reldef.Name);

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

Console.Write(«STAGES:»);


if (reldef.Environments != null) foreach (var env in reldef.Environments) Console.Write(env.Name + «; «);

Console.WriteLine();

}

Чтобы получить список выполненных в командном проекте релизов, можно воспользоваться методом GetReleasesAsync с именем командного проекта, который вернет все релизы проекта. Если нужно получить релизы по определению релиза, то нужно добавить идентификатор определения. Полученный список также содержит базовую информацию. Если необходимо добавить дополнительно какие-то данные (среды или артефакты), то можно указать это в параметре expand. Пример получения последних 10-ти релизов и состояния их сред:

var rels = ReleaseClient.GetReleasesAsync(teamProjectName, reldefId, expand: ReleaseExpands.Environments, top: 10).Result;

foreach (var rel in rels)

{

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

Console.WriteLine(«ID: {0} REASON: {1} NAME: {2}», rel.Id, rel.Reason, rel.Name);

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

Console.WriteLine(«STAGES:»);


if (rel.Environments != null) foreach (var env in rel.Environments) Console.Write(env.Name + » : « + env.Status + «; «);

Console.WriteLine();

}

Также можно «посмотреть», какие были изменения добавлены в релиз, т.е. комиты и рабочие элементы. В этом нам помогут методы GetBuildChangesAsync и GetBuildWorkItemsRefsAsync клиента BuildHttpClient. Данные методы используют имя командного проекта и идентификатор сборки. Если сборка связана с релизом, то ее можно найти в свойстве Artifacts. При этом тип артефакта должен быть «Build», и тогда в словаре DefinitionReference через ключ «version» можно найти идентификатор сборки. Пример просмотра рабочих элементов и комитов, связанных с релизом, приведен ниже. В примере для получения детализации релиза используется метод GetReleaseAsync, который возвращает всю информацию по идентификатору релиза и наименованию проекта.

var relDetails = ReleaseClient.GetReleaseAsync(teamProjectName, relId).Result;

if (relDetails.Artifacts != null)

{

foreach (var artifact in relDetails.Artifacts)

{

if (artifact.Type == «Build»)

{

int buildId;

if (Int32.TryParse(artifact.DefinitionReference[«version»].Name, out buildId))

{

var commits = BuildClient.GetBuildChangesAsync(teamProjectName, buildId, top: 10).Result;

var workItems = BuildClient.GetBuildWorkItemsRefsAsync(teamProjectName, buildId, top: 10).Result;

Console.WriteLine(«BUILDID : {0}», buildId);

Console.WriteLine(«COMMITS : {0}», String.Join(«; «, from x in commits select x.Id.Substring(0, 8)));

Console.WriteLine(«WORK ITEMS: {0}», String.Join(«; «, from x in workItems select x.Id));

}

}

}

}

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

https://github.com/ashamrai/TFRestApi/tree/master/24.TFRestApiAppExploreReleases

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

Клонирование рабочих элементов Azure DevOps через REST API

Posted by Shamrai Alexander на 31 марта, 2020

Azure DevOps содержит у себя функцию для ручного копирования рабочих элементов Copy or clone work items. Но если нужно клонировать несколько или несколько десятков штук, то ручной метод не очень эффективен. Здесь будет представлен базовый функционал для клонирования рабочих элементов через клиент для Rest API Microsoft.TeamFoundationServer.Client.

Операция разделяется на две основные части:

  1. Получить всю информацию о рабочем элементе.
  2. Полученные поля передать для создания нового рабочего элемента.

Получение выполняется довольно просто через метод GetWorkItemAsync. Если нам нужны только поля, то мы передаем идентификатор рабочего элемента. А если нам нужны еще и связи для клонирования, то тогда для параметра expand нужно указать значение WorkItemExpand.Relations. Пример:

WorkItem wiToClone = (CopyLink) ?

witClient.GetWorkItemAsync(wiIdToClone, expand: WorkItemExpand.Relations).Result

witClient.GetWorkItemAsync(wiIdToClone).Result;

Поля можно найти в свойстве Fields, а связи – в Relations. Т.е. можно выполнять копирование, но при этом нужно исключить некоторые составляющие:

  1. Системные поля. Например, System.Id и System.Rev назначаются системой, а поле System.State может быть в состоянии Закрыто. Перечень полей можно посмотреть в примере в конце этой заметки.
  2. Автоматически заполняемые поля или поля, которые недоступны для заполнения при создании. Например, Microsoft.VSTS.Common.ActivatedDate заполняется на основе внутренних правил рабочего элемента.
  3. Конфликтующие связи. Например, нужно исключить дочерние связи, т.к. родитель может быть только один.

Скопировав поля и связи, можно выполнять создание нового рабочего элемента CreateWorkItemAsync. Пример копирования и создания:

foreach (var key in wiToClone.Fields.Keys)

if (!systemFields.Contains(key) && !customFields.Contains(key))

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/fields/» + key,

Value = wiToClone.Fields[key]

});

foreach (var link in wiToClone.Relations)

{

if (link.Rel != ChildRefStr)

{

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/relations/-«,

Value = new

{

rel = link.Rel,

url = link.Url

}

});

}

}

WorkItem clonedWi = witClient.CreateWorkItemAsync(patchDocument, teamProjectName, wiType).Result;

Полный пример можно посмотреть здесь: https://github.com/ashamrai/AzureDevOpsExtensions/tree/master/CustomNetTasks/CloneWorkItem

Дополнительные ссылки на методы для Rest API:

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

Восстановление Git репозиториев в Azure DevOps через Rest Api и PowerShell

Posted by Shamrai Alexander на 20 февраля, 2020

Удаление репозиториев Git в Azure DevOps не приводит к их полному удалению из командного проекта. Удаленные репозитории перемещаются в корзину проекта, но пока нет никаких инструментов для работы с ней. Однако можно воспользоваться функциями Rest Api для того, чтобы:

  1. Узнать какие репозитории были удалены
  2. Восстановить нужные репозитории
  3. Очистить корзину окончательно

Для работы с Rest Api воспользуемся PowerShell, который позволяет довольно быстро выполнять вызовы и разбирать их результаты. Перед выполнением запросов необходимо знать имя командного проекта и имя организации, а также необходимо сгенерировать Personal Access Token. Эти параметры нужно будет установить в скриптах ниже.

Перед тем как выполнить восстановление репозитория, нужно убедиться, что он находится в корзине проекта. Для этого можно воспользоваться следующим вызовом: Get Recycle Bin Repositories. Далее в результирующем списке можно выполнить поиск необходимого репозитория. Пример просмотра корзины (скрипт GetRecycleBinRepositories.ps1):

$listDeletedRepo = «https://dev.azure.com/$org/$teamProject/_apis/git/recycleBin/repositories?api-version=5.1-preview.1″

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

foreach ($repo in $resultDeletedRepo.value)

{

    Write-Host «=============================================»

    Write-Host «Id :» $repo.id

    Write-Host «Name:» $repo.name

}

Для восстановления репозитория нужно выполнить следующую команду: Restore Repository From Recycle Bin. В этой функции нужно становить признак deleted в значение false. Пример восстановления репозитория (скрипт RestoreRepositoryFromRecycleBin.ps1):

$restoreRepo = «https://dev.azure.com/$org/$teamProject/_apis/git/recycleBin/repositories/» + $repoId + «?api-version=5.1-preview.1»

$restoreBody = «{deleted:false}»

$resultrestoredRepo = Invoke-RestMethod -Uri $restoreRepo -Method Patch -ContentType «application/json» -Headers @{Authorization=(«Basic {0}» -f $base64AuthInfo)} -Body $restoreBody

Write-Host $resultrestoredRepo

Если репозиторий не нужен, то его можно удалить окончательно через: Delete Repository From Recycle Bin. При этом здесь нужно передать идентификатор репозитория, который можно узнать через функцию Get Recycle Bin Repositories. Пример удаления репозитория (скрипт для очистки корзины DeleteRepositoriesFromRecycleBin.ps1)

$hardDeleteRepo = «https://dev.azure.com/$org/$teamProject/_apis/git/recycleBin/repositories/» + $repo.id + «?api-version=5.1-preview.1»

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

Write-Host «Deleted repo:» $repo.name

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

Автоматизация изменения состояния родительских рабочих элементов 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 Rest Api. 23. Создание, удаление и восстановление репозиториев GIT

Posted by Shamrai Alexander на 26 августа, 2019

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

  • Создание репозитория.
  • Просмотр свойств репозитория
  • Удаление и восстановление репозитория.

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

Создание нового пустого репозитория выполняется довольно просто через метод CreateRepositoryAsync, в который можно передать всего лишь два параметра: объект GitRepository, в котором указать только имя нового репозитория, и название командного проекта. Пример выполнения:

newRepo = new GitRepository();
newRepo.Name = GitNewRepoName;

newRepo = GitClient.CreateRepositoryAsync(newRepo, TeamProjectName).Result;

Также можно создать ответвленный репозиторий через тот же метод. Для этого необходимо свойства родительского репозитория определить через объект GitRepositoryCreateOptions, который мы будем использовать вместо GitRepository. В этом объекте необходимо указать идентификатор родительского репозитория и ссылку на родительский проект. Далее необходимо вызвать метод CreateRepositoryAsync с дополнительным параметром – ссылку на ветвь для ответвления. Пример использования:

GitRepositoryCreateOptions newGitRepository = new GitRepositoryCreateOptions();
newGitRepository.Name = GitNewRepoName;

GitRepository parent = GitClient.GetRepositoryAsync(TeamProjectName, ParentRepo).Result;

newGitRepository.ParentRepository = new GitRepositoryRef();

newGitRepository.ParentRepository.Id = parent.Id;

newGitRepository.ParentRepository.ProjectReference = parent.ProjectReference;

newRepo = GitClient.CreateRepositoryAsync(newGitRepository, TeamProjectName, «refs/heads/master»).Result;

Просмотр свойств репозитория

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

  1. Методом GetRepositoriesAsync, который возвращает список объектов GitRepository. При этом достаточно передать только имя командного проекта в качестве параметра.
  2. Методом GetRepositoryAsync, который возвращает объект GitRepository необходимого репозитория. Здесь можно передать два параметра: имя командного проекта и имя репозитория.

Пример получения репозитория:

GitRepository GitRepo = GitClient.GetRepositoryAsync(TeamProjectName, RepoName).Result; gitThread.Status = Status;
Console.WriteLine(«—————————————————————«);

Console.WriteLine(» GIT REPO: « + GitRepo.Name);

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

Console.WriteLine(«Remote url : « + GitRepo.RemoteUrl);

Console.WriteLine(«Size : « + GitRepo.Size);

Объект GitRepository содержит следующие полезные свойства:

  • Id – идентификатор репозитория
  • Name – имя репозитория
  • RemoteUrl – ссылка на репозиторий
  • Size – размер репозитория
  • И другие.

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

Удаление репозитория выполняется с помощью метода DeleteRepositoryAsync, который принимает один параметр: идентификатор репозитория.

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

GitRepository gitRepo = GitClient.GetRepositoryAsync(TeamProjectName, RepoName).Result;
GitClient.DeleteRepositoryAsync(gitRepo.Id).Wait();

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

  1. Получить содержимое корзины командного проекта через функцию GetRecycleBinRepositoriesAsync.
  2. Восстановить репозиторий через функцию RestoreRepositoryFromRecycleBinAsync, которая принимает следующие параметры: объект GitRecycleBinRepositoryDetails с единственным свойством Deleted, имя командного проекта, идентификатор репозитория.

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

List<GitDeletedRepository> repos = GitClient.GetRecycleBinRepositoriesAsync(TeamProjectName).Result;
if (repos.Count == 0) return;

var repotorestore = repos.FirstOrDefault(x => x.Name == GitRepoName);

if (repotorestore != null)

{

GitClient.RestoreRepositoryFromRecycleBinAsync(new GitRecycleBinRepositoryDetails { Deleted = false }, TeamProjectName, repotorestore.Id).Wait();

Console.WriteLine(«Restored repo: « + GitRepoName);

}

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

Пример очистки корзины проекта:

List<GitDeletedRepository> repos = GitClient.GetRecycleBinRepositoriesAsync(TeamProjectName).Result;
foreach (var repo in repos)

GitClient.DeleteRepositoryFromRecycleBinAsync(TeamProjectName, repo.Id).Wait();

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

https://github.com/ashamrai/TFRestApi/tree/master/23.TFRestApiAppManageGitRepo

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

Azure DevOps Rest Api. 22. Завершение запросов на включение кода

Posted by Shamrai Alexander на 7 августа, 2019

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

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

Добавление ревьювера при создании запроса на включение кода

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

List<TeamMember> teamMembers = TeamClient.GetTeamMembersWithExtendedPropertiesAsync(TeamProjectName, TeamProjectName + » Team»).Result;
var users = from x in teamMembers where x.Identity.DisplayName == UserDisplayName select x.Identity.Id;

if (users.Count() == 1) return users.First();

Набор ревьюверов находится в свойстве Reviewers класса GitPullRequest в виде массива объектов IdentityRefWithVote. Пример создания запроса на включение кода с один ревьювером:

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

pr.SourceRefName = SourceRef;

pr.TargetRefName = TargetRef;

if (ReviewerId != «»)

{

IdentityRefWithVote[] identityRefWithVotes = { new IdentityRefWithVote { Id = ReviewerId } };

pr.Reviewers = identityRefWithVotes;

}

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

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

Создание потока комментариев выполнятся через класс GitPullRequestCommentThread, который содержит следующие основные свойства:

  • Id – идентификатор потока комментариев
  • Status – состояние потока комментариев
  • Comments – список комментариев. Первый комментарий – это тема потока комментариев, а каждый следующий является ответом по данной теме.

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

  • commentThread – экземпляр класса GitPullRequestCommentThread, который описывает новый поток комментариев.
  • project – наименование проекта.
  • repositoryId – наименование репозитория GIT.
  • pullRequestId – идентификатор запроса на включение кода.

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

GitPullRequest pr = GitClient.GetPullRequestAsync(TeamProjectName, RepoName, PrId).Result;
GitPullRequestCommentThread gitThread = new GitPullRequestCommentThread();

gitThread.Status = Status;

List<Microsoft.TeamFoundation.SourceControl.WebApi.Comment> comments = new List<Microsoft.TeamFoundation.SourceControl.WebApi.Comment>();

comments.Add(new Microsoft.TeamFoundation.SourceControl.WebApi.Comment{ Content = Title });

gitThread.Comments = comments;

var thread = GitClient.CreateThreadAsync(gitThread, TeamProjectName, RepoName, PrId).Result;

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

Для отклонения запроса на включение кода, необходимо обновить его состояние в Abandoned. Состояние запроса на включение кода описывается свойством Status класса GitPullRequest. Набор состояний можно увидеть в перечислении PullRequestStatus. При этом нужно создать новый объект класса GitPullRequest, в котором нужно указать обновляемые свойства. Далее вызывается метод UpdatePullRequestAsync, который принимает следующие параметры:

  • gitPullRequestToUpdate – обновления для существующего запроса на включение кода в виде объекта класса GitPullRequest.
  • project – наименование командного проекта.
  • repositoryId – наименование репозитория GIT.
  • pullRequestId – идентификатор существующего запроса на включение кода.

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

CreateNewCommentThread(TeamProjectName, RepoName, PrId, «Reject this PR»);
GitPullRequest prUdated = new GitPullRequest();

prUdated.Status = PullRequestStatus.Abandoned;

prUdated = GitClient.UpdatePullRequestAsync(prUdated, TeamProjectName, RepoName, PrId).Result;

Завершение запроса на включение кода и закрытые комментариев

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

  • updatedThread – обновления для существующего потока комментариев. При этом в свойство Comments можно добавить дополнительные комментарии.
  • project – наименование командного проекта.
  • repositoryId – наименование репозитория GIT.
  • pullRequestId – идентификатор существующего запроса на включение кода.
  • pullRequesThreadtId – идентификатор существующего потока комментариев.

Пример разрешения потока комментариев и добавление нового комментария в поток:

GitPullRequest pr = GitClient.GetPullRequestAsync(TeamProjectName, RepoName, PrId).Result;
List<GitPullRequestCommentThread> threads = GitClient.GetThreadsAsync(TeamProjectName, RepoName, PrId).Result;

foreach (var thread in threads)

{


if (thread.Status == CommentThreadStatus.Active)

{

GitPullRequestCommentThread updatedThread = new GitPullRequestCommentThread();

updatedThread.Status = CommentThreadStatus.Fixed;

Microsoft.TeamFoundation.SourceControl.WebApi.Comment[] comments = { new Microsoft.TeamFoundation.SourceControl.WebApi.Comment { Content = «Task is completed.» } };

updatedThread.Comments = comments;

updatedThread = GitClient.UpdateThreadAsync(updatedThread, TeamProjectName, RepoName, PrId, thread.Id).Result;

}

}

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

GitPullRequest pr = GitClient.GetPullRequestAsync(TeamProjectName, RepoName, PrId).Result;
GitPullRequest prUdated = new GitPullRequest();

prUdated.Status = PullRequestStatus.Completed;

prUdated.LastMergeSourceCommit = pr.LastMergeSourceCommit;

prUdated = GitClient.UpdatePullRequestAsync(prUdated, TeamProjectName, RepoName, PrId).Result;

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

https://github.com/ashamrai/TFRestApi/tree/master/22.TFRestApiAppCompletePullRequests

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 | Отмечено: , | 1 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 »

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