Как я подружил BPMN и Bitbucket

Привет, Хабр! Я техлид в компании ДомКлик. В основном занимаюсь backend-разработкой. Мне периодически приходится погружаться и во front-разработку, но этого не происходило уже более двух лет. Сегодня я расскажу, как мне пришлось заняться front-разработкой для создания плагина для Bitbucket, с какими сложностями я столкнулся и как их решал. Также поделюсь результатом своей работы: надеюсь, он окажется полезен кому-нибудь ещё. Эта статья не является руководством по написанию плагинов для продуктов Atlassian и не описывает всех возможностей системы плагинов.

Проблема


Некоторые наши команды используют нотацию BPMN для описания бизнес-процессов, которые мы реализуем. Недавно мой коллега рассказал, как мы пришли к применению BPMN. В качестве движка исполнения бизнес-процессов мы используем платформу Camunda, популярность которой, как мне кажется, обусловлена несколькими важными факторами:
  • Отличный инструментарий. Сюда входят инструменты для моделирования, мониторинга, анализа бизнес-процессов.
  • Отличная документация, полная и подробная.
  • Возможность тонкой настройки под свои нужды благодаря огромному количеству настроек среды исполнения.
  • Возможность расширения базовой функциональности через реализацию своих плагинов.
  • Сообщество. Разработчики Camunda организуют конференции, митапы, записывают обучающие видео, ведут тематические блоги, поддерживают диалог на форуме и, конечно, выкладывают свой код на GitHub.

И всё было бы хорошо, но есть одна существенная проблема. Нотация BPMN использует XML для описания всех шагов, связей и расположения всех элементов схемы бизнес-процесса. Существуют различные инструменты визуального проектирования схем BPMN. Одно из самых удобных — Camunda Modeler. Любое изменение визуального представления влечет за собой изменение XML-описания. Мы в командах придерживаемся практики обязательных code review, которые проводятся средствами Bitbucket в рамках пулл-реквестов. Но рецензировать изменения в большом XML-файле, который описывает визуальное представление, практически невозможно. Попробую проиллюстрировать проблему на примере стандартного сравнения текстовых файлов, которое производит Bitbucket:

tvsucosicmdacl1qd8oygo-q32e.gif

В данном случае сравнение показывает нам, что всё предыдущее содержимое файла было удалено и было добавлено полностью новое содержимое. На самом же деле на схеме изменилось лишь несколько элементов, и дополнительно был отформатирован файл BPMN.

До сих пор мы вынуждены были скачивать две версии файла (старую и новую) на локальную машину, открывать их в среде визуального просмотра и сравнивать вручную. Очень неудобно. И из-за такого подхода в прод уже просачивалось несколько багов. Актуальность этой проблемы растет вместе с количеством людей и команд, которые используют BPMN.

Долгое время меня не покидала мысль, что необходимо как-то облегчить жизнь командам, вынужденным вручную сравнивать схемы. И хорошо бы иметь встроенный в Bitbucket визуальный инструмент. Я начал изучать вопрос расширения возможностей Bitbucket с помощью плагинов. Ничего подходящего я не нашел, но зато натолкнулся на такое демо возможностей JavaScript-библиотек от разработчиков Camunda. Это ведь то, что надо! На свой вопрос о планах разработки плагина для Bitbucket на форуме я получил отрицательный ответ. Поэтому пришлось собраться с мыслями и сделать плагин самому.

Разработка плагина для Bitbucket


На момент начала разработки плагина я понятия не имел о том, как это делать, поэтому, как настоящий разработчик, сначала спросил у Google: «bitbucket plugin development». Google первым же результатом выдал страницу Beginner guide to Bitbucket Server plugin development. На этой странице мы узнаём, что есть две версии продукта: Bitbucket Server и Bitbucket Cloud. Нас интересовал Bitbucket Server. Поэтому дальнейшие шаги будут относиться только к разработке для него.

Следует заметить, что у документации Atlassian есть одна особенность: информация разбросана по множеству различных страниц, слабо связанных друг с другом. Такое впечатление, что по мере развития в документацию добавляют новые разделы, но при этом не пересматривают старые. Такой подход затрудняет поиск необходимой информации. К тому же нередко встречаются битые ссылки. Я пытался писать репорты об этом, но ситуация не меняется.

В этой статье я попробую сэкономить время тем, кто впервые сталкивается с разработкой плагинов для продуктов Atlassian, направив на действительно важные страницы и поделившись существенной информацией.

Самая важная страница — это, пожалуй, страница с инструкциями по установке, ссылкой на шаблонный проект и инструкциями по его запуску: Getting started. Шаблонный проект представляет собой полноценный проект с настроенной сборкой, нужными зависимостями, примерами добавления различных расширений и т.п. Необходимо лишь кое-что переименовать по прилагаемой инструкции, и можно добавлять свои расширения.

Существует два способа добавления своих элементов в UI Bitbucket на стороне клиента: Client Web Fragments и Client-side Extensions (aka CSE). Второй способ появился в Bitbucket Server 7 и предполагает постепенное замещение первого способа. Пока CSE доступны только на страницах, связанных с пулл-реквестами.

В CSE входят пять типов расширений: кнопка, ссылка, модальное окно, панель, страница. Все типы описаны на соответствующих страницах с примерами использования. Чтобы определить, какие элементы страницы предполагают расширение с помощью CSE, достаточно добавить ?clientside-extensions к URL страницы. При переходе на такой URL подходящие места будут подсвечены специальной иконкой, при нажатии на которую можно узнать:

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

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

Client Web Fragments я подробно рассматривать не буду, так как при реализации плагина этим инструментом воспользоваться не пришлось.

Помимо расширений на стороне клиента разработчику доступен механизм Plugin modules с разнообразным функционалом. Например, можно добавить свои ресурсы (CSS, JS и т.д.) и таким образом адаптировать поведение и UI под свои нужды.

Трудности


Первая трудность, с которой я столкнулся при попытке запустить шаблонный проект, заключалась в том, что расширения, реализованные в проекте, не появляются в UI Bitbucket. В логах старта обнаружилась ошибка, которая сообщала, что плагин не запускается из-за какого-то несоответствия версии библиотеки. После достаточно продолжительной медитации, гугления и исследования админки Bitbucket, причина нашлась: шаблонный проект требовал библиотеку обработки CSE версии 1.2.3. При этом на сервере оказалась установлена библиотека версии 1.0.0. Для решения этой проблемы необходимо модифицировать шаблонный проект, добавив следующий фрагмент в конфигурацию bitbucket-maven-plugin:

   com.atlassian.maven.plugins
   bitbucket-maven-plugin
        ....
        
            
                com.atlassian.plugins
                atlassian-clientside-extensions-page-bootstrapper
                1.2.3
            
        
    

Трудность № 2. Мне необходимо было реализовать следующую логику на стороне клиента: получение двух версий содержимого BPMN-файла через REST API Bitbucket, построение модели BPMN, сравнение, отрисовка и раскраска схем. Отрисовка и раскраска требует возможности добавления собственного HTML-кода и подключения собственных стилей.

Единственным подходящим местом размещения управляющего элемента для переключения в режим графического сравнения схем оказалась шапка панели сравнения: она поддерживает CSE и обеспечивает отображение необходимого контекста (информации о проекте, репозитории, текущем выбранном файле для сравнения и номерах ревизий двух версий файла). Здесь поддерживается три типа расширений: кнопка, ссылка и модальное окно. Очевидным решением виделось использование модального окна: в этом случае пользователь оставался бы на той же странице и не терял бы контекст. Однако при использовании модального окна я столкнулся с двумя проблемами:

  1. У модального окна есть несколько предустановленных размеров и нельзя указать произвольный размер. В частности, нельзя нарисовать модальное окно на весь экран, что является желательным для отрисовки схем.
  2. Сейчас нет возможности привязать свои ресурсы к расширениям CSE. Либо я не обнаружил такого способа. Можно попробовать добавить JS-код и CSS-классы внутрь кода модального окна (и я даже смог это сделать и отрисовать схемы), но в результате получается совершенно неподдерживаемый кусок кода, который было бы стыдно показывать людям. К тому же это не решает первую проблему.

Далее я попробовал использовать другой тип CSE: страницу. Её использование решает первую проблему модального окна, но не решает вторую: со страницей я тоже не нашел адекватного способа подключения своих ресурсов.

Промучившись какое-то время, мне пришло в голову, что у Atlassian должна быть какая-то поддержка, форум для разработчиков. Форум быстро обнаружился и я задал в подходящем разделе свой вопрос: https://community.developer.atlassian.com/t/alternative-diff-view-plugin/43717. Однако, ответа так и не дождался. И это трудность № 3, с которой я столкнулся: низкая активность сообщества в целом и представителей Atlassian в частности. Спустя 17 дней после того, как я задал вопрос, я сам же на него и запостил ответ. Заодно ответил на вопрос другого разработчика в соседней теме, который также ждал 17 дней.

В конце концов мне удалось решить свою задачу. Я использовал кнопку CSE на странице сравнения, которая открывает новую вкладку со страницей, где отрисовывается графическое сравнение схем. Для отдельной страницы я использовал Servlet plugin module, который поддерживает подключение статических ресурсов. А для самого подключения я применил Web Resource plugin module.

Чтобы использовать Servlet plugin module, необходимо реализовать свой сервлет, генерирующий HTML-код страницы. Очевидно, что отдавать контент сервлет должен только аутентифицированным пользователям. Но как это обеспечить? Если покопаться в примерах кода на ресурсах Atlassian, то можно обнаружить необходимый код для Jira с использованием её библиотеки, которая не подходит для Bitbucket. Но этот код наводит на мысль, что подобный API должен быть и у Bitbucket (хотя прямого описания в документации я не обнаружил). После некоторых поисков обнаружилась нужная библиотека:


   com.atlassian.bitbucket.server
   bitbucket-api
   ${bitbucket.api.version}
   provided


В этой библиотеке есть класс AuthenticationContext с искомым методом isAuthenticated (). Осталось только заавтовайрить этот класс в классе сервлета.

Аналогичная проблема с библиотекой генерации HTML по шаблону (в моем случае это шаблон Velocity). Необходимо подключить библиотеку:


   com.atlassian.templaterenderer
   atlassian-template-renderer-api
   ${atr.version}
   provided


И далее использовать ее в сервлете:
templateRenderer.render(TEMPLATE_PATH, params, response.getWriter());

Трудность № 4 заключалась в том, что совершенно непонятно, что за библиотеки тебе нужны для решения вполне обычных задач. В документации это либо не описано, либо находится где-то очень глубоко (поправьте меня, если я вдруг ошибаюсь).

И последний совет. Опытным frontend-разработчикам, наверное, это покажется очевидным, но я дошел до этого не сразу. Используйте режим инкогнито в браузере для тестирования своих плагинов. Это сэкономит много времени и нервов, которые были бы потрачены на поиски «странных» багов.

Результат


У меня получился плагин для Bitbucket Server версии 7. Плагин добавляет кнопку «BPMN Visual Diff» в шапку панели сравнения:

7wzgqwyrq7fo5_dfrkfrkt0av8o.png

Кнопка отрисовывается только в том случае, если для сравнения выбран файл с расширением .bpmn. Таким образом, пользователи, не использующие BPMN, даже не заметят изменений.

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

rqjglilvw6qvfqmochbum7rjchi.png

Исходный код проекта плагина доступен на GitHub под лицензией MIT. Пожелания, критика и пулл-реквесты приветствуются. В ближайших планах — адаптация плагина для Bitbucket Server версии 6.

© Habrahabr.ru