Как я подружил BPMN и Bitbucket
Проблема
Некоторые наши команды используют нотацию BPMN для описания бизнес-процессов, которые мы реализуем. Недавно мой коллега рассказал, как мы пришли к применению BPMN. В качестве движка исполнения бизнес-процессов мы используем платформу Camunda, популярность которой, как мне кажется, обусловлена несколькими важными факторами:
- Отличный инструментарий. Сюда входят инструменты для моделирования, мониторинга, анализа бизнес-процессов.
- Отличная документация, полная и подробная.
- Возможность тонкой настройки под свои нужды благодаря огромному количеству настроек среды исполнения.
- Возможность расширения базовой функциональности через реализацию своих плагинов.
- Сообщество. Разработчики Camunda организуют конференции, митапы, записывают обучающие видео, ведут тематические блоги, поддерживают диалог на форуме и, конечно, выкладывают свой код на GitHub.
И всё было бы хорошо, но есть одна существенная проблема. Нотация BPMN использует XML для описания всех шагов, связей и расположения всех элементов схемы бизнес-процесса. Существуют различные инструменты визуального проектирования схем BPMN. Одно из самых удобных — Camunda Modeler. Любое изменение визуального представления влечет за собой изменение XML-описания. Мы в командах придерживаемся практики обязательных code review, которые проводятся средствами Bitbucket в рамках пулл-реквестов. Но рецензировать изменения в большом XML-файле, который описывает визуальное представление, практически невозможно. Попробую проиллюстрировать проблему на примере стандартного сравнения текстовых файлов, которое производит Bitbucket:
В данном случае сравнение показывает нам, что всё предыдущее содержимое файла было удалено и было добавлено полностью новое содержимое. На самом же деле на схеме изменилось лишь несколько элементов, и дополнительно был отформатирован файл 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:
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>bitbucket-maven-plugin</artifactId>
…
<configuration>
....
<pluginArtifacts>
<pluginArtifact>
<groupId>com.atlassian.plugins</groupId>
<artifactId>atlassian-clientside-extensions-page-bootstrapper</artifactId>
<version>1.2.3</version>
</pluginArtifact>
</pluginArtifacts>
</configuration>
</plugin>
Трудность № 2. Мне необходимо было реализовать следующую логику на стороне клиента: получение двух версий содержимого BPMN-файла через REST API Bitbucket, построение модели BPMN, сравнение, отрисовка и раскраска схем. Отрисовка и раскраска требует возможности добавления собственного HTML-кода и подключения собственных стилей.
Единственным подходящим местом размещения управляющего элемента для переключения в режим графического сравнения схем оказалась шапка панели сравнения: она поддерживает CSE и обеспечивает отображение необходимого контекста (информации о проекте, репозитории, текущем выбранном файле для сравнения и номерах ревизий двух версий файла). Здесь поддерживается три типа расширений: кнопка, ссылка и модальное окно. Очевидным решением виделось использование модального окна: в этом случае пользователь оставался бы на той же странице и не терял бы контекст. Однако при использовании модального окна я столкнулся с двумя проблемами:
- У модального окна есть несколько предустановленных размеров и нельзя указать произвольный размер. В частности, нельзя нарисовать модальное окно на весь экран, что является желательным для отрисовки схем.
- Сейчас нет возможности привязать свои ресурсы к расширениям 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 (хотя прямого описания в документации я не обнаружил). После некоторых поисков обнаружилась нужная библиотека:
<dependency>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-api</artifactId>
<version>${bitbucket.api.version}</version>
<scope>provided</scope>
</dependency>
В этой библиотеке есть класс AuthenticationContext с искомым методом isAuthenticated(). Осталось только заавтовайрить этот класс в классе сервлета.
Аналогичная проблема с библиотекой генерации HTML по шаблону (в моем случае это шаблон Velocity
). Необходимо подключить библиотеку:
<dependency>
<groupId>com.atlassian.templaterenderer</groupId>
<artifactId>atlassian-template-renderer-api</artifactId>
<version>${atr.version}</version>
<scope>provided</scope>
</dependency>
И далее использовать ее в сервлете:
templateRenderer.render(TEMPLATE_PATH, params, response.getWriter());
Трудность № 4 заключалась в том, что совершенно непонятно, что за библиотеки тебе нужны для решения вполне обычных задач. В документации это либо не описано, либо находится где-то очень глубоко (поправьте меня, если я вдруг ошибаюсь).
И последний совет. Опытным frontend-разработчикам, наверное, это покажется очевидным, но я дошел до этого не сразу. Используйте режим инкогнито в браузере для тестирования своих плагинов. Это сэкономит много времени и нервов, которые были бы потрачены на поиски «странных» багов.
Результат
У меня получился плагин для Bitbucket Server версии 7. Плагин добавляет кнопку «BPMN Visual Diff» в шапку панели сравнения:
Кнопка отрисовывается только в том случае, если для сравнения выбран файл с расширением .bpmn
. Таким образом, пользователи, не использующие BPMN, даже не заметят изменений.
По нажатию на кнопку открывается новая вкладка, в которой производится визуальное сравнение двух версий схемы: можно увидеть удалённые, добавленные, изменённые элементы. А для изменённых элементов дополнительно можно посмотреть, какие атрибуты этих элементов изменились и как. В результате абсолютно бесполезное сравнение текстовых файлов, приведенное в качестве примера в начале статьи, превращается вот в такое визуальное сравнение:
Исходный код проекта плагина доступен на GitHub под лицензией MIT. Пожелания, критика и пулл-реквесты приветствуются. В ближайших планах — адаптация плагина для Bitbucket Server версии 6.