Один бот от всех забот

Пока не принята конвенция «О защите прав нечеловеческой личности», нужно этим пользоваться и отдавать рабочую рутину ботам. Есть смысл начать прямо сейчас, а то через 5 лет начнется восстание машин, массовые иски об оскорблении чувств ботов скучными задачами заполонят суды по регулированию отношений «человек-машина». Так что поторопитесь.
ogrlmoadcpzks4cxhqcjncpweyc.png

Консервативный распорядок и метод работы, рабское следование заведённому шаблону, превратившееся в механическую привычку. 6 букв.


Есть такая работа, которую делать не хочется, но нужно. В этой статье не будет больших вставок с кодом и инструкции как создать своего бота с нуля. Лучше я расскажу как устроен релизный процесс у нас в Dodo Pizza, как мы автоматизируем и ускоряем его, отдавая часть скучной рутины нашему боту, написанному на C#. Уделю внимание функционалу и логике работы бота. Будет круто, если этот материал вдохновит вас на написание своего помощника, который облегчит жизнь вам и вашим коллегам.

Пару лет назад мы выпускали один релиз раз в неделю. В мае 2018, имея максимальный показатель 147 часов на релиз, мы ставили цель релизиться каждый день. Сейчас наш минимум: четыре часа на релиз, но такое происходит не часто. Мы хотим закрепить рекорд и иметь возможность свести весь процесс к нажатию одной кнопки.

Релизный цикл


Сейчас в Dodo IS семь команд по очереди занимаются выпуском релиза. Один человек от команды становится «счастливчиком» — релизмэном. Релизмэн как пилот самолета: у него куча рычажков и приборов, которыми нужно умело орудовать, чтобы выкатить очередные обновления. Мы подумали и решили: «Пришло время сделать автопилот, а своё время лучше потратим на что-то более захватывающее, чем заполнение скучных таблиц со статистикой и слежку за прогонами автотестов».

Итак, чтобы стать релизмэном, нужно чтобы до твоей команды дошла очередь. Чтобы всё было наглядно и никто не путался, мы наклеили на стену стикеры с названиями команд. Релизная команда получает почетную корону, которую мы каждый раз передвигаем ручками.

После получения черной метки короны релизмэн должен вспомнить, где лежит чек-лист шагов релиза. Далее: вспомнили → нашли → создали копию из шаблона и, наконец, открыли чек-лист в системе Kaiten. Kaiten — это электронная доска, на которой в виде карточек мы размещаем и следим за состоянием задач в разработке. Для новых разработчиков эта процедура в целом была весьма неочевидной. Да и откуда узнать, где искать этот чек лист и с чего начинать, когда нет никаких подсказок?

Собрав волю в кулак, мы решили, что хватит это терпеть. Пришло время отдать часть скучной рутины боту. Кто, если не мы? Когда, если не сейчас?

Что нам удалось автоматизировать


Решение принято, пора начинать конструировать наш автопилот! Найдя Kaiten API тут: https://faq.kaiten.io/docs/api, мы всего одним запросом создали карточку для нового релизмэна.

 //  Делаем POST запрос на создание карточки
var createCardRequest = new RestRequest("https://.kaiten.io/api/latest/cards/", Method.POST);

// Добавляем  информацию для авторизации
AddBasicAuth(createCardRequest); 

// В теле запроса укажем на какой доске со-дать карточку и как ее назвать
createCardRequest.AddJsonBody( 
   new
   {
       board_id = _kaitenSettings.ReleasesBoardId,
       column_id = _kaitenSettings.ReleasesColumnId,
       lane_id = _kaitenSettings.ReleasesLaneId,
       title = $"release-{nextReleaseNumber}"
   }
);

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

Логика здесь такая:

1. Предыдущий релизмэн завершает релиз, набирая в Slack команду для бота.
2. Бот берет ID релизмэна в Slack и ищет, в какой команде разработчиков числится наш счастливчик. Для этого бот пробегается по группам пользователей Slack и смотрит, в какой их них состоит наш релизмэн.
3. Найдя группу, бот смотрит, какая команда будет релизить следующей и отправляет в общий чат оповещение. В сообщении бот заботливо дает ссылку на уже созданный чек-лист, чтобы никуда за ним не ходить.

apwhrub9rb0yyjd8ypnutxgqlli.png

1ysb0iyt7rvotwmgeedjp82tkm8.png

Прекрасно! Теперь у нас есть подсказка что делать дальше. Открываем чек-лист, смотрим в него: «Создайте канал для релиза в Slack, пригласите туда все команды, чьи изменения есть в релизе и узнайте у них, нужно ли будет ручное тестирование». Осталось научить этому нашего бота.

Открываем документацию по Slack API тут https://api.slack.com и ищем там метод создания канала.

4spqnjtah8zglsoss4xtqbp-lzq.png

Как видите, в Slack, как и в других инструментах, нет ничего сложного. Все сводится к отправке одного POST запроса с двумя обязательными параметрами (это те, напротив которых написано required). В запросе нам нужно передать название создаваемого канала (параметр name) и авторизационный токен (параметр token). Обратите внимание на строчку «Works with: Token type — user, required scope (s) — channels: write».

У Slack есть два типа токенов: user — выдается пользователям и bot — выдается приложениям. При выдаче токена, мы определяем какими правами наделить его владельца. Чтобы создавать каналы, нам нужен пользовательский токен (token type — user), у которого есть права на чтение каналов (channels: write).

Хочу отметить один нюанс нашей отправки сообщений в Slack. Изначально мы не продумали, что будем делать, если что-то пойдет не так. Мы набираем команду в Slack, и она выполняет все задачи, которые мы в нее вложили. А что будет, если на одной из задач в составе команды упадет? В нашем случае ответ был: «ничего». И это плохо. Решением для нас стало писать в релизный чат, какое действие сейчас выполняется, и если команда не выполнилась, сообщать об ошибке в чат и логировать ошибку.

Вторым удачным решением стало подключение базы данных, в которой мы храним состояние выполнения действий команд. Теперь, стартовав новый релиз с помощью команды »/startregress» мы не боимся что что-то упадет, а при повторном вызове команды будут выполняться с начала по второму разу. Нам ведь не нужно каждый раз создавать новый канал в Slack, делать пулл-реквест и т.д. Создали канал в Slack — записали в базу статус об успешном выполнении и больше не возвращаемся к этому действию.

hbqacnv-qupq_tztgccgathkyri.png

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

Следующими на очереди стали интеграция с Github и TeamCity. Работаем мы по Gitflow. Когда хотим релизиться, берём ветку DEV, рабочую = зеленую = на которой проходят тесты, и от нее создаем релизную ветку.

Для этого наш бот идет в TeamCity, смотрит там на запуск тестового прогона для ветки DEV. Если тесты зеленые, как трава у дома, — вперед в GitHub, создавать релизную ветку и пулл-реквест!

При создании пулл-реквеста нам нужно добавить описание изменений, которые мы выкатываем. Тут нам на помощь приходит Kaiten. Наш бот создает колонку с названием релиза, берет задачи из колонки DEV и перемещает их в релиз. Так мы знаем и видим что у нас будет зарелижено. После перемещения бот копирует названия карточек и добавляет их в описание пулл-реквеста со ссылкой на сами карточки. Теперь мы можем по каждому релизу посмотреть, какие задачи в нем вышли и, открыв карточку по ссылке, узнать все подробности по этим задачам.

x30x-klbu6uiajhs9bipupayflc.png

Почти можно релизить, осталось только хорошенько протестировать наши изменения. Для этого релизная ветка деплоится на окружение, приближенное к продакшн (называем мы его stage), и после деплоя тестируется. Деплой и тесты у нас собраны в один пайплайн в TeamCity, а наша задача сводится к его запуску, и ожиданию, скрестив пальцы, что тесты пройдут нормально. Бот запускает пайплайн во время старта регресса.

Напомню, что мы начинали с того, что все это делалось вручную. Стиснув кулаки, релизмэн переключался по ссылкам и инструментам: TeamCity, Kaiten, Slack, Github и это еще не всё! А теперь у нас есть целый набор действий из которых уже сформирована первая команду для бота. Релизмен набирает »/startregress» и откинувшись на спинку кресла наблюдает как наш бот:

  • создает канал в мессенджере
  • зовет туда всех, кого нужно
  • проверяет, можно ли создавать пулл-реквест
  • создает пулл-реквест и заполняет его описание
  • создает релизную колонку на электронной доске и передвигает туда карточки с задачами
  • запускает пайплайн, который задеплоит на окружение релизную ветку и прогонит там тесты

Весь релизный процесс мы анализируем, записываем, сколько времени занимает каждый этап релиза. Это дает разработке и бизнесу понимание, на что тратится время и что тормозит нас в доставке новых фич пользователям. Сидим два дня и не можем прогнать тесты?! Значит что-то не так с нашими тестами, нужно уделить им больше времени и внимания. Раньше, выполняя действия нашего чек-листа, мы заходили в Google Sheets минимум 5 раз. Каждый раз вписывая туда по одной дате и ставя время.

mufq6drstsaqsbrb3m6mme6piei.png

Окей, Google, автоматизируем и тебя! Чтобы легко и непринужденно работать с таблицами подключаем к проекту нашего бота nuget-пакет Google.Apis.Sheets.v4. А дальше все происходит по аналогичной с другими сервисами по схеме: мы отправляем запрос, в котором говорим какое значение в какую ячейку вставить. Выглядит этот запрос так:

public void InsertEntry(string cellAddress, string value)
{
// Задаем из настроек лист  в который будем вставлять значение - _googleSettings.SheetName и адрес ячейки в которую вставляем значение - cellAddress
   var range = $"{_googleSettings.SheetName}!{cellAddress}";
   var valueRange = new ValueRange();

// Добавляем значпение которе нужно вставить в ячейку - value
   var objectsList = new List {$"{value}"};

   valueRange.Values = new List> {objectsList};

// Используя метод библиотеки Google.Apis.Sheets.v4 отправляем запрос на вставку значения в ячейку таблицы и идентификатором SpreadsheetId
  
   var insertEntryRequest =
       _service.Spreadsheets.Values.Update(valueRange, _googleSettings.SpreadsheetId, range);
   insertEntryRequest.ValueInputOption =
       SpreadsheetsResource.ValuesResource.UpdateRequest.ValueInputOptionEnum.USERENTERED;
   insertEntryRequest.Execute();
}

Настроив интеграцию с Google, мы подготовили вторую команду нашего бота »/update» и вот что она делает:

  • добавляет пустую строку, чтобы вставлять в нее значения
  • идет в GitHub, смотрит когда создали релизную ветку и добавляет дату ее создания в табличку
  • из TeamCity берет данные о первом запуске пайплайна и информацию о том, когда пайплайн успешно финишировал


Следующим шагом релизмен катит релиз. Сейчас выкладка производится вручную. Выложив одну страну мы смотрим, как релиз ведет себя на бою. Убедившись, что все хорошо по логам и инструментами мониторинга Kibana и Grafana, мы выкладываем следующую страну. Этот процесс уже не так просто автоматизировать. Но и здесь есть что улучшить, пусть и не с помощью бота. Например, раньше мы каждый раз спрашивали у команды инфраструктуры можно ли релизиться. Потому что когда мы собирались это делать, на наших серверах могли проходить другие работы и наш релиз пришелся бы некстати.

Мы собрали встречу по оптимизации процесса релиза. Одним из решений было то, что теперь релизмен просто смотрит статус в одном из каналов Slack, где инфраструктура вывешивает разрешение на «взлет». Это удобней, чем постоянно спрашивать одно и то же и в 90% случаев получать ответ «Можно».

tfmidcakdy0dn1m2q9ywvgqb9g4.png

Такие, казалось бы, элементарные вещи почему-то сразу не пришли в голову. Отдельное спасибо стоит сказать новым разработчикам в компании. Придя к нам они рано или поздно становились релизмэнами. Ребятам, которые работали у нас давно, процесс не казался чем-то сложным, скорее чем-то привычным. Новые члены команды обратили наше внимание на точки роста и приняли активное участие в организации работы по улучшениям.

Тем временем мы подошли к последнему этапу. Наш релизный лайнер приземлился, от конца нас отделяет всего одна команда »/releasecomplete». Что она делает:

  • мерджит пулл-реквест с релизом в ветку master
  • удаляет релизную ветку
  • создает описание релиза в GitHub
  • архивирует релизный канала в Slack
  • передвигает карточки в Kaiten из колонки «release-…» в колонку «Done» и удаляет релизную колонку
  • передает эстафету, приглашая релизить следующую команду

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

© Habrahabr.ru