paratrooper 0.0.2 → 0.0.3
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/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
|