Jira REST API и Битрикс КП. Учимся разговаривать с Jira, синхронизация с Битрикс КП.
10.02.2016
Как-то у нас исторически сложилось, что Менеджеры сидят в Битрикс КП, а Разработчики в Jira. Менеджеры привыкли ставить и решать задачи через КП, Разработчики — через Джиру. Отсюда пришла мне крайне узкоспециализированная, но крайне интересная задача по частичной синхронизации Джиры и Битрикс КП.
Мне не разрешили выкладывать готовый код, но я могу описать здесь все проблемы, с которыми столкнулась.
Ахтунг! Букавмнога, очень многа!
Что требовалось:
- При создании задачи в КП, если отмечена галочка синхронизации, - создавать задачу и в Джире.
- Опять же, если отмечена галочка синхронизации, то стягивать потраченное время из задач Джиры в задачи КП.
- Для уже существующих задач в КП иметь возможность выставить задачу из Джиры ручками, чтобы синхронизовать время.
- Стягивание времени осуществляется по соответствующему агенту (у нас они естественно на кроне).
- Для уже существующих задач КП иметь возможность создавать задачу в Джире.
Джира вообще достаточно оригинальна в использовании непривычных терминов. Поэтому укажу соответствия.
- issue - запрос. Далее по статье я буду называть issue - задачами Джиры (в противоположность задачам КП).
- summary - имя задачи, TITLE, заголовок.
- reporter - кем создана задача, автор задачи, CREATED_BY
- assignee - на кого задача, ответственный, RESPONSIBLE.
- project - проект, в рамках которого создаётся задача. наиболее близкое понятие в КП - группа задачи, но соответствие конечно натянутое.
- worklog - единица отмеченного времени. Для КП это единица отмеченного затраченного времени, или в терминах битрикс апи - elapsed time. Мне нравится термин ворклог, далее в статье я буду его использовать.
Продумываем реализацию
1. добавляем свойство для задачи КП, в котором будем хранить номер задачи в Джире, и свойство для галочки, синхронизовать время или нет. Возможно также создание свойства для хранения типа создаваемой задачи Джиры (Баг, Задание, Новая функция и т.п.)
2. для создания задачи в Джире требуется указать проект (ключ проекта), в рамках которого создаётся эта задача. В нашем КП это свойство группы, в которой создаётся задача. Если свойство "Ключ проекта" в группе не прописано, то задачу в Джире не создаём. (ну или создаём в дефолтовом проекте например)
3. пользователей выясняем по емейлам, можно сделать свойство соответствия в КП - пользователь в Джире. Остальные соответствия достаточно прозрачны.
4. синхронизируем задачи с отмеченной галочкой и с определёнными статусами. вешаем на агента (у нас они естественно на кроне)
Хелло, ворлд
Собственно, на первый разговор с Джирой было потрачено некоторое количество нервов. Но по накоплению опыта, удачного и не очень, всё было сделано.
Во-первых, смотрим на номер версии вашей Джиры и выбираем соответствующий REST API вот
Прежде чем изобретать велосипед были перепробованы несколько проектов с гитхаба.
Потом я плюнула и попробовала просто кодом закурлить список проектов с нашей Джиры.
$objCurl = curl_init(); curl_setopt_array($objCurl, array( CURLOPT_URL => JIRA_URL.'/rest/api/latest/project', CURLOPT_USERPWD => JIRA_USERNAME . ':' . JIRA_PASSWORD, CURLOPT_HTTPHEADER => array('Content-type: application/json'), CURLOPT_RETURNTRANSFER => true )); $result = curl_exec($objCurl); curl_close($objCurl); |
Радости были полные штаны =)
Примеры простых GET адресов для запросов Джиры
- /rest/api/latest/project - получить список проектов
- /rest/api/latest/project/SUPPORT - получить информацию о проекте с ключом SUPPORT
- /rest/api/latest/issue/SUPPORT-13 - получить информацию о задаче SUPPORT-13
- /rest/api/latest/priority - список возможных приоритетов для задач
- /rest/api/latest/issue/SUPPORT-13/worklog - список ворклогов для задачи с ключом SUPPORT-13
Запрос данных у createmeta осуществляется методом GET, но возможно указание дополнительных параметров. Для чего он нужен?
Для каждого проекта в Джире могут быть ограничения как типы создаваемых задач, так и поля этих задач. Так вот createmeta позволяет узнавать данные, необходимые для создания задачи.
Имеется возможность фильтрации по:
- проекту - указываются ключи projectKeys или айдишки projectIds проекта
- типу задач - указываются айдишки issuetypeIds или названия issutypeNamesтипов задач
Например, получим свойства полей задач, для проектов SUPPORT и TEST, задач типа Баг (айди 1).
/rest/api/latest/issue/createmeta?projectKeys=SUPPORT,TEST&issuetypeIds=1&expand=projects.issuetypes.fields
Тестовое создание задачи в Джире
Создание осуществляется POST запросом по адресу /rest/api/latest/issue. Посмотрим в документацию:
Запрос создаёт задачу или подзадачу из массива, представленного в формате JSON.
Поля (а также параметры полей), которые могут быть заполнены при создании, вы можете выяснить у createmeta.
Все задачи у нас в Джире от проекта к проекту не отличаются структурой и типами, поэтому я один раз спросила список полей на заполнение и сформировала массив, который нужен для создания задачи в Джире (чем быстрее, тем лучше; если всё делать правильно, то закопаемся).
$arFields = array( 'fields'=>array( 'summary' => 'Test create task', 'description' => 'test description task', 'issuetype' => array( 'id' => 1 ), 'assignee' => array( 'name' => 'c_piper' ), 'reporter' => array( 'name' => 'c_piper' ), 'project' => array( 'key' => 'SUPPORT' ), 'duedate' => '2016-01-16', 'priority' => array( 'name' => 'Низкий' ) ) ); |
Этот массив надо json_encode и отправить POST-запросом Джире. Как? Читаем дальше.
Методы отправки запросов
Все методы регулируются опциями curl, которые соответственно добавляем в зависимости от того, чего хотим добиться, например для метода POST добавляем
if ($request_type == 'POST') { curl_setopt($objCurl, CURLOPT_POST, true); curl_setopt($objCurl, CURLOPT_POSTFIELDS, $jdata); } |
Где jdata - это json закодированный массив данных (например, на добавление задачи Джиры)
Итак, чтобы добавить задачу Джиры:
- формируем массив с полями, необходимыми для создания задачи
- делаем json_encode этих полей
- отправляем POST запрос Джире
Пользовательское свойство задачи создаётся через админку Настройки -- Настройки продукта -- Пользовательские поля -- Добавить. Пользовательское поле задачи отличается тем, что при создании в пункте Объект надо прописать TASKS_TASK, а Код поля принято начинать с префикса UF_
Соответствия полей задач КП и полей задач Джиры
После добавления задачи в Битрикс КП происходит событие onTaskAdd, на него и вешается создание задачи в Джире.
Приоритетов к задачах КП всего три, прописываем соответствия для Джиры
- CTasks::PRIORITY_LOW = Низкий
- CTasks::PRIORITY_AVERAGE = Средний
- CTasks::PRIORITY_HIGH = Высокий
$hJU = CUserFieldEnum::GetList(array(), array('USER_FIELD_ID' => $uf_id)); while($row = $hJU->Fetch()) { echo $row['ID'].' = '.$row['VALUE'].' '; } |
Секунды задачи из КП нужно преобразовать в вид Джиры, это справитесь сами.
Итак, для создания задачи в Джире после создания задачи в Битрикс КП:
- заводим обработчик события onTaskAdd
- в обработчике осуществляем перевод нужных полей из Битрикс задачи в соответствующие значения Джира задачи
- переводим этот массив в json
- отправляем POST-запрос Джире
- узнаём по ответу ключ задачи и прописываем его через CTasks::Update
- заводим обработчик OnBeforeTaskUpdate
- если до этого у задачи КП была проставлена галочка синхронизации или заполнено поле ключа задачи в Джире, то ничего не делаем, иначе - продолжаем
- в обработчике осуществляем перевод нужных полей из Битрикс задачи в соответствующие значения Джира задачи
- переводим массив в json
- отправляем POST-запрос джире на создание задачи
- по ответу от Джиры узнаём ключ созданной задачи и записываем его в массив$arFields, который поступает в обработчик события
Так как разработчики отмечают время в Джире, то надо переносить это время в КП. Продумаем реализацию.
- создаём агента, внутри которого и будет происходить вся обработка
- спрашиваем у КП задачи (CTasks::GetList) определённого статуса, у которых есть галочка синхронизации и заполнено поле Ключа задачи в Джире
- для этих задач в КП спрашиваем уже существующие ворклоги (CTaskElapsedTime::GetList)
- для найденных ключей задач в Джире спрашиваем ворклоги
- сравниваем уже существующие в КП с теми, которые пришли из Джиры
- прописываем если надо в КП новые ворклоги (CTaskElapsedTime::Add)
где SUPPORT-13 -- это ключ задачи в Джире
Проблема только в том, что нельзя получить у Джиры все ворклоги сразу для массива ключей задач Джиры, поэтому, сами понимаете, приходится получать их в цикле.
Чтобы опознать ворклоги, добавленные из Джиры, в начале комментария к ворклогу добавляется метка, содержащая ключ задачи Джиры, айди ворклога и подпись что ворклог импортирован из Джиры.
При добавлении ворклога в КП есть одна особенность: если отдельно не прописать пользователя, создавшего ворклог, то в КП автором ворклога будет считаться Админ с id=1, хотя время и пропишется для пользователя-ответственного.
//формируем массив на добавление
$arWFields = array( //кому время добавляется 'USER_ID' => $arUser[$worklog->author->name], 'TASK_ID' => $cp_task_id, 'MINUTES' => floor($worklog->timeSpentSeconds/60), 'COMMENT_TEXT' => $worklog->comment ); //кто создатель времени $arParams = array('USER_ID' => $arUser[$worklog->author->name]); //добавление ворклога $objCTET = new CTaskElapsedTime(); $objCTET->Add($arWFields, $arParams); |
Ссылки
14060