Continuous Delivery
Idea
TDD, BDD, CI, CD, REST-API - короткий перечень тех аббревиатур, которые гуляют по ветру, но не использовались мною. Складывалось впечатление, что я далеко от этого мира. Будучи С++ прогером, ковыряющим в основном бэкенд, я начал писать небольшое веб-приложение. Про путь от Clojure до Django рассказывать грустно (хотя Django весьма хорош), поэтому начну с момента, когда я начал прикручивать CircleCI.
Continuos Integration(CI)
CirleCI весьма приятен. Настройка проста и вполне возможно что она отсутствует, т.к. он сам все находит. Просто следуйте стандартным гайдам и настройкам своих фреймворков.
Вкусно здесь то, что отправка в ветку запускает билд там, далеко и прогон тестов. Всегда. Не будет в репозитории отныне коммита, для котого не прогонялись тесты.
CI & Tests
Для тестирования python нужен django_nose, с которым я повозился, что бы локально он умел watch. Без watch, постоянно рестартовать тесты напрягает. django_nose нужен, чтобы circleCI генерил вывод в формате xUnit. Как я понял, это одщестандартный вид вывода тестов. Дальше, circleCI сам найдет django, тесты и запустит их.
Из коробки он нашел мои тесты python + JS(npm). Про JS тестирование ниже.
Continuous Delivery(CD) to Heroku
Это был второй шаг спустя наверно пару месяцев после внедрения circleCI. Зря я тянул, теперь все проще гораздо. Много багов, которые были полученные в неудачных мержах возникли из-за отсутствия csrf, какие-то части вообще не имели тестов, поэтому им нужно ручное тестирование. Как тут без деплоя?
И ведь нужно чтобы ошибки на этом этапе были полученны как можно скорее, пока программист не потерял контекст кода, который писал и который привел к ошибке. Иначе будут затрачены лишние минуты/часы/дни в зависимости от сложности.”
Настройка была в духе нажать 2 кнопки и прикрутить API Token. Потом только начались вкусности.
Deploy dev branch
Основную работу я веду в ветке dev и когда завершаю набор задач, подходящий под концепт “новая версия”, пушу в мастер. Прекрасный кейс: запушил в dev, оно собралось и проверилось на circleCI, если все ок - задеплоилось на heroku. В slack я получаю уведомление об удачной сборке от circleCI и через пару минут открываю страничку приложения для ветки dev. Да, это отдельное приложение, ведь я же не хочу в production отправить битую сборку(когда не 100% покрытие).
По поводу пары минут и slack - heroku имеет интеграцию со slack, но она платная, а я жмот: 40$ за уведомления в месяц это перебор.
Что бы circleCI отправлял на heroku, нужно добавить в конфиг circle.yml:
deployment:
staging:
branch: dev
heroku:
appname: stage-appname
master:
branch: master
heroku:
appname: appname
Указываем с каких веток куда деплоить. Дальше circleCI и Heroku сами разберутся.
Когда задеплоен последний коммит в dev, по новой версии, и все работает, одной кнопкой отправляем это дело в master, последняя проверка и на приложение production. Его естественно нет в конфиге. Оно и правильно: развертка на production должна быть только ручной. ИМХО, конечно же. Мало ли что машине взбредет в голову.
Deploy Pull Request
Да, есть даже такие чудеса. Пока что только увидел о таком, но не использую - пока что пишу один. Может когда Костян закончит с учебой присоединится. Но чую ему не понравится делать pull-request’ы. С другой стороны, если пулька будет рабочей(а рабочей она теперь будет сразу “на продакшне”) то можно будет не парясь мержить. И писать release notes. =)
CD & React+ES2015 Transpiling
С фронтендом посложнее, сырцы написаны на jsx и к тому же вездесущие es2015 вставочки, словом все это надо превратить в обычный JS + минификация. Для этого есть babel и webpack, все просто - 1 раз настроили(как vim, ага) и прогнали - готово. Главное положить куда надо.
Загвоздка в том, что circleCI, и Heroku между собой передают кеш сырцов полученный из Git. Поэтому первый простой путь - это Windows way - хранить билды в сырцах. Я сразу отказался от этого варианта. “Наверно надо сбилдить это дела на circleCI, там ему самое место. Билдим, проверяем и отправляем. Круто!” - думал я. Сделать такое просто, достаточно настроить circle.yml в репозитории:
dependencies:
pre:
- npm i --only=dev
- $(npm bin)/webpack
Т.о. при сборке зависимостей, будет запушен билд JS’ов.
Как же сильно я расстроился, когда после успешного билда и деплоя, я увидел в приложении ошибку, о не найденных файлах. Да-да, webpack-stat.json не был найден. Он генерился как раз запуском webpack, для создания инфы по сгенереным файлам.
Эх, с горя я запушил в мастер сбилженные JS’ники и все заработало. Но жить с этим я не хотел, потому думал дальше, читал, гуглил.
Heroku Buildpacks
Да, решение оказалось тоже более-менее элегантным - побороздив просторы github’а, я наткнулся на heroku-buildpack-webpack.
Heroku ведь тоже билдом занимается. Ладно, пускай билдится тут, с тестами потом что-нибудь придумаю. На крайний случай будет дилдиться 2 раза.
Это был мой первый форк с целью использования. Исходный вариант не работал как мне нужно: он только выполнял запуск webpack’а. А ведь его сначала установить надо!
git cm "[fix] Install packs"
git poh
heroku buildpacks:set -a banking-master --index 3 https://github.com/intey/heroku-buildpack-webpack
Поправил форк, запушил и сразу заюзал где-то у себя закромах. тут понастоящему начиаешь чувствовать связь. Что ты не просто кнопки тычешь, а реально собираешь.
Но все же “ээээх”, печаль. Дабл-билд, как не эстетично. О чем это я?
C-Continuous
Дибл на CircleCI, билд на Heroku. Я понимаю билд python, ладно(хотя нет). Я понимаю, что это разные платформы и они частично конкурируют: circleCI занимается сборкой, тестированием, А Heroku как бы хостинг но еще и сборка+тестирование, только платные. Вот и получается что и тут и там сиди подбирай. Больше всего боли доставляет сборка webpack’а. Его бы собрать на circleCI, прогнать тесты на собранном-минифицированном коде(импорты в тестах придется поменять), и оправить все это собранное на Heroku. Надо бы наверно поспрашивать на их форуме. Ведь webpack жрет 1 минуту на сборку. И это с нашим метким кодом! И жрет он их 2 раза, блин!
Хотя кипишь я раньше времени навожу. Можно обойтись тестами не минифицированного кода, а сырцов как есть. Все что нужно добавить на circleCI - зависимости npm для тестов.
dependencies:
pre:
- pip install django_nose
- npm i --only=dev
Собственно все. Должно же, б***ь, работать!