… Или как автоматизировать некоторые действия в TFS 2010.
Сразу скажу, что для TFS 2012 автор обещает быстро выпустить обновленную версию, однако, на мой взгляд, с учетом того, что API не поменялось или мало поменялось, то данный небольшой проект вполне может завестись и на новом TFS 2012 RC.
Идея
Мои последние статьи (раз, два) повествуют о настройке шаблонов процессов для TFS, но данные шаблоны оторваны друг о друга, по сути, хотя и связываются в работе связями типа: Child, Parent, Related To и так далее. Было бы логично использовать эту связь, для добавления интерактивности во всю схему, чтобы элементы действительно были связанны, чтобы они действительно реагировали на состояния друг друга в зависимости от типа связи и состояния. Чтобы можно было делать некоторые аккумулирующие подсчеты в метриках, ведь все эти данные доступны и их можно использовать в автоматическом режиме, сокращая время рутинных действий.
Можно придумать достаточно много сценариев, когда автоматизация смены состояний в связанных элементах экономила бы время. В стандартной схеме, при смене состояния возможно изменение полей принадлежащих этому же рабочему элементу, но этого мало.
Например, представим себе ситуацию, когда пользовательская история имеет полный набор артефактов и готова к работе, созданы конкретные задания для реализации этой истории. В данной ситуации история находится в состоянии Ready For Development, а все задачи в состоянии Proposed. Разработчик берет задачу в работу, меняет ее состояние на Active. Далее он должен поменять состояние истории на WIP (Work In Progress). Однако этот шаг ведь можно автоматизировать! А автоматизация в свою очередь ведет к большему порядку и красоте. Т.е. как только разработчик взял задачу в работу, состояние всей истории поменялось автоматически!
Или еще пример, например работу над всей историей было решено приостановить, так как внезапно выяснились новые обстоятельства работы какого-либо компонента. В работе находятся несколько задач, какие-то еще не начаты, какие-то завершены. При переводе истории в статус Hold, по-хорошему надо и все активные задачи перевести в статус Hold. Вручную это делать было бы несколько утомительно – это тоже можно автоматизировать. Или же обратную ситуацию, когда одна задача ставится на Hold, и вся история ставится в состояние ожидания.
Так же полезным функционалом было бы, когда все задачи решены, то статус истории автоматически переходит в состояние Resolved.
Еще было бы хорошо автоматически калькулировать разные метрические данные из дочерних элементов в родительские. Например, оставшаяся работа, сделанная. Или если идут различные поля оценки работ для тестирования и разработки, то можно автоматически рассчитывать значение поля для общей работы.
Реализация
Да, как вы уже можете догадаться, для перечисленных целей можно использовать серверное дополнение для TFS 2010 – TFS Aggregator. Так как это дополнение работает на стороне сервера, то выполнение различных правил будет происходить очень быстро. Самая первая обработка, конечно, займет секунд 7-10, так как будет устанавливаться соединение и кэшироваться. Остальные обновления обычно происходят быстрее, чем вы сможете обновить свой клиент.
Установка
TFS Aggregator состоит всего из двух файлов: библиотека выполнения задач и файл настройки формата XML.
После того, как вы скачаете дополнение и распакуете его, оба файла надо перенести в директорию дополнений TFS. Обычно она располагается по адресу: C:Program FilesMicrosoft Team Foundation Server 2010Application TierWeb ServicesbinPlugins.
На этом все. TFS следит за указанной директорией, и когда файл будет скопирован, сервер загрузит его в память.
Настройка
Все настройки содержаться в файле AggregatorItems.xml. В этом файле содержится информация о соединении и обо всех правилах, которые будут применены в процессе работы.
Итак, рассмотрим основные составляющие файла AggregatorItems.xml:
<?xml version="1.0" encoding="utf-8"?>
Заголовок файла, это трогать и менять не стоит.
<AggregatorItems tfsServerUrl="http://tfs2010dev:8080/tfs" >
AggregatorItems: основной элемент для конфигурации, корневой элемент.
tfsServerUrl: адрес до TFS сервера.
В этой строке задается адрес к TFS серверу. Вместо tfs2010dev необходимо написать адрес до своего сервера. При этом есть еще один нюанс: адрес должен вести до какой-либо коллекции проектов. Если ваш проект находится не в коллекции по умолчанию, которая так и называется DefaultCollection, то необходимо указать имя коллекции. Например, в моем случае, проект находится в коллекции MigrationProject, поэтому строка будет выглядеть как:
<AggregatorItems tfsServerUrl="http://violet-tape-tfs:8080/tfs/MigrationProject" >
Название коллекции можно узнать из студии, когда вы выбираете свой проект. Например:
<AggregatorItem operationType="Numeric" operation="Sum" linkType="Parent" linkLevel="2" workItemType="Task">
AggregatorItem: Обозначает правило для агрегации.
operationType: Определяет будет ли произведена математическая операция или же будет работа с текстовыми переменными. Доступны пока что только два значения: Numeric или String. По умолчанию выставляется Numeric. Если выбран тип Numeric, то рабочие поля должны иметь тип double или integer.
operation: Указывает какая математическая операция будет применена к участвующим полям. Поддерживается на данный момент только сложение, вычитание, умножение, деление (Sum, Subtract, Multiply, Divide). По умолчанию выбирается сложение.
linkType:указывает на тип связи будет ли целью агрегирования родитель или этот же элемент. Соответственно возможные значения: Self, Parent. По умолчанию будет стоять Self.
linkLevel: Если linkType указан как Parent, то данный параметр указывать на сколько родителей вверх идти. По умолчанию значение равно единице.
workItemType: Имя рабочего элемента (Task, Bug и так далее) к которому будет применено правило.
<TargetItem name="Total Estimate"/>
TargetItem: Указывает на поле в TFS которое будет обновлено. В единственном экземпляре может быть в правиле.
name: Имя поля в TFS которое предназначено для результата агрегации.
<SourceItem name="Estimated Dev Work"/>
SourceItem: Указывает на поле в TFS которое будет выступать источником данных. Может быть использовано несколько раз.
name: Имя поля в TFS, из которого будут браться данные.
<Conditions>
Conditions: Определяют условия, которые должны быть соблюдены при срабатывании агрегации. Опциональное поле.
<Condition leftField="Finish Date" operator="GreaterThan" rightValue="$NOW$"/>
Condition: Определяет условие, при котором агрегация будет произведена.
leftField: Левый операнд выражения. Поле должно принадлежать тому типу, который указан в Target Work Item. В свойстве workItemType оно указано.
operator: Оператор сравнения. Для строк определено два оператора EqualTo, NotEqualTo. Для чисел определены дополнительные операторы: LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo. По умолчанию будет использован EqualTo.
rightValue: Значение с которым будут сравниваться данные из leftFiled. Должно быть определено либо это свойство, либо rightField. В качестве возможных макросов определены значения $NOW$ и $NULL$.
rightField: Поле должно принадлежать тому типу, который указан в Target Work Item. Сравнивается с левым операндом. Не будет использовано, если определено rightValue.
<Mappings>
Mappings: предоставляет список значений для строковых агрегаций.
<Mapping targetValue="Done" inclusive="And">
Mapping: представляет единичный элемент возможной агрегации. Если условие сработает, то результатом маппинга будет занесение значения из targetValue в TargetItem для AggregationItem.
targetValue: Значение, которое будет использовано для замены.
Inclusive: Данный параметр отвечает за то, должны ли все (And) или же какое-либо одно (Or) значение быть встречены из набора SourceValue, для того, чтобы маппинг сработал.
<SourceValue>Removed</SourceValue>
SourceValue: возможные значения, которым должен удовлетворить маппинг для срабатывания.
Здесь надо заметить, что при упоминании имени поля из рабочего элемента, необходимо писать именно короткое имя, а не с неймспейсом.
На этом определения закончены, и можно рассмотреть конкретные примеры.
Примеры
Можно начать с примера про переход истории к состоянию WIP. Пример основан на схеме из последних статей.
<AggregatorItem operationType="String" linkType="Parent" linkLevel="1" workItemType="Task"> <TargetItem name="State"/> <SourceItem name="State"/> <Mappings> <Mapping targetValue="WIP" inclusive="Or"> <SourceValue>Active</SourceValue> </Mapping> </Mappings> </AggregatorItem>
Здесь указано, что работа будет вестись со строками, с родительским элементом, изменения будут начинаться на уровне Task. Источником данных для анализа изменений будет поле State (SourceItem) элемента Task (workItemType), назначением тоже поле State (TargetItem), но родительского элемента (linkType). При этом родителями может быть как UserStory, так и Bug или еще какой-либо элемент. В секции маппинга описывается, что значение должно смениться на WIP (targetValue), если значение в ресурсе стало Acitve.
При этом важно понимать, что условия перехода состояния все равно будет проверяться внутренними средствами TFS. Невозможно будет перейти из одного состояния в другое, если такой переход не описан в схеме. Нельзя перейти из одного состояния в другое, если не выполняются условия перехода, как например заполненное поле Description или же Story Points. Т.е. это не overdrive и overwrite условий workflow. Финальное состояние должно быть достижимо из указанного, с учетом всех правил.
Честно сказать, при данном конкретном переходе, у меня сбрасывается значение поля AssignedTo на NETWORK SERVICE, но при других автоматизированных переходах этого не происходит. Чудеса! Надеюсь, что разработчики мне помогут в этой проблеме, и я расскажу вам, что было не так.
Еще один пример, переход истории в состояние Resloved, когда все задачи завершены.
<AggregatorItem operationType="String" linkType="Parent" linkLevel="1" workItemType="Task"> <TargetItem name="State"/> <SourceItem name="State"/> <Mappings> <Mapping targetValue="Resolved" inclusive="And"> <SourceValue>Resolved</SourceValue> <SourceValue>Closed</SourceValue> <SourceValue>Abandoned</SourceValue> </Mapping> </Mappings> </AggregatorItem>
Здесь указано, что работа будет вестись со строками, с родительским элементом, изменения будут начинаться на уровне Task. Источником данных для анализа изменений будет поле State (SourceItem) элемента Task (workItemType), назначением тоже поле State (TargetItem), но родительского элемента (linkType). В секции маппинга описывается, что значение должно смениться на Resolved (targetValue), если значение в ресурсе стало или Resolved, или Closed, или Abandoned.
Эти примеры у меня заработали на ура, и очень приятно, что они есть, меньше действий теперь придется совершать при работе с задачами.
Следующую группу примеров я не проверял, но особых сомнений в их работоспособности особых нет.
В следующем примере проводится автоматический подсчет общей ориентировочной работы разработчиков и тестировщиков. Результат записывается в поле Estimated Work в сам же элемент типа Task.
<AggregatorItem operationType="Numeric" operation="Sum" linkType="Self" workItemType="Task"> <TargetItem name="Estimated Work"/> <SourceItem name="Estimated Dev Work"/> <SourceItem name="Estimated Test Work"/> </AggregatorItem>
Больше примеров на странице разработчиков, но они все в таком же духе.
В планах
Планы у разработчиков так же большие, хотя проект и делается в свободное время. Итак, в ближайших планах сделать возможность агрегирования от родителя к потомкам. В этой ситуации будет, например, проще менять IterationPath и прочие вещи, которые при создании наследуются/копируются от родителя.
Рассматривается вариант создания редактора файла AggregatorItems.
Так же в планах сделать возможным указание более одного элемента для workItemType.
Сделать возможным использование разницы значений в условиях, например Today – 5 дней. К этому же плану относится возможность использования в формулах произвольных коэффициентов. На данный момент это невозможно, так как код плагина будет искать поля с названием значения коэффициента.
Найти хороший способ для того, чтобы не прогонять повторно условия из файла AggregatorItems. Допустим, какое-то правило отработало успешно, что повлекло изменения которые запускают правило еще раз. На этот раз изменений уже не происходит и все хорошо. Это конечно не смертельно, так как результат остается все равно верный, но ненужные действия напрягают.
Если не заработал плагин
Вы все успешно распаковали, установили в нужную директорию, необходимым образом отредактировали файл настроек и не заработало…
Что ж, ниже небольшой чек-лист для проверки, все ли сделано на самом деле правильно:
- Вы используете TFS 2010.
- Все ли элементы, упомянутые в правилах агрегации, содержат ссылки типа Parent-Child
- Вы обновили элемент, который требует выполнения правила. TFS Aggregation срабатывает только когда элемент был обновлен и правило смогло определить это и все условия сработали. В будущем, возможно, это поведение изменится.
- Вы обновили файл AggregatorItems.xml и поставили правильный адрес до своего сервера. При этом не забываем про имя коллекции проектов.
- Вы скопировали и dll и AggregatorItems.xml файл в директорию плагинов для TFS.
- Вы указали правильные имена элементов, источников и приемников данных.
- Файл настроек сохранен в кодировке utf-8. Notepad++ зовет ее «utf-8 without BOM». Это в целом должно быть не критично, но тем не менее.
В любом случае, если не работает вообще ничего, сделайте какой-нибудь простой файл правил и попробуйте снова.
Если и в этом случае не заработало, то рекомендуется экспортировать настройки для рабочих элементов и файл AggregatorItems.xml разработчикам по адресу TFSAggregatorIssues@spamex.com.
Итого
Мне очень понравился плагин, я его настроил для своих нужд и теперь радуюсь тому, как он работает. Осталось только получить информацию от разработчиков по поводу смены поля AssignedTo и будет вообще все очень хорошо.
Автор: VioletTape