Интересные фишки с Clojure

Полезные фишки Clojure

Язык программирования Clojure используется такими open source проектами, как NASA CMR, Cisco Threat Grid, CircleCI, Jepsen, стартапами и некоторыми крупными компаниями. В Positive Technologies мы решили попробовать применить Clojure как платформу для базовой автоматизации процессов управления разработкой программного обеспечения.

Зачем оно тимлиду

Я — тимлид в одной из команд разработки Positive Technologies Application Firewall. В один прекрасный момент размер команды превысил критическое значение, когда можно делать руками всю свою рутинную работу, и я начал писать автоматизированную систему, которая умела бы взаимодействовать с почтой, трекерами задач и системами контроля версий. Я назвал ее «автоматический тимлид».

Распределение задач — одна из рутинных процедур, которую легко автоматизировать, если в команде существует матрица компетенций: назначить исполнителя в зависимости от заголовка задачи или ее компонента можно, если уметь программно читать задачу с таск-трекера и обновлять некоторые поля в ней. Аналогичная история с автоматическим назначением по набору критериев ответственного проверяющего в пулл-реквест в системе контроля версий для рецензирования исходного кода.

В итоге, конечно, автоматический тимлид был разделен на бизнес-логику и общую библиотеку интеграций (я назвал ее Flower). О последней давай и поговорим.

Зачем оно вообще всем

Зачем мне понадобилось такое программное обеспечение, в целом понятно, но зачем же оно тебе?

Допустим, по счастливому стечению обстоятельств, у тебя есть учетные данные некоего пользователя Jira. Очень хочется на память сохранить пару тысяч задач этого пользователя (а заодно и всю его почту), чтобы развлекаться серыми осенними вечерами, почитывая занимательные комментарии. Почему бы не сделать это, написав три строчки кода?

Или ты менеджер проекта по разработке программных продуктов и решил устроить своим программистам полный KPI, замеряя производительность людей в условных пулл-реквестах на задачу. Собирать статистику с двух и более разных систем одновременно тоже можно без технических проблем.

Как вариант, ты желаешь перенести все задачи из GitLab и Jira на GitHub (потому что твой проект резко стал опенсорсным), а заодно настроить автоматическую пересылку сообщений из почты в Slack. И даже это делается не очень сложно!

Почему Clojure

Первый вопрос, который можно было бы мне задать, звучит примерно так: почему ты не выбрал Python, ведь ты с ним знаком десяток лет и он имеет все необходимые библиотеки интеграций? Не имеет. Имеет, конечно, но не все работает так гладко, как SDK на Java, созданный разработчиками систем, с которыми мы интегрируемся. А в некоторых случаях еще и не хватает многопоточности. Тут нужно заметить, что для первоначального прототипа я, конечно же, и выбрал Python, а точнее HyLang (Lisp на его стеке), но в итоге решил внимательнее присмотреться к JVM.

И второй очевидный вопрос — почему вообще Lisp? Потому что, насколько мне известно, лучший способ создать свой DSL, не изобретая новый синтаксис, — взять Lisp, проверенный временем язык с префиксной нотацией и веселыми скобочками (на самом деле это называется S-выражения), и, используя макросы, обогатить его до домена использования.

Совокупность этих двух факторов и побудила меня выбрать Clojure как язык программирования и платформу для интеграций с различными системами.

Интересные фишки с Clojure
Пример приложения, использующего библиотеку Flower

Show me the code

Чтобы начать писать на Clojure свой скрипт или даже целую систему, использующую Flower, необходимо для начала установить Leiningen (для Windows в некоторых случаях это может оказаться немного нетривиальной задачей, поэтому рекомендую взять любую *nix-систему). Если ты вдруг не знаешь Clojure, то рекомендую книгу Clojure for the Brave and True — идеальное пособие для освоения языка за пару вечеров.

Чтобы начать новый проект на базе Flower, можно воспользоваться шаблоном, набрав в терминале

При этом в файл project.clj в созданной директории проекта будет добавлена зависимость [flower "0.4.3"] — это метапакет, содержащий почти все необходимое. Для тестового приложения он нам вполне подойдет.

Давай теперь напишем наше приложение. В качестве подопытной системы контроля версий и трекера задач воспользуемся GitHub.

Для аутентификации нам понадобится добавить токен пользователя GitHub, чтобы иметь возможность делать изменения и не быть ограниченными рейтом запросов. Добавь сгенерированный для своей учетной записи токен вместо звездочек в файл .credentials.edn в домашней директории пользователя ( ~/.credentials.edn) в следующем формате:

[/crayon]
Теперь можно начать ставить эксперименты. Для этого в директории проекта запустим REPL из командной строки:

Трекеры задач

Подключим необходимые модули и определим наш трекер задач:

Давай посмотрим, что теперь содержится в определении pt-github-tracker. Для наглядности я сделал pretty-вывод и убрал не очень важные сейчас поля.

Функция get-tracker подставила авторизационные данные и развернула строковый адрес трекера задач в запись с общим протоколом flower.tracker.proto.TrackerProto. Если тип трекера не определился верно, то тип записи будет flower.tracker.default.tracker.DefaultTracker. Это поведение можно изменить, эксплицитно указав тип трекера с помощью макроса flower.tracker.core/with-tracker-type.

Получить все задачи из трекера можно следующей командой:

Самостоятельно можешь взглянуть, из каких полей состоит, например, первая задача в трекере после выборки, с помощью команды (first tasks), а затем давай сделаем полную выборку в формате JSON. Зависимость clojure.data.json приехала к нам вместе с метапакетом flower, поэтому весь оставшийся код будет выглядеть так:

Из интересных вещей, которые содержит в себе библиотека Flower при работе с трекерами задач, можно выделить еще изменение полей задачи. Делается это двумя строчками кода (и требует прав на запись):

На этом месте, конечно, вывалится ошибка о невозможности что-либо записать в репозиторий, если не хватает на это прав: RequestException Must have admin rights to Repository. (403). Но если вдруг хватает, то для первой задачи из выборки будут фактически обновлены заголовок и теги, а результатом вернется обновленная запись.

Системы контроля версий

С системами контроля версий абсолютно аналогичная история:

Знакомо, не правда ли? Во время разработки библиотеки я старался сделать так, чтобы определения для разных типов систем были похожи между собой и чтобы из названий функций было понятно их назначение.

Посмотреть, какие функции поддерживаются протоколами различных систем, можно здесь (однако идея записей в том, что обращаться к их полям можно и напрямую, минуя вызовы этих функций в протоколах; так что, если для какого-то поля не определена функция выборки, его можно выбрать из записи через функцию get).

Полистаем теперь пулл-реквесты из репозитория:

Для выбранного пулл-реквеста выведем на печать все комментарии и счетчики (например, количество комментариев LGTM):

Если вдруг у тебя есть права на запись в репозиторий, то можно смерджить пулл-реквест. Мерджить будем, только если один из комментариев содержит слово LGTM:

Системы обмена сообщениями

Пора программно почитать рабочую почту! Для этого нужно добавить в созданный раньше ~/.credentials.edn запись аккаунта Exchange. После добавления учетных данных файл может выглядеть, например, так (в примере поле :login содержит пользователя Exchange, :password — его пароль, :domain — домен Active Directory и :email — почтовый адрес пользователя):

Так как метапакет не включает в себя зависимости конкретных реализаций мессенджинговых систем, то каждую нужно указывать в project.clj эксплицитно. Для Exchange необходимо подключить пакет [flower/flower-integration-exchange "0.4.3"]. Итоговый файл проекта после этого будет выглядеть, например, так:

Перезапустим REPL, закрыв его и повторно из директории проекта выполнив команду lein repl. После этого можно приступить к подключению библиотек и определению почтового ящика:

Выберем первое сообщение из почтового ящика с загрузкой тела сообщения и отправим его же на другой почтовый ящик (фактически это не пересылка, а отправка нового сообщения с заменой получателя):

Но еще интереснее настроить автоматическую пересылку писем. Так как пакет clojure.core.async установлен как зависимость метапакета flower, то можно сразу же использовать его для асинхронной обработки входящих сообщений:

Теперь при запущенном приложении с подобным кодом все входящие сообщения будут отправляться на другой почтовый ящик сразу же, как только будут получены.

Заключительное слово

В статье я показал лишь небольшую часть примеров применения библиотеки интеграции. С этими знаниями уже можно писать небольшие сценарии ad hoc. А после погружения в Clojure можно писать и готовый программный продукт.

В моих планах — добавить в библиотеку поддержку большего числа сервисов. YouTrack, HipChat, Telegram и некоторые другие системы ждут своей очереди на добавление. Поскольку проект опенсорсный, я предлагаю тебе присоединиться любым доступным способом: даже простой фидбек в виде Issue на «Гитхабе» будет очень ценным для меня. А заведенный автоматизированно, с использованием самой библиотеки — вдвойне!

Понравилась статья? Поделиться с друзьями:
Добавить комментарий