После того, как пользователь авторизовал сервис, BitBucket отправляет код авторизации на указанный при регистрации агента адрес (URL) в виде HTTP GET запроса. Обработка запроса выглядит следующим образом:
app.get('/BitBucket/auth', (req, res) => {
const code = req.query.code;
if (code) {
BitBucketClient.authorizeUser(code);
} else {
res.sendStatus(400);
return;
}
res.sendStatus(200);
});
Полученный код в последствии используется для получения токена доступа и токена обновления. Данная процедура необходима для выполнения запросов к BitBucket API, связанных с операциями с приватной информацией, а также операциями, выполняемыми от лица пользователей (к примеру, сброс состояния одобрения возможен только самим проверяющим). Для авторизации запроса сервиса, необходимо добавить данные токена в HTTP заголовок Authorization.
Jira, в отличие от BitBucket, использует протокол OAuth (RFC 5849), которая не требует постоянного обновления токенов. Кроме того, операции, выполняемые сервисом в Jira, не требуют персональных токенов, поэтому был создан сервисный аккаунт, от лица которого выполняются все операции с задачами в Jira. В остальном, механизм авторизации соответствует описанному для OAuth2 в BitBucket.
Взаимодействие с BitBucket и Jira.
Сервис получает уведомления о новых событиях в системе посредством механизма Webhooks. Панель управления BitBucket позволяет настроить отправку уведомлений по различным категориям событий и на различные URL. Тип события передаётся в заголовке “X-Event-Key” HTTP POST запроса, генерируемого BitBucket. Помимо типа события, передаётся объект данных, над которым было произведено действие. Так, в теле запроса события “pullrequest:created” содержится только что созданный запрос на включение изменений. Пример тела запроса представлен в Приложении F.
Обмен информацией между сервисом и внешними системами происходит по протоколу HTTPS. Сервис использует GET запросы для получения и POST отправки данных. Операции выполняются асинхронно, что позволяет обеспечить быстродействие системы, поскольку одновременно могут обрабатываться несколько событий [10].
Для поддержки асинхронности кода используется механизм Promise и ключевые слова async / await. Async указывает на то, что данная функция асинхронная, и поток может продолжать выполнение без ожидания завершения функции. Await позволяет дождаться выполнения метода в требуемом участке кода (в своего рода критической точке). Работа данного механизма схожа с аналогичным в языке программирования C# и доступна с версии JavaScript ES6 и NodeJS 7.8. Цель функций async/await упростить использование асинхронных функций и обратного вызова функций, сохранив при этом линейную структуру кода без потерь в производительности.
Обработка разницы файлов с помощью git-diff.
REST API BitBucket позволяет запрашивать разницу файлов для различных объектов: ревизий (между коммитами), веток и тэгов. Сервис использует разницу веток (между веткой задачи и целевой веткой) при назначении проверяющих и разницу ревизий при сбросе статусов одобрения у существующих проверяющих.
Git-diff является стандартной операцией для всех Git систем контроля версий [8]. Помимо полной разницы, команда поддерживает опции, позволяющие получить только имена файлов или разницу конкретных файлов. Однако, API BitBucket не поддерживает опциональные параметры, возвращая только полную разницу. Ответ сервера представляет собой простой текст следующего вида:
diff --git a/about.html b/about.html
index d09ab79..0c20c33 100644
--- a/about.html
+++ b/about.html
@@ -19,7 +19,7 @@
</div>
<div id="headerContainer">
- <h1>About</h1>
+ <h1>About This Project</h1>
</div>
<div id="contentContainer">
Для работы сервиса требуется определить, какие файлы были изменены. В данном примере, первая строка и вторая строки содержат информацию о том, какие ревизии сравниваются (формально, разница между ветками, это разница их последних ревизий). Следующие две строки содержат данные о соответствующих файлах, измененных в конечной ревизии. В данном случае, префиксы a и b указывают, из какой ревизии взят файл (a - начальная, b - конечная). Далее следует детальное различие между файлами, а после его окончания идёт следующий блок, содержащий ту же информацию для другого файла (при наличии).
Также, файлы могут добавляться в проект или удаляться из него. В случае добавления, во третьей строке будет содержаться “a/null” (файла не существовало), в случае удаления - наоборот, в строке конечной ревизии будет “b/null”.
При обработке git-diff сервис разбивает ответ сервера на блоки, соответствующие отдельным файлам, а затем, при помощи регулярного выражения получает имена файлов и их состояние (измененный, новый, удаленный). Полученная информация передаётся обработчику события и затем используется Reviewers service для назначения проверяющих и формировании отчёта менеджеру проекта.
Также, для удобства обновления карты ответственности, сервис определяет перемещения и переименования файлов, используя алгоритм схожести строк (библиотека string-similarity). После того, как изменения в ветке были совершены и задача принята, сервис пытается найти файлы, похожие содержанием и наименованием на удалённые, среди добавленных. При определении степени схожести используется стандартный для Git-diff коэффициент 0.5 (50%) [8].
Развёртывание сервиса автоматизации.
Для работы сервиса необходима его публикация в сети интернет. На данном этапе работы сервиса не требуется высокая производительная мощность сервера, поэтому компания выделила место на виртуальной машине, работающей рамках её домена. Данное решение, помимо экономии средств, продиктовано ещё и требованиями безопасности: для шифрованного взаимодействия с BitBucket и Jira используется протокол HTTPS, требующий наличия SSL сертификата. Ввиду того, что на используемом сервере и соответствующем ему домене уже имеется SSL сертификат, процедура настройки и регистрации не требуется.
Сервер, на котором работает сервис, является виртуальной машиной и базируется в облачном хостинге Amazon EC2. Операционной системой является Microsoft Windows Server 2010, в качестве веб сервера (обратного прокси) используется Microsoft IIS 7.5. Поскольку для хранения данных предусмотрен уже существующий сервер СУБД, установка и настройка экземпляра Microsoft SQL Server не требуется.
Для работы сервиса, разработанного на Node.js требуется наличие среды исполнения, которая находится на официальном сайте фреймворка. Для поддержки последних нововведений среды и стабильной работы сервис использует последнюю LTS сборку Node.js версии 8.11.1 (по состоянию на 02.05.2018).
Запуск сервиса происходит посредством выполнения команды “node app.js” в командной строке Windows из директории с исходным кодом приложения. Однако, при этом возникают две проблемы: необходимость в постоянной открытой командной строке и отсутствие автоматического перезапуска сервиса при критических ошибках или перезагрузке сервиса[5]. Для того, чтобы решить данные проблемы, используется сервисный менеджер NSSM с открытым исходным кодом, который позволяет упаковывать исполняемые команды в службы Windows. Используя встроенные в Windows механизмы служб, сервис автоматически запускается при старте системы и возобновляет работу, в случае экстренного завершения работы. Также, посредством системы событий Windows ведётся архив работы сервиса, что позволяет восстановить логику работы в случае ошибок или неправильного выполнения алгоритма [7].
Поскольку служба работает «всегда», если возникает некоторая ошибка, невозможно остановить экземпляр и отладить некорректные процессы, так как данные и события являются уникальными для конкретной операции [4]. Кроме того, микросервис выполняет несколько операций для каждого события, поэтому также могут возникать каскадные ошибки [7]. Для того, чтобы быть уверенным, что все работает так, как ожидается [6], потому что вы даже при работе с небольшим проектом могут возникать непредвиденные ошибки[8], служба регистрирует свою работу, события, ошибки и запросы в журналах (логах). Эти журналы структурированы и содержат всю необходимую информацию для воссоздания состояния службы из моментального снимка.
В процессе разработки сервиса, была создана база данных с использованием СУБД Microsoft SQL Server, реализованная в соответствии с схемой базы данных, построенной в разделе 2.2. Также, дополнительно реализован уникальный индекс для названий файлов в таблице с текущими файлами проекта.
Пользовательский интерфейс, разработанный для приложения, является веб страницей и разработан с использованием CSS фреймворка Bulma и движка разметки Handlebars. С помощью данных средств интерфейс открыт для дальнейшего расширения и стилизации, при этом используя шаблонные средства, позволяющие сохранить простоту в поддержке решения.
При разработке сервиса была произведена интеграция приложения с BitBucket и Jira с применением авторизации на основе токенов доступа (OAuth2 и OAuth соответственно). Также, для обработки событий BitBucket, были созданы конечные точки и настроена подписка на механизм Webhooks. Сервис, реагируя на события, обменивается данными с REST API обеих систем, используя специально разработанные клиенты. Помимо метаданных, сервис также получает и обрабатывает Git-diff, на основе которого сопоставляется список файлов и карта ответственности.
Сервис был развёрнут на виртуальной машине в облаке Amazon EC2 под управлением ОС Windows Server 2010 в качестве службы Windows и опубликован в сети интернет на домене компании по адресу https://bbapprovals.6grain.com:4431.
Заключение
В ходе написания данной выпускной квалификационной работы был проанализирован процесс разработки программного обеспечения в компании «6th Grain», в частности, процесс проверки кода, который является «узким» местом и значительно ухудшает общую производительность команды разработки. Были выделены проблемные зоны процесса, построена TO-BE модель процесса проверки кода, опирающаяся на современные практики крупных ИТ-компаний.
Для реализации новой модели процесса проверки кода, был спроектирован сервис автоматизации, распределяющий задачи на проверку кода между проверяющими на основании карты ответственности, и управляющий рабочим процессом. Проектирование сервиса происходило с использованием UML, в частности были построены диаграммы прецедентов, последовательностей и компонентов.
На этапе разработки сервис был реализован в качестве REST API, базирующегося на серверном фреймворке Node.js. Сервис взаимодействует с BitBucket и Jira используя механизмы Webhooks, а также напрямую через собственные REST API систем. Сервис также включает в себя два микросервиса, призванных снизить централизацию вычислений в одном компоненте. Исходный код приложения является открытым и доступен в Git репозитории по адресу: https://github.com/almostcake/code-review-service.
Во время развёртывания сервис был успешно запущен на облачном хостинге Amazon EC2 в качестве службы Windows с использованием сервисного менеджера NSSM. Также, сервис обладает веб интерфейсом и системой записи логов. Актуальная версия сервиса доступна в сети интернет по адресу https://bbapprovals.6grain.com:4431. Первичный запуск сервиса состоялся 16.04.2018.
Говоря про результаты от внедрения сервиса, можно отметить, что участники процесса разработки высоко оценивают позитивное влияние автоматизации процесса проверки кода на производительность работы в целом. Оптимизация процесса разработки напрямую снижает затраты компании и дает возможность расти дальше, потому что рабочий процесс готов удовлетворить большие потребности команды. Однако, у сервиса есть потенциал для расширения функционала относительно итерационных проверок, а также возможной интеграции в BitBucket в качестве виджета.
Процесс разработки является итеративным, и служба автоматизации будет усовершенствоваться на основе обратной связи сотрудников и новых требований, которые возникают из-за стремительной жизни в ИТ-индустрии. Таким образом, сервис поддерживается и развивается, чтобы в дальнейшем отвечать требованиям компании и её сотрудников, автоматизируя процессы, требующие рутинной работы.
BitBucket - Atlassian BitBucket Cloud, корпоративная система контроля версий, хранилище исходного кода.
Jira - Atlassian Jira Cloud, корпоративная система управления задачами.
Ревью, code review - проверка кода.
Pull request - запрос на включение изменений (слияние) в основную ветку.
Git - распределённая система управления версиями.
Webhook - способ асинхронного взаимодействия посредством обратного вызова HTTP методов.
REST - Representation State Transfer, архитектурный стиль взаимодействия компонентов распределённого приложения в сети.
LTS - Long Term Support, долгосрочная поддержка.
API - Application Programming Interface, набор готовых классов, процедур, функций, структур и констант, предоставляемых приложением (библиотекой, сервисом) или операционной системой для использования во внешних программных продуктах.
Токен - программный объект, содержит информацию о безопасности сеанса и идентифицирует пользователя, группу пользователей и пользовательские привилегии.
Литература
1. Cohn, M. H. Agile Estimating and Planning. - Stoughton, MA, USA: Prentice Hall, 2005.
2. Cohen, J. A. 11 Proven Practices for More Effective, Efficient Peer.
3. Cohen, J. A. Best Kept Secrets of Peer Code Review. - Beverly, MA, USA: SmartBear, 2013.
4. Newman, J. W. Building Microservices: Designing Fine-Grained Systems. - Sebastopol, CA, USA: O'Reilly Media, 2015.
5. Van Steen, M. Distributed Systems / M. Van Steen, A. S. Tanenbaum. - Enschede, Netherlands: University of Twente, 2017. - pp. 1-66.