heroku-rails 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ module Heroku
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ rake_tasks do
5
+ load 'heroku/rails/tasks.rb'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,224 +1,180 @@
1
1
  HEROKU_CONFIG_FILE = Rails.root.join('config', 'heroku.yml')
2
+ HEROKU_CONFIG = Heroku::Rails::HerokuConfig.new(HEROKU_CONFIG_FILE)
3
+ HEROKU_RUNNER = Heroku::Rails::HerokuRunner.new(HEROKU_CONFIG)
2
4
 
3
- require 'heroku/rails/config'
4
- HEROKU_CONFIG = Heroku::Rails::Config.new(HEROKU_CONFIG_FILE)
5
-
6
- (HEROKU_CONFIG.settings['apps'] || []).each do |name, app|
7
- desc "Select #{name} Heroku app for later commands"
8
- task name do
9
- @heroku_apps ||= []
10
- @heroku_apps << name
5
+ # create all the the environment specific tasks
6
+ (HEROKU_CONFIG.apps).each do |heroku_env, app_name|
7
+ desc "Select #{heroku_env} Heroku app for later commands"
8
+ task heroku_env do
9
+ HEROKU_RUNNER.add_environment(heroku_env)
11
10
  end
12
11
  end
13
12
 
14
13
  desc 'Select all Heroku apps for later command'
15
14
  task :all do
16
- @heroku_apps = HEROKU_CONFIG.settings['apps'].keys
15
+ HEROKU_RUNNER.all_environments
17
16
  end
18
17
 
19
18
  namespace :heroku do
20
- desc "Creates the Heroku app"
21
- task :create do
22
- each_heroku_app do |name, app, repo|
23
- system_with_echo "heroku create #{app}"
24
- end
25
- end
26
-
27
- desc "Generate the Heroku gems manifest from gem dependencies"
28
- task :gems => 'gems:base' do
29
- RAILS_ENV='production'
30
- Rake::Task[:environment].invoke
31
- gems = Rails.configuration.gems.reject { |g| g.frozen? && !g.framework_gem? }
32
- list = gems.collect do |g|
33
- command, *options = g.send(:install_command)
34
- options.join(" ")
35
- end
36
-
37
- list.unshift(%Q{rails --version "= #{Rails.version}"})
38
-
39
- File.open(Rails.root.join('.gems'), 'w') do |f|
40
- f.write(list.join("\n"))
41
- end
19
+ def system_with_echo(*args)
20
+ HEROKU_RUNNER.system_with_echo(*args)
42
21
  end
43
22
 
44
23
  desc 'Add git remotes for all apps in this project'
45
24
  task :remotes do
46
- each_heroku_app do |name, app, repo|
47
- system("git remote add #{name} #{repo}")
48
- end
49
- end
50
-
51
- desc 'Adds a collaborator'
52
- task :share do
53
- print "Email address of collaborator to add: "
54
- $stdout.flush
55
- email = $stdin.gets
56
- each_heroku_app do |name, app, repo|
57
- system_with_echo "heroku sharing:add --app #{app} #{email}"
58
- end
59
- end
60
-
61
- desc 'Adds a collaborator'
62
- task :unshare do
63
- print "Email address of collaborator to remove: "
64
- $stdout.flush
65
- email = $stdin.gets
66
- each_heroku_app do |name, app, repo|
67
- system_with_echo "heroku sharing:remove --app #{app} #{email}"
25
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
26
+ system_with_echo("git remote add #{app_name} #{repo}")
68
27
  end
69
28
  end
70
29
 
71
30
  desc 'Lists configured apps'
72
31
  task :apps => :all do
73
- each_heroku_app do |name, app, repo|
74
- puts "#{name} is shorthand for the Heroku app #{app} located at:"
32
+ puts "\n"
33
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
34
+ puts "#{heroku_env} maps to the Heroku app #{app_name} located at:"
75
35
  puts " #{repo}"
76
36
  puts
77
37
  end
78
38
  end
79
39
 
80
- desc 'Add proper RACK_ENV to each application'
81
- task :rack_env => :all do
82
- each_heroku_app do |name, app, repo|
83
- command = "heroku config --app #{app}"
84
- puts command
85
- config = Hash[`#{command}`.scan(/^(.+?)\s*=>\s*(.+)$/)]
86
- if config['RACK_ENV'] != name
87
- system_with_echo "heroku config:add --app #{app} RACK_ENV=#{name}"
88
- end
89
- end
90
- end
91
-
92
- desc 'Creates an example configuration file'
93
- task :create_config do
94
- example = File.join(File.dirname(__FILE__), '..', 'templates', 'heroku.example.yml')
95
- if File.exists?(HEROKU_CONFIG_FILE)
96
- puts "config/heroku.yml already exists"
97
- else
98
- puts "Copied example config to config/heroku.yml"
99
- FileUtils.cp(example, HEROKU_CONFIG_FILE)
100
- system_with_echo("#{ENV['EDITOR']} #{HEROKU_CONFIG_FILE}")
40
+ desc "Get remote server information on the heroku app"
41
+ task :info do
42
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
43
+ system_with_echo "heroku info --app #{app_name}"
44
+ puts "\n"
101
45
  end
102
46
  end
103
47
 
104
- namespace :setup do
105
- # TODO
106
- end
48
+ desc "Deploys, migrates and restarts latest code"
49
+ task :deploy => "heroku:before_deploy" do
50
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
107
51
 
108
- end
52
+ # set the current heroku_app so that callbacks can read the data
53
+ @heroku_app = {:env => heroku_env, :app_name => app_name, :repo => repo}
54
+ Rake::Task["heroku:before_each_deploy"].invoke
109
55
 
110
- desc "Deploys, migrates and restarts latest code"
111
- task :deploy => :before_deploy do
112
- each_heroku_app do |name, app, repo|
113
- @heroku_app = {:name => name, :app => app, :repo => repo}
114
- Rake::Task[:before_each_deploy].invoke
115
- branch = `git branch`.scan(/^\* (.*)\n/).flatten.first.to_s
116
- if branch.present?
117
- @git_push_arguments ||= []
118
- system_with_echo "git push #{repo} #{@git_push_arguments.join(' ')} #{branch}:master && heroku rake --app #{app} db:migrate && heroku restart --app #{app}"
119
- else
120
- puts "Unable to determine the current git branch, please checkout the branch you'd like to deploy"
121
- exit(1)
56
+ branch = `git branch`.scan(/^\* (.*)\n/).flatten.first.to_s
57
+ if branch.present?
58
+ @git_push_arguments ||= []
59
+ system_with_echo "git push #{repo} #{@git_push_arguments.join(' ')} #{branch}:master && heroku rake --app #{app_name} db:migrate && heroku restart --app #{app_name}"
60
+ else
61
+ puts "Unable to determine the current git branch, please checkout the branch you'd like to deploy"
62
+ exit(1)
63
+ end
64
+ Rake::Task["heroku:after_each_deploy"].invoke
122
65
  end
123
- Rake::Task[:after_each_deploy].invoke
66
+ Rake::Task["heroku:after_deploy"].execute
124
67
  end
125
- Rake::Task[:after_deploy].execute
126
- end
127
68
 
128
- desc "Callback before all deploys"
129
- task :before_deploy do
130
- end
131
-
132
- desc "Callback after all deploys"
133
- task :after_deploy do
134
- end
135
-
136
- desc "Callback before each deploy"
137
- task :before_each_deploy do
138
- end
139
-
140
- desc "Callback after each deploy"
141
- task :after_each_deploy do
142
- end
69
+ # Callback before all deploys
70
+ task :before_deploy do
71
+ end
143
72
 
73
+ # Callback after all deploys
74
+ task :after_deploy do
75
+ end
144
76
 
145
- desc "Force deploys, migrates and restarts latest code"
146
- task :force_deploy do
147
- @git_push_arguments ||= []
148
- @git_push_arguments << '--force'
149
- Rake::Task[:deploy].execute
150
- end
77
+ # Callback before each deploy
78
+ task :before_each_deploy do
79
+ end
151
80
 
152
- desc "Captures a bundle on Heroku"
153
- task :capture do
154
- each_heroku_app do |name, app, repo|
155
- system_with_echo "heroku bundles:capture --app #{app}"
81
+ # Callback after each deploy
82
+ task :after_each_deploy do
156
83
  end
157
- end
158
84
 
159
- desc "Opens a remote console"
160
- task :console do
161
- each_heroku_app do |name, app, repo|
162
- system_with_echo "heroku console --app #{app}"
85
+ desc "Force deploys, migrates and restarts latest code"
86
+ task :force_deploy do
87
+ @git_push_arguments ||= []
88
+ @git_push_arguments << '--force'
89
+ Rake::Task["heroku:deploy"].execute
163
90
  end
164
- end
165
91
 
166
- desc "Restarts remote servers"
167
- task :restart do
168
- each_heroku_app do |name, app, repo|
169
- system_with_echo "heroku restart --app #{app}"
92
+ desc "Captures a bundle on Heroku"
93
+ task :capture do
94
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
95
+ system_with_echo "heroku bundles:capture --app #{app_name}"
96
+ end
170
97
  end
171
- end
172
98
 
173
- desc "Migrates and restarts remote servers"
174
- task :migrate do
175
- each_heroku_app do |name, app, repo|
176
- system_with_echo "heroku rake --app #{app} db:migrate && heroku restart --app #{app}"
99
+ desc "Opens a remote console"
100
+ task :console do
101
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
102
+ system_with_echo "heroku console --app #{app_name}"
103
+ end
177
104
  end
178
- end
179
105
 
180
- namespace :db do
181
- task :pull do
182
- each_heroku_app do |name, app, repo|
183
- system_with_echo "heroku pgdumps:capture --app #{app}"
184
- dump = `heroku pgdumps --app #{app}`.split("\n").last.split(" ").first
185
- system_with_echo "mkdir -p #{Rails.root}/db/dumps"
186
- file = "#{Rails.root}/db/dumps/#{dump}.sql.gz"
187
- url = `heroku pgdumps:url --app #{app} #{dump}`.chomp
188
- system_with_echo "wget", url, "-O", file
189
- system_with_echo "rake db:drop db:create"
190
- system_with_echo "gunzip -c #{file} | #{Rails.root}/script/dbconsole"
191
- system_with_echo "rake jobs:clear"
106
+ desc "Restarts remote servers"
107
+ task :restart do
108
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
109
+ system_with_echo "heroku restart --app #{app_name}"
192
110
  end
193
111
  end
194
- end
195
112
 
196
- def system_with_echo(*args)
197
- puts args.join(' ')
198
- system(*args)
199
- end
113
+ namespace :setup do
200
114
 
201
- def each_heroku_app
202
- if @heroku_apps.blank? && HEROKU_CONFIG.settings['apps'].size == 1
203
- app = HEROKU_CONFIG.settings['apps'].keys.first
204
- puts "Defaulting to #{app} app since only one app is defined"
205
- @heroku_apps = [app]
206
- end
207
- if @heroku_apps.present?
208
- @heroku_apps.each do |name|
209
- app = HEROKU_CONFIG.settings['apps'][name]
210
- yield(name, app, "git@heroku.com:#{app}.git")
115
+ desc "Creates the apps on Heroku"
116
+ task :create_apps do
117
+ HEROKU_RUNNER.create_apps
118
+ end
119
+
120
+ desc "Setup the Heroku stacks from heroku.yml config"
121
+ task :stacks do
122
+ HEROKU_RUNNER.setup_stacks
123
+ end
124
+
125
+ desc "Setup the Heroku collaborators from heroku.yml config"
126
+ task :collaborators do
127
+ HEROKU_RUNNER.setup_collaborators
128
+ end
129
+
130
+ desc "Setup the Heroku environment config variables from heroku.yml config"
131
+ task :config do
132
+ HEROKU_RUNNER.setup_config
211
133
  end
212
- puts
213
- else
214
- puts "You must first specify at least one Heroku app:
215
- rake <app> [<app>] <command>
216
- rake production restart
217
- rake demo staging deploy"
218
134
 
219
- puts "\nYou can use also command all Heroku apps for this project:
220
- rake all heroku:share"
135
+ desc "Setup the Heroku addons from heroku.yml config"
136
+ task :addons do
137
+ HEROKU_RUNNER.setup_addons
138
+ end
221
139
 
222
- exit(1)
140
+ desc "Setup the Heroku domains from heroku.yml config"
141
+ task :domains do
142
+ HEROKU_RUNNER.setup_domains
143
+ end
223
144
  end
224
- end
145
+
146
+ desc "Setup Heroku deploy environment from heroku.yml config"
147
+ task :setup => [
148
+ "heroku:setup:stacks",
149
+ "heroku:setup:collaborators",
150
+ "heroku:setup:config",
151
+ "heroku:setup:addons",
152
+ "heroku:setup:domains",
153
+ ]
154
+
155
+ namespace :db do
156
+ desc "Migrates and restarts remote servers"
157
+ task :migrate do
158
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
159
+ system_with_echo "heroku rake --app #{app_name} db:migrate && heroku restart --app #{app_name}"
160
+ end
161
+ end
162
+
163
+ desc "Pulls the database from heroku and stores it into db/dumps/"
164
+ task :pull do
165
+ HEROKU_RUNNER.each_heroku_app do |heroku_env, app_name, repo|
166
+ system_with_echo "heroku pgdumps:capture --app #{app_name}"
167
+ dump = `heroku pgdumps --app #{app_name}`.split("\n").last.split(" ").first
168
+ system_with_echo "mkdir -p #{Rails.root}/db/dumps"
169
+ file = "#{Rails.root}/db/dumps/#{dump}.sql.gz"
170
+ url = `heroku pgdumps:url --app #{app_name} #{dump}`.chomp
171
+ system_with_echo "wget", url, "-O", file
172
+
173
+ # TODO: these are a bit distructive...
174
+ # system_with_echo "rake db:drop db:create"
175
+ # system_with_echo "gunzip -c #{file} | #{Rails.root}/script/dbconsole"
176
+ # system_with_echo "rake jobs:clear"
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,48 @@
1
+ apps:
2
+ production: awesomeapp
3
+ staging: awesomeapp-staging
4
+
5
+ stacks:
6
+ all: bamboo-mri-1.9.2
7
+ staging: bamboo-ree-1.8.7
8
+
9
+ config:
10
+ all:
11
+ BUNDLE_WITHOUT: "test development"
12
+ CONFIG_VAR1: "config1"
13
+ CONFIG_VAR2: "config2"
14
+
15
+ production:
16
+ CONFIG_VAR1: "config1-production"
17
+
18
+ staging:
19
+ CONFIG_VAR1: "config1-staging"
20
+ STAGING_CONFIG: "special-staging"
21
+
22
+ collaborators:
23
+ all:
24
+ - "all-user1@somedomain.com"
25
+ - "all-user2@somedomain.com"
26
+ - "all-user2@somedomain.com"
27
+ staging:
28
+ - "staging-user@somedomain.com"
29
+ production:
30
+ - "production-user@somedomain.com"
31
+
32
+ domains:
33
+ staging:
34
+ - "staging.awesomeapp.com"
35
+ production:
36
+ - "awesomeapp.com"
37
+ - "www.awesomeapp.com"
38
+
39
+ addons:
40
+ all:
41
+ # add any other addons here
42
+ - custom_domains:basic
43
+ - newrelic:bronze
44
+
45
+ production:
46
+ # list production env specific addons here
47
+ - ssl:piggyback
48
+ - cron:hourly
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+
3
+ module Heroku::Rails
4
+ describe HerokuConfig do
5
+ before(:each) do
6
+ @config = HerokuConfig.new(config_path("heroku-config.yml"))
7
+ end
8
+
9
+ it "should read the configuration file" do
10
+ @config.settings.should_not be_empty
11
+ end
12
+
13
+ describe "#apps" do
14
+ it "should return the list of apps defined" do
15
+ @config.apps.should have(2).apps
16
+ @config.apps.should include("production" => "awesomeapp")
17
+ @config.apps.should include("staging" => "awesomeapp-staging")
18
+ end
19
+ end
20
+
21
+ describe "#app_names" do
22
+ it "should return the list of apps defined" do
23
+ @config.app_names.should have(2).names
24
+ @config.app_names.should include("awesomeapp")
25
+ @config.app_names.should include("awesomeapp-staging")
26
+ end
27
+ end
28
+
29
+ describe "#app_environments" do
30
+ it "should return a list of the environments defined" do
31
+ @config.app_environments.should have(2).environments
32
+ @config.app_environments.should include("production")
33
+ @config.app_environments.should include("staging")
34
+ end
35
+ end
36
+
37
+ describe "#stack" do
38
+ it "should return the associated stack for an environment" do
39
+ @config.stack("staging").should == "bamboo-ree-1.8.7"
40
+ end
41
+
42
+ it "should default to the all setting if not explicitly defined" do
43
+ @config.stack("production").should == "bamboo-mri-1.9.2"
44
+ end
45
+ end
46
+
47
+ describe "#config" do
48
+ context "staging environment" do
49
+ before(:each) do
50
+ @config = @config.config("staging")
51
+ end
52
+ it "should include configs defined in 'staging'" do
53
+ @config["STAGING_CONFIG"].should == "special-staging"
54
+ end
55
+
56
+ it "should include configs defined in 'all'" do
57
+ @config["BUNDLE_WITHOUT"].should == "test development"
58
+ end
59
+
60
+ it "should use configs defined in 'staging' ahead of configs defined in 'all'" do
61
+ @config["CONFIG_VAR1"].should == "config1-staging"
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#collaborators" do
67
+ context "staging environment" do
68
+ before(:each) do
69
+ @collaborators = @config.collaborators('staging')
70
+ end
71
+
72
+ it "should include the collaborators defined in 'all'" do
73
+ @collaborators.should include('all-user1@somedomain.com')
74
+ @collaborators.should include('all-user2@somedomain.com')
75
+ @collaborators.should have(3).collaborators
76
+ end
77
+
78
+ it "should include collaborators defined in 'staging'" do
79
+ @collaborators.should include('staging-user@somedomain.com')
80
+ end
81
+
82
+ it "should not include collaborators defined in 'production'" do
83
+ @collaborators.should_not include('production-user@somedomain.com')
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "#domains" do
89
+ context "staging environment" do
90
+ before(:each) do
91
+ @domains = @config.domains('staging')
92
+ end
93
+
94
+ it "should include the domains defined in 'staging'" do
95
+ @domains.should include('staging.awesomeapp.com')
96
+ end
97
+
98
+ it "should not include the domains defined in 'production'" do
99
+ @domains.should_not include('awesomeapp.com')
100
+ @domains.should_not include('www.awesomeapp.com')
101
+ end
102
+ end
103
+
104
+ context "production environment" do
105
+ it "should include the domains defined in 'production'" do
106
+ @domains = @config.domains('production')
107
+ @domains.should include('awesomeapp.com')
108
+ @domains.should include('www.awesomeapp.com')
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "#addons" do
114
+ context "staging environment" do
115
+ before(:each) do
116
+ @addons = @config.addons('staging')
117
+ end
118
+
119
+ it "should include addons defined in 'all'" do
120
+ @addons.should include('custom_domains:basic')
121
+ @addons.should include('newrelic:bronze')
122
+ end
123
+
124
+ it "should not include addons defined in 'production'" do
125
+ @addons.should_not include('ssl:piggyback')
126
+ end
127
+ end
128
+ end
129
+
130
+ end
131
+ end