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

Собственно все. Должно же, б***ь, работать!