Skip to content

Commit

Permalink
feat(framework): "hanami.rb" support added
Browse files Browse the repository at this point in the history
Resolves ajgon#43
  • Loading branch information
ajgon committed Sep 15, 2016
1 parent 9e50b70 commit 71e4f9f
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 27 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -25,6 +25,7 @@ then [add recipes to the corresponding OpsWorks actions](#recipes).
* git
* Framework
* Null (no framework)
* hanami.rb
* Ruby on Rails
* App server
* Null (no appserver)
Expand Down Expand Up @@ -141,7 +142,7 @@ you don't need to provide them here. Currently only `git` is supported.
### framework

Pre-optimalization for specific frameworks (like migrations, cache etc.).
Currently only `Rails` is supported.
Currently `hanami.rb` and `Rails` are supported.

* `app['framework']['adapter']`
* **Supported values:** `null`, `rails`
Expand All @@ -160,6 +161,9 @@ Currently only `Rails` is supported.
* **Default:** `true`
* `app['framework']['assets_precompilation_command']`
* A command which will be invoked to precompile assets.

#### rails

* `app['framework']['envs_in_console']`
* **Supported values:** `true`, `false`
* **Default:** `false`
Expand Down
11 changes: 8 additions & 3 deletions libraries/drivers_appserver_base.rb
Expand Up @@ -59,7 +59,7 @@ def manual_action(context, action)

def add_appserver_service_script(context)
opts = { deploy_dir: deploy_dir(app), app_shortname: app['shortname'], deploy_env: globals[:environment],
name: adapter, command: appserver_command(context), environment: app['environment'] }
name: adapter, command: appserver_command(context), environment: environment }

context.template File.join(opts[:deploy_dir], File.join('shared', 'scripts', "#{opts[:name]}.service")) do
owner node['deployer']['user']
Expand Down Expand Up @@ -96,20 +96,25 @@ def setup_dot_env(context)
# rubocop:disable Metrics/MethodLength
def env_config(context, options = { source_file: nil, destination_file: nil })
deploy_to = deploy_dir(app)
environment = app['environment']
env = environment

context.template File.join(deploy_to, 'shared', options[:source_file]) do
owner node['deployer']['user']
group www_group
source "#{File.basename(options[:source_file])}.erb"
variables environment: environment
variables environment: env
end

context.link File.join(deploy_to, 'current', options[:destination_file]) do
to File.join(deploy_to, 'shared', options[:source_file])
end
end
# rubocop:enable Metrics/MethodLength

def environment
framework = Drivers::Framework::Factory.build(app, node, options)
app['environment'].merge(framework.out[:deploy_environment] || {})
end
end
end
end
92 changes: 92 additions & 0 deletions libraries/drivers_framework_hanami.rb
@@ -0,0 +1,92 @@
# frozen_string_literal: true
module Drivers
module Framework
class Hanami < Drivers::Framework::Base
adapter :hanami
allowed_engines :hanami
output filter: [
:migrate, :migration_command, :deploy_environment, :assets_precompile, :assets_precompilation_command
]
packages debian: 'zlib1g-dev', rhel: 'zlib-devel'

def raw_out
assets_command = node['deploy'][app['shortname']]['framework']['assets_precompilation_command'] ||
'/usr/local/bin/bundle exec hanami assets precompile'
migration_command = node['deploy'][app['shortname']]['framework']['migration_command'] ||
'/usr/local/bin/bundle exec hanami db migrate'

super.merge(
deploy_environment: { 'HANAMI_ENV' => globals[:environment], 'DATABASE_URL' => database_url },
assets_precompilation_command: assets_command,
migration_command: migration_command
)
end

def configure(context)
build_env(context)
end

def deploy_before_restart(context)
link_env(context)
assets_precompile(context) if out[:assets_precompile]
end

private

def build_env(context)
deploy_to = deploy_dir(app)
env = environment

context.template File.join(deploy_to, 'shared', 'config', ".env.#{globals[:environment]}") do
owner node['deployer']['user']
group www_group
source 'dot_env.erb'
variables environment: env
end
end

def link_env(context)
deploy_to = deploy_dir(app)
env_name = globals[:environment]

context.link File.join(deploy_to, 'current', ".env.#{env_name}") do
to File.join(deploy_to, 'shared', 'config', ".env.#{env_name}")
ignore_failure true
end
end

def assets_precompile(context)
output = out
deploy_to = deploy_dir(app)
env = environment.merge('HOME' => node['deployer']['home'])

context.execute 'assets:precompile' do
command output[:assets_precompilation_command]
user node['deployer']['user']
cwd File.join(deploy_to, 'current')
group www_group
environment env
end
end

def database_url
database_url = "sqlite://db/#{app['shortname']}_#{globals[:environment]}.sqlite"

Array.wrap(options[:databases]).each do |db|
next unless db.applicable_for_configuration?

database_url =
"#{db.out[:adapter]}://#{db.out[:username]}:#{db.out[:password]}@#{db.out[:host]}/#{db.out[:database]}"

database_url = "sqlite://#{db.out[:database]}" if db.out[:adapter].start_with?('sqlite')
end

database_url
end

def environment
app['environment'].merge(out[:deploy_environment])
end
end
end
end
2 changes: 1 addition & 1 deletion libraries/drivers_worker_delayed_job.rb
Expand Up @@ -49,7 +49,7 @@ def process_count
end

def environment
framework = Drivers::Framework::Factory.build(app, node)
framework = Drivers::Framework::Factory.build(app, node, options)
app['environment'].merge(framework.out[:deploy_environment] || {})
end
end
Expand Down
2 changes: 1 addition & 1 deletion libraries/drivers_worker_resque.rb
Expand Up @@ -42,7 +42,7 @@ def process_count
end

def environment
framework = Drivers::Framework::Factory.build(app, node)
framework = Drivers::Framework::Factory.build(app, node, options)
app['environment'].merge(framework.out[:deploy_environment] || {})
end
end
Expand Down
2 changes: 1 addition & 1 deletion libraries/drivers_worker_sidekiq.rb
Expand Up @@ -57,7 +57,7 @@ def process_count
end

def environment
framework = Drivers::Framework::Factory.build(app, node)
framework = Drivers::Framework::Factory.build(app, node, options)
app['environment'].merge(framework.out[:deploy_environment] || {})
end

Expand Down
6 changes: 3 additions & 3 deletions recipes/configure.rb
Expand Up @@ -21,9 +21,9 @@
end

scm = Drivers::Scm::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node)
appserver = Drivers::Appserver::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node, databases: databases)
appserver = Drivers::Appserver::Factory.build(application, node, databases: databases)
worker = Drivers::Worker::Factory.build(application, node, databases: databases)
webserver = Drivers::Webserver::Factory.build(application, node)

fire_hook(:configure, context: self, items: databases + [scm, framework, appserver, worker, webserver])
Expand Down
4 changes: 2 additions & 2 deletions recipes/deploy.rb
Expand Up @@ -11,9 +11,9 @@
end

scm = Drivers::Scm::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node, databases: databases)
appserver = Drivers::Appserver::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node, databases: databases)
webserver = Drivers::Webserver::Factory.build(application, node)
bundle_env = scm.class.adapter.to_s == 'Chef::Provider::Git' ? { 'GIT_SSH' => scm.out[:ssh_wrapper] } : {}

Expand Down
4 changes: 2 additions & 2 deletions recipes/setup.rb
Expand Up @@ -37,9 +37,9 @@
end

scm = Drivers::Scm::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node, databases: databases)
appserver = Drivers::Appserver::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node, databases: databases)
webserver = Drivers::Webserver::Factory.build(application, node)

fire_hook(:setup, context: self, items: databases + [scm, framework, appserver, worker, webserver])
Expand Down
4 changes: 2 additions & 2 deletions recipes/shutdown.rb
Expand Up @@ -13,9 +13,9 @@
end

scm = Drivers::Scm::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node, databases: databases)
appserver = Drivers::Appserver::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node, databases: databases)
webserver = Drivers::Webserver::Factory.build(application, node)

fire_hook(:shutdown, context: self, items: databases + [scm, framework, appserver, worker, webserver])
Expand Down
4 changes: 2 additions & 2 deletions recipes/undeploy.rb
Expand Up @@ -9,9 +9,9 @@
end

scm = Drivers::Scm::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node)
framework = Drivers::Framework::Factory.build(application, node, databases: databases)
appserver = Drivers::Appserver::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node)
worker = Drivers::Worker::Factory.build(application, node, databases: databases)
webserver = Drivers::Webserver::Factory.build(application, node)

fire_hook(:before_undeploy, context: self, items: databases + [scm, framework, appserver, worker, webserver])
Expand Down
24 changes: 24 additions & 0 deletions spec/unit/libraries/drivers_framework_hanami_spec.rb
@@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'spec_helper'

describe Drivers::Framework::Hanami do
it 'receives and exposes app and node' do
driver = described_class.new(aws_opsworks_app, node)

expect(driver.app).to eq aws_opsworks_app
expect(driver.node).to eq node
expect(driver.options).to eq({})
end

it 'returns proper out data' do
expect(described_class.new(aws_opsworks_app, node).out).to eq(
assets_precompile: true,
assets_precompilation_command: '/usr/local/bin/bundle exec hanami assets precompile',
deploy_environment: {
'HANAMI_ENV' => 'staging', 'DATABASE_URL' => 'sqlite://db/dummy_project_staging.sqlite'
},
migration_command: '/usr/local/bin/bundle exec hanami db migrate',
migrate: false
)
end
end
47 changes: 38 additions & 9 deletions spec/unit/recipes/configure_spec.rb
Expand Up @@ -54,7 +54,7 @@
end
end

context 'Postgresql + Git + Unicorn + Nginx + Sidekiq' do
context 'Postgresql + Git + Unicorn + Nginx + Rails + Sidekiq' do
it 'creates proper database.yml template' do
db_config = Drivers::Db::Postgresql.new(aws_opsworks_app, node, rds: aws_opsworks_rds_db_instance).out
expect(db_config[:adapter]).to eq 'postgresql'
Expand All @@ -77,6 +77,9 @@
end

it 'creates proper unicorn.service file' do
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/unicorn.service")
.with_content('ENV[\'RAILS_ENV\'] = "staging"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/unicorn.service")
.with_content('ENV[\'ENV_VAR1\'] = "test"')
Expand Down Expand Up @@ -305,13 +308,14 @@
end
end

context 'Mysql + Puma + Apache2 + resque' do
context 'Mysql + Puma + Apache2 + hanami.rb + resque' do
let(:chef_run) do
ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04') do |solo_node|
deploy = node['deploy']
deploy['dummy_project']['appserver']['adapter'] = 'puma'
deploy['dummy_project']['webserver']['adapter'] = 'apache2'
deploy['dummy_project']['webserver']['keepalive_timeout'] = '65'
deploy['dummy_project']['framework']['adapter'] = 'hanami'
deploy['dummy_project']['worker']['adapter'] = 'resque'
solo_node.set['deploy'] = deploy
end.converge(described_recipe)
Expand All @@ -321,13 +325,24 @@
stub_search(:aws_opsworks_rds_db_instance, '*:*').and_return([aws_opsworks_rds_db_instance(engine: 'mysql')])
end

it 'creates proper database.yml template' do
it 'creates proper .env.*' do
db_config = Drivers::Db::Mysql.new(aws_opsworks_app, node, rds: aws_opsworks_rds_db_instance(engine: 'mysql')).out
expect(db_config[:adapter]).to eq 'mysql2'

expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/database.yml").with_content(
JSON.parse({ development: db_config, production: db_config, staging: db_config }.to_json).to_yaml
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/.env.staging")
.with_content('ENV_VAR1="test"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/.env.staging")
.with_content('ENV_VAR2="some data"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/.env.staging")
.with_content('HANAMI_ENV="staging"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/config/.env.staging")
.with_content(
"DATABASE_URL=\"mysql2://dbuser:#{db_config[:password]}@" \
'dummy-project.c298jfowejf.us-west-2.rds.amazon.com/dummydb"'
)
end

Expand All @@ -350,9 +365,18 @@
end

it 'creates proper puma.service file' do
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/puma.service")
.with_content('ENV[\'HANAMI_ENV\'] = "staging"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/puma.service")
.with_content('ENV[\'ENV_VAR1\'] = "test"')
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/puma.service")
.with_content(
'ENV[\'DATABASE_URL\'] = "mysql2://dbuser:03c1bc98cdd5eb2f9c75@' \
'dummy-project.c298jfowejf.us-west-2.rds.amazon.com/dummydb"'
)
expect(chef_run)
.to render_file("/srv/www/#{aws_opsworks_app['shortname']}/shared/scripts/puma.service")
.with_content("APP_NAME=\"#{aws_opsworks_app['shortname']}\"")
Expand Down Expand Up @@ -461,7 +485,8 @@
.to render_file("/etc/monit/conf.d/resque_#{aws_opsworks_app['shortname']}.monitrc")
.with_content(
'start program = "/bin/su - deploy -c \'cd /srv/www/dummy_project/current && ENV_VAR1="test" ' \
'ENV_VAR2="some data" RAILS_ENV="staging" QUEUE=test_queue VERBOSE=1 ' \
'ENV_VAR2="some data" HANAMI_ENV="staging" DATABASE_URL="mysql2://dbuser:03c1bc98cdd5eb2f9c75@' \
'dummy-project.c298jfowejf.us-west-2.rds.amazon.com/dummydb" QUEUE=test_queue VERBOSE=1 ' \
'PIDFILE=/srv/www/dummy_project/shared/pids/resque_dummy_project-1.pid COUNT=2 ' \
'bundle exec rake environment resque:work 2>&1 | logger -t resque-dummy_project-1\'" with timeout 90 seconds'
)
Expand All @@ -482,7 +507,8 @@
.to render_file("/etc/monit/conf.d/resque_#{aws_opsworks_app['shortname']}.monitrc")
.with_content(
'start program = "/bin/su - deploy -c \'cd /srv/www/dummy_project/current && ENV_VAR1="test" ' \
'ENV_VAR2="some data" RAILS_ENV="staging" QUEUE=test_queue VERBOSE=1 ' \
'ENV_VAR2="some data" HANAMI_ENV="staging" DATABASE_URL="mysql2://dbuser:03c1bc98cdd5eb2f9c75@' \
'dummy-project.c298jfowejf.us-west-2.rds.amazon.com/dummydb" QUEUE=test_queue VERBOSE=1 ' \
'PIDFILE=/srv/www/dummy_project/shared/pids/resque_dummy_project-2.pid COUNT=2 ' \
'bundle exec rake environment resque:work 2>&1 | logger -t resque-dummy_project-2\'" with timeout 90 seconds'
)
Expand All @@ -506,6 +532,7 @@
deploy['dummy_project']['appserver']['adapter'] = 'puma'
deploy['dummy_project']['webserver']['adapter'] = 'apache2'
deploy['dummy_project']['webserver']['keepalive_timeout'] = '65'
deploy['dummy_project']['framework']['adapter'] = 'hanami'
deploy['dummy_project']['worker']['adapter'] = 'resque'
solo_node.set['deploy'] = deploy
end.converge(described_recipe)
Expand All @@ -523,7 +550,8 @@
.to render_file("/etc/monit.d/resque_#{aws_opsworks_app['shortname']}.monitrc")
.with_content(
'start program = "/bin/su - deploy -c \'cd /srv/www/dummy_project/current && ENV_VAR1="test" ' \
'ENV_VAR2="some data" RAILS_ENV="staging" QUEUE=test_queue VERBOSE=1 ' \
'ENV_VAR2="some data" HANAMI_ENV="staging" DATABASE_URL="mysql2://dbuser:03c1bc98cdd5eb2f9c75@' \
'dummy-project.c298jfowejf.us-west-2.rds.amazon.com/dummydb" QUEUE=test_queue VERBOSE=1 ' \
'PIDFILE=/srv/www/dummy_project/shared/pids/resque_dummy_project-1.pid COUNT=2 ' \
'bundle exec rake environment resque:work 2>&1 | logger -t resque-dummy_project-1\'" ' \
'with timeout 90 seconds'
Expand All @@ -545,7 +573,8 @@
.to render_file("/etc/monit.d/resque_#{aws_opsworks_app['shortname']}.monitrc")
.with_content(
'start program = "/bin/su - deploy -c \'cd /srv/www/dummy_project/current && ENV_VAR1="test" ' \
'ENV_VAR2="some data" RAILS_ENV="staging" QUEUE=test_queue VERBOSE=1 ' \
'ENV_VAR2="some data" HANAMI_ENV="staging" DATABASE_URL="mysql2://dbuser:03c1bc98cdd5eb2f9c75@' \
'dummy-project.c298jfowejf.us-west-2.rds.amazon.com/dummydb" QUEUE=test_queue VERBOSE=1 ' \
'PIDFILE=/srv/www/dummy_project/shared/pids/resque_dummy_project-2.pid COUNT=2 ' \
'bundle exec rake environment resque:work 2>&1 | logger -t resque-dummy_project-2\'" ' \
'with timeout 90 seconds'
Expand Down

0 comments on commit 71e4f9f

Please sign in to comment.