heroku_san 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +33 -0
- data/README.rdoc +41 -31
- data/examples/push_revision.rake +8 -0
- data/features/config.feature +2 -0
- data/lib/git.rb +13 -5
- data/lib/heroku_san.rb +1 -0
- data/lib/heroku_san/stage.rb +31 -7
- data/lib/heroku_san/version.rb +1 -1
- data/lib/tasks.rb +119 -94
- data/spec/git_spec.rb +19 -0
- data/spec/heroku_san/stage_spec.rb +88 -1
- metadata +18 -16
data/CHANGELOG.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Change log (curated)
|
2
|
+
|
3
|
+
## v2.1.0
|
4
|
+
|
5
|
+
* Documentation update
|
6
|
+
* Push `REVISION` to Heroku example
|
7
|
+
* Bug fixes
|
8
|
+
|
9
|
+
### New tasks
|
10
|
+
|
11
|
+
* rake logs:tail
|
12
|
+
* rake shell
|
13
|
+
* All HerokuSan tasks inside heroku: namespace, with aliases in the global namespace
|
14
|
+
|
15
|
+
### New methods
|
16
|
+
|
17
|
+
* `Stage#deploy`
|
18
|
+
* `Stage#maintenance` can now take a block, and ensures that maintenance mode is off afterwards.
|
19
|
+
* `Stage#push_config`
|
20
|
+
|
21
|
+
## v2.0.0
|
22
|
+
|
23
|
+
* Major rewrite into classes `Project` & `Stage`, with helper `Git` module
|
24
|
+
* Tests for _everything_
|
25
|
+
* Examples directory (e.g. `auto-tagger`)
|
26
|
+
* Removed dependencies on Rails
|
27
|
+
* `tasks.rb` is greatly simplified, mostly API calls into the `Stage` class
|
28
|
+
* Support for tagging releases and deploying apps using a tag glob
|
29
|
+
* Support for Heroku stacks (aspen, bamboo & cedar)
|
30
|
+
|
31
|
+
## v1.3.0
|
32
|
+
|
33
|
+
N/A
|
data/README.rdoc
CHANGED
@@ -68,37 +68,47 @@ Need to add remotes for each app?
|
|
68
68
|
|
69
69
|
A full list of tasks provided:
|
70
70
|
|
71
|
-
rake
|
72
|
-
rake
|
73
|
-
rake
|
74
|
-
rake
|
75
|
-
rake
|
76
|
-
rake
|
77
|
-
rake
|
78
|
-
rake
|
79
|
-
rake
|
80
|
-
rake heroku:
|
81
|
-
rake heroku:
|
82
|
-
rake heroku:
|
83
|
-
rake heroku:
|
84
|
-
rake heroku:
|
85
|
-
rake heroku:
|
86
|
-
rake heroku:
|
87
|
-
rake heroku:
|
88
|
-
rake heroku:maintenance
|
89
|
-
rake heroku:maintenance_off
|
90
|
-
rake heroku:
|
91
|
-
rake heroku:push
|
92
|
-
rake heroku:
|
93
|
-
rake heroku:rake[task]
|
94
|
-
rake heroku:remotes
|
95
|
-
rake heroku:
|
96
|
-
rake heroku:
|
97
|
-
rake
|
98
|
-
rake
|
99
|
-
|
100
|
-
|
101
|
-
|
71
|
+
rake heroku:apps # Lists configured apps
|
72
|
+
rake heroku:apps:local # Lists configured apps without hitting heroku
|
73
|
+
rake heroku:config # Add config:vars to each application.
|
74
|
+
rake heroku:config:list # Lists config variables as set on Heroku
|
75
|
+
rake heroku:config:list:local # Lists local config variables without setting them
|
76
|
+
rake heroku:config:rack_env # Add proper RACK_ENV to each application
|
77
|
+
rake heroku:console # Opens a remote console
|
78
|
+
rake heroku:create # Creates the Heroku app
|
79
|
+
rake heroku:create_config # Creates an example configuration file
|
80
|
+
rake heroku:db:migrate # Migrates and restarts remote servers
|
81
|
+
rake heroku:db:pull # Pull database from stage to local dev database
|
82
|
+
rake heroku:deploy[commit] # Pushes the given commit, migrates and restarts (default: HEAD)
|
83
|
+
rake heroku:deploy:after # Callback after deploys
|
84
|
+
rake heroku:deploy:before # Callback before deploys
|
85
|
+
rake heroku:deploy:force[commit] # Force-pushes the given commit, migrates and restarts (default: HEAD)
|
86
|
+
rake heroku:logs # Shows the Heroku logs
|
87
|
+
rake heroku:logs:tail # Tail the Heroku logs (requires logging:expanded)
|
88
|
+
rake heroku:maintenance # Enable maintenance mode
|
89
|
+
rake heroku:maintenance_off # Disable maintenance mode
|
90
|
+
rake heroku:maintenance_on # Enable maintenance mode
|
91
|
+
rake heroku:push[commit] # Pushes the given commit (default: HEAD)
|
92
|
+
rake heroku:push:force[commit] # Force-pushes the given commit (default: HEAD)
|
93
|
+
rake heroku:rake[task] # Runs a rake task remotely
|
94
|
+
rake heroku:remotes # Add git remotes for all apps in this project
|
95
|
+
rake heroku:restart # Restarts remote servers
|
96
|
+
rake heroku:share # Adds a collaborator (asks for email)
|
97
|
+
rake heroku:unshare # Removes a collaborator (asks for email)
|
98
|
+
rake heroku:stage:all # Select all Heroku apps for later command
|
99
|
+
|
100
|
+
Frequently used tasks are aliased into the global namespace:
|
101
|
+
|
102
|
+
task :all => 'heroku:stage:all'
|
103
|
+
task :deploy => 'heroku:deploy'
|
104
|
+
task 'deploy:force' => 'heroku:deploy:force'
|
105
|
+
task :before_deploy => 'heroku:deploy:before'
|
106
|
+
task :after_deploy => 'heroku:deploy:after'
|
107
|
+
task :console => 'heroku:console'
|
108
|
+
task :restart => 'heroku:restart'
|
109
|
+
task :migrate => 'heroku:db:migrate'
|
110
|
+
task :logs => 'heroku:logs:default'
|
111
|
+
task 'logs:tail' => 'heroku:logs:tail'
|
102
112
|
|
103
113
|
== Links
|
104
114
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Adding this to your :after_deploy task this will add an environment variable,
|
2
|
+
# in this case, "REVISION", to your Heroku environment with the current revision.
|
3
|
+
task :after_deploy do
|
4
|
+
each_heroku_app do |stage|
|
5
|
+
revision = stage.revision.split.first
|
6
|
+
stage.push_config('REVISION' => revision) if revision
|
7
|
+
end
|
8
|
+
end
|
data/features/config.feature
CHANGED
data/lib/git.rb
CHANGED
@@ -23,17 +23,25 @@ module Git
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
%x{git tag -l '#{glob}'}.split("\n").last
|
26
|
+
def git_parsed_tag(tag)
|
27
|
+
git_rev_parse(git_tag(tag))
|
29
28
|
end
|
30
29
|
|
31
30
|
def git_rev_parse(ref)
|
32
31
|
return nil if ref.nil?
|
33
32
|
%x{git rev-parse #{ref}}.split("\n").first
|
33
|
+
end
|
34
|
+
|
35
|
+
def git_tag(glob)
|
36
|
+
return nil if glob.nil?
|
37
|
+
%x{git tag -l '#{glob}'}.split("\n").last
|
34
38
|
end
|
35
39
|
|
36
|
-
def
|
37
|
-
|
40
|
+
def git_revision(repo)
|
41
|
+
%x{git ls-remote --heads #{repo} master}.split.first
|
42
|
+
end
|
43
|
+
|
44
|
+
def git_named_rev(ref)
|
45
|
+
%x{git name-rev #{ref}}.chomp
|
38
46
|
end
|
39
47
|
end
|
data/lib/heroku_san.rb
CHANGED
data/lib/heroku_san/stage.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module HerokuSan
|
2
2
|
class Stage
|
3
3
|
attr_reader :name
|
4
|
+
include Git
|
4
5
|
|
5
6
|
def initialize(stage, options = {})
|
6
7
|
@name = stage
|
@@ -8,7 +9,7 @@ module HerokuSan
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def app
|
11
|
-
@options['app']
|
12
|
+
@options['app'] or raise MissingApp, "#{name}: is missing the app: configuration value. I don't know what to access on Heroku."
|
12
13
|
end
|
13
14
|
|
14
15
|
def repo
|
@@ -35,14 +36,28 @@ module HerokuSan
|
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
39
|
+
def deploy(sha = nil, force = false)
|
40
|
+
sha ||= git_parsed_tag(tag)
|
41
|
+
git_push(sha, repo, force ? %w[--force] : [])
|
42
|
+
end
|
43
|
+
|
38
44
|
def migrate
|
39
45
|
run 'rake', 'db:migrate'
|
40
46
|
sh_heroku "restart"
|
41
47
|
end
|
42
48
|
|
43
|
-
def maintenance(action)
|
44
|
-
|
45
|
-
|
49
|
+
def maintenance(action = nil)
|
50
|
+
if block_given?
|
51
|
+
sh_heroku "maintenance:on"
|
52
|
+
begin
|
53
|
+
yield
|
54
|
+
ensure
|
55
|
+
sh_heroku "maintenance:off"
|
56
|
+
end
|
57
|
+
else
|
58
|
+
raise ArgumentError, "Action #{action.inspect} must be one of (:on, :off)", caller if ![:on, :off].include?(action)
|
59
|
+
sh_heroku "maintenance:#{action}"
|
60
|
+
end
|
46
61
|
end
|
47
62
|
|
48
63
|
def create
|
@@ -60,18 +75,27 @@ module HerokuSan
|
|
60
75
|
def long_config
|
61
76
|
sh_heroku 'config --long'
|
62
77
|
end
|
78
|
+
|
79
|
+
def push_config(options = {})
|
80
|
+
vars = (options == {} ? config : options).map {|var,value| "#{var}=#{Shellwords.escape(value)}"}.join(' ')
|
81
|
+
sh_heroku "config:add #{vars}"
|
82
|
+
end
|
63
83
|
|
64
84
|
def restart
|
65
85
|
sh_heroku 'restart'
|
66
86
|
end
|
67
87
|
|
68
|
-
def logs
|
69
|
-
sh_heroku 'logs'
|
88
|
+
def logs(tail = false)
|
89
|
+
sh_heroku 'logs' + (tail ? ' --tail' : '')
|
90
|
+
end
|
91
|
+
|
92
|
+
def revision
|
93
|
+
git_named_rev(git_revision(repo))
|
70
94
|
end
|
71
95
|
|
72
96
|
private
|
73
97
|
|
74
|
-
def sh_heroku
|
98
|
+
def sh_heroku(command)
|
75
99
|
sh "heroku #{command} --app #{app}"
|
76
100
|
end
|
77
101
|
end
|
data/lib/heroku_san/version.rb
CHANGED
data/lib/tasks.rb
CHANGED
@@ -5,17 +5,18 @@ include Git
|
|
5
5
|
|
6
6
|
@heroku_san.all.each do |stage|
|
7
7
|
desc "Select #{stage} Heroku app for later commands"
|
8
|
-
task stage do
|
8
|
+
task "heroku:stage:#{stage}" do
|
9
9
|
@heroku_san << stage
|
10
10
|
end
|
11
|
-
|
12
|
-
|
13
|
-
desc 'Select all Heroku apps for later command'
|
14
|
-
task :all do
|
15
|
-
@heroku_san << @heroku_san.all
|
11
|
+
task stage => "heroku:stage:#{stage}"
|
16
12
|
end
|
17
13
|
|
18
14
|
namespace :heroku do
|
15
|
+
desc 'Select all Heroku apps for later command'
|
16
|
+
task 'stage:all' do
|
17
|
+
@heroku_san << @heroku_san.all
|
18
|
+
end
|
19
|
+
|
19
20
|
desc "Creates the Heroku app"
|
20
21
|
task :create do
|
21
22
|
each_heroku_app do |stage|
|
@@ -23,7 +24,7 @@ namespace :heroku do
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
|
-
desc "Generate the Heroku gems manifest from gem dependencies"
|
27
|
+
#desc "Generate the Heroku gems manifest from gem dependencies"
|
27
28
|
task :gems => 'gems:base' do
|
28
29
|
raise HerokuSan::Deprecated
|
29
30
|
end
|
@@ -35,7 +36,7 @@ namespace :heroku do
|
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
|
-
desc 'Adds a collaborator'
|
39
|
+
desc 'Adds a collaborator (asks for email)'
|
39
40
|
task :share do
|
40
41
|
print "Email address of collaborator to add: "
|
41
42
|
$stdout.flush
|
@@ -45,7 +46,7 @@ namespace :heroku do
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
|
-
desc 'Removes a collaborator'
|
49
|
+
desc 'Removes a collaborator (asks for email)'
|
49
50
|
task :unshare do
|
50
51
|
print "Email address of collaborator to remove: "
|
51
52
|
$stdout.flush
|
@@ -58,15 +59,10 @@ namespace :heroku do
|
|
58
59
|
desc 'Lists configured apps'
|
59
60
|
task :apps => :all do
|
60
61
|
each_heroku_app do |stage|
|
62
|
+
rev = stage.revision
|
61
63
|
puts "#{stage.name} is shorthand for the Heroku app #{stage.app} located at:"
|
62
64
|
puts " #{stage.repo}"
|
63
|
-
|
64
|
-
rev = `git ls-remote -h #{stage.repo}`.split(' ').first
|
65
|
-
if rev.blank?
|
66
|
-
puts 'not deployed'
|
67
|
-
else
|
68
|
-
puts `git name-rev #{rev}`
|
69
|
-
end
|
65
|
+
puts " @ #{rev.blank? ? 'not deployed' : rev}"
|
70
66
|
puts
|
71
67
|
end
|
72
68
|
end
|
@@ -83,26 +79,10 @@ namespace :heroku do
|
|
83
79
|
end
|
84
80
|
end
|
85
81
|
|
86
|
-
desc 'Add proper RACK_ENV to each application'
|
87
|
-
task :rack_env => :all do
|
88
|
-
each_heroku_app do |stage|
|
89
|
-
command = "heroku config --app #{stage.app}"
|
90
|
-
puts command
|
91
|
-
config = Hash[`#{command}`.scan(/^(.+?)\s*=>\s*(.+)$/)]
|
92
|
-
if config['RACK_ENV'] != stage.name
|
93
|
-
sh "heroku config:add --app #{stage.app} RACK_ENV=#{stage.name}"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
82
|
desc 'Add config:vars to each application.'
|
99
83
|
task :config do
|
100
84
|
each_heroku_app do |stage|
|
101
|
-
|
102
|
-
stage.config.each do |var, value|
|
103
|
-
command += " #{var}=#{value}"
|
104
|
-
end
|
105
|
-
sh(command)
|
85
|
+
stage.push_config
|
106
86
|
end
|
107
87
|
end
|
108
88
|
|
@@ -122,6 +102,18 @@ namespace :heroku do
|
|
122
102
|
end
|
123
103
|
|
124
104
|
namespace :config do
|
105
|
+
desc 'Add proper RACK_ENV to each application'
|
106
|
+
task :rack_env => :all do
|
107
|
+
each_heroku_app do |stage|
|
108
|
+
command = "heroku config --app #{stage.app}"
|
109
|
+
puts command
|
110
|
+
config = Hash[`#{command}`.scan(/^(.+?)\s*=>\s*(.+)$/)]
|
111
|
+
if config['RACK_ENV'] != stage.name
|
112
|
+
stage.push_config RACK_ENV: stage.name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
125
117
|
desc "Lists config variables as set on Heroku"
|
126
118
|
task :list do
|
127
119
|
each_heroku_app do |stage|
|
@@ -152,7 +144,7 @@ namespace :heroku do
|
|
152
144
|
desc "Pushes the given commit (default: HEAD)"
|
153
145
|
task :push, :commit do |t, args|
|
154
146
|
each_heroku_app do |stage|
|
155
|
-
|
147
|
+
stage.deploy(args[:commit])
|
156
148
|
end
|
157
149
|
end
|
158
150
|
|
@@ -160,7 +152,7 @@ namespace :heroku do
|
|
160
152
|
desc "Force-pushes the given commit (default: HEAD)"
|
161
153
|
task :force, :commit do |t, args|
|
162
154
|
each_heroku_app do |stage|
|
163
|
-
|
155
|
+
stage.deploy(args[:commit], :force)
|
164
156
|
end
|
165
157
|
end
|
166
158
|
end
|
@@ -185,89 +177,122 @@ namespace :heroku do
|
|
185
177
|
stage.maintenance :off
|
186
178
|
end
|
187
179
|
end
|
188
|
-
end
|
189
|
-
|
190
|
-
desc "Pushes the given commit, migrates and restarts (default: HEAD)"
|
191
|
-
task :deploy, [:commit] => [:before_deploy] do |t, args|
|
192
|
-
each_heroku_app do |stage|
|
193
|
-
git_push(args[:commit] || git_parsed_tag(stage.tag), stage.repo)
|
194
|
-
stage.migrate
|
195
|
-
end
|
196
|
-
Rake::Task[:after_deploy].execute
|
197
|
-
end
|
198
180
|
|
199
|
-
|
200
|
-
|
201
|
-
task :force, [:commit] => [:before_deploy] do |t, args|
|
181
|
+
desc "Pushes the given commit, migrates and restarts (default: HEAD)"
|
182
|
+
task :deploy, [:commit] => [:before_deploy] do |t, args|
|
202
183
|
each_heroku_app do |stage|
|
203
|
-
|
184
|
+
stage.deploy(args[:commit])
|
204
185
|
stage.migrate
|
205
186
|
end
|
206
187
|
Rake::Task[:after_deploy].execute
|
207
188
|
end
|
208
|
-
end
|
209
189
|
|
210
|
-
|
211
|
-
|
212
|
-
|
190
|
+
namespace :deploy do
|
191
|
+
desc "Force-pushes the given commit, migrates and restarts (default: HEAD)"
|
192
|
+
task :force, [:commit] => [:before_deploy] do |t, args|
|
193
|
+
each_heroku_app do |stage|
|
194
|
+
stage.deploy(args[:commit], :force)
|
195
|
+
stage.migrate
|
196
|
+
end
|
197
|
+
Rake::Task[:after_deploy].execute
|
198
|
+
end
|
213
199
|
|
214
|
-
desc "Callback before deploys"
|
215
|
-
task :
|
216
|
-
end
|
200
|
+
desc "Callback before deploys"
|
201
|
+
task :before do
|
202
|
+
end
|
217
203
|
|
218
|
-
desc "Callback after deploys"
|
219
|
-
task :
|
220
|
-
end
|
204
|
+
desc "Callback after deploys"
|
205
|
+
task :after do
|
206
|
+
end
|
221
207
|
|
222
|
-
|
223
|
-
task :capture do
|
224
|
-
raise Deprecated
|
225
|
-
end
|
208
|
+
end
|
226
209
|
|
227
|
-
|
228
|
-
|
229
|
-
each_heroku_app do |stage|
|
230
|
-
stage.run 'console'
|
210
|
+
task :force_deploy do
|
211
|
+
raise HerokuSan::Deprecated
|
231
212
|
end
|
232
|
-
end
|
233
213
|
|
234
|
-
desc "
|
235
|
-
task :
|
236
|
-
|
237
|
-
stage.restart
|
214
|
+
#desc "Captures a bundle on Heroku"
|
215
|
+
task :capture do
|
216
|
+
raise HerokuSan::Deprecated
|
238
217
|
end
|
239
|
-
end
|
240
218
|
|
241
|
-
desc "
|
242
|
-
task :
|
243
|
-
|
244
|
-
|
219
|
+
desc "Opens a remote console"
|
220
|
+
task :console do
|
221
|
+
each_heroku_app do |stage|
|
222
|
+
stage.run 'console'
|
223
|
+
end
|
245
224
|
end
|
246
|
-
end
|
247
225
|
|
248
|
-
desc "
|
249
|
-
task :
|
250
|
-
|
251
|
-
|
226
|
+
desc "Restarts remote servers"
|
227
|
+
task :restart do
|
228
|
+
each_heroku_app do |stage|
|
229
|
+
stage.restart
|
230
|
+
end
|
252
231
|
end
|
253
|
-
end
|
254
232
|
|
255
|
-
namespace :
|
256
|
-
|
233
|
+
namespace :logs do
|
234
|
+
task :default do
|
235
|
+
each_heroku_app do |stage|
|
236
|
+
stage.logs
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
desc "Tail the Heroku logs (requires logging:expanded)"
|
241
|
+
task :tail do
|
242
|
+
each_heroku_app do |stage|
|
243
|
+
stage.logs(:tail)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
desc "Shows the Heroku logs"
|
249
|
+
task :logs => 'logs:default'
|
250
|
+
|
251
|
+
namespace :db do
|
252
|
+
desc "Migrates and restarts remote servers"
|
253
|
+
task :migrate do
|
254
|
+
each_heroku_app do |stage|
|
255
|
+
stage.migrate
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
desc "Pull database from stage to local dev database"
|
260
|
+
task :pull do
|
261
|
+
each_heroku_app do |stage|
|
262
|
+
sh "heroku pgdumps:capture --app #{stage.app}"
|
263
|
+
dump = `heroku pgdumps --app #{stage.app}`.split("\n").last.split(" ").first
|
264
|
+
sh "mkdir -p #{Rails.root}/db/dumps"
|
265
|
+
file = "#{Rails.root}/db/dumps/#{dump}.sql.gz"
|
266
|
+
url = `heroku pgdumps:url --app #{stage.app} #{dump}`.chomp
|
267
|
+
sh "wget", url, "-O", file
|
268
|
+
sh "rake db:drop db:create"
|
269
|
+
sh "gunzip -c #{file} | #{Rails.root}/script/dbconsole"
|
270
|
+
sh "rake jobs:clear"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
desc "Run a bash shell on Heroku"
|
276
|
+
task :shell do
|
257
277
|
each_heroku_app do |stage|
|
258
|
-
|
259
|
-
dump = `heroku pgdumps --app #{stage.app}`.split("\n").last.split(" ").first
|
260
|
-
sh "mkdir -p #{Rails.root}/db/dumps"
|
261
|
-
file = "#{Rails.root}/db/dumps/#{dump}.sql.gz"
|
262
|
-
url = `heroku pgdumps:url --app #{stage.app} #{dump}`.chomp
|
263
|
-
sh "wget", url, "-O", file
|
264
|
-
sh "rake db:drop db:create"
|
265
|
-
sh "gunzip -c #{file} | #{Rails.root}/script/dbconsole"
|
266
|
-
sh "rake jobs:clear"
|
278
|
+
stage.run 'bash'
|
267
279
|
end
|
268
280
|
end
|
269
281
|
end
|
270
282
|
|
283
|
+
task :all => 'heroku:stage:all'
|
284
|
+
task :deploy => 'heroku:deploy'
|
285
|
+
task 'deploy:force' => 'heroku:deploy:force'
|
286
|
+
task :before_deploy => 'heroku:deploy:before'
|
287
|
+
task :after_deploy => 'heroku:deploy:after'
|
288
|
+
task :console => 'heroku:console'
|
289
|
+
task :restart => 'heroku:restart'
|
290
|
+
task :migrate => 'heroku:db:migrate'
|
291
|
+
task :logs => 'heroku:logs:default'
|
292
|
+
task 'logs:tail' => 'heroku:logs:tail'
|
293
|
+
task 'heroku:rack_env' => 'heroku:config:rack_env'
|
294
|
+
task :shell => 'heroku:shell'
|
295
|
+
|
271
296
|
def each_heroku_app(&block)
|
272
297
|
@heroku_san.each_app(&block)
|
273
298
|
puts
|
data/spec/git_spec.rb
CHANGED
@@ -52,4 +52,23 @@ describe GitTest do
|
|
52
52
|
subject.git_rev_parse(nil).should == nil
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
describe "#git_revision" do
|
57
|
+
it "returns the current revision of the repository (on Heroku)" do
|
58
|
+
subject.should_receive("`").with("git ls-remote --heads staging master") { "sha\n" }
|
59
|
+
subject.git_revision('staging').should == 'sha'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns nil if there is no revision (i.e. not deployed yet)" do
|
63
|
+
subject.should_receive("`").with("git ls-remote --heads staging master") { "\n" }
|
64
|
+
subject.git_revision('staging').should == nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#git_named_rev" do
|
69
|
+
it "returns symbolic names for given rev" do
|
70
|
+
subject.should_receive("`").with("git name-rev sha") {"sha production/123456\n"}
|
71
|
+
subject.git_named_rev('sha').should == 'sha production/123456'
|
72
|
+
end
|
73
|
+
end
|
55
74
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe HerokuSan::Stage do
|
4
|
+
include Git
|
4
5
|
subject { HerokuSan::Stage.new('production', {"app" => "awesomeapp", "stack" => "bamboo-ree-1.8.7"})}
|
5
6
|
|
6
7
|
context "initializes" do
|
@@ -19,6 +20,16 @@ describe HerokuSan::Stage do
|
|
19
20
|
its(:repo) { should == 'git@heroku.com:awesomeapp-demo.git' }
|
20
21
|
end
|
21
22
|
|
23
|
+
describe "#app" do
|
24
|
+
its(:app) { should == 'awesomeapp'}
|
25
|
+
context "blank app" do
|
26
|
+
subject { HerokuSan::Stage.new('production') }
|
27
|
+
it "should raise an error" do
|
28
|
+
expect { subject.app }.to raise_error(HerokuSan::MissingApp, /production: is missing the app: configuration value\./)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
22
33
|
context "celadon cedar stack has a different API" do
|
23
34
|
describe "#stack" do
|
24
35
|
it "returns the name of the stack from Heroku" do
|
@@ -54,6 +65,28 @@ EOT
|
|
54
65
|
end
|
55
66
|
end
|
56
67
|
|
68
|
+
describe "#deploy" do
|
69
|
+
it "deploys to heroku" do
|
70
|
+
subject.should_receive(:git_push).with(git_parsed_tag(subject.tag), subject.repo, [])
|
71
|
+
subject.deploy
|
72
|
+
end
|
73
|
+
|
74
|
+
it "deploys with a custom sha" do
|
75
|
+
subject.should_receive(:git_push).with('deadbeef', subject.repo, [])
|
76
|
+
subject.deploy('deadbeef')
|
77
|
+
end
|
78
|
+
|
79
|
+
it "deploys with --force" do
|
80
|
+
subject.should_receive(:git_push).with(git_parsed_tag(subject.tag), subject.repo, %w[--force])
|
81
|
+
subject.deploy(nil, :force)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "deploys with a custom sha & --force" do
|
85
|
+
subject.should_receive(:git_push).with('deadbeef', subject.repo, %w[--force])
|
86
|
+
subject.deploy('deadbeef', :force)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
57
90
|
describe "#migrate" do
|
58
91
|
it "runs rake db:migrate" do
|
59
92
|
subject.should_receive(:sh).with("heroku run:rake db:migrate --app awesomeapp")
|
@@ -62,7 +95,7 @@ EOT
|
|
62
95
|
end
|
63
96
|
end
|
64
97
|
|
65
|
-
describe "#maintenance" do
|
98
|
+
describe "#maintenance" do
|
66
99
|
it ":on" do
|
67
100
|
subject.should_receive(:sh).with("heroku maintenance:on --app awesomeapp")
|
68
101
|
subject.maintenance :on
|
@@ -78,6 +111,27 @@ EOT
|
|
78
111
|
subject.maintenance :busy
|
79
112
|
end.to raise_error ArgumentError, "Action #{:busy.inspect} must be one of (:on, :off)"
|
80
113
|
end
|
114
|
+
|
115
|
+
context "with a block" do
|
116
|
+
it "wraps it in a maitenance mode" do
|
117
|
+
subject.should_receive(:sh).with("heroku maintenance:on --app awesomeapp")
|
118
|
+
reactor = mock("Reactor"); reactor.should_receive(:scram).with(:now)
|
119
|
+
subject.should_receive(:sh).with("heroku maintenance:off --app awesomeapp")
|
120
|
+
subject.maintenance do
|
121
|
+
reactor.scram(:now)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
it "ensures that maintenance mode is turned off" do
|
125
|
+
subject.should_receive(:sh).with("heroku maintenance:on --app awesomeapp")
|
126
|
+
reactor = mock("Reactor"); reactor.should_receive(:scram).with(:now).and_raise(RuntimeError)
|
127
|
+
subject.should_receive(:sh).with("heroku maintenance:off --app awesomeapp")
|
128
|
+
expect {
|
129
|
+
subject.maintenance do
|
130
|
+
reactor.scram(:now)
|
131
|
+
end
|
132
|
+
}.to raise_error
|
133
|
+
end
|
134
|
+
end
|
81
135
|
end
|
82
136
|
|
83
137
|
describe "#create" do
|
@@ -133,6 +187,39 @@ EOT
|
|
133
187
|
subject.should_receive(:sh).with("heroku logs --app awesomeapp")
|
134
188
|
subject.logs
|
135
189
|
end
|
190
|
+
it "tails log files" do
|
191
|
+
subject.should_receive(:sh).with("heroku logs --tail --app awesomeapp")
|
192
|
+
subject.logs(:tail)
|
193
|
+
end
|
136
194
|
end
|
137
195
|
|
196
|
+
describe "#push_config" do
|
197
|
+
it "updates the configuration settings on Heroku" do
|
198
|
+
subject = HerokuSan::Stage.new('test', {"app" => "awesomeapp", "config" => {FOO: 'bar', DOG: 'emu'}})
|
199
|
+
subject.should_receive(:sh).with("heroku config:add FOO=bar DOG=emu --app awesomeapp")
|
200
|
+
subject.push_config
|
201
|
+
end
|
202
|
+
it "properly escapes variables" do
|
203
|
+
subject = HerokuSan::Stage.new('test', {"app" => "awesomeapp", "config" => {FOO: ' bar\emu bat zebra '}})
|
204
|
+
subject.should_receive(:sh).with("heroku config:add FOO=#{Shellwords.escape(' bar\emu bat zebra ')} --app awesomeapp")
|
205
|
+
subject.push_config
|
206
|
+
end
|
207
|
+
it "pushes the options hash" do
|
208
|
+
subject.should_receive(:sh).with("heroku config:add RACK_ENV=magic --app awesomeapp")
|
209
|
+
subject.push_config(RACK_ENV: 'magic')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#revision" do
|
214
|
+
it "returns the named remote revision for the stage" do
|
215
|
+
subject.should_receive(:git_revision).with(subject.repo) {"sha"}
|
216
|
+
subject.should_receive(:git_named_rev).with('sha') {"sha production/123456"}
|
217
|
+
subject.revision.should == 'sha production/123456'
|
218
|
+
end
|
219
|
+
it "returns nil if the stage has never been deployed" do
|
220
|
+
subject.should_receive(:git_revision).with(subject.repo) {nil}
|
221
|
+
subject.should_receive(:git_named_rev).with(nil) {''}
|
222
|
+
subject.revision.should == ''
|
223
|
+
end
|
224
|
+
end
|
138
225
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heroku_san
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,11 +12,11 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2012-03-
|
15
|
+
date: 2012-03-06 00:00:00.000000000Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rails
|
19
|
-
requirement: &
|
19
|
+
requirement: &2153413220 !ruby/object:Gem::Requirement
|
20
20
|
none: false
|
21
21
|
requirements:
|
22
22
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: '2'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *2153413220
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: heroku
|
30
|
-
requirement: &
|
30
|
+
requirement: &2153412680 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ! '>='
|
@@ -35,10 +35,10 @@ dependencies:
|
|
35
35
|
version: '2'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *2153412680
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: rake
|
41
|
-
requirement: &
|
41
|
+
requirement: &2153412280 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ! '>='
|
@@ -46,10 +46,10 @@ dependencies:
|
|
46
46
|
version: '0'
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *2153412280
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: aruba
|
52
|
-
requirement: &
|
52
|
+
requirement: &2153411640 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ! '>='
|
@@ -57,10 +57,10 @@ dependencies:
|
|
57
57
|
version: '0'
|
58
58
|
type: :development
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *2153411640
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: cucumber
|
63
|
-
requirement: &
|
63
|
+
requirement: &2153411060 !ruby/object:Gem::Requirement
|
64
64
|
none: false
|
65
65
|
requirements:
|
66
66
|
- - ! '>='
|
@@ -68,10 +68,10 @@ dependencies:
|
|
68
68
|
version: '0'
|
69
69
|
type: :development
|
70
70
|
prerelease: false
|
71
|
-
version_requirements: *
|
71
|
+
version_requirements: *2153411060
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: rake
|
74
|
-
requirement: &
|
74
|
+
requirement: &2153410400 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
76
76
|
requirements:
|
77
77
|
- - ! '>='
|
@@ -79,10 +79,10 @@ dependencies:
|
|
79
79
|
version: '0'
|
80
80
|
type: :development
|
81
81
|
prerelease: false
|
82
|
-
version_requirements: *
|
82
|
+
version_requirements: *2153410400
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: bundler
|
85
|
-
requirement: &
|
85
|
+
requirement: &2153409500 !ruby/object:Gem::Requirement
|
86
86
|
none: false
|
87
87
|
requirements:
|
88
88
|
- - ~>
|
@@ -90,7 +90,7 @@ dependencies:
|
|
90
90
|
version: '1.0'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
|
-
version_requirements: *
|
93
|
+
version_requirements: *2153409500
|
94
94
|
description: Manage multiple Heroku instances/apps for a single Rails app using Rake
|
95
95
|
email: elijah.miller@gmail.com
|
96
96
|
executables: []
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- .gitignore
|
102
102
|
- .gitmodules
|
103
103
|
- .rvmrc
|
104
|
+
- CHANGELOG.md
|
104
105
|
- Gemfile
|
105
106
|
- LICENSE
|
106
107
|
- README.rdoc
|
@@ -108,6 +109,7 @@ files:
|
|
108
109
|
- autotest/discover.rb
|
109
110
|
- cucumber.yml
|
110
111
|
- examples/auto_tagger.rake
|
112
|
+
- examples/push_revision.rake
|
111
113
|
- features/config.feature
|
112
114
|
- features/extended-config.feature
|
113
115
|
- features/remote.feature
|