relevance_rails 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +2 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +24 -0
  5. data/README.md +101 -4
  6. data/Rakefile +10 -0
  7. data/aws_config.example.yml +15 -0
  8. data/bin/relevance_rails +2 -19
  9. data/lib/generators/deployment/deployment_generator.rb +31 -0
  10. data/lib/generators/fixtures/fixtures_generator.rb +44 -0
  11. data/lib/generators/provision_config/provision_config_generator.rb +56 -0
  12. data/lib/generators/provision_config/templates/authorized_keys.json.erb +6 -0
  13. data/lib/generators/relevance_file/relevance_file_generator.rb +14 -76
  14. data/lib/generators/relevance_file/templates/{Gemfile → Gemfile.erb} +11 -5
  15. data/lib/generators/relevance_file/templates/README.markdown.erb +36 -0
  16. data/lib/generators/relevance_file/templates/application.html.haml.erb +9 -0
  17. data/lib/generators/relevance_file/templates/database.example.yml.mysql.erb +17 -0
  18. data/lib/generators/relevance_file/templates/database.example.yml.postgresql.erb +15 -0
  19. data/lib/generators/relevance_file/templates/deploy.rb.erb +22 -0
  20. data/lib/relevance_rails.rb +26 -1
  21. data/lib/relevance_rails/chef_dna.rb +32 -0
  22. data/lib/relevance_rails/provision.rb +69 -0
  23. data/lib/relevance_rails/railtie.rb +9 -0
  24. data/lib/relevance_rails/relevance_rails_template.rb +18 -26
  25. data/lib/relevance_rails/runner.rb +24 -0
  26. data/lib/relevance_rails/version.rb +1 -1
  27. data/lib/tasks/provision.rake +8 -0
  28. data/relevance_rails.gemspec +7 -2
  29. data/script/ci +57 -0
  30. data/spec/acceptance_spec.rb +25 -0
  31. data/spec/lib/provision_config_generator_spec.rb +27 -0
  32. data/spec/lib/relevance_rails_spec.rb +15 -0
  33. data/spec/lib/runner_spec.rb +22 -0
  34. data/spec/spec_helper.rb +59 -0
  35. data/techdebt.md +15 -0
  36. metadata +115 -12
  37. data/lib/relevance_rails/template_injector.rb +0 -5
@@ -1,19 +1,24 @@
1
1
  source :rubygems
2
2
 
3
- gem 'rails', '3.1.1'
4
- gem 'haml', '3.1.3'
3
+ gem 'rails', '3.2.2'
4
+ gem 'haml', '3.1.4'
5
5
  gem 'configatron', '2.8.3'
6
6
  gem 'airbrake', '~> 3.0.4'
7
7
  gem 'factory_girl_rails', '1.2.0'
8
8
  gem 'jquery-rails', '1.0.14'
9
9
  gem 'therubyracer'
10
+ <%- if database == 'mysql' -%>
10
11
  gem 'mysql2', '~> 0.3.11'
12
+ <%- end -%>
13
+ <%- if database == 'postgresql' -%>
14
+ gem 'pg', '~> 0.13.2'
15
+ <%- end -%>
11
16
 
12
17
  # Gems used only for assets and not required
13
18
  # in production environments by default.
14
19
  group "assets" do
15
- gem 'sass-rails', '~> 3.1.4'
16
- gem 'coffee-rails', '~> 3.1.1'
20
+ gem 'sass-rails', '~> 3.2.2'
21
+ gem 'coffee-rails', '~> 3.2.2'
17
22
  gem 'uglifier', '>= 1.0.3'
18
23
  end
19
24
 
@@ -28,8 +33,9 @@ group "development", "test" do
28
33
  gem 'mocha', '~> 0.9.12'
29
34
  gem 'guard-rspec', '~> 0.5.0', :require => false
30
35
  gem 'growl', '~> 1.0.3', :require => false
31
- gem 'rb-fsevent', '~> 0.4.2', :require => false
36
+ gem 'rb-fsevent', '~> 0.9.0', :require => false
32
37
  gem 'capistrano', '~> 2.11.2'
33
38
  gem 'capistrano-ext', '1.2.1', :require => nil
34
39
  gem 'capistrano_colors'
40
+ gem 'relevance_rails', '<%= RelevanceRails::VERSION %>'
35
41
  end
@@ -0,0 +1,36 @@
1
+ # <%= name %>
2
+
3
+ ## Getting Started
4
+
5
+ gem install bundler
6
+ [TODO other setup commands here]
7
+
8
+ ## Provisioning on EC2 (Optional)
9
+
10
+ First create an aws config in ~/.relevance\_rails/aws\_config.yml.
11
+ An example config looks like this:
12
+
13
+ ```yaml
14
+ aws_credentials:
15
+ :aws_access_key_id: <your aws access key id>
16
+ :aws_secret_access_key: <your aws secret access key>
17
+
18
+ server:
19
+ creation_config:
20
+ :flavor_id: <instance type, e.g. 'm1.large'>
21
+ :image_id: <ami to bootstrap with. Must be some UBUNTU image. e.g. "ami-fd589594">
22
+ :groups: <security group to place the new deployment in, e.g. "default">
23
+ :key_name: <name of the public/private keypair to start instance with>
24
+ private_key: |
25
+ -----BEGIN RSA PRIVATE KEY-----
26
+ Include the RSA private key here. This should correspond to the keypair indicated
27
+ by :key_name above.
28
+ -----END RSA PRIVATE KEY-----
29
+ ```
30
+
31
+ Now just provision your instance:
32
+
33
+ ```sh
34
+ $ rails g deployment qa
35
+ $ cap qa deploy:setup deploy
36
+ ```
@@ -0,0 +1,9 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title <%= name %>
5
+ = stylesheet_link_tag :application
6
+ = javascript_include_tag :application
7
+ = csrf_meta_tag
8
+ %body
9
+ = yield
@@ -0,0 +1,17 @@
1
+ development:
2
+ adapter: mysql2
3
+ encoding: utf8
4
+ database: <%= name %>_development
5
+
6
+ # Warning: The database defined as "test" will be erased and
7
+ # re-generated from your development database when you run "rake".
8
+ # Do not set this db to the same as development or production.
9
+ test:
10
+ adapter: mysql2
11
+ encoding: utf8
12
+ database: <%= name %>_test
13
+
14
+ production:
15
+ adapter: mysql2
16
+ encoding: utf8
17
+ database: <%= name %>_production
@@ -0,0 +1,15 @@
1
+ development:
2
+ adapter: postgresql
3
+ database: <%= name %>_development
4
+
5
+ # Warning: The database defined as "test" will be erased and
6
+ # re-generated from your development database when you run "rake".
7
+ # Do not set this db to the same as development or production.
8
+ test:
9
+ adapter: postgresql
10
+ database: <%= name %>_test
11
+
12
+ production:
13
+ adapter: postgresql
14
+ database: <%= name %>_production
15
+ user: deploy
@@ -0,0 +1,22 @@
1
+ require 'bundler/capistrano'
2
+ require 'capistrano_colors'
3
+
4
+ set :application, "<%= name %>"
5
+ set :repository, "."
6
+ set :deploy_via, :copy
7
+
8
+ set :scm, :git
9
+
10
+ set :deploy_to, "/var/www/apps/#{ application }"
11
+ default_run_options[:pty] = true
12
+ set :ssh_options, { :paranoid => false, :forward_agent => true }
13
+
14
+ set :copy_exclude, '.git/*'
15
+
16
+ set :stages, %w(vagrant)
17
+ set :default_stage, 'vagrant'
18
+
19
+ after "deploy:setup", "deploy:copy_shared_db_config"
20
+ after "deploy:create_symlink", "deploy:symlink_shared_db_config"
21
+
22
+ Dir['config/deploy/recipes/*.rb'].sort.each { |f| eval(File.read(f)) }
@@ -1,6 +1,31 @@
1
1
  require "relevance_rails/version"
2
2
  require "relevance_rails/public_key_fetcher"
3
+ require "relevance_rails/chef_dna"
4
+ require 'relevance_rails/railtie' if defined? Rails
3
5
 
4
6
  module RelevanceRails
5
- # Your code goes here...
7
+ def self.rvm_gemset
8
+ @rvm_gemset ||= rvm_current.split('@')[1] || 'global'
9
+ end
10
+
11
+ def self.rvm_version
12
+ @rvm_version ||= rvm_current.split('@')[0] || 'ruby-1.9.3-p0'
13
+ end
14
+
15
+ def self.rvm_current
16
+ @rvm_current ||= rvm_exec('rvm current').chomp
17
+ end
18
+
19
+ # rvm_current SHOULD be in $PATH and execute ruby for the
20
+ # correct version and gemset
21
+ def self.rvm_run(command)
22
+ ret = `#{rvm_current} -S #{command}`
23
+ unless $?.success?
24
+ abort "\n Command '#{command}' failed with:\n#{ret}"
25
+ end
26
+ end
27
+
28
+ def self.rvm_exec(command)
29
+ `bash -c 'source ~/.rvm/scripts/rvm > /dev/null && #{command}'`
30
+ end
6
31
  end
@@ -0,0 +1,32 @@
1
+ module RelevanceRails::ChefDNA
2
+ def self.gene_splice(json, database)
3
+ set_ruby(json)
4
+ set_database(json, database)
5
+ end
6
+
7
+ def self.set_database(json, database)
8
+ if database == 'postgresql'
9
+ db_index = json['run_list'].find_index { |e| e == 'mysql::server' || e == 'role[postgres_database]'}
10
+ json['run_list'][db_index] = 'role[postgres_database]'
11
+ elsif database.nil? || database == 'mysql'
12
+ db_index = json['run_list'].find_index { |e| e == 'mysql::server' || e == 'role[postgres_database]'}
13
+ json['run_list'][db_index] = 'mysql::server'
14
+ end
15
+ end
16
+
17
+ def self.set_ruby(json)
18
+ if RelevanceRails.rvm_version =~ /^ree-(.*)/i
19
+ json['ruby_enterprise']['version'] = $1
20
+ json['ruby_enterprise']['url'] = "http://rubyenterpriseedition.googlecode.com/files/ruby-enterprise-#{$1}"
21
+ appstack_index = json['run_list'].find_index {|e| e[/^role\[.*_appstack\]$/] }
22
+ json['run_list'][appstack_index] = 'role[enterprise_appstack]'
23
+ elsif RelevanceRails.rvm_version =~ /^ruby-(.*)/i
24
+ json['ruby']['version'] = $1
25
+ json['ruby']['url'] = "http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-#{$1}.tar.gz"
26
+ appstack_index = json['run_list'].find_index {|e| e[/^role\[.*_appstack\]$/] }
27
+ json['run_list'][appstack_index] = 'role[ruby_appstack]'
28
+ else
29
+ raise "Your ruby is NOT SUPPORTED. Please use ree or ruby."
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,69 @@
1
+ require 'fog'
2
+
3
+ module RelevanceRails
4
+ module Provision
5
+ def self.create_ec2(name = nil)
6
+ abort "Please provide a $NAME" unless name
7
+ provision_ec2_instances(name)
8
+ end
9
+
10
+ private
11
+ def self.provision_ec2_instances(name)
12
+ config = YAML::load(File.read(File.expand_path("~/.relevance_rails/aws_config.yml")))
13
+ fog = Fog::Compute.new(config['aws_credentials'].merge(:provider => 'AWS'))
14
+ server = fog.servers.create(config['server']['creation_config'])
15
+ fog.tags.create(:key => 'Name',
16
+ :value => "#{Rails.application.class.parent_name} #{name}",
17
+ :resource_id => server.id)
18
+ server.private_key = config['server']['private_key']
19
+ wait_for_ssh server
20
+ jobs = []
21
+ puts "Updating apt cache..."
22
+ jobs += server.ssh('sudo apt-get update')
23
+ puts "Installing ruby..."
24
+ jobs += server.ssh('sudo apt-get -y install ruby')
25
+ puts "Installing rubygems..."
26
+ jobs += server.ssh('sudo apt-get -y install rubygems1.8')
27
+ puts "Installing chef..."
28
+ jobs += server.ssh('sudo gem install chef --no-ri --no-rdoc --version 0.10.8')
29
+ puts "Copying chef resources from provision directory.."
30
+ server.scp("#{Rails.root.join('provision')}/", '/tmp/chef-solo', :recursive => true)
31
+ puts "Converging server, this may take a while (10-20 minutes)"
32
+ jobs += server.ssh('cd /tmp/chef-solo && sudo /var/lib/gems/1.8/bin/chef-solo -c solo.rb -j dna.json')
33
+ print_errors(jobs)
34
+ puts "Server IP: #{server.public_ip_address}"
35
+ end
36
+
37
+ def self.wait_for_ssh(server)
38
+ server.wait_for { ready? }
39
+ succeeded = false
40
+ attempts = 0
41
+ last_error = nil
42
+ until succeeded || attempts > 4
43
+ sleep 10
44
+ begin
45
+ server.ssh('ls')
46
+ succeeded = true
47
+ rescue Errno::ECONNREFUSED => e
48
+ puts "Connection #{attempts} refused, retrying..."
49
+ attempts += 1
50
+ last_error = e
51
+ end
52
+ end
53
+ raise last_error unless succeeded
54
+ puts "Server up and listening for SSH..."
55
+ end
56
+
57
+ def self.print_errors(jobs)
58
+ return if jobs.all? { |job| job.status == 0 }
59
+ jobs.each do |job|
60
+ puts "----------------------"
61
+ puts "Running #{job.command}"
62
+ puts "STDOUT: #{job.stdout}"
63
+ puts "STDERR: #{job.stderr}"
64
+ puts "----------------------"
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails'
2
+
3
+ module RelevanceRails
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load 'tasks/provision.rake'
7
+ end
8
+ end
9
+ end
@@ -1,22 +1,25 @@
1
- RVM_RUBY = "ree-1.8.7-2012.02"
2
- RVM_GEMSET = app_name
1
+ require 'relevance_rails'
2
+ require 'json'
3
3
 
4
- def rvm_run(command, config = {})
5
- run ". ~/.rvm/scripts/rvm && rvm use #{RVM_RUBY}@#{RVM_GEMSET} && #{command}", config
4
+ def rvm_run(command)
5
+ say_status :rvm_run, command
6
+ RelevanceRails.rvm_run(command)
6
7
  end
7
8
 
8
- run 'rm README.rdoc'
9
- run 'rm doc/README_FOR_APP'
10
- run 'rm public/index.html'
11
- run 'rm public/favicon.ico'
12
- run 'rm -rf test'
13
- run 'rm Gemfile'
14
- run 'rm app/assets/images/rails.png'
15
- run 'rm app/views/layouts/application.html.erb'
9
+ db = ['postgresql','mysql'].include?(options[:database]) ? options[:database] : 'mysql'
16
10
 
17
- generate(:relevance_file, app_name)
11
+ remove_file 'README.rdoc'
12
+ remove_file 'doc/README_FOR_APP'
13
+ remove_file 'public/index.html'
14
+ remove_file 'public/favicon.ico'
15
+ remove_file 'test'
16
+ remove_file 'Gemfile'
17
+ remove_file 'app/assets/images/rails.png'
18
+ remove_file 'app/views/layouts/application.html.erb'
18
19
 
19
- rvm_run "rvm use #{RVM_RUBY}@#{RVM_GEMSET} --create"
20
+ generate(:relevance_file, app_name, db)
21
+
22
+ run "rvm gemset create #{app_name}"
20
23
  rvm_run "gem install bundler"
21
24
  rvm_run "bundle install"
22
25
 
@@ -25,15 +28,4 @@ append_file ".gitignore", "config/database.yml\n"
25
28
  run 'cp config/database.example.yml config/database.yml'
26
29
  git :add => "."
27
30
  git :commit => "-a -m 'Initial commit'"
28
-
29
- git :remote => 'add -f elzar git://github.com/relevance/elzar.git'
30
- git :merge => '-s ours --no-commit elzar/master'
31
- git :"read-tree" => '--prefix=provision/ -u elzar/master'
32
- gsub_file 'provision/Vagrantfile', /config\.vm\.host_name(\s+)= .*$/, "config.vm.host_name\\1= '#{app_name.gsub('_','-')}.local'"
33
- gsub_file 'provision/roles/rails.rb', /:rails_app => \{$(\s+):name => .*$(\s+)\}/,":rails_app => {\\1:name => '#{app_name}'\\2}"
34
- run 'mv authorized_keys.json provision/data_bags/deploy/authorized_keys.json'
35
- git :rm => 'authorized_keys.json'
36
- git :add => 'provision/data_bags/deploy/authorized_keys.json'
37
- git :add => 'provision/Vagrantfile'
38
- git :add => 'provision/roles/rails.rb'
39
- git :commit => '-m "Merge Elzar as our provision subdirectory"'
31
+ generate(:provision_config, app_name, db)
@@ -0,0 +1,24 @@
1
+ require 'relevance_rails'
2
+
3
+ module RelevanceRails
4
+ class Runner
5
+ def self.start(argv=ARGV)
6
+ if argv.delete '--version'
7
+ puts "RelevanceRails #{RelevanceRails::VERSION}"
8
+ else
9
+ add_default_options! argv
10
+ exec 'rails', *argv
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def self.add_default_options!(argv)
17
+ unless argv.any? =~ /^-d$/
18
+ template = File.join(File.dirname(__FILE__), "relevance_rails_template.rb")
19
+ argv << '-m'
20
+ argv << template
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module RelevanceRails
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,8 @@
1
+ require 'relevance_rails/provision'
2
+
3
+ namespace :provision do
4
+ desc 'Provision a deployable EC2 instance'
5
+ task :ec2 do
6
+ RelevanceRails::Provision.create_ec2(ENV['NAME'])
7
+ end
8
+ end
@@ -5,6 +5,7 @@ require "relevance_rails/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "relevance_rails"
7
7
  s.version = RelevanceRails::VERSION
8
+ s.homepage = "http://github.com/relevance/relevance_rails"
8
9
  s.authors = ["Alex Redington"]
9
10
  s.email = ["alex.redington@thinkrelevance.com"]
10
11
  s.homepage = ""
@@ -22,6 +23,10 @@ Gem::Specification.new do |s|
22
23
  s.executables = ['relevance_rails']
23
24
 
24
25
  # specify any dependencies here; for example:
25
- # s.add_development_dependency "rspec"
26
- s.add_runtime_dependency "rails", "~> 3.1"
26
+ s.add_runtime_dependency "rails", "~> 3.2"
27
+ s.add_runtime_dependency 'fog', '~> 1.3.0'
28
+ s.add_development_dependency 'pry'
29
+ s.add_development_dependency 'capybara'
30
+ s.add_development_dependency 'rspec'
31
+ s.add_development_dependency 'rake', '~> 0.9.2.2'
27
32
  end
data/script/ci ADDED
@@ -0,0 +1,57 @@
1
+ #!/bin/bash -v
2
+
3
+ RAILS_APP="app_for_ci"
4
+ TARGET_HOST="placeholder.example.com"
5
+
6
+ source "$HOME/.rvm/scripts/rvm"
7
+ rvm use "ruby-1.9.2@relevance_rails"
8
+
9
+ gem install bundler
10
+ bundle install
11
+ bundle exec rake spec
12
+
13
+ # exit if any statement fails; must be set AFTER loading RVM
14
+ set -e
15
+
16
+ echo "Building new relevance_rails gem..."
17
+ rm -Rf relevance_rails-*.gem
18
+ gem build --verbose relevance_rails.gemspec
19
+ echo "Done"
20
+
21
+ # NOTE: Manual install of just-built gem to workaround bundler wanting
22
+ # it to live on rubygems.org.
23
+ # NOTE: RVM 1.x doesn't work with "set -e", so you have to unset/set it.
24
+ set +e
25
+ rvm --force gemset delete $RAILS_APP
26
+ rvm gemset create $RAILS_APP
27
+ rvm gemset use $RAILS_APP
28
+ set -e
29
+
30
+ if [ `gem list relevance_rails --installed` = "true" ]; then
31
+ echo "Removing old relevance_rails gem..."
32
+ gem uninstall --verbose --all --executables relevance_rails
33
+ echo "Done"
34
+ fi
35
+
36
+ echo "Installing relevance_rails gem into $RAILS_APP gemset..."
37
+ gem install relevance_rails-*.gem
38
+ echo "Done."
39
+
40
+ rm -Rf ./$RAILS_APP
41
+ relevance_rails new $RAILS_APP --database=postgresql
42
+
43
+ # NOTE: this does NOT change the RVM gemset; we set it manually above
44
+ builtin cd $RAILS_APP
45
+
46
+ echo "Generating relevance_rails deployment scripts..."
47
+ ./script/rails generate deployment staging $TARGET_HOST
48
+ git add .
49
+ git commit -m "Generated relevance_rails deployment scripts."
50
+ echo "Done."
51
+
52
+ echo "Generating relevance_rails fixtures..."
53
+ ./script/rails generate fixtures
54
+ git add .
55
+ git commit -m "Generated relevance_rails fixtures."
56
+ echo "Done."
57
+