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

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

Archive for the ‘Microsoft’ Category

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

Posted by Shamrai Alexander на Февраль 14, 2019

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

Для работы с объектами тестирования используется клиент TestManagementHttpClient. В рамках планирования тестирования используются следующие основные объекты:

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

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

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

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

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

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

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

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

TestPlan testPlan = TestManagementClient.GetPlanByIdAsync(TeamProjectName, TestPlanId).Result;

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

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

Console.WriteLine(«Plan Dates : {0} — {1}», testPlan.StartDate.ToShortDateString(), testPlan.EndDate.ToShortDateString());

Набор тестов можно получить через метод GetTestSuiteByIdAsync, который использует наименование проекта, идентификатор плана тестирования и идентификатор набора тесто, а также признак необходимости получения информации о дочерних объектах. Корневой набор тестов можно получить из свойств плана тестирования testPlan.RootSuite.Id. При этом существует метод GetTestSuitesForPlanAsync, который позволяет получить наборы тестов без необходимости получения корневого набора, но в рамках примера для обеспечения единого подхода, он не используется. Пример получения набора тестов:

TestSuite suiteDetail = TestManagementClient.GetTestSuiteByIdAsync(TeamProjectName, PlanId, suiteId, 1).Result;

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

//Sute Types: StaticTestSuite, RequirementTestSuite, DynamicTestSuite

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

(suiteDetail.SuiteType == «StaticTestSuite») ? «» :

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

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

Информация о дочерних наборах тестов находится в suiteDetail.Suites, а информация о наличии тестовых сценариев в suiteDetail.TestCaseCount.

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

List<SuiteTestCase> testCases = TestManagementClient.GetTestCasesAsync(TeamProjectName, PlanId, suiteId).Result;

foreach(SuiteTestCase testCase in testCases)

{

int testId = 0;

if (!int.TryParse(testCase.Workitem.Id, out testId)) continue;


WorkItem wi = WitClient.GetWorkItemAsync(testId).Result;


Console.WriteLine(«Test: {0} — {1}», wi.Id, wi.Fields[«System.Title»].ToString());

foreach(var config in testCase.PointAssignments)


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

}

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

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

Реклама

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

Создание собственной задачи сборки и релиза TFS для регистрации новых рабочих элементов на основе Node.JS

Posted by Shamrai Alexander на Февраль 14, 2019

Введение

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

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

Исходный код решения

Полный пример исходного кода решения находится здесь: https://github.com/ashamrai/AzureDevOpsExtensions/tree/master/CustomBuildTask

Решение подготовлено с помощью Visual Studio Code.

Предварительные настройки

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

  1. Развернуть пакет TFS Cross Platform Command Line Interface через команду npm i -g tfx-cli.
  2. Создать каталог, в котором будет находится все решение (Каталог решения).
  3. Создать каталог, в котором будет находится исходный код для создания рабочего элемента (Каталог исходного кода).
  4. Перейти в каталог исходного кода и выполнить следующие действия:
    1. Выполнить команду npm init, которая создаст файл package.json.
    2. Добавить библиотеки azure-pipelines-task-lib через команду npm install azure-pipelines-task-lib –save.
    3. Добавить внешние библиотеки через команды npm install @types/node —save-dev и npm install @types/q —save-dev.
    4. Добавить решение для создания запросов к сервису через команду npm install xmlhttprequest –save.
    5. Добавить решение для кодирования личного ключа доступа к сервису npm install buffer —save.
    6. Создать файл настройки компиляции tsconfig.json через команду tsc –init. В данном файле устанавливаем целевую версию typescript «target»: «es6».

Создание расширения

Файл описания задачи

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

{

«id»: «c6ff84bf-0260-47d6-889d-6c2ecbbe2aa5»,

«name»: «CreateWorkItemCustomTask»,

«friendlyName»: «Create New Work Item Custom Task»,

«description»: «Create a new work item and link it to a new build or release»,

«helpMarkDown»: «»,

«category»: «Utility»,

«author»: «Aleksandr Shamrai»,

«version»: {

«Major»: 0,

«Minor»: 1,

«Patch»: 32

},

«instanceNameFormat»: «New Work Item $(workitemtype) $(titletemplate)»,

«inputs»: [

{

«name»: «workitemtype»,

«type»: «pickList»,

«label»: «Worm Item Type»,

«defaultValue»: «Task»,

«required»: true,

«helpMarkDown»: «Select the type for new work item»,

«options»: {

«Task»: «Task»,

«Bug»: «Bug»

}

},

{

«name»: «titletemplate»,

«type»: «string»,

«label»: «Title Template»,

«defaultValue»: «»,

«required»: false,

«helpMarkDown»: «A title template»

},

{

«name»: «assignedto»,

«type»: «string»,

«label»: «Assigne to»,

«defaultValue»: «»,

«required»: false,

«helpMarkDown»: «Set an owner of a work item»

},

{

«name»: «linktobuild»,

«type»: «radio»,

«label»: «Link New Work Item to Build»,

«defaultValue»: «No»,

«required»: true,

«helpMarkDown»: «Link a new work item to build»,

«options»: {

«No»: «No»,

«LinkAsArtifact»: «Link as artifact (only for builds)»,

«LinkAsWebUrl»: «Link as Web Url»

}

}

],

«execution»: {

«Node»: {

«target»: «index.js»

}

}

}

Полное описание формата файла можно найти здесь: https://github.com/Microsoft/azure-pipelines-task-lib/blob/master/tasks.schema.json

В нашем случае основные пункты:

  1. Id – уникальный идентификатор
  2. Name – наименование задачи без пробелов.
  3. friendlyName – описательное наименование задачи
  4. category – категория, в которой мы найдем нашу задачу
  5. author – автор задачи
  6. instanceNameFormat – как данный шаг будет отражаться в списке задач сборки или релиза.
  7. Inputs – список входных параметров для задачи. Каждый параметр имеет следующие основные элементы:
    1. Name – наименование параметра
    2. Type – тип параметра (boolean, filePath, multiLine, pickList, radio, secureFile, string).
    3. Label – название параметра на форме задачи
  8. Execution – описание того, что нужно выполнять. В данном случае будет выполняться файл index.js, который создается ниже.

Исполняемый код задачи

Создадим файл index.ts, который будет содержать основной код. В данном файле можно выделить следующие моменты:

  • Как основная запускаемая функция используется функция run, которая детализируется под конкретные задачи.
  • Для получения входных параметров задачи, которые описаны в «task.json», используется метод getInput с передачей наименования параметра.
  • Для получения переменных окружения используется метод getVariable. Все переменные окружения, которые присутствуют при выполнении задачи можно посмотреть здесь: Default and custom release variables and debugging. При этом в рамках задачи используются следующие важные переменные:
    • System.AccessToken – содержит персональный ключ доступа к сервису. При этом доступ к нему обеспечивается отдельно в самом определении сборки или релиза в параметре Allow scripts to access the OAuth token. Если данный параметр не будет выставлен, то авторизация будет невозможна.
    • System.TeamFoundationCollectionUri – адрес сервера TFS.
    • System.TeamProject – командный проект, в котором выполняется сборки или развертывается релиз.
    • И т.д.

Пример получение значения параметров и переменных окружения:

const inputWIType: string = tl.getInput(‘workitemtype’, true);

const inputTitle: string = tl.getInput(‘titletemplate’, false);

const inputAssignedTo: string = tl.getInput(‘assignedto’, false);

const inputLinkToBuild: string = tl.getInput(‘linktobuild’, true);

const strAC = tl.getVariable(‘System.AccessToken’);

if (strAC == null)

{

tl.setResult(tl.TaskResult.Failed, ‘Access to OAuth token is not allowed’);

return;

}

const strServiceUrl = tl.getVariable(‘System.TeamFoundationCollectionUri’);

const strTeamProjectName = tl.getVariable(‘System.TeamProject’);

  • Создание рабочего элемента выполняется на основе запроса Rest Api Work Items – Create. Код для выполнения запроса следующий:
let devRequest = new XMLHttpRequest();

let encodedData = new Buffer(«:» + strAC).toString(‘base64’);

devRequest.open(«POST», strServiceUrl + strTeamProjectName + urlCreateTask)

devRequest.setRequestHeader(‘Authorization’, ‘Basic ‘ + encodedData);

devRequest.setRequestHeader(‘Accept’, ‘application/json’);

devRequest.setRequestHeader(‘Content-Type’, ‘application/json-patch+json’);

devRequest.send(JSON.stringify(patchFields));

devRequest.onreadystatechange = function () {

if (devRequest.readyState === 4) {

let newWorkItem = JSON.parse(devRequest.responseText);

if («id» in newWorkItem)

console.log(«The work item has been created», newWorkItem.id);

else

console.log(‘Error’,devRequest.responseText);

}

}

В данном примере создается запрос на основе авторизации Personal Access Token с использования адреса для создания нового рабочего элемента:

POST http://{server_name}:{port}/{collection name}/{project}/_apis/wit/workitems/${type}?api-version=2.0

В тело запроса в формате JSON добавляется список создаваемых полей и связей с другими объектами:

  • Для указания содержимого в поле применяется формат:
[

{

«op»: «add»,

«path»: «/fields/System.Title»,

«from»: null,

«value»: «Sample task»

}

]

  • Для создания новой гиперссылки используется формат:
[

{

«op»: «add»,

«path»: «/relations/-«,

«value»: {

«rel»: «Hyperlink»,

«url»: «URL»

}

}

]

  • Для создания ссылки на сборку используется следующий формат:
[

{

«op»: «add»,

«path»: «/relations/-«,

«value»: {

«rel»: «ArtifactLink»,

«url»: «artifact URI»,

«attributes»: {«name»:»Build»}

}

}

]

Компиляция решения

Для формирования файла index.js необходимо выполнить в каталоге исходного кода команду tsc.

Файл манифест расширения

Манифест расширения описывает расширение для TFS и создается через файл vss-extension.json. Файл содержит следующее:

{

«manifestVersion»: 1,

«id»: «new-work-item-custom-task»,

«name»: «Create New Work Item Custom Task»,

«version»: «0.1.32»,

«publisher»: «AShamrai»,

«targets»: [

{

«id»: «Microsoft.TeamFoundation.Server»

}

],

«description»: «Create a new work item and link it a build or release»,

«content»: {

«details»: {

«path»: «details.md»

}

},

«categories»: [

«Build and release»

],

«icons»: {

«default»: «images/newworkitem.png»

},

«files»: [

{

«path»: «NewWICustomTask»

}

],

«contributions»: [

{

«id»: «mew-work-tem-custom-build-release-task»,

«type»: «ms.vss-distributed-task.task»,

«targets»: [

«ms.vss-distributed-task.tasks»

],

«properties»: {

«name»: «NewWICustomTask»

}

}

]

}

Описание важных пунктов:

  • Id – уникальный идентификатор задачи
  • Targets:id – целевая платформа
  • Contributions:Id – уникальный идентификатор задачи
  • Сontributions :type – тип задачи
  • Contributions:targets – целевые задачи, в которых будет участвовать расширение.
  • Contributions:properties:name – наименование задачи, которое совпадает с каталогом, котором находятся скомпилированные исходники.
  • Files: path – путь к каталогу с содержимым задачи.

Полная спецификация содержимого находится по этому адресу: Extension manifest reference.

Сборка решения

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

tfx extension create —manifest-globs vss-extension.json

Установка

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

  • Перейти на страницу управления расширениями Team Foundation Server. Она обычно находится по адресу http://server_name:8080/tfs/_gallery/manage. На этой странице необходимо нажать кнопку Upload new extension, найти сформированный после сборки решения файл расширения и выполнить его установку. Эта операция установит решение в сервер.

Рисунок 1. Страница управления расширениями

  • После того как появилось решение в списке, мы нажимаем на его ссылку и выполняем установку на необходимую коллекцию проектов.

Рисунок 2. Развертывание решения в необходимой коллекции

  • После развертывания решения мы можем приступить к созданию необходимого определения сборки или релиза.

Рисунок 3. Новая задача в списке утилит

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

Рисунок 4. Доступ к персональному ключу доступа

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

Рисунок 5. Лог работы задачи

Рисунок 6. Новый рабочий элемент, который ссылается на сборку

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

Azure DevOps Services Rest Api. 11. Перемещение рабочих элементов в другой командный проект

Posted by Shamrai Alexander на Январь 29, 2019

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

  1. Рабочий элемент не там изначально зарегистрировали.
  2. Для команды создали новый командный проект и необходимо забрать ее требования и ошибки.
  3. И т.д.

Сама операция переноса не очень сложная (Move a work item to another project), но если необходимо перенести тысячи рабочих элементов, то ручная работа займет много времени.

Для переноса рабочего элемента необходимо обновить всего три поля:

  1. Командный проект
  2. Путь итерации
  3. Путь области

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

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

static
int MoveWorkItem(int WIId, string NewTeamProject)

{

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

fields.Add(«System.TeamProject», NewTeamProject);

fields.Add(«System.AreaPath», NewTeamProject);

fields.Add(«System.IterationPath», NewTeamProject);


var editedWI = UpdateWorkItem(WIId, fields);

Console.WriteLine(«Work item has been moved: « + editedWI.Id.Value);


return editedWI.Id.Value;

}

static WorkItem UpdateWorkItem(int WIId, Dictionary<string, object> Fields)

{

JsonPatchDocument patchDocument = new JsonPatchDocument();


foreach (var key in Fields.Keys)

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/fields/» + key,

Value = Fields[key]

});


return WitClient.UpdateWorkItemAsync(patchDocument, WIId).Result;

}

Если же нам необходимо перенести большое количество рабочих элементов, то предварительно необходимо создать запрос по рабочим элементам, который выберет их все (Create and save managed queries with the query editor). Далее запрос можно выполнить и получить все идентификаторы и выполнить обновление каждого рабочего элемента:

List<int> wis = RunStoredQuery(teamProjectOld, queryPath);

foreach (int wiId in wis) MoveWorkItem(wiId, teamProjectNew);

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

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

https://github.com/ashamrai/TFRestApi/tree/master/11.TFRestApiAppMoveWorkItems

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

Azure DevOps Services Rest Api. 10. Управление настройками команд

Posted by Shamrai Alexander на Декабрь 29, 2018

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

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

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

TeamContext teamContext = new TeamContext(TeamProjectName);

Итерации

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

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

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

WorkItemClassificationNode projectIt = WitClient.GetClassificationNodeAsync(TeamProjectName, TreeStructureGroup.Iterations, iterationName).Result; // get iteration from project

TeamSettingsIteration teamIt = WorkClient.PostTeamIterationAsync(new TeamSettingsIteration { Id = projectIt.Identifier }, teamContext).Result; //add iteration to a team by guid

Console.WriteLine(«Added iteration « + teamIt.Name);

Удаление итерации из настроек команды выполняется подобным методом через метод DeleteTeamIterationAsync, при этом передаются контекст команды и идентификатор итерации:

WorkItemClassificationNode projectIt = WitClient.GetClassificationNodeAsync(TeamProjectName, TreeStructureGroup.Iterations, iterationNameToRemove).Result;

WorkClient.DeleteTeamIterationAsync(teamContext, projectIt.Identifier).SyncResult(); //delete iteration from team settings by guid

Console.WriteLine(«Removed iteration « + projectIt.Name);

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

TeamSettingsIteration currentiteration = (WorkClient.GetTeamIterationsAsync(teamContext, «Current»).Result).FirstOrDefault();

В результаты мы получаем объект TeamSettingsIteration, который включает:

  • Id – GUID итерации
  • Name – наименование итерации
  • Path – путь итерации
  • Attributes – дополнительные атрибуты итерации:
    • StartDate – дата начала итерации
    • FinishDate – дата окончания итерации
    • TimeFrame – фрейм итерации Past (прошедшая), Current (текущая), Future (будущая)

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

List<TeamSettingsIteration> teamIterations = WorkClient.GetTeamIterationsAsync(teamContext).Result; //get all iterations

Console.WriteLine(«Team Iterations: «);

foreach (TeamSettingsIteration teamIteration in teamIterations)

Console.WriteLine(«{0} : {1} : {2}-{3}», teamIteration.Attributes.TimeFrame, teamIteration.Name, teamIteration.Attributes.StartDate, teamIteration.Attributes.FinishDate);

Области

Области имеет смысл автоматически обновлять, если основное управление ответственностями команд выполняется во внешней системе, например, через CMDB и их необходимо переносить в соответствующие команды Azure DevOps.

Как и с итерациями область должна быть сначала добавлена в настройки командного проекта (Управление областями и итерациями в командном проекте). Но оперирование областями в настройках команды отличается от управления итерациями.

Посмотреть список областей команды можно через метод GetTeamFieldValuesAsync, который вернет объект TeamFieldValues с атрибутами:

  • DefaultValue – строковое значение области по умолчанию.
  • Values – список областей TeamFieldValue, которые будет контролировать команда. TeamFieldValue включает наименование области Value и признак включения в контроль дочерних областей IncludeChildren.

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

TeamFieldValues teamAreas = WorkClient.GetTeamFieldValuesAsync(teamContext).Result; //Get All Areas

Console.WriteLine(«Default Area: « + teamAreas.DefaultValue);

Console.WriteLine(«Team Areas : «);

foreach (TeamFieldValue teamField in teamAreas.Values)

Console.WriteLine(«\t» + teamField.Value + ((teamField.IncludeChildren)? » (include sub-areas)» : «»));

Обновление набора областей команды выполняется через один метод UpdateTeamFieldValuesAsync с параметром TeamFieldValuesPatch. TeamFieldValuesPatch включает те же атрибуты, что и TeamFieldValues. Т.е. для обновления настройки можно взять текущие значения и добавить или удалить необходимые:

string[] areas = { @»Application\WinClient», @»Application\WebClient» };

TeamFieldValues currentTeamAreas = WorkClient.GetTeamFieldValuesAsync(teamContext).Result; // get current areas

TeamFieldValuesPatch teamAreasPatch = new TeamFieldValuesPatch();

List<TeamFieldValue> newTeamAreas = new List<TeamFieldValue>(currentTeamAreas.Values); // just copy old areas. Here we may remove unneeded areas

foreach (string area in areas)

newTeamAreas.Add(new TeamFieldValue { Value = TeamProjectName + «\\» + area, IncludeChildren = false }); // add new areas

teamAreasPatch.DefaultValue = currentTeamAreas.DefaultValue;

teamAreasPatch.Values = newTeamAreas;

TeamFieldValues updatedTeamAreas = WorkClient.UpdateTeamFieldValuesAsync(teamAreasPatch, teamContext).Result;

Общие настройки

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

Получить текущие настройки можно через метод GetTeamSettingsAsync, который возвращает TeamSetting с атрибутами:

  • DefaultIteration – итерация, которая автоматически подставляется при создании нового рабочего элемента в контексте команды.
  • BacklogIteration – в рамках какой итерации отображаются рабочие элементы журнала требований.
  • DefaultIterationMacro – подстановка для определения текущей итерации: https://docs.microsoft.com/ru-ru/azure/devops/boards/queries/query-by-date-or-current-iteration?view=vsts#query-for-items-based-on-belonging-to-a-teams-current-iteration
  • BacklogVisibilities – список всех журналов, которые используются в проекте, и их отображение в команде.
  • WorkingDays – список дней, которые учитываются как рабочие для команды.

Пример выполнения:

TeamContext teamContext = new TeamContext(TeamProjectName, TeamName);

TeamSetting teamSetting = WorkClient.GetTeamSettingsAsync(teamContext).Result;

Console.WriteLine(«Settings for the team « + TeamName);

Console.WriteLine(«Backlog Iteration : « + teamSetting.BacklogIteration.Name);

Console.WriteLine(«Default Iteration : « + teamSetting.DefaultIteration.Name);

Console.WriteLine(«Macro of Iteration : « + teamSetting.DefaultIterationMacro);

Console.WriteLine(«Categories of backlog:»);

foreach(string bkey in teamSetting.BacklogVisibilities.Keys)


if (teamSetting.BacklogVisibilities[bkey]) Console.WriteLine(«\t» + bkey);

Console.WriteLine(«Working days :»);

foreach (var wday in teamSetting.WorkingDays) Console.WriteLine(«\t» + wday.ToString());

switch (teamSetting.BugsBehavior)

{

case BugsBehavior.AsRequirements:

Console.WriteLine(«Bugs Behavior: Bugs in a requirements backlog.»);

break;

case BugsBehavior.AsTasks:

Console.WriteLine(«Bugs Behavior: Bugs in a sprint backlog as tasks.»);

break;

case BugsBehavior.Off:

Console.WriteLine(«Bugs Behavior: Find bugs through queries.»);

break;

}

Обновление настроек выполняется через метод UpdateTeamSettingsAsync с параметром TeamSettingsPatch, который имеет те же атрибуты, как и TeamSetting. При этом будут обновляться только те настройки, атрибуты которых были проинициализированы. Обновление видимых команде журналов можно выполнить следующим образом:

TeamSetting teamSetting = WorkClient.GetTeamSettingsAsync(teamContext).Result;

TeamSettingsPatch teamSettingsPatch = new TeamSettingsPatch();

teamSettingsPatch.BacklogVisibilities = teamSetting.BacklogVisibilities;

if (teamSettingsPatch.BacklogVisibilities.ContainsKey(«Microsoft.EpicCategory») && teamSettingsPatch.BacklogVisibilities[«Microsoft.EpicCategory»])

teamSettingsPatch.BacklogVisibilities[«Microsoft.EpicCategory»] = false;

if (teamSettingsPatch.BacklogVisibilities.ContainsKey(«Microsoft.FeatureCategory») && teamSettingsPatch.BacklogVisibilities[«Microsoft.FeatureCategory»])

teamSettingsPatch.BacklogVisibilities[«Microsoft.FeatureCategory»] = false;

teamSetting = WorkClient.UpdateTeamSettingsAsync(teamSettingsPatch, teamContext).Result;

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

https://github.com/ashamrai/TFRestApi/tree/master/10.TFRestApiAppManageTeamSettings

English version

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

Azure DevOps Services Rest Api. 9. Управление командами проекта

Posted by Shamrai Alexander на Декабрь 27, 2018

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

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

  • Id – идентификатор.
  • Name – наименование команды.
  • Description – описание команды.
  • ProjectName – наименование проекта, в которую входит команда.
  • ProjectId – идентификатор проекта, в которую входит команда.

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

List<WebApiTeam> teams = TeamClient.GetTeamsAsync(TeamProjectName).Result;

Console.WriteLine(«Project Teams:»);

foreach (WebApiTeam team in teams) Console.WriteLine(team.Name);

Если необходимо получить информацию об участниках команды, то можно выполнить метод GetTeamMembersWithExtendedPropertiesAsync, в который передаются все те же имя проекта и имя команды. Участник команды описывается классом TeamMember, который содержит два свойства:

  • IsTeamAdmin – является ли участник команды администратором.
  • Identity – информация об учетной записи пользователя.

Пример изучения состава команды:

List<TeamMember> teamMembers = TeamClient.GetTeamMembersWithExtendedPropertiesAsync(TeamProjectName, TeamName).Result;

string teamAdminName = (from tm in teamMembers where tm.IsTeamAdmin == true
select tm.Identity.DisplayName).FirstOrDefault();

if (teamAdminName != null) Console.WriteLine(«Team Administrator:» + teamAdminName);

Console.WriteLine(«Team members:»);

foreach (TeamMember teamMember in teamMembers)

if (!teamMember.IsTeamAdmin) Console.WriteLine(teamMember.Identity.DisplayName);

 

Для создания и обновления команды используются методы CreateTeamAsync и UpdateTeam соответственно. Основные параметры это:

  • team – объект WebApiTeam, в котором устанавливаются наименование и описание команды.
  • projectId – наименование проекта команды
  • teamId – идентификатор существующей команды, который используется только при обновлении наименования или описания.

Пример обновления команды:

WebApiTeam team = TeamClient.GetTeamAsync(TeamProjectName, TeamName).Result;

WebApiTeam updatedTeam = new WebApiTeam {

Name = team.Name + » updated»,

Description = team.Description.Replace(«Created», «Updated»)

};

updatedTeam = TeamClient.UpdateTeamAsync(updatedTeam, team.ProjectName, team.Name).Result;

Console.WriteLine(«The team ‘{0}’ has been updated in the team project ‘{1}'», updatedTeam.Name, updatedTeam.ProjectName);

 

Для удаления команды используется метод DeleteTeamAsync с наименованием проекта и удаляемой команды:

TeamClient.DeleteTeamAsync(TeamProjectName, TeamName).SyncResult();

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

https://github.com/ashamrai/TFRestApi/tree/master/09.TFRestApiAppManageTeams

English version

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

Azure DevOps Services Rest Api. 8. Управление областями и итерациями в командном проекте

Posted by Shamrai Alexander на Декабрь 26, 2018

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

Управление областями и итерациями выполняется через WorkItemTrackingHttpClient одинаковыми методами, отличаются только некоторые моменты. Общим классом, который описывает области и итерации, является класс WorkItemClassificationNode. Он включает следующие основные свойства:

  • Id – идентификатор области или итерации.
  • Name – наименование области или итерации.
  • StructureType – тип объекта: «TreeNodeStructureType.Area» и «TreeNodeStructureType.Iteration».
  • Attributes – содержит дату начала и окончания итерации, которые доступны через ключи startDate и finishDate.

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

  • postedNode – объект WorkItemClassificationNode, который содержит наименование и атрибуты.
  • project – имя командного проекта, в котором будет создана область или итерация.
  • structureGroup – тип объекта: TreeStructureGroup.Areas или TreeStructureGroup.Iterations
  • path – путь к родительской области или итерации, если она необходима.

Пример для создания области. Для создания области важно только наименование и родительская область. Если родительская область не указана, то новая область будет размещена в корне командного проекта

WorkItemClassificationNode newArea = new WorkItemClassificationNode();

newArea.Name = AreaName;

WorkItemClassificationNode result = WitClient.CreateOrUpdateClassificationNodeAsync(newArea, TeamProjectName, TreeStructureGroup.Areas, ParentAreaPath).Result;

 

Пример для создания итерации. Итерация создается также, как и область, но кроме этого можно использовать дополнительные необязательные атрибуты startDate и finishDate.

WorkItemClassificationNode newIteration = new WorkItemClassificationNode();

newIteration.Name = IterationName;

newIteration.Attributes = new Dictionary<string, object>();

newIteration.Attributes.Add(«startDate», StartDate);

newIteration.Attributes.Add(«finishDate», FinishDate);

WorkItemClassificationNode result = WitClient.CreateOrUpdateClassificationNodeAsync(newIteration, TeamProjectName, TreeStructureGroup.Iterations, ParentIterationPath).Result;

 

Обновление области и итерации выполняется через UpdateClassificationNode с теми же параметрами, как и в CreateOrUpdateClassificationNodeAsync. При этом нужно обращать внимание на параметр path. Он будет обязательным для области или итерации, если она имеет родителя. Если для такой области или итерации не указать path, то она будет перемещена в корень командного проекта. Т.е. если нам нужно переименовать или изменить даты, то необходимо снова указать необходимый путь, в котором будет находится область или итерация.

Удаление области или итерации выполняется через DeleteClassificationNodeAsync с параметрами:

  • project – имя командного проекта, в котором находится область или итерация.
  • structureGroup – тип объекта: TreeStructureGroup.Areas или TreeStructureGroup.Iterations
  • path – путь удаляемой области или итерации.
  • reclassifyId – идентификатор новой области или итерации, в которую будут перемещены рабочие элементы, которые находятся в удаляемой области или итерации.

Пример удаления.

WorkItemClassificationNode newNode = WitClient.GetClassificationNodeAsync(

TeamProjectName,

treeStructureGroup,

NewNodePath, 4).Result;

WitClient.DeleteClassificationNodeAsync(TeamProjectName, treeStructureGroup, NodePath, newNode.Id).SyncResult();

 

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

https://github.com/ashamrai/TFRestApi/tree/master/08.TFRestApiAppAreasAndIterations

English version

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

Azure DevOps Services Rest Api. 7. Добавление и редактирование связей между рабочими элементами

Posted by Shamrai Alexander на Декабрь 21, 2018

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

Добавление и обновление ссылок между рабочими элементами выполняется схожим подходом с редактированием полей рабочего элемента и применяются те же методы UpdateWorkItemAsync и CreateWorkItemAsync. Отличается только информация о передаваемых объектах JsonPatchOperation. Для добавления объект формируется в следующем виде:

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/relations/-«,

Value = new {

rel = RelName,

url = RelUrl,

attributes = new

{

comment = Comment,

isLocked = IsLocked // you must be an administrator to lock a link

}

}

});

Указываются следующие атрибуты:

  • Operation – операция со ссылкой, в основном Add и Remove для добавления и удаления.
  • Path – может иметь следующие значения:
    • «/relations/-» – добавляется новая связь между рабочими элементами
    • «/relations/[индекс ссылки]» – для редактирования свойств или удаление ссылки, где [индекс ссылки] – порядковый номер ссылки в списке WorkItem.Relations.
  • Value – детализация информации о ссылке, которая содержит:
    • rel – наименование типа ссылки, перечень можно посмотреть здесь: Link type reference.
    • url – прямой url адрес к необходимому рабочему элементу.
    • attributes – дополнительные необязательные атрибуты ссылки:
      • comment – комментарий для ссылки.
      • isLocked – блокировка ссылки. Если ссылка заблокирована, то ее можно удалить только через API.

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

JsonPatchDocument patchDocument = new JsonPatchDocument();

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/relations/-«,

Value = new {

rel = «System.LinkTypes.Related»,

url = RelUrl,

attributes = new

{

comment = «Comment for the link»

}

}

});

return WitClient.UpdateWorkItemAsync(patchDocument, WiId).Result;

Обновление выполняется по следующему примеру:

JsonPatchDocument patchDocument = new JsonPatchDocument();

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/relations/0»,

Value = new {

rel = «System.LinkTypes.Related»,

url = RelUrl,

attributes = new

{

comment = «New comment for the link»

}

}

});

return WitClient.UpdateWorkItemAsync(patchDocument, WiId).Result;

Удаление выполняется по следующему шаблону:

JsonPatchDocument patchDocument = new JsonPatchDocument();

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Remove,

Path = «/relations/0»

});

return WitClient.UpdateWorkItemAsync(patchDocument, WiId).Result;

Если необходимо за один раз удалить несколько ссылок, то их индексы нужно добавлять в JsonPatchDocument в обратном порядке. Т.к. механизм удаления выполняет эту операцию последовательно. Т.е. если у вас есть рабочий элемент с двумя связями, а вы добавляете для удаления сначала индекс 1, потом 2, то вы получите следующую ошибку:

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

https://github.com/ashamrai/TFRestApi/tree/master/07.TFRestApiAppWorkItemLinks

English version

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

Azure DevOps Services Rest Api. 6. Загрузка и получение вложений для рабочих элементов

Posted by Shamrai Alexander на Декабрь 14, 2018

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

При автоматизации некоторых процессов полезно использовать вложения рабочих элементов, которые могут включать в себя журнал работы приложения, скриншот и т.д. Для управления вложениями используются методы CreateAttachmentAsync и GetAttachmentContentAsync для загрузки и получения.

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

  1. Создание потока для чтения содержимого файла.
  2. Создание вложения на сервисе через метод CreateAttachmentAsync, который включает параметры поток и наименование вложения. Можно использовать создание вложения без файлового потока, а только с наименованием файла. Но этот подход нужно использовать, если файл для вложения находится в локальном каталоге. Иначе имя файла во вложении будет содержать путь к файлу, а не просто его наименование.
  3. Обновление рабочего элемента. Формируется JsonPatchDocument, который добавляет новую связь для рабочего элемента с типом AttachedFile. Также передается URL вложения, который будет получен на шаге 2.

AttachmentReference att;

using (FileStream attStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read))

att = WitClient.CreateAttachmentAsync(attStream, filePathSplit[filePathSplit.Length — 1]).Result; // upload the file

JsonPatchDocument patchDocument = new JsonPatchDocument();

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/relations/-«,

Value = new

{

rel = «AttachedFile»,

url = att.Url,

attributes = new { comment = «Comments for the file « + filePathSplit[filePathSplit.Length — 1] }

}

});

WitClient.UpdateWorkItemAsync(patchDocument, WIId).Result;

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

  1. Получить рабочий элемент и его ссылки. Что получить ссылки, в метод GetWorkItemAsync передается параметр expand: WorkItemExpand.Relations.
  2. Ссылки, которые имеют вложения, имеют тип AttachedFile в свойстве Rel класса WorkItemRelation. Если нам нужен конкретный файл, то его наименование можно найти через атрибут name.
  3. Для того, чтобы получить вложение, нам необходимо получить его идентификатор. Идентификатор можно выделить из URL вложения.
  4. Далее выполняется получение потока через метод GetAttachmentContentAsync и сохранение его в необходимом файле.

WorkItem workItem = WitClient.GetWorkItemAsync(WIId, expand: WorkItemExpand.Relations).Result;

foreach(var rf in workItem.Relations)

{


if (rf.Rel == «AttachedFile»)

{


string[] urlSplit = rf.Url.ToString().Split(new
char[] { ‘/’ }, StringSplitOptions.RemoveEmptyEntries);


using (Stream attStream = WitClient.GetAttachmentContentAsync(new Guid(urlSplit[urlSplit.Length — 1])).Result) // get an attachment stream


using (FileStream destFile = new FileStream(DestFolder + «\\» + rf.Attributes[«name»], FileMode.Create, FileAccess.Write)) // create new file

attStream.CopyTo(destFile); //copy content to the file

}

}

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

https://github.com/ashamrai/TFRestApi/tree/master/06.TFRestApiAppWorkItemAttachments

English version

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

Azure DevOps Services Rest Api. 5. Создание рабочих элементов на основе шаблонов

Posted by Shamrai Alexander на Ноябрь 29, 2018

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

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

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

Эти же шаблоны можно применять при создании рабочих элементов на основе Rest Api. В этом случае будет использоваться метод CreateWorkItemAsync, который рассматривался здесь. Но перед этим необходимо получить определение хранимого шаблона рабочего элементам, чтоб понимать какие поля необходимо заполнить по умолчанию.

Для получения информации о шаблонах рабочих элементов необходимо выполнить следующее:

  • Получить информацию о проекте через клиента ProjectHttpClient.
  • Создать контекст команды TeamContext, в которой хранится шаблон рабочего элемента. В данном примере используется контекст команды по умолчанию.
  • Через контекст команды получить список всех шаблонов через метод GetTemplatesAsync, из которого уже можно получить идентификатор необходимого шаблона. Метод принимает только один параметр – контекст команды. Результат метода – список шаблонов WorkItemTemplateReference без набора полей.
  • Получить полную информацию о шаблоне и его полях через метод GetTemplateAsync. Данный метод требует использование контекста команды и идентификатора необходимого шаблона.

Пример поиска шаблона рабочего элемента:

//получить проект

var project = ProjectClient.GetProject(projectName).Result;

//создать контекст команды

TeamContext tmcntx = new TeamContext(project.Id, project.DefaultTeam.Id);

//получить все шаблоны команды

var templates = WitClient.GetTemplatesAsync(tmcntx).Result;

//получить идентификатор шаблона через его имя

var id = (from tm in templates where tm.Name == templateName select tm.Id).FirstOrDefault();

if (id != null) return WitClient.GetTemplateAsync(tmcntx, id).Result;

Полученный шаблон WorkItemTemplate включает следующие атрибуты:

  1. Id – идентификатор шаблона.
  2. Name – наименование шаблона.
  3. WorkItemTypeName – наименование типа рабочего элемента, к которому применяется шаблон.
  4. Fields – словарь с набором полей по умолчанию и их значениями.

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

Dictionary<string, object> fields = new Dictionary<string, object>();//поля пользователя

fields.Add(«System.Title», «New work item»);

JsonPatchDocument patchDocument = new JsonPatchDocument();

foreach (var templateKey in template.Fields.Keys) //применяем все поля из шаблона

if (!fields.ContainsKey(templateKey)) //исключаем поля, которые определяет пользователь

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/fields/» + templateKey,

Value = template.Fields[templateKey]

});

//добавляем поля пользователя

foreach (var key in fields.Keys)

patchDocument.Add(new JsonPatchOperation()

{

Operation = Operation.Add,

Path = «/fields/» + key,

Value = fields[key]

});

return WitClient.CreateWorkItemAsync(patchDocument, projectName, template.WorkItemTypeName).Result;

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

https://github.com/ashamrai/TFRestApi/tree/master/05.TFRestApiAppCreateWorkItemFromTemplate

English version

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

Azure DevOps Services Rest Api. 4. Выполнение запросов по рабочим элементам

Posted by Shamrai Alexander на Октябрь 17, 2018

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

Основным клиентом для работы с запросами по рабочим элементам является WorkItemTrackingHttpClient. Используются следующие методы:

  • GetQueryAsync – информация о запросе по рабочим элементам.
  • QueryByWiqlAsync – выполнение запроса WIQL.
  • CreateQueryAsync – создание нового запроса по рабочим элементам.
  • UpdateQueryAsync – обновление существующего запроса.
  • DeleteQueryAsync – удаление существующего запроса.

Получить детальную информацию об известном запросе по рабочим элементам можно через метод GetQueryAsync со следующими основными параметрами:

  1. project – имя командного проекта, в котором находится запрос.
  2. query – путь к запросу, детализацию которого нужно получить.
  3. expand – уровень детализации информации о запросе.
  4. depth – количество уровней дочерних запросов и каталогов, который будет загружен в ответ метода

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

QueryHierarchyItem detiledQuery = WitClient.GetQueryAsync(project, query.Path, QueryExpand.All, 1).Result;

Результатом является экземпляр класса detiledQuery со следующими полезными атрибутами:

  1. Name – наименование запроса
  2. Path – полный путь к запросу.
  3. IsFolder – признак, что это каталог.
  4. Wiql – Wiql текст запроса
  5. HasChildren – признак, что существуют дочерние экземпляры.
  6. Children – список дочерних экземпляров.

Для получения информации о корневых запросах (обычно это «Мои запросы» и «Общие запросы») можно использовать метод GetQueriesAsync, который имеет почти такие же параметры, как и в GetQueryAsync. Отличается только отсутствием параметра query, т.к. выполняется получение информации из корня дерева запросов.

List<QueryHierarchyItem>
rootQueries = WitClient.GetQueriesAsync(project, QueryExpand.All).Result;

Выполнить запрос можно через метод QueryByWiqlAsync со следующими параметрами:

  1. wiql – текст запроса на основе синтаксиса WIQL.
  2. project – наименование командного проекта, если используется макрос @project в теле запроса.

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

WorkItemQueryResult result = WitClient.QueryByWiqlAsync(wiql, teamProject).Result;

Результат WorkItemQueryResult может быть обработан двумя методами:

1. Если запрос является простым списком, то получить список идентификаторов рабочих элементов можно из атрибута WorkItems. Этот атрибут включает список из WorkItemReference, который включает Id рабочего элемента и его URL.

foreach (var wiRef in result.WorkItems)

{

var wi = GetWorkItem(wiRef.Id);

Console.WriteLine(String.Format(«{0} — {1}», wi.Id, wi.Fields[«System.Title»].ToString()));

}

2. Если запрос включает ссылки, то результат можно получить из атрибута WorkItemRelations, который представляет собой список экземпляров WorkItemLink. WorkItemLink включает атрибуты:

  1. Rel – системное наименование ссылки. Наименование будет пустым, если это элемент верхнего уровня.
  2. Source – экземпляр WorkItemReference, который определяет рабочий элемент источник ссылки. Будет равным null, если это элемент верхнего уровня.
  3. Target – экземпляр WorkItemReference, который определяет рабочий элемент, на который ссылаются.

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

foreach (var wiRel in result.WorkItemRelations)

{

if (wiRel.Source == null)

{

var wi = GetWorkItem(wiRel.Target.Id);

Console.WriteLine(String.Format(«Top Level: {0} — {1}», wi.Id, wi.Fields[«System.Title»].ToString()));

}

else

{

var wiParent = GetWorkItem(wiRel.Source.Id);

var wiChild = GetWorkItem(wiRel.Target.Id);

Console.WriteLine(String.Format(«{0} —> {1} — {2}», wiParent.Id, wiChild.Id, wiChild.Fields[«System.Title»].ToString()));

}

}

Запрос по рабочим элементам можно сконструировать с помощью синтаксиса WIQL: Syntax for the Work Item Query Language (WIQL). Однако можно пойти простым путем:

  1. В Visual Studio создать запрос и сохранить его на локальный диск:

  1. Сам текст WIQL можно просмотреть в теле запроса с помощью блокнота:

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

  1. Получить WIQL текст запроса через метод GetQueryAsync
  2. Выполнить запрос через метод QueryByWiqlAsync

Пример выполнения сохраненного запроса:

QueryHierarchyItem query = WitClient.GetQueryAsync(teamProject, queryPath, QueryExpand.Wiql).Result;

WorkItemQueryResult result = WitClient.QueryByWiqlAsync(query.Wiql, teamProject).Result;

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

https://github.com/ashamrai/TFRestApi/blob/master/04.TFRestApiAppWorkItemQueries

English version

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

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