Каждой ветке по хосту c помощью capistrano

Думаю многим знакомо понятие «борьба за staging», когда все разработчики одновременно за день до релиза хотят поделиться своими наработками, чтобы тестировщик их проверил как можно скорее и не пришлось всю ночь править баги, да? Кому интересно посмотреть как мы решаем данную проблему для RoR-проектов с помощью Capistrano прошу под кат.

4924063c43c44b13a8bb372a26fa7f0c.png


Немного об инструментах


Каждый новый тикет мы делаем в отдельной ветке, как советует это git-flow. В качестве таск-менеджера/баг-трекера мы используем JIRA, поэтому номер тикета в JIRA = названию ветки. Jenkins CI мы используем не на полную мощь, пока только для деплоя кода на staging разработческой версии после мержа в нее для интеграционного тестирования.

Суть проблемы


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

Что кроме Capistrano?


Рассматривались различные варианты от шаринга рабочей машины с помощью ngrok до SaaS наподобие teatro. Первый вариант оказался неудобен, а второй отпал потому что не все проекты есть возможность отправить третьей стороне. Поэтому ввиду того, что все наши RoR-проекты деплоятся с помощью capistrano, было принято решение написать небольшое расширение, которое будет разворачивать проект из определенной ветки на свой хост (например, jira-123.example.com).

Процесс


Если коротко, то процесс разработки выглядит так: после выполнения тикета разработчик выливает его на демо-хост, после проверки тестировщиком создается мерж реквест, после закрытия которого Jenkins выливает будущий релиз на staging.

Что делает capistrano-demo


Все то, что делает разработчик при разработке — выливает код, накатывает миграции и запускает сторонние сервисы (sidekiq, resque и т.д.).

Данный плагин имеет ряд ограничений, самое больше это то, что он работает только для RoR-проектов, и только с git.

Конфигурация

# По умолчанию используется одна БД для всех хостов, если есть деструктивные миграции, 
# то гем дает возможность вручную вписать имя БД
set :demo_db, -> { demo_default_db }

# Хост, на поддомене которого будет создавать демо-хост
set :demo_host, -> { fetch(:application) }

# Команда которую нужно выполнить при рестарте хоста.
# Пример с одно из наших проектов, где требовалось перезагрузить unicorn, nginx и sidekiq:
#      invoke 'unicorn:restart'
#      invoke 'sidekiq:restart'
#      execute :sudo, :service, 'nginx restart'
#      execute :rake, 'cache:clear'
set :demo_restart_cmd, -> { raise 'You must specify "demo_restart_cmd" proc' }

# Папка, в которой лежат шаблоны конфигов, для конкретного окружения
# Пример:
#      File.expand_path("../../../../config/stages/#{fetch(:stage)}/templates", __FILE__)
set :demo_templates_dir, nil

# Хеш, для настройки какой шаблон куда положить после компиляции, шаблоны должны быть .erb
# Пример:
#       set :demo_templates_entries, [
#            {template: '/nginx.conf.erb', file: demo_path.join('config', 'nginx.conf')},
#            {template: '/database.yml.erb', file: demo_path.join('config', 'database.yml')},
#            {template: '/unicorn.rb.erb', file: demo_path.join('config', 'unicorn.rb')},
#            {template: '/settings.local.yml.erb', file: demo_path.join('config', 'settings.local.yml')}]
set :demo_templates_entries, []


Как пользоваться


Данный плагин имеет всего три команды:

  • demo: create — создание/обновление демо-хоста
  • demo: restart — перезагрузка
  • demo: destroy — Остановка процессов (настраивается с помощью before/after) и удаление директории.


Чтобы создать демо-хост нужно просто из рабочей директории набрать команду cap staging demo: create и все. По умолчанию будет предложено вылить текущую ветку.

Заключение


На данный момент самая большая проблема это долгая сборка ассетов, нужно заставить его не пересобирать всё, а только диф. А также, чья-то миграция может сломать чужие хосты, поэтому на staging мы держим чистую базу, на такой случай. Были попытки делать отдельную БД для каждой ветки, но тогда приходилось создавать либо пустую БД, либо копировать. Первый вариант плох тем, что приходилось бы забивать контент для тестирования, а второй — нет универсального средства для копирования данных для нескольких СУБД, но в будущем планируем сделать адаптеры для SqlLite, MySql и Postgres.

Наши наработки мы выложили в открытый доступ, поэтому каждый может ознакомиться и воспользоваться, pull request’ы приветствуются.

PS: В комментариях готов ответить на ваши вопросы, выслушать альтернативные варианты решения и конструктивную критику.

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

© Habrahabr.ru