Я Саша Хрущев, технический директор IT-компании WINFOX. Рассказываю о своем опыте освоения скриптинга в YouTrack и о том, как при помощи этого можно делать крутые отчеты.

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

Автоматическое определение просрочки задач
Начнем с определения просрочки задач. Казалось бы, что в этом сложного? Просто сделайте фильтр по задачам, у которых планируемая дата исполнения раньше текущей, и готово. Сказано — сделано.
Сначала создаем рабочий процесс.
А после создаем в этом процессе модуль, который срабатывает по таймеру. Для этого нам нужен вот такой код:
var entities = require('@jetbrains/youtrack-scripting-api/entities'); var workflow = require('@jetbrains/youtrack-scripting-api/workflow'); var dateTime = require('@jetbrains/youtrack-scripting-api/date-time'); var http = require('@jetbrains/youtrack-scripting-api/http'); exports.rule = entities.Issue.onSchedule({ title: workflow.i18n('Notify assignee about overdue issues'), search: '#Unresolved has: {Due Date}', cron: '* 0/1 * ? * * *', guard: function(ctx) { return ctx.issue.fields.DueDate < Date.now(); }, action: function(ctx) { var issue = ctx.issue; if(!issue.hasTag('Просрочена')){ issue.addTag('Просрочена'); var formattedDate = dateTime.format(issue.fields.DueDate); var notificationText = workflow.i18n('Issue became overdue on <i>{0}</i>:', formattedDate) + ' <a href="' + issue.url + '">' + issue.summary + '</a><p style="color: gray;font-size: 12px;margin-top: 1em;border-top: 1px solid #D4D5D6">' + workflow.i18n('Sincerely yours, Angry Fox') + '</p>'; // если вдруг решили добавить информирование в дискорде через вебхук, мы побаловались и отключили var connection = new http.Connection('https://discord.com/api/webhooks/********/***************'); connection.addHeader('Content-Type', 'application/json'); var content = { "username": "AngryFox", "avatar_url": "https://i.imgur.com/4M34hi2.png", "content": notificationText }; var response = connection.postSync('', [], JSON.stringify(content)); if (response && response.code === 200) { issue.addComment('О просрочке задачи доложено в соответствующие инстанции'); } else { issue.addComment('Ошибка информирования о просрочке: '+response.code); } } }, requirements: { DueDate: { type: entities.Field.dateType, name: "Срок" }, Assignee: { type: entities.User.fieldType } } });
Нам удобнее запускать модуль рано утром, так как команда распределенная, и есть любители поработать поздно вечером или даже ночью.
Мы попробовали добавить информирование в Discord. Жутко неудобно и надоедает, но для примера в коде этот кусок оставили.
Размяли лапки на простейшем скрипте, а теперь что-то посерьезней)
Аналитика
Представим, что нам нужно настроить сложную аналитику, например, посчитать рентабельность проектов или отдельных разработчиков, оценить результативность команды. Что нам мешает сделать это стандартными средствами?
Дело в том, что самое слабое место встроенной аналитики в YouTrack — переходы по состояниям. Вот для примера стандартный флоу работы с задачей, принятый у нас в команде:
-
Регистрируем задачу в статусе «Зарегистрирована».
-
Оцениваем задачу (Estimate) и ставим дату исполнения согласно проектному плану.
-
Задача переходит на исполнителя, мы меняем статус на «Открыта», а после корректируем его исходя из рабочего процесса. Например, задача падает на джуна и Estimate увеличивается. Или план поехал, тогда меняется DueDate.
-
Исполнитель переводит задачу в статус «В работе».
-
Исполнитель трекает время в задаче.
-
Исполнитель решает задачу и переводит ее в статус «Решена».
-
После сборки исполнителем назначается тестировщик и задача переходит в статус «Передано в тестирование».
-
Тестировщик проводит тесты и трекает затраченное время в задаче.
-
Если всплывают проблемы по части функциональности, задача переходит в статус «Открыта повторно».
-
Переходим к пункту 4 и повторяем все до победного.
Стандартные средства, то есть отчеты YouTrack, не показывают нам всю картину ни по затраченному времени, ни по качеству, ни по производительности команды разработки и тестирования. Ну, по крайней мере этого не могут версии YouTrack, которые стоят у нас — 2020-й год с каким-то апдейтом в 2021-м. Поговаривают, что в версии 2023 года все точно так же.
Смена исполнителей, многократная смена и откат статусов (а это мы еще самый простой вариант разобрали) не дает нам никаких шансов собирать инфу традиционным способом. При этом все необходимые данные в трекере есть!
Чтобы решить проблему, мы ввели новый рабочий процесс Register Youtrack Actions. По факту мы просто добавили логгер всех изменений задач через REST в дополнительную базу данных.
Теперь каждая ревизия задачи за исключением аттачей летит в REST, на основе которого мы уже собираем аналитику. Вот как это сделать.
Для начала создаем новый рабочий процесс и прикрепляем к нему модуль, который работает при изменении.
После этого пишем скрипт модуля, который будет логировать все данные по задаче:
var entities = require('@jetbrains/youtrack-scripting-api/entities'); var workflow = require('@jetbrains/youtrack-scripting-api/workflow'); var dateTime = require('@jetbrains/youtrack-scripting-api/date-time'); var http = require('@jetbrains/youtrack-scripting-api/http'); exports.rule = entities.Issue.onSchedule({ title: workflow.i18n('Notify assignee about overdue issues'), search: '#Unresolved has: {Due Date}', cron: '* 0/1 * ? * * *', guard: function(ctx) { return ctx.issue.fields.DueDate < Date.now(); }, action: function(ctx) { var issue = ctx.issue; if(!issue.hasTag('Просрочена')){ issue.addTag('Просрочена'); var formattedDate = dateTime.format(issue.fields.DueDate); var notificationText = workflow.i18n('Issue became overdue on <i>{0}</i>:', formattedDate) + ' <a href="' + issue.url + '">' + issue.summary + '</a><p style="color: gray;font-size: 12px;margin-top: 1em;border-top: 1px solid #D4D5D6">' + workflow.i18n('Sincerely yours, Angry Fox') + '</p>'; // если вдруг решили добавить информирование в дискорде через вебхук, мы побаловались и отключили var connection = new http.Connection('https://discord.com/api/webhooks/********/***************'); connection.addHeader('Content-Type', 'application/json'); var content = { "username": "AngryFox", "avatar_url": "https://i.imgur.com/4M34hi2.png", "content": notificationText }; var response = connection.postSync('', [], JSON.stringify(content)); if (response && response.code === 200) { issue.addComment('О просрочке задачи доложено в соответствующие инстанции'); } else { issue.addComment('Ошибка информирования о просрочке: '+response.code); } } }, requirements: { DueDate: { type: entities.Field.dateType, name: "Срок" }, Assignee: { type: entities.User.fieldType } } });
Ничего сложного, зато ревизия задачи теперь летит в REST и ложится в таблицу. В результате такого преобразования получаем таблицу ревизий.
|
Поле |
Тип |
Описание |
|
ID |
String |
Идентификатор ревизии, генерится при регистрации |
|
ISSUE_ID |
String |
Идентификатор задачи в YouTrack |
|
PROJECT |
String |
Идентификатор проекта |
|
TITLE |
String |
Заголовок (summary) задачи |
|
DESCRIPTION |
String |
Описание задачи |
|
REPORTER |
String |
Ссылка на автора задачи |
|
ASSIGNEE |
String |
Ссылка на исполнителя задачи |
|
LINK |
String |
Ссылка на задачу в трекере |
|
CREATED |
Unixtime |
Дата создания задачи |
|
UPDATED |
Unixtime |
Дата ревизии задачи |
|
DUE_DATE |
Unixtime |
Due date, плановая дата исполнения |
|
ESTIMATION |
Int |
Плановая оценка в минутах |
|
TYPE |
String |
Тип задачи (Bug/Task) |
|
STATE |
String |
Статус задачи |
|
WORKITEMS |
Array |
Записи о затреканном времени (автор, длительность, дата) |
|
COMMENTS |
Array |
Записи о комментариях (автор, содержимое, дата) |
Выглядит это примерно так:
Когда у нас есть все ревизии каждой задачи, мы можем собрать полную историю модификации задачи.
Написав нехитрый скрипт аналитики, мы получили краткую сводку по каждой задаче.
|
Поле |
Тип |
Описание |
|
Идентификатор задачи |
String |
Идентификатор задачи в YouTrack |
|
Дата обновления |
Unixtime |
Дата последней ревизии задачи |
|
Первый исполнитель |
String |
Разработчик, на которого первый раз была назначена задача |
|
Дата постановки |
Unixtime |
Дата первого назначения на разработчика |
|
Первый трекер |
String |
Первый разработчик, затрекавший время на задачу |
|
Дата/время первого трека |
Unixtime |
Дата первого трекинга разработчиком |
|
Дата возврата задачи |
Unixtime |
Дата, когда задача была первый раз переоткрыта (Reopen) = точка с которой время становится бесполезным |
|
Кому была возвращена задача |
String |
На кого задача была переоткрыта |
|
Последний трекер |
String |
Разработчик, последним трекавший время на задачу |
|
Дата последнего трека |
Unixtime |
Дата последнего трекинга разработчиком |
|
Тип задачи |
String |
Bug/Task |
|
Изначальная оценка |
Float |
Первая оценка (в задачу она приходит из сметы и первоначального плана) |
|
Трекинг времени |
Array |
Последняя информация по трекингу времени |
|
Дата решения задачи |
Unixtime |
Время, когда задача или баг перешли в статус Verified |
С такой промежуточной таблицей гораздо проще отлаживать и отслеживать аномалии, продумывать алгоритмы и фиксить баги в скрипте.
Например, после того, как мы собрали данные в таблицу, мы смогли выявить случаи, когда разработчик, на которого заведена задача, первый трекер, тот, на кого задача возвращена, и последний трекер — четыре разных человека. Мы также можем отследить, когда последним трекает время тот, кто смотрел пулреквест, но не относится к фактическим работам в задаче.
Вариантов и флуктуаций — масса, но в целом такие данные позволяют строить более-менее адекватную аналитику.
На основе этих данных мы можем формировать два нужных отчета: отчет план/факт и отчет по разработчикам.
Отчет план-факт
Имея статистику по всем задачам, мы можем генерить хороший отчет в разрезе проектов.
Чтобы получать такие отчеты, мы разделили все переходы на «хорошие» и «плохие». Пока задача идет по «хорошим» переходам, все затраченное на нее время считается полезным. Если хотя бы один переход задачи идет по «плохому» пути, это означает, что в задаче что-то пошло не так в сравнении с идеальным вариантом, и мы должны учитывать все оставшееся время как бесполезное. Баги — изначально бесполезное время.
Вот как выглядит отчет план-факт.
Это не тот отчет, где мы просто считаем планируемое и затраченное время и уходим плакать. Здесь мы точно знаем, где ковырялись с задачами дольше планируемого, где тратили время на исправление багов, а где — на недоделанные и неисправленные баги и задачи.
Боже, почему мы не сделали этого раньше?
Отчет по разработчикам
Этот детальный отчет с разбивкой по разработчикам.
Нас интересуют следующие показатели:
-
сколько задач было в работе;
-
сколько задач закрыто;
-
полезные часы;
-
бесполезные часы;
-
сколько задач вернулось к разработчику;
-
сколько багов было заведено;
-
сколько багов было закрыто;
-
сколько полезных часов подтверждено тестировщиками;
-
сколько бесполезных часов подтверждено тестировщиками;
-
соотношение продуктивного и непродуктивного времени.
Теперь мы знаем, сколько часов реально тратит каждый разработчик в среднем на один час полезной работы, и можем подсчитать корректную юнит-экономику. А еще можем измерить качество работы отдельных разработчиков.
У нас за стандарт принято 20% непродуктивного времени. Разработчики, которые показывают худший результат, должны улучшать свои показатели. А те, у кого непродуктивное время заняло меньше 20% рабочего, претендуют на премию.
У внимательного читателя наверняка появились вопросы к таблице. Почему есть разработчики с 0% бесполезного времени? Почему у кого-то проверено больше часов, чем отработано? Дело вот в чем.
Показатель «Проверено» говорит лишь о том, подтверждаются часы отдельно взятого разработчика или нет. Например, сотрудник может пилить чудовищный функционал полтора-два месяца, и за это время ни одна его задача не уйдет в тесты. Это маркер того, что показатель текущего месяца для этого разработчика может быть неактуален, и его результаты стоит рассматривать в разрезе статистики за два-три месяца.
Соответственно, в следующем месяце по таким разработчикам проверенных часов будет значительно больше, чем отработанных.
Что дальше
Мы написали и другие полезные скрипты для YouTrack. Вот несколько задач, которые они решают:
-
Невозможность трекать время в задачу без Estimation.
-
Невозможность закрывать задачи по фронту без приложения аттачей. У нас правило: если что-то сделано по фронту, нужен скрин или видео.
-
Напоминания о забытых задачах.
Останавливаться на этом не собираемся. В будущем хотим подключить к аналитике задач ChatGPT и доделать-таки наше приложение для работы с трекером.
Пишите в комментариях, если вам интересно узнать про скриптинг в YouTrack что-то еще — я постараюсь поделиться опытом. Ну и рассказывайте, как вы допиливаете трекер, чтобы решать свои задачи.
ссылка на оригинал статьи https://habr.com/ru/articles/750976/
Добавить комментарий