heroku_san 2.2.2 → 3.0.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.
@@ -1,12 +1,18 @@
1
+ require 'heroku_san'
1
2
  require 'git'
2
3
  include Git
3
4
 
4
- @heroku_san = HerokuSan::Project.new(Rails.root.join('config', 'heroku.yml'))
5
+ if defined?(Rails)
6
+ HerokuSan.project ||= HerokuSan::Project.new(
7
+ Rails.root.join("config", "heroku.yml"),
8
+ :deploy => HerokuSan::Deploy::Rails
9
+ )
10
+ end
5
11
 
6
- @heroku_san.all.each do |stage|
12
+ HerokuSan.project.all.each do |stage|
7
13
  desc "Select #{stage} Heroku app for later commands"
8
14
  task "heroku:stage:#{stage}" do
9
- @heroku_san << stage
15
+ HerokuSan.project << stage
10
16
  end
11
17
  task stage => "heroku:stage:#{stage}"
12
18
  end
@@ -14,7 +20,7 @@ end
14
20
  namespace :heroku do
15
21
  desc 'Select all Heroku apps for later command'
16
22
  task 'stage:all' do
17
- @heroku_san << @heroku_san.all
23
+ HerokuSan.project << HerokuSan.project.all
18
24
  end
19
25
 
20
26
  desc "Creates the Heroku app"
@@ -108,8 +114,9 @@ namespace :heroku do
108
114
 
109
115
  desc 'Creates an example configuration file'
110
116
  task :create_config do
111
- filename = %Q{#{@heroku_san.config_file.to_s}}
112
- if @heroku_san.create_config
117
+ # FIXME: sh "rails generate heroku_san"
118
+ filename = %Q{#{HerokuSan.project.config_file.to_s}}
119
+ if HerokuSan.project.create_config
113
120
  puts "Copied example config to #{filename.inspect}"
114
121
  if ENV['EDITOR'] && ENV['EDITOR'] != ''
115
122
  sh "#{ENV['EDITOR']} #{filename}"
@@ -163,7 +170,7 @@ namespace :heroku do
163
170
  desc "Pushes the given commit (default: HEAD)"
164
171
  task :push, :commit do |t, args|
165
172
  each_heroku_app do |stage|
166
- stage.deploy(args[:commit])
173
+ stage.push(args[:commit])
167
174
  end
168
175
  end
169
176
 
@@ -171,7 +178,7 @@ namespace :heroku do
171
178
  desc "Force-pushes the given commit (default: HEAD)"
172
179
  task :force, :commit do |t, args|
173
180
  each_heroku_app do |stage|
174
- stage.deploy(args[:commit], :force)
181
+ stage.push(args[:commit], :force)
175
182
  end
176
183
  end
177
184
  end
@@ -203,8 +210,7 @@ namespace :heroku do
203
210
  desc "Pushes the given commit, migrates and restarts (default: HEAD)"
204
211
  task :deploy, [:commit] => [:before_deploy] do |t, args|
205
212
  each_heroku_app do |stage|
206
- stage.deploy(args[:commit])
207
- stage.migrate
213
+ stage.deploy(args)
208
214
  end
209
215
  Rake::Task[:after_deploy].execute
210
216
  end
@@ -213,8 +219,7 @@ namespace :heroku do
213
219
  desc "Force-pushes the given commit, migrates and restarts (default: HEAD)"
214
220
  task :force, [:commit] => [:before_deploy] do |t, args|
215
221
  each_heroku_app do |stage|
216
- stage.deploy(args[:commit], :force)
217
- stage.migrate
222
+ stage.deploy(args.merge(:force => true))
218
223
  end
219
224
  Rake::Task[:after_deploy].execute
220
225
  end
@@ -325,7 +330,7 @@ alias_task 'heroku:rack_env' => 'heroku:config:rack_env'
325
330
  alias_task :shell => 'heroku:shell'
326
331
 
327
332
  def each_heroku_app(&block)
328
- @heroku_san.each_app(&block)
333
+ HerokuSan.project.each_app(&block)
329
334
  puts
330
335
  rescue HerokuSan::NoApps => e
331
336
  puts "You must first specify at least one Heroku app:
@@ -1,3 +1,3 @@
1
1
  module HerokuSan
2
- VERSION = "2.2.2"
2
+ VERSION = "3.0.0"
3
3
  end
data/lib/heroku_san.rb CHANGED
@@ -1,10 +1,13 @@
1
- require 'railtie' if defined?(Rails) && Rails::VERSION::MAJOR == 3
1
+ require 'railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
2
2
  require 'git'
3
3
  require 'heroku_san/stage'
4
4
  require 'heroku_san/project'
5
+ require 'heroku_san/deploy/rails'
6
+ require 'heroku_san/deploy/sinatra'
5
7
 
6
8
  module HerokuSan
9
+ mattr_accessor :project
7
10
  class NoApps < StandardError; end
8
11
  class MissingApp < StandardError; end
9
12
  class Deprecated < StandardError; end
10
- end
13
+ end
data/lib/railtie.rb CHANGED
@@ -1,10 +1,9 @@
1
- require 'heroku_san'
2
1
  require 'rails'
3
2
 
4
3
  module HerokuSan
5
4
  class Railtie < Rails::Railtie
6
5
  rake_tasks do
7
- load 'tasks.rb'
6
+ load 'heroku_san/tasks.rb'
8
7
  end
9
8
  end
10
9
  end
@@ -1 +1 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'tasks'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../heroku_san', 'tasks'))
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ module HerokuSan
4
+ module Deploy
5
+ describe Base do
6
+ let(:stage) { HerokuSan::Stage.new('test', {"app" => "awesomeapp", "deploy" => 'HerokuSan::Deploy::Base'}) }
7
+
8
+ it "calls push" do
9
+ subject = described_class.new(stage, {})
10
+ stage.should_receive(:push).with(nil, nil)
11
+ subject.deploy
12
+ end
13
+
14
+ it "calls push(sha)" do
15
+ subject = described_class.new(stage, {:commit => 'sha'})
16
+ stage.should_receive(:push).with('sha', nil)
17
+ subject.deploy
18
+ end
19
+
20
+ it "calls push(nil, :force)" do
21
+ subject = described_class.new(stage, {:force => true})
22
+ stage.should_receive(:push).with(nil, true)
23
+ subject.deploy
24
+ end
25
+
26
+ it "calls push(sha, :force)" do
27
+ subject = described_class.new(stage, {:commit => 'sha', :force => true})
28
+ stage.should_receive(:push).with('sha', true)
29
+ subject.deploy
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ module HerokuSan
4
+ module Deploy
5
+ describe Rails do
6
+ let(:stage) { HerokuSan::Stage.new('test', {"app" => "awesomeapp", "deploy" => 'HerokuSan::Deploy::Rails'}) }
7
+
8
+ it "calls migrate" do
9
+ subject = described_class.new(stage, {})
10
+ stage.should_receive(:push) # "mock" super
11
+ stage.should_receive(:rake).with('db:migrate')
12
+ stage.should_receive(:restart)
13
+ subject.deploy
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,96 +2,106 @@ require 'spec_helper'
2
2
  require 'tmpdir'
3
3
 
4
4
  describe HerokuSan::Project do
5
- specify ".new with a missing config file has no stages" 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
- subject { heroku_san }
18
-
19
- its(:all) { should =~ %w[production staging demo] }
20
-
21
- context "using the heroku_san format" do
22
- let(:heroku_san) { HerokuSan::Project.new(File.join(SPEC_ROOT, "fixtures", "old_format.yml")) }
5
+ let(:heroku_config_file) { File.join(SPEC_ROOT, "fixtures", "example.yml") }
6
+ let(:heroku_san) { HerokuSan::Project.new(heroku_config_file) }
7
+ subject { heroku_san }
23
8
 
24
- it "returns a list of apps" do
25
- heroku_san.all.should =~ %w[production staging demo]
9
+ describe ".new" do
10
+ its(:all) { should =~ %w[production staging demo] }
11
+ specify "with a missing config file has no stages" do
12
+ heroku_san = HerokuSan::Project.new("/u/should/never/get/here")
13
+ heroku_san.all.should == []
14
+ end
15
+
16
+ specify "with a deploy option configures each stage with the strategy" do
17
+ heroku_san = HerokuSan::Project.new(heroku_config_file, :deploy => HerokuSan::Deploy::Base)
18
+ heroku_san << heroku_san.all
19
+ heroku_san.each_app do |stage|
20
+ stage.instance_variable_get('@options')['deploy'].should == HerokuSan::Deploy::Base
26
21
  end
27
22
  end
28
-
29
- describe "#apps adds an app to the deploy list" do
30
- it "appends known shorthands to apps" do
31
- heroku_san.apps.should == []
32
- heroku_san << 'production'
33
- heroku_san.apps.should == %w[production]
34
- heroku_san << 'staging'
35
- heroku_san.apps.should == %w[production staging]
36
- heroku_san << 'unknown'
37
- heroku_san.apps.should == %w[production staging]
23
+ end
24
+
25
+ describe "#apps constructs the deploy list" do
26
+ it "appends known shorthands to apps" do
27
+ heroku_san.apps.should == []
28
+ heroku_san << 'production'
29
+ heroku_san.apps.should == %w[production]
30
+ heroku_san << 'staging'
31
+ heroku_san.apps.should == %w[production staging]
32
+ heroku_san << 'unknown'
33
+ heroku_san.apps.should == %w[production staging]
34
+ end
35
+
36
+ it "appends .all (or any array)" do
37
+ heroku_san << heroku_san.all
38
+ heroku_san.apps.should == heroku_san.all
39
+ end
40
+
41
+ describe "extra (default) behaviors" do
42
+ specify "on a git branch that matches an app name" do
43
+ heroku_san.should_receive(:git_active_branch) { "staging" }
44
+ $stdout.should_receive(:puts).with("Defaulting to 'staging' as it matches the current branch")
45
+ expect {
46
+ heroku_san.apps.should == %w[staging]
47
+ }.to change{heroku_san.instance_variable_get('@apps')}.from([]).to(%w[staging])
38
48
  end
39
49
 
40
- it "appends .all (or any array)" do
41
- heroku_san << heroku_san.all
42
- heroku_san.apps.should == heroku_san.all
50
+ specify "on a git branch that doesn't matches an app name" do
51
+ heroku_san.should_receive(:git_active_branch) { "master" }
52
+ heroku_san.apps.should == %w[]
43
53
  end
44
54
 
45
- describe "extra (default) behaviors" do
46
- specify "on a git branch that matches an app name" do
47
- heroku_san.should_receive(:git_active_branch) { "staging" }
48
- $stdout.should_receive(:puts).with("Defaulting to 'staging' as it matches the current branch")
55
+ context "with only a single configured app" do
56
+ let(:heroku_san) { HerokuSan::Project.new(File.join(SPEC_ROOT, "fixtures", "single_app.yml")) }
57
+ it "returns the app" do
58
+ $stdout.should_receive(:puts).with('Defaulting to "production" since only one app is defined')
49
59
  expect {
50
- heroku_san.apps.should == %w[staging]
51
- }.to change{heroku_san.instance_variable_get('@apps')}.from([]).to(%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 "with 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
- expect {
64
- heroku_san.apps.should == %w[production]
65
- }.to change{heroku_san.instance_variable_get('@apps')}.from([]).to(%w[production])
66
- end
60
+ heroku_san.apps.should == %w[production]
61
+ }.to change{heroku_san.instance_variable_get('@apps')}.from([]).to(%w[production])
67
62
  end
68
63
  end
69
64
  end
65
+ end
66
+
67
+ describe "#each_app" do
68
+ it "raises an error is no apps were specified" do
69
+ expect { heroku_san.each_app do true; end }.to raise_error HerokuSan::NoApps
70
+ end
70
71
 
71
- describe "#each_app" do
72
- it "raises an error is no apps were specified" do
73
- expect { heroku_san.each_app do true; end }.to raise_error HerokuSan::NoApps
74
- end
75
-
76
- it "yields to a block with args" do
77
- heroku_san << 'production'
78
- block = double('block')
79
- block.should_receive(:action).with(heroku_san['production'])
80
- heroku_san.each_app do |stage|
81
- block.action(stage)
82
- end
72
+ it "yields to a block with args" do
73
+ heroku_san << 'production'
74
+ block = double('block')
75
+ block.should_receive(:action).with(heroku_san['production'])
76
+ heroku_san.each_app do |stage|
77
+ block.action(stage)
83
78
  end
84
79
  end
85
-
86
- describe "#[]" do
87
- it "returns a config section" do
88
- heroku_san.all.each do |app|
89
- heroku_san[app].should be_a HerokuSan::Stage
90
- end
80
+ end
81
+
82
+ describe "#[]" do
83
+ it "returns a config section" do
84
+ heroku_san.all.each do |app|
85
+ heroku_san[app].should be_a HerokuSan::Stage
91
86
  end
92
87
  end
88
+ end
89
+
90
+ context "using the heroku_san format" do
91
+ let(:heroku_san) { HerokuSan::Project.new(File.join(SPEC_ROOT, "fixtures", "old_format.yml")) }
92
+
93
+ it "returns a list of apps" do
94
+ heroku_san.all.should =~ %w[production staging demo]
95
+ end
96
+ end
97
+
98
+ describe "#create_config" do
99
+ context "unknown project" do
100
+ let(:template_config_file) do
101
+ path = File.join(SPEC_ROOT, "..", "lib/templates", "heroku.example.yml")
102
+ (File.respond_to? :realpath) ? File.realpath(path) : path
103
+ end
93
104
 
94
- describe "#create_config" do
95
105
  it "creates a new file using the example file" do
96
106
  Dir.mktmpdir do |dir|
97
107
  tmp_config_file = File.join dir, 'config.yml'
@@ -100,11 +110,12 @@ describe HerokuSan::Project do
100
110
  heroku_san.create_config.should be_true
101
111
  end
102
112
  end
103
-
113
+
104
114
  it "does not overwrite an existing file" do
105
115
  FileUtils.should_not_receive(:cp)
106
116
  heroku_san.create_config.should be_false
107
117
  end
108
118
  end
109
- end
119
+ end
120
+
110
121
  end
@@ -83,25 +83,25 @@ describe HerokuSan::Stage do
83
83
  end
84
84
  end
85
85
 
86
- describe "#deploy" do
86
+ describe "#push" do
87
87
  it "deploys to heroku" do
88
88
  subject.should_receive(:git_push).with(git_parsed_tag(subject.tag), subject.repo, [])
89
- subject.deploy
89
+ subject.push
90
90
  end
91
91
 
92
92
  it "deploys with a custom sha" do
93
93
  subject.should_receive(:git_push).with('deadbeef', subject.repo, [])
94
- subject.deploy('deadbeef')
94
+ subject.push('deadbeef')
95
95
  end
96
96
 
97
97
  it "deploys with --force" do
98
98
  subject.should_receive(:git_push).with(git_parsed_tag(subject.tag), subject.repo, %w[--force])
99
- subject.deploy(nil, :force)
99
+ subject.push(nil, :force)
100
100
  end
101
101
 
102
102
  it "deploys with a custom sha & --force" do
103
103
  subject.should_receive(:git_push).with('deadbeef', subject.repo, %w[--force])
104
- subject.deploy('deadbeef', :force)
104
+ subject.push('deadbeef', :force)
105
105
  end
106
106
  end
107
107
 
@@ -114,6 +114,25 @@ describe HerokuSan::Stage do
114
114
  end
115
115
  end
116
116
 
117
+ describe "#deploy" do
118
+ context "using the default strategy" do
119
+ it "(rails) pushes & migrates" do
120
+ HerokuSan::Deploy::Rails.any_instance.should_receive(:deploy)
121
+ subject.deploy
122
+ end
123
+ end
124
+ context "using a custom strategy" do
125
+ class TestDeployStrategy < HerokuSan::Deploy::Base
126
+ def deploy; end
127
+ end
128
+ subject = HerokuSan::Stage.new('test', {"app" => "awesomeapp", "deploy" => TestDeployStrategy})
129
+ it "(custom) calls deploy" do
130
+ TestDeployStrategy.any_instance.should_receive(:deploy)
131
+ subject.deploy
132
+ end
133
+ end
134
+ end
135
+
117
136
  describe "#maintenance" do
118
137
  it ":on" do
119
138
  with_app(subject, 'name' => subject.app )do |app_data|