heroku-rails 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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