paratrooper 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +22 -4
- data/README.md +6 -4
- data/lib/paratrooper.rb +1 -2
- data/lib/paratrooper/default_formatter.rb +11 -0
- data/lib/paratrooper/deploy.rb +52 -22
- data/lib/paratrooper/system_caller.rb +5 -0
- data/lib/paratrooper/version.rb +1 -1
- data/paratrooper.gemspec +2 -0
- data/spec/paratrooper/deploy_spec.rb +182 -0
- data/spec/spec_helper.rb +1 -0
- metadata +41 -3
data/Gemfile.lock
CHANGED
@@ -1,18 +1,36 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
paratrooper (0.0.
|
4
|
+
paratrooper (0.0.2)
|
5
5
|
heroku-api
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
coderay (1.0.8)
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
excon (0.16.7)
|
13
|
+
heroku-api (0.3.6)
|
14
|
+
excon (~> 0.16.7)
|
15
|
+
method_source (0.8.1)
|
16
|
+
pry (0.9.10)
|
17
|
+
coderay (~> 1.0.5)
|
18
|
+
method_source (~> 0.8)
|
19
|
+
slop (~> 3.3.1)
|
20
|
+
rspec (2.12.0)
|
21
|
+
rspec-core (~> 2.12.0)
|
22
|
+
rspec-expectations (~> 2.12.0)
|
23
|
+
rspec-mocks (~> 2.12.0)
|
24
|
+
rspec-core (2.12.2)
|
25
|
+
rspec-expectations (2.12.1)
|
26
|
+
diff-lcs (~> 1.1.3)
|
27
|
+
rspec-mocks (2.12.1)
|
28
|
+
slop (3.3.3)
|
13
29
|
|
14
30
|
PLATFORMS
|
15
31
|
ruby
|
16
32
|
|
17
33
|
DEPENDENCIES
|
18
34
|
paratrooper!
|
35
|
+
pry
|
36
|
+
rspec (~> 2.12)
|
data/README.md
CHANGED
@@ -18,16 +18,18 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
>> Note: Before getting started, ensure that `ENV['HEROKU_API_KEY']` is set. If you do not know your api key, you can `cat ~/.netrc`. Your api key will be listed as password in that file. This is necessary until reading your crendentials out of the `.netrc` file is implemented.
|
22
|
+
|
21
23
|
Instantiate Paratrooper with the name of your heroku application
|
22
24
|
|
23
25
|
```ruby
|
24
|
-
Paratrooper.new('amazing-app')
|
26
|
+
Paratrooper::Deploy.new('amazing-app')
|
25
27
|
```
|
26
28
|
|
27
29
|
also you can provide a tag name for repository use
|
28
30
|
|
29
31
|
```ruby
|
30
|
-
Paratrooper.new('amazing-app', tag: 'staging')
|
32
|
+
Paratrooper::Deploy.new('amazing-app', tag: 'staging')
|
31
33
|
```
|
32
34
|
|
33
35
|
Then there are methods available to perform common tasks like creating git tags, running migrations, and warming your application instance.
|
@@ -54,14 +56,14 @@ require 'paratrooper'
|
|
54
56
|
namespace :deploy do
|
55
57
|
desc 'Deploy app in staging environment'
|
56
58
|
task :staging do
|
57
|
-
deployment = Paratrooper.new("amazing-staging-app", tag: 'staging')
|
59
|
+
deployment = Paratrooper::Deploy.new("amazing-staging-app", tag: 'staging')
|
58
60
|
|
59
61
|
deployment.deploy
|
60
62
|
end
|
61
63
|
|
62
64
|
desc 'Deploy app in production environment'
|
63
65
|
task :production do
|
64
|
-
deployment = Paratrooper.new("amazing-production-app", tag: 'production')
|
66
|
+
deployment = Paratrooper::Deploy.new("amazing-production-app", tag: 'production')
|
65
67
|
|
66
68
|
deployment.deploy
|
67
69
|
end
|
data/lib/paratrooper.rb
CHANGED
data/lib/paratrooper/deploy.rb
CHANGED
@@ -1,51 +1,55 @@
|
|
1
1
|
require 'heroku-api'
|
2
|
+
require 'paratrooper/default_formatter'
|
2
3
|
|
3
4
|
module Paratrooper
|
4
5
|
class Deploy
|
5
|
-
attr_reader :app_name, :heroku, :tag_name
|
6
|
+
attr_reader :app_name, :formatter, :system_caller, :heroku, :tag_name
|
6
7
|
|
7
8
|
def initialize(app_name, options = {})
|
8
|
-
@app_name
|
9
|
-
@
|
10
|
-
@
|
9
|
+
@app_name = app_name
|
10
|
+
@formatter = options[:formatter] || DefaultFormatter.new
|
11
|
+
@heroku = options[:heroku_auth] || Heroku::API.new(api_key: ENV['HEROKU_API_KEY'])
|
12
|
+
@tag_name = options[:tag]
|
13
|
+
@system_caller = options[:system_caller] || SystemCaller.new
|
11
14
|
end
|
12
15
|
|
13
16
|
def activate_maintenance_mode
|
14
17
|
notify_screen("Activating Maintenance Mode")
|
15
|
-
|
18
|
+
app_maintenance_on
|
16
19
|
end
|
17
20
|
|
18
21
|
def deactivate_maintenance_mode
|
19
22
|
notify_screen("Deactivating Maintenance Mode")
|
20
|
-
|
23
|
+
app_maintenance_off
|
21
24
|
end
|
22
25
|
|
23
26
|
def update_repo_tag
|
24
|
-
unless tag_name.empty?
|
27
|
+
unless tag_name.nil? || tag_name.empty?
|
25
28
|
notify_screen("Updating Repo Tag: #{tag_name}")
|
26
|
-
|
27
|
-
|
29
|
+
system_call "git tag #{tag_name} -f"
|
30
|
+
system_call "git push origin #{tag_name}"
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
34
|
def push_repo(branch = 'master')
|
32
35
|
notify_screen("Pushing #{branch} to Heroku")
|
33
|
-
|
36
|
+
system_call "git push -f #{git_remote} #{branch}"
|
34
37
|
end
|
35
38
|
|
36
39
|
def run_migrations
|
37
40
|
notify_screen("Running database migrations")
|
38
|
-
|
41
|
+
system_call "heroku run rake db:migrate --app #{app_name}"
|
39
42
|
end
|
40
43
|
|
41
44
|
def app_restart
|
42
|
-
|
45
|
+
notify_screen("Restarting application")
|
46
|
+
_app_restart
|
43
47
|
end
|
44
48
|
|
45
|
-
def warm_instance(wait_time =
|
49
|
+
def warm_instance(wait_time = 3)
|
46
50
|
sleep wait_time
|
47
51
|
notify_screen("Accessing #{app_url} to warm up your application")
|
48
|
-
|
52
|
+
system_call "curl -Il http://#{app_url}"
|
49
53
|
end
|
50
54
|
|
51
55
|
def default_deploy
|
@@ -60,20 +64,46 @@ module Paratrooper
|
|
60
64
|
alias_method :deploy, :default_deploy
|
61
65
|
|
62
66
|
private
|
63
|
-
def
|
64
|
-
|
67
|
+
def _app_maintenance(flag)
|
68
|
+
heroku.post_app_maintenance(app_name, flag)
|
65
69
|
end
|
66
70
|
|
67
|
-
def
|
71
|
+
def _app_restart
|
72
|
+
heroku.post_ps_restart(app_name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def _app_domain_name
|
68
76
|
heroku.get_domains(app_name).body.last['domain']
|
69
77
|
end
|
70
78
|
|
79
|
+
def app_maintenance_off
|
80
|
+
_app_maintenance('0')
|
81
|
+
end
|
82
|
+
|
83
|
+
def app_maintenance_on
|
84
|
+
_app_maintenance('1')
|
85
|
+
end
|
86
|
+
|
87
|
+
def app_url
|
88
|
+
_app_domain_name
|
89
|
+
end
|
90
|
+
|
91
|
+
def git_remote
|
92
|
+
"git@heroku.com:#{app_name}.git"
|
93
|
+
end
|
94
|
+
|
71
95
|
def notify_screen(message)
|
72
|
-
puts
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
96
|
+
formatter.puts(message)
|
97
|
+
end
|
98
|
+
|
99
|
+
def system_call(call)
|
100
|
+
system_caller.execute(call)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
SystemCaller = Struct.new(:call) do
|
105
|
+
def execute
|
106
|
+
system(call)
|
77
107
|
end
|
78
108
|
end
|
79
109
|
end
|
data/lib/paratrooper/version.rb
CHANGED
data/paratrooper.gemspec
CHANGED
@@ -17,5 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
+
gem.add_development_dependency 'rspec', '~> 2.12'
|
21
|
+
gem.add_development_dependency 'pry'
|
20
22
|
gem.add_dependency 'heroku-api'
|
21
23
|
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'paratrooper/deploy'
|
3
|
+
|
4
|
+
describe Paratrooper::Deploy do
|
5
|
+
let(:deployer) do
|
6
|
+
described_class.new(app_name, default_options.merge(options))
|
7
|
+
end
|
8
|
+
let(:app_name) { 'app' }
|
9
|
+
let(:default_options) do
|
10
|
+
{
|
11
|
+
heroku_auth: heroku,
|
12
|
+
formatter: formatter,
|
13
|
+
system_caller: system_caller
|
14
|
+
}
|
15
|
+
end
|
16
|
+
let(:options) { Hash.new }
|
17
|
+
let(:heroku) do
|
18
|
+
double(:heroku,
|
19
|
+
post_app_maintenance: true,
|
20
|
+
post_ps_restart: true,
|
21
|
+
get_domains: domain_response
|
22
|
+
)
|
23
|
+
end
|
24
|
+
let(:formatter) { double(:formatter, puts: '') }
|
25
|
+
let(:system_caller) { double(:system_caller) }
|
26
|
+
let(:domain_response) do
|
27
|
+
double(:domain_response, body: [{'domain' => 'application_url'}])
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "options" do
|
31
|
+
context "accepts :tag" do
|
32
|
+
let(:options) { { tag: 'tag_name' } }
|
33
|
+
|
34
|
+
it "and responds to #tag_name" do
|
35
|
+
expect(deployer.tag_name).to eq('tag_name')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "accepts :heroku_auth" do
|
40
|
+
let(:options) { { heroku_auth: heroku } }
|
41
|
+
let(:heroku) { double(:heroku) }
|
42
|
+
|
43
|
+
it "and responds to #heroku" do
|
44
|
+
expect(deployer.heroku).to eq(heroku)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "accepts :formatter" do
|
49
|
+
let(:options) { { formatter: formatter } }
|
50
|
+
let(:formatter) { double(:formatter) }
|
51
|
+
|
52
|
+
it "and responds to #formatter" do
|
53
|
+
expect(deployer.formatter).to eq(formatter)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#activate_maintenance_mode" do
|
59
|
+
let(:options) { { formatter: formatter } }
|
60
|
+
let(:formatter) { double(:formatter, puts: true) }
|
61
|
+
|
62
|
+
it "displays message" do
|
63
|
+
formatter.should_receive(:puts).with('Activating Maintenance Mode')
|
64
|
+
deployer.activate_maintenance_mode
|
65
|
+
end
|
66
|
+
|
67
|
+
it "makes call to heroku to turn on maintenance mode" do
|
68
|
+
heroku.should_receive(:post_app_maintenance).with(app_name, '1')
|
69
|
+
deployer.activate_maintenance_mode
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#deactivate_maintenance_mode" do
|
74
|
+
it "displays message" do
|
75
|
+
formatter.should_receive(:puts).with('Deactivating Maintenance Mode')
|
76
|
+
deployer.deactivate_maintenance_mode
|
77
|
+
end
|
78
|
+
|
79
|
+
it "makes call to heroku to turn on maintenance mode" do
|
80
|
+
heroku.should_receive(:post_app_maintenance).with(app_name, '0')
|
81
|
+
deployer.deactivate_maintenance_mode
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#update_repo_tag" do
|
86
|
+
context "when a tag_name is available" do
|
87
|
+
let(:options) { { tag: 'awesome' } }
|
88
|
+
|
89
|
+
before do
|
90
|
+
system_caller.stub(:execute)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'displays message' do
|
94
|
+
formatter.should_receive(:puts).with('Updating Repo Tag: awesome')
|
95
|
+
deployer.update_repo_tag
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'creates a git tag' do
|
99
|
+
system_caller.should_receive(:execute).with('git tag awesome -f')
|
100
|
+
deployer.update_repo_tag
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'pushes git tag' do
|
104
|
+
system_caller.should_receive(:execute).with('git push origin awesome')
|
105
|
+
deployer.update_repo_tag
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when a tag_name is unavailable" do
|
110
|
+
let(:options) { Hash.new }
|
111
|
+
|
112
|
+
it 'no repo tags are created' do
|
113
|
+
system_caller.should_not_receive(:execute)
|
114
|
+
deployer.update_repo_tag
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#push_repo" do
|
120
|
+
before do
|
121
|
+
system_caller.stub(:execute)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'displays message' do
|
125
|
+
formatter.should_receive(:puts).with('Pushing master to Heroku')
|
126
|
+
deployer.push_repo
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'pushes repo to heroku' do
|
130
|
+
expected_call = 'git push -f git@heroku.com:app.git master'
|
131
|
+
system_caller.should_receive(:execute).with(expected_call)
|
132
|
+
deployer.push_repo
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "#run_migrations" do
|
137
|
+
before do
|
138
|
+
system_caller.stub(:execute)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'displays message' do
|
142
|
+
formatter.should_receive(:puts).with('Running database migrations')
|
143
|
+
deployer.run_migrations
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'pushes repo to heroku' do
|
147
|
+
expected_call = 'heroku run rake db:migrate --app app'
|
148
|
+
system_caller.should_receive(:execute).with(expected_call)
|
149
|
+
deployer.run_migrations
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "#app_restart" do
|
154
|
+
it 'displays message' do
|
155
|
+
formatter.should_receive(:puts).with('Restarting application')
|
156
|
+
deployer.app_restart
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'restarts your heroku instance' do
|
160
|
+
heroku.should_receive(:post_ps_restart).with(app_name)
|
161
|
+
deployer.app_restart
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "#warm_instance" do
|
166
|
+
before do
|
167
|
+
system_caller.stub(:execute)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'displays message' do
|
171
|
+
expected_notice = 'Accessing application_url to warm up your application'
|
172
|
+
formatter.should_receive(:puts).with(expected_notice)
|
173
|
+
deployer.warm_instance(0)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'pings application url' do
|
177
|
+
expected_call = 'curl -Il http://application_url'
|
178
|
+
system_caller.should_receive(:execute).with(expected_call)
|
179
|
+
deployer.warm_instance(0)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rspec'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paratrooper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,8 +10,40 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-01-
|
13
|
+
date: 2013-01-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.12'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '2.12'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: pry
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
15
47
|
- !ruby/object:Gem::Dependency
|
16
48
|
name: heroku-api
|
17
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -43,9 +75,13 @@ files:
|
|
43
75
|
- README.md
|
44
76
|
- Rakefile
|
45
77
|
- lib/paratrooper.rb
|
78
|
+
- lib/paratrooper/default_formatter.rb
|
46
79
|
- lib/paratrooper/deploy.rb
|
80
|
+
- lib/paratrooper/system_caller.rb
|
47
81
|
- lib/paratrooper/version.rb
|
48
82
|
- paratrooper.gemspec
|
83
|
+
- spec/paratrooper/deploy_spec.rb
|
84
|
+
- spec/spec_helper.rb
|
49
85
|
homepage: http://github.com/hashrocket/paratrooper
|
50
86
|
licenses: []
|
51
87
|
post_install_message:
|
@@ -70,4 +106,6 @@ rubygems_version: 1.8.24
|
|
70
106
|
signing_key:
|
71
107
|
specification_version: 3
|
72
108
|
summary: Library to create task for deployment to Heroku
|
73
|
-
test_files:
|
109
|
+
test_files:
|
110
|
+
- spec/paratrooper/deploy_spec.rb
|
111
|
+
- spec/spec_helper.rb
|