heroku_san 1.3.0 → 2.0.rc.1

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.
data/lib/tasks.rb ADDED
@@ -0,0 +1,284 @@
1
+ require 'git'
2
+ include Git
3
+
4
+ @heroku_san = HerokuSan::Project.new(Rails.root.join('config', 'heroku.yml'))
5
+
6
+ @heroku_san.all.each do |stage|
7
+ desc "Select #{stage} Heroku app for later commands"
8
+ task stage do
9
+ @heroku_san << stage
10
+ end
11
+ end
12
+
13
+ desc 'Select all Heroku apps for later command'
14
+ task :all do
15
+ @heroku_san << @heroku_san.all
16
+ end
17
+
18
+ namespace :heroku do
19
+ desc "Creates the Heroku app"
20
+ task :create do
21
+ each_heroku_app do |stage|
22
+ stage.create
23
+ end
24
+ end
25
+
26
+ desc "Generate the Heroku gems manifest from gem dependencies"
27
+ task :gems => 'gems:base' do
28
+ raise HerokuSan::Deprecated
29
+ end
30
+
31
+ desc 'Add git remotes for all apps in this project'
32
+ task :remotes do
33
+ each_heroku_app do |stage|
34
+ sh "git remote add #{stage.name} #{stage.repo}"
35
+ end
36
+ end
37
+
38
+ desc 'Adds a collaborator'
39
+ task :share do
40
+ print "Email address of collaborator to add: "
41
+ $stdout.flush
42
+ email = $stdin.gets
43
+ each_heroku_app do |stage|
44
+ stage.sharing_add email
45
+ end
46
+ end
47
+
48
+ desc 'Removes a collaborator'
49
+ task :unshare do
50
+ print "Email address of collaborator to remove: "
51
+ $stdout.flush
52
+ email = $stdin.gets
53
+ each_heroku_app do |stage|
54
+ stage.sharing_remove email
55
+ end
56
+ end
57
+
58
+ desc 'Lists configured apps'
59
+ task :apps => :all do
60
+ each_heroku_app do |stage|
61
+ puts "#{stage.name} is shorthand for the Heroku app #{stage.app} located at:"
62
+ puts " #{stage.repo}"
63
+ print " @ "
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
70
+ puts
71
+ end
72
+ end
73
+
74
+ namespace :apps do
75
+ desc 'Lists configured apps without hitting heroku'
76
+ task :local => :all do
77
+ each_heroku_app do |stage|
78
+ puts "#{stage.name} is shorthand for the Heroku app #{stage.app} located at:"
79
+ puts " #{stage.repo}"
80
+ puts " the #{stage.name} TAG is '#{stage.tag}'" if stage.tag
81
+ puts
82
+ end
83
+ end
84
+ end
85
+
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
+ desc 'Add config:vars to each application.'
99
+ task :config do
100
+ each_heroku_app do |stage|
101
+ command = "heroku config:add --app #{stage.app}"
102
+ stage.config.each do |var, value|
103
+ command += " #{var}=#{value}"
104
+ end
105
+ sh(command)
106
+ end
107
+ end
108
+
109
+ desc 'Creates an example configuration file'
110
+ task :create_config do
111
+ filename = %Q{#{@heroku_san.config_file.to_s}}
112
+ if @heroku_san.create_config
113
+ puts "Copied example config to #{filename.inspect}"
114
+ if ENV['EDITOR'].present?
115
+ sh "#{ENV['EDITOR']} #{filename}"
116
+ else
117
+ puts "Please edit #{filename.inspect} with your application's settings."
118
+ end
119
+ else
120
+ puts "#{filename.inspect} already exists"
121
+ end
122
+ end
123
+
124
+ namespace :config do
125
+ desc "Lists config variables as set on Heroku"
126
+ task :list do
127
+ each_heroku_app do |stage|
128
+ puts "#{stage.name}:"
129
+ stage.long_config
130
+ end
131
+ end
132
+
133
+ namespace :list do
134
+ desc "Lists local config variables without setting them"
135
+ task :local do
136
+ each_heroku_app do |stage|
137
+ (stage.config).each do |var, value|
138
+ puts "#{stage.name} #{var}: '#{value}'"
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ desc 'Runs a rake task remotely'
146
+ task :rake, [:task] do |t, args|
147
+ each_heroku_app do |stage|
148
+ stage.run 'rake', args.task
149
+ end
150
+ end
151
+
152
+ desc "Pushes the given commit (default: HEAD)"
153
+ task :push, :commit do |t, args|
154
+ each_heroku_app do |stage|
155
+ git_push(args[:commit] || git_parsed_tag(stage.tag), stage.repo)
156
+ end
157
+ end
158
+
159
+ namespace :push do
160
+ desc "Force-pushes the given commit (default: HEAD)"
161
+ task :force, :commit do |t, args|
162
+ each_heroku_app do |stage|
163
+ git_push(args[:commit] || git_parsed_tag(stage.tag), stage.repo, %w[--force])
164
+ end
165
+ end
166
+ end
167
+
168
+ desc "Enable maintenance mode"
169
+ task :maintenance do
170
+ each_heroku_app do |stage|
171
+ stage.maintenance :on
172
+ end
173
+ end
174
+
175
+ desc "Enable maintenance mode"
176
+ task :maintenance_on do
177
+ each_heroku_app do |stage|
178
+ stage.maintenance :on
179
+ end
180
+ end
181
+
182
+ desc "Disable maintenance mode"
183
+ task :maintenance_off do
184
+ each_heroku_app do |stage|
185
+ stage.maintenance :off
186
+ end
187
+ 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
+
199
+ namespace :deploy do
200
+ desc "Force-pushes the given commit, migrates and restarts (default: HEAD)"
201
+ task :force, [:commit] => [:before_deploy] do |t, args|
202
+ each_heroku_app do |stage|
203
+ git_push(args[:commit] || git_parsed_tag(stage.tag), stage.repo, %w[--force])
204
+ stage.migrate
205
+ end
206
+ Rake::Task[:after_deploy].execute
207
+ end
208
+ end
209
+
210
+ task :force_deploy do
211
+ raise Deprecated
212
+ end
213
+
214
+ desc "Callback before deploys"
215
+ task :before_deploy do
216
+ end
217
+
218
+ desc "Callback after deploys"
219
+ task :after_deploy do
220
+ end
221
+
222
+ desc "Captures a bundle on Heroku"
223
+ task :capture do
224
+ raise Deprecated
225
+ end
226
+
227
+ desc "Opens a remote console"
228
+ task :console do
229
+ each_heroku_app do |stage|
230
+ stage.run 'console'
231
+ end
232
+ end
233
+
234
+ desc "Restarts remote servers"
235
+ task :restart do
236
+ each_heroku_app do |stage|
237
+ stage.restart
238
+ end
239
+ end
240
+
241
+ desc "Migrates and restarts remote servers"
242
+ task :migrate do
243
+ each_heroku_app do |stage|
244
+ stage.migrate
245
+ end
246
+ end
247
+
248
+ desc "Shows the Heroku logs"
249
+ task :logs do
250
+ each_heroku_app do |stage|
251
+ stage.logs
252
+ end
253
+ end
254
+
255
+ namespace :db do
256
+ task :pull do
257
+ each_heroku_app do |stage|
258
+ sh "heroku pgdumps:capture --app #{stage.app}"
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"
267
+ end
268
+ end
269
+ end
270
+
271
+ def each_heroku_app(&block)
272
+ @heroku_san.each_app(&block)
273
+ puts
274
+ rescue HerokuSan::NoApps => e
275
+ puts "You must first specify at least one Heroku app:
276
+ rake <app> [<app>] <command>
277
+ rake production restart
278
+ rake demo staging deploy"
279
+
280
+ puts "\nYou can use also command all Heroku apps for this project:
281
+ rake all heroku:share"
282
+
283
+ exit(1)
284
+ end
@@ -1,15 +1,18 @@
1
1
  #
2
2
  # Format:
3
3
  #
4
- # <heroku_san shorthand name>:
4
+ # <stage name>:
5
5
  # app: <Heroku app name>
6
6
  # stack: <Heroku stack, optional>
7
+ # tag: <git tag pattern, optional>
8
+ # repo: <git repository, optional>
7
9
  # config:
8
10
  # - <Heroku config:var name>: <Heroku config:var value>
9
11
  #
10
12
  production:
11
13
  app: awesomeapp
12
14
  stack: bamboo-ree-1.8.7
15
+ tag: production/*
13
16
  config:
14
17
  BUNDLE_WITHOUT: "development:test"
15
18
  GOOGLE_ANALYTICS: "UA-12345678-1"
@@ -0,0 +1,26 @@
1
+ #
2
+ # Format:
3
+ #
4
+ # <heroku_san shorthand name>:
5
+ # app: <Heroku app name>
6
+ # tag: <git tag pattern>
7
+ # config:
8
+ # - <Heroku config:var name>: <Heroku config:var value>
9
+ #
10
+ production:
11
+ app: awesomeapp
12
+ tag: production/*
13
+ config:
14
+ BUNDLE_WITHOUT: "development:test"
15
+ GOOGLE_ANALYTICS: "UA-12345678-1"
16
+
17
+ staging:
18
+ app: awesomeapp-staging
19
+ stack: bamboo-ree-1.8.7
20
+ config: &default
21
+ BUNDLE_WITHOUT: "development:test"
22
+
23
+ demo:
24
+ app: awesomeapp-demo
25
+ stack: cedar
26
+ config: *default
@@ -0,0 +1,7 @@
1
+ config_repo: 'file:///<%= File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', 'features', 'data', 'test-config') %>'
2
+ production:
3
+ app: awesomeapp
4
+ staging:
5
+ app: awesomeapp-staging
6
+ demo:
7
+ app: awesomeapp-demo
@@ -0,0 +1,10 @@
1
+ #
2
+ # Format:
3
+ #
4
+ # apps:
5
+ # shorthand: <Heroku app name>
6
+ #
7
+ apps:
8
+ production: awesomeapp
9
+ staging: awesomeapp-staging
10
+ demo: awesomeapp-demo
@@ -0,0 +1,6 @@
1
+ production:
2
+ app: awesomeapp
3
+ tag: production/*
4
+ config:
5
+ BUNDLE_WITHOUT: "development:test"
6
+ GOOGLE_ANALYTICS: "UA-12345678-1"
data/spec/git_spec.rb ADDED
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require 'git'
3
+
4
+ class GitTest; include Git; end
5
+
6
+ describe GitTest do
7
+ describe "#git_push" do
8
+ it "pushes to heroku" do
9
+ subject.should_receive(:sh).with("git update-ref refs/heroku_san/deploy HEAD")
10
+ subject.should_receive(:sh).with("git push git@heroku.com:awesomeapp.git refs/heroku_san/deploy:refs/heads/master")
11
+ subject.should_receive(:sh).with("git update-ref -d refs/heroku_san/deploy")
12
+ subject.git_push(nil, 'git@heroku.com:awesomeapp.git')
13
+ end
14
+
15
+ it "pushes a specific commit to heroku" do
16
+ subject.should_receive(:sh).with("git update-ref refs/heroku_san/deploy kommit")
17
+ subject.should_receive(:sh).with("git push git@heroku.com:awesomeapp.git refs/heroku_san/deploy:refs/heads/master")
18
+ subject.should_receive(:sh).with("git update-ref -d refs/heroku_san/deploy")
19
+ subject.git_push('kommit', 'git@heroku.com:awesomeapp.git')
20
+ end
21
+
22
+ it "includes options, too" do
23
+ subject.should_receive(:sh).with("git update-ref refs/heroku_san/deploy HEAD")
24
+ subject.should_receive(:sh).with("git push git@heroku.com:awesomeapp.git --force -v refs/heroku_san/deploy:refs/heads/master")
25
+ subject.should_receive(:sh).with("git update-ref -d refs/heroku_san/deploy")
26
+ subject.git_push(nil, 'git@heroku.com:awesomeapp.git', %w[--force -v])
27
+ end
28
+ end
29
+
30
+ describe "#git_tag" do
31
+ it "returns the latest tag that matches the pattern" do
32
+ subject.should_receive("`").with("git tag -l 'pattern*'") { "x\n\y\n\z\n" }
33
+ subject.git_tag('pattern*').should == "z"
34
+ end
35
+ it "returns nil if no tags match the pattern" do
36
+ subject.should_receive("`").with("git tag -l 'pattern*'") { "\n" }
37
+ subject.git_tag('pattern*').should == nil
38
+ end
39
+ it "returns nil for a nil tag" do
40
+ subject.should_not_receive("`").with("git tag -l ''") { "\n" }
41
+ subject.git_tag(nil).should == nil
42
+ end
43
+ end
44
+
45
+ describe "#git_rev_parse" do
46
+ it "returns the rev based on the tag" do
47
+ subject.should_receive("`").with("git rev-parse prod/1234567890") { "sha\n" }
48
+ subject.git_rev_parse('prod/1234567890').should == "sha"
49
+ end
50
+ it "returns nil for a blank tag" do
51
+ subject.should_not_receive("`").with("git rev-parse ") { "\n" }
52
+ subject.git_rev_parse(nil).should == nil
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+ require 'tmpdir'
3
+
4
+ describe HerokuSan::Project do
5
+ specify ".new with a missing config file" do
6
+ heroku_san = HerokuSan::Project.new("/u/should/never/get/here")
7
+ heroku_san.all.should == []
8
+ end
9
+
10
+ context "using the example config file" do
11
+ let(:heroku_config_file) { File.join(SPEC_ROOT, "fixtures", "example.yml") }
12
+ let(:template_config_file) {
13
+ path = File.join(SPEC_ROOT, "..", "lib/templates", "heroku.example.yml")
14
+ (File.respond_to? :realpath) ? File.realpath(path) : path
15
+ }
16
+ let(:heroku_san) { HerokuSan::Project.new(heroku_config_file) }
17
+
18
+ it "#all" do
19
+ heroku_san.all.should =~ %w[production staging demo]
20
+ end
21
+
22
+ context "using the heroku_san format" do
23
+ let(:heroku_san) { HerokuSan::Project.new(File.join(SPEC_ROOT, "fixtures", "old_format.yml")) }
24
+
25
+ it "returns a list of apps" do
26
+ heroku_san.all.should =~ %w[production staging demo]
27
+ end
28
+ end
29
+
30
+ describe "Adding an app to the deploy list" do
31
+ it "appends known shorthands to apps" do
32
+ heroku_san.apps.should == []
33
+ heroku_san << 'production'
34
+ heroku_san.apps.should == %w[production]
35
+ heroku_san << 'staging'
36
+ heroku_san.apps.should == %w[production staging]
37
+ heroku_san << 'unknown'
38
+ heroku_san.apps.should == %w[production staging]
39
+ end
40
+
41
+ it "appends .all (or any array)" do
42
+ heroku_san << heroku_san.all
43
+ heroku_san.apps.should == heroku_san.all
44
+ end
45
+ end
46
+
47
+ describe "#apps extra default behaviors" do
48
+ specify "on a git branch that matches an app name" do
49
+ heroku_san.should_receive(:git_active_branch) { "staging" }
50
+ $stdout.should_receive(:puts).with("Defaulting to 'staging' as it matches the current branch")
51
+ heroku_san.apps.should == %w[staging]
52
+ end
53
+
54
+ specify "on a git branch that doesn't matches an app name" do
55
+ heroku_san.should_receive(:git_active_branch) { "master" }
56
+ heroku_san.apps.should == %w[]
57
+ end
58
+
59
+ context "but only a single configured app" do
60
+ let(:heroku_san) { HerokuSan::Project.new(File.join(SPEC_ROOT, "fixtures", "single_app.yml")) }
61
+ it "returns the app" do
62
+ $stdout.should_receive(:puts).with('Defaulting to "production" since only one app is defined')
63
+ heroku_san.apps.should == %w[production]
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#each_app" do
69
+ it "raises an error is no apps were specified" do
70
+ expect { heroku_san.each_app do true; end }.to raise_error HerokuSan::NoApps
71
+ end
72
+
73
+ it "yields to a block with args" do
74
+ heroku_san << 'production'
75
+ block = double('block')
76
+ block.should_receive(:action).with(heroku_san['production'])
77
+ heroku_san.each_app do |stage|
78
+ block.action(stage)
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#[]" do
84
+ it "returns a config section" do
85
+ heroku_san.all.each do |app|
86
+ heroku_san[app].should be_a HerokuSan::Stage
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#create_config" do
92
+ it "creates a new file using the example file" do
93
+ Dir.mktmpdir do |dir|
94
+ tmp_config_file = File.join dir, 'config.yml'
95
+ heroku_san = HerokuSan::Project.new(tmp_config_file)
96
+ FileUtils.should_receive(:cp).with(File.expand_path(template_config_file), tmp_config_file)
97
+ heroku_san.create_config.should be_true
98
+ end
99
+ end
100
+
101
+ it "does not overwrite an existing file" do
102
+ FileUtils.should_not_receive(:cp)
103
+ heroku_san.create_config.should be_false
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe HerokuSan::Stage do
4
+ subject { HerokuSan::Stage.new('production', {"app" => "awesomeapp", "stack" => "bamboo-ree-1.8.7"})}
5
+
6
+ context "initializes" do
7
+ subject { HerokuSan::Stage.new('production',
8
+ {"stack" => "cedar",
9
+ "app" => "awesomeapp-demo",
10
+ "tag" => "demo/*",
11
+ "config"=> {"BUNDLE_WITHOUT"=>"development:test"}
12
+ })}
13
+
14
+ its(:name) { should == 'production' }
15
+ its(:app) { should == 'awesomeapp-demo' }
16
+ its(:stack) { should == 'cedar' }
17
+ its(:tag) { should == "demo/*" }
18
+ its(:config) { should == {"BUNDLE_WITHOUT"=>"development:test"} }
19
+ its(:repo) { should == 'git@heroku.com:awesomeapp-demo.git' }
20
+ end
21
+
22
+ context "celadon cedar stack has a different API" do
23
+ describe "#stack" do
24
+ it "returns the name of the stack from Heroku" do
25
+ subject = HerokuSan::Stage.new('production', {"app" => "awesomeapp"})
26
+ subject.should_receive("`").with("heroku stack --app awesomeapp") {
27
+ <<EOT
28
+ aspen-mri-1.8.6
29
+ * bamboo-mri-1.9.2
30
+ bamboo-ree-1.8.7
31
+ cedar (beta)
32
+ EOT
33
+ }
34
+ subject.stack.should == 'bamboo-mri-1.9.2'
35
+ end
36
+
37
+ it "returns the stack name from the config if it is set there" do
38
+ subject = HerokuSan::Stage.new('production', {"app" => "awesomeapp", "stack" => "cedar"})
39
+ subject.should_not_receive("`")
40
+ subject.stack.should == 'cedar'
41
+ end
42
+ end
43
+
44
+ describe "#run" do
45
+ it "runs commands using the pre-cedar format" do
46
+ subject.should_receive(:sh).with("heroku run:rake foo bar bleh --app awesomeapp")
47
+ subject.run 'rake', 'foo bar bleh'
48
+ end
49
+ it "runs commands using the new cedar format" do
50
+ subject = HerokuSan::Stage.new('production', {"app" => "awesomeapp", "stack" => "cedar"})
51
+ subject.should_receive(:sh).with("heroku run worker foo bar bleh --app awesomeapp")
52
+ subject.run 'worker', 'foo bar bleh'
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#migrate" do
58
+ it "runs rake db:migrate" do
59
+ subject.should_receive(:sh).with("heroku run:rake db:migrate --app awesomeapp")
60
+ subject.should_receive(:sh).with("heroku restart --app awesomeapp")
61
+ subject.migrate
62
+ end
63
+ end
64
+
65
+ describe "#maintenance" do
66
+ it ":on" do
67
+ subject.should_receive(:sh).with("heroku maintenance:on --app awesomeapp")
68
+ subject.maintenance :on
69
+ end
70
+
71
+ it ":off" do
72
+ subject.should_receive(:sh).with("heroku maintenance:off --app awesomeapp")
73
+ subject.maintenance :off
74
+ end
75
+
76
+ it "otherwise raises an ArgumentError" do
77
+ expect do
78
+ subject.maintenance :busy
79
+ end.to raise_error ArgumentError, "Action #{:busy.inspect} must be one of (:on, :off)"
80
+ end
81
+ end
82
+
83
+ describe "#create" do
84
+ it "creates an app on heroku" do
85
+ subject.should_receive(:sh).with("heroku apps:create awesomeapp --stack bamboo-ree-1.8.7")
86
+ subject.create
87
+ end
88
+ it "uses the default stack if none is given" do
89
+ subject = HerokuSan::Stage.new('production', {"app" => "awesomeapp"})
90
+ subject.should_receive(:sh).with("heroku apps:create awesomeapp")
91
+ subject.create
92
+ end
93
+ end
94
+
95
+ describe "#sharing_add" do
96
+ it "add collaborators" do
97
+ subject.should_receive(:sh).with("heroku sharing:add email@example.com --app awesomeapp")
98
+ subject.sharing_add 'email@example.com'
99
+ end
100
+ end
101
+
102
+ describe "#sharing_remove" do
103
+ it "removes collaborators" do
104
+ subject.should_receive(:sh).with("heroku sharing:remove email@example.com --app awesomeapp")
105
+ subject.sharing_remove 'email@example.com'
106
+ end
107
+ end
108
+
109
+ describe "#long_config" do
110
+ it "prints out the remote config" do
111
+ subject.should_receive(:sh).with("heroku config --long --app awesomeapp") {
112
+ <<EOT
113
+ BUNDLE_WITHOUT => development:test
114
+ DATABASE_URL => postgres://thnodhxrzn:T0-UwxLyFgXcnBSHmyhv@ec2-50-19-216-194.compute-1.amazonaws.com/thnodhxrzn
115
+ LANG => en_US.UTF-8
116
+ RACK_ENV => production
117
+ SHARED_DATABASE_URL => postgres://thnodhxrzn:T0-UwxLyFgXcnBSHmyhv@ec2-50-19-216-194.compute-1.amazonaws.com/thnodhxrzn
118
+ EOT
119
+ }
120
+ subject.long_config
121
+ end
122
+ end
123
+
124
+ describe "#restart" do
125
+ it "restarts an app" do
126
+ subject.should_receive(:sh).with("heroku restart --app awesomeapp")
127
+ subject.restart
128
+ end
129
+ end
130
+
131
+ describe "#logs" do
132
+ it "returns log files" do
133
+ subject.should_receive(:sh).with("heroku logs --app awesomeapp")
134
+ subject.logs
135
+ end
136
+ end
137
+
138
+ end
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ SPEC_ROOT = File.dirname(__FILE__)
5
+
6
+ # Requires supporting ruby files with custom matchers and macros, etc,
7
+ # in spec/support/ and its subdirectories.
8
+ Dir[File.join(SPEC_ROOT, "support/**/*.rb")].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ # == Mock Framework
12
+ #
13
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
14
+ #
15
+ # config.mock_with :mocha
16
+ # config.mock_with :flexmock
17
+ # config.mock_with :rr
18
+ config.mock_with :rspec
19
+ end
20
+
21
+ require File.join(SPEC_ROOT, '/../lib/heroku_san')