![](https://habrastorage.org/getpro/habr/upload_files/7db/d50/d58/7dbd50d58a60ebddeb017a59b0514446.png)
Всем привет, меня зовут Алексей - я руководитель отдела интеграции EvaTeam. Это статья о том, как реализована настройка автоматизаций в EvaProject - российском аналоге Jira. В ней рассказывается о том, с чем пришлось столкнуться при переезде с Jira, и как мы реализовали функционал в нашей системе.
Об автоматизации в Jira
Базовая автоматизация в Jira, прямо скажем, весьма скудная. Она подойдёт только небольшим и нетребовательным командам. По факту более менее полноценную автоматизацию можно получить только с использованием расширений и плагинов. Например, есть официальное расширение Jira Automation, которое позволяет добавлять свои правила. Но работа с ним тоже не очевидная и его болтает как матроса в лодке. Полноценно работает в премиум тарифе Cloud-версии. С недавних пор встроено в версию Data Centre. А для Server-тарифа устанавливается только как отдельное расширение с возможностью продлить его до февраля 2024 года.
Ещё есть плагины вроде ScriptRunner. Входит в топ самых популярных расширений в маркетплейсе и позволяет выстраивать процессы и автоматизации. Это действительно мощная вещь, которая может помочь организовать всё что происходит в компании. Но устанавливается отдельно и требует доплаты.
В целом у Jira богатая автоматизация за счет плагинов и расширений. Можно настроить всё что угодно: от смены исполнителя при изменении статуса по задаче, до включения кофемашины каждый день в 9 утра.
Поэтому возникают сложности у людей при переходе на российское ПО. Мало систем, которые позволят также гибко автоматизировать процессы, но и мы не из трусливых. Рассказываю о том, как работает этот функционал у нас в системе.
Автоматизация переходов
За основу работы автоматизации брались привычные настройки Jira, а также популярные плагины. В данный момент уже многое из этого реализовано в EvaProject, но ещё получаем много запросов, по специфичным настройкам, которые постоянно добавляем. Главное что сделано - заложены архитектурные возможности для дальнейшего развития в сторону замены Atlassian.
Для настройки логики бизнес-процессов используем классические 3 кита автоматизации:
Условия перехода;
Валидаторы;
Действия.
Условия перехода
Условия перехода отрабатываются для визуального отображения в списке статусов. Они определяют именно видимость. Если условие для отображения перехода верное, то он будет отображаться в списке статусов. Например, можно настроить появление статуса "DONE" только тогда, когда в задаче оставили комментарий по ней.
![Отображение статуса при выполненном условии "Оставлен комментарий" Отображение статуса при выполненном условии "Оставлен комментарий"](https://habrastorage.org/getpro/habr/upload_files/75a/718/6a1/75a7186a1eab1d29e5cade52c3468cf1.png)
Валидатор
Это дополнительные условия для статусов. Если условие валидатора не выполняется, при переходе на определённый статус возникает ошибка. Валидатор фиксирует почему возникла ошибка и выводит информативное окно с причиной её возникновения.
![Появление окна с предупреждением при невыполненном условии Появление окна с предупреждением при невыполненном условии](https://habrastorage.org/getpro/habr/upload_files/c55/671/501/c55671501eb8615760b42b6a55cbfc19.png)
Используется для создания дополнительной логики при совершении переходов. Пример настройки сообщения для ошибки, получаемое пользователем при срабатывании определённых условий:
![Настройка валидатора Настройка валидатора](https://habrastorage.org/getpro/habr/upload_files/f9e/71d/3d7/f9e71d3d778135f0e63b4ed0f0c100b7.png)
Примеры использования валидатора.
Например, нам нужно добавить условие, чтобы нельзя было изменить статус, если текущее время больше дедлайна, или изменять статус вне рабочего времени (к примеру, брать в работу).
Действия
Это именно то, что произойдёт в системе после смены статуса. Действие не накладывает дополнительных условий на отображение и смены статуса, а выполняется после перехода из одного статуса заявки в другой.
Помимо предустановленных опций для настроек переходов также доступен более гибкий инструмент bzPython, который является аналогом плагина ScriptRunner в Jira.
bzPyton
Используя bzPyton можно реализовать абсолютно любую автоматизацию.
![Пример добавления bzPython Пример добавления bzPython](https://habrastorage.org/getpro/habr/upload_files/b7d/fbf/2f0/b7dfbf2f05237efc418494611cbbd58a.png)
bzPyton – внутренний бизнес-интерпретатор. Задача, в которой совершается определенный переход, передаётся в интерпретатор в переменной self, которая является объектом класса CmfTask и содержит всю информацию об этой задаче, то есть все поля и методы объекта CmfTask. Мы можем поменять статус, можем поменять будильник и любые другие поля, которые есть в модели CmfTask. Список доступных полей можно найти в официальной документации.
Для примера, сделаем чтобы ответственным для задачи стал пользователь, изменивший статус задачи. Добавляем новое действие для статуса, Вид Действия – bzPyton. В окно интерпретатора пишем:
self.responsible = g.current_user
В этом примере:
self.responsible – ответственный за текущую задачу;
g.current_user – специальная переменная, в которой содержится текущий пользователь, который совершает переход.
После окончания перехода, пользователь, совершивший этот переход, автоматически будет назначен ответственным по задаче.
Популярные шаблоны реализации автоматизации с помощью bzPyton можно посмотреть в официальной документации (https://docs.evateam.ru/docs/docs/DOC-000193#primery-bz-python)
Для переходов количество кода обычно невелико. Можно использовать более объемные скрипты в Триггерах или Cron.
И ещё один пример bzPython для валидатора. "Разрешить выполнять переход только тому пользователю, который является исполнителем по задаче":
if self.responsible != g.current_user:
return False
Триггеры
Триггеры могут выполняться, когда в системе происходят какие-либо события. К примеру, кто-то перенес задачу в канбане на следующую стадию, наступил новый рабочий или любое другое событие. На него мы можем назначить триггер.
![Добавление события для триггера Добавление события для триггера](https://habrastorage.org/getpro/habr/upload_files/247/d53/a17/247d53a1745622c4eb7aafd9b55e168a.png)
События для триггеров:
Комментирование;
Создание;
Удаление;
Сохранение;
Обновление.
Любое это событие может быть использовано вместе с моделями:
Задача (CmfTask);
Документ (CmfDocument);
Список (CmfList);
Сделка (CmfDeal).
Для создания нового триггера необходимо перейти в настройки, выбрать режим администратора, нажать «Автоматизация триггеры».
В поле «Название» впишите нужное имя триггера и нажмите «Добавить».
Нажмите «Изменить», откроется окно с параметрами триггера.
![Настройка триггера Настройка триггера](https://habrastorage.org/getpro/habr/upload_files/767/971/444/767971444c4e6dca1a32763ce5f00231.png)
Есть уже предустановленные фильтры. Это "Фильтр по логическому типу объекта", "Фильтр по виду деятельности", "Фильтр по схеме бизнес-процессов". Для более гибкой настройки фильтра есть возможность использовать интерпретатор bzPyton.
Подробное описание по настройкам содержится в официальной документации (https://docs.evateam.ru/docs/docs/DOC-000238#avtomatizacziya-triggery)
Попробуем работу триггеров.
Задача для триггера: Автоматизация по созданию дочерней задачи с типом "Подзадача".
Для этого выбираем такие настройки:
![](https://habrastorage.org/getpro/habr/upload_files/44c/c1b/595/44cc1b595320ecc6cf87779b35f649c7.png)
Добавляем такой код:
task_code = self.name.value
relation_task = models.CmfTask.get(code=task_code, fields=['name', 'cf_custom_field_1'])
if relation_task:
# Меняем имя дочерней задачи
self.name = f'{task_code} - {relation_task.name}'
# Получаем кастомное поле из второй задачи
custom_1 = relation_task.cf_custom_field_1
# Меняем текст дочерней задачи
self.text = f'<p>Это текст первой строки. Кастом поле-{custom_1}</p>\n<p>Это текст второй строки</p>'
# Получаем нужный тип связи. В данном случае тип связи "Взаимная" - "Относится к"
relation_type = models.CmfRelationType.get(code='system.link')
# Создаем связь между второй задачей и новой созданной(дочерней)
new_rel = models.CmfRelationOption(out_link=self, in_link=relation_task, relation_type=relation_type)
new_rel.save()
А логика скрипта получается такой:
Скрипт выполняется если в основной задаче нажать кнопку "Добавить дочернюю задачу" и прописать в названиеcode другой уже созданной задачи.
По полю code будет найдена вторая задача. Из этой задачи будут получены поля name и cf_custom_field_1.
Полученные поля из второй задачи будут прописаны в дочернюю.
Между дочерней и второй задаче создается связь с типом system.link (Взаимная).
В настройках триггера указано "Событие: Создание", "Фильтр по логическому типу объекта - Подзадача".
Cron
Автоматизировать работу системы можно не только по определённым действиям со стороны пользователей, но и по времени. Для этого есть специальный инструмент-планировщик. С помощью него, к примеру можно убирать выполненные задачи из списка задач, или настроить периодическую очистку архива.
Создать действие по времени можно также в настройках в режиме администратора. Для этого выбираем «Автоматизация Cron». Создаём новое правило и переходим к редактированию:
![Окно настройки Cron Окно настройки Cron](https://habrastorage.org/getpro/habr/upload_files/2e4/b3f/8cd/2e4b3f8cd5ae6ce9dd72e1199f317301.png)
Выполняемые задачи для Cron не содержат переменную self. Вызываемые по расписанию объекты должны быть найдены в БД по определенному критерию. К примеру, по расписанию можно найти все задачи, у которых просрочен будильник, и изменить их статус. То есть с помощью Cron обычно производится автоматизация по большому списку задач, которые нужно раз в какой-то промежуток времени обработать.
Правила заполнения поля «Выражение Cron»
Время выполнения задается пятью колонками, разделёнными пробелами: минуты (0—59), часы (0—23), дни месяца(1—31), месяцы(1—12) и день недели(0—7). Значения могут быть в виде чисел, диапазонов или «». Примеры заполнения:
5 0 * * * – выполняется каждый день в 0 часов 5 минут;0-59 * * * * – выполняется ежеминутно;/5 * * * * – выполняется каждые пять минут;
5 4 * * sun – выполняется в 4:05 в воскресенье;
Рассмотрим пример. Нам нужно каждый день находить все задачи, у которых статус не менялся 7 дней, автоматически их закрывать и отправить уведомление владельцу задачи.
from datetime import timedelta
# Находим нужный workflow
wf = models.CmfWorkflow.get(code='WF-000005')
# Статус закрыто в нужном workflow
status_closed = models.CmfStatus.get(code='closed', workflow=wf)
seven_days_ago = g.now - timedelta(days=7)
# Находим задачи, у которых статус не менялся 7 дней
tasks = models.CmfTask.list(filter=['status_modified_at', '<=', seven_days_ago])
for task in tasks:
task.status = status_closed
task.save()
# Отправляем сообщение владельцу задачи
models.CmfNotify.place_notify(obj=task, person_id=task.cmf_owner.id.value,
msg=f'Заявка {task.code} отмечена как выполненная автоматически', text='Заголовок')
Помимо трёх вариантов автоматизации в EvaProject есть ещё Webhook и Git. Основные варианты автоматизации, благодаря bzPyton, имеют максимальную гибкость. Конкретные описания полей можно посмотреть в документации, либо обратиться в техподдержку.
Встроенный интерпретатор поддерживает подсветку синтаксиса, а также имеет подсказки по доступным командам. К примеру, если после self. нажать букву r, то мы увидим все возможные варианты. Все названия «говорящие», то есть по названию можно понять, что это за функция или переменная.
Конец
В следующей статье расскажу как мы помогали настраивать автоматизацию на примере одной крупной компании. Ну и это ещё минимальная часть от реализованного и планируемого функционала. Постоянно от клиентов получаем информацию о том как они "интересно" использовали Джиру и продолжаем добавлять фичи для автоматизаций.