paratrooper 1.1.3 → 1.2.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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paratrooper (0.3.0)
4
+ paratrooper (1.1.3)
5
5
  heroku-api (~> 0.3)
6
6
  netrc (~> 0.7)
7
7
 
@@ -11,7 +11,7 @@ GEM
11
11
  coderay (1.0.8)
12
12
  diff-lcs (1.1.3)
13
13
  excon (0.16.10)
14
- heroku-api (0.3.7)
14
+ heroku-api (0.3.8)
15
15
  excon (~> 0.16.10)
16
16
  method_source (0.8.1)
17
17
  netrc (0.7.7)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ## Paratrooper
1
+ ![Paratrooper](http://f.cl.ly/items/0Z1v1P1l1B1h1k1l2q0E/paratrooper_header.png)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/paratrooper.png)](http://badge.fury.io/rb/paratrooper)
4
4
  [![Build Status](https://travis-ci.org/mattpolito/paratrooper.png?branch=master)](https://travis-ci.org/mattpolito/paratrooper)
@@ -175,6 +175,11 @@ end
175
175
  4. Push to the branch (`git push origin my-new-feature`)
176
176
  5. Create new Pull Request
177
177
 
178
+ ## Thanks
179
+
180
+ * [Rye Mason][] for the fantastic heading image
181
+
178
182
  [Heroku]: http://heroku.com
179
183
  [Heroku Toolbelt]: http://toolbelt.heroku.com
180
184
  [New Relic]: http://newrelic.com
185
+ [Rye Mason]: https://github.com/ryenotbread
@@ -1,62 +1,119 @@
1
1
  require 'paratrooper/heroku_wrapper'
2
- require 'paratrooper/default_formatter'
3
2
  require 'paratrooper/system_caller'
3
+ require 'paratrooper/notifiers/screen_notifier'
4
4
 
5
5
  module Paratrooper
6
+
7
+ # Public: Entry point into the library.
8
+ #
6
9
  class Deploy
7
- attr_reader :app_name, :formatter, :system_caller, :heroku, :tag_name,
10
+ attr_reader :app_name, :notifiers, :system_caller, :heroku, :tag_name,
8
11
  :match_tag
9
12
 
13
+ # Public: Initializes a Deploy
14
+ #
15
+ # app_name - A String naming the Heroku application to be interacted with.
16
+ # options - The Hash options is used to provide additional functionality.
17
+ # :notifiers - Array of objects responsible for handling
18
+ # notifications (optional).
19
+ # :heroku - Object wrapper around heroku-api (optional).
20
+ # :tag - String name to be used as a git reference
21
+ # point (optional).
22
+ # :match_tag_to - String name of git reference point to match
23
+ # :tag to (optional).
24
+ # :system_caller - Object responsible for calling system
25
+ # commands (optional).
10
26
  def initialize(app_name, options = {})
11
27
  @app_name = app_name
12
- @formatter = options[:formatter] || DefaultFormatter.new
28
+ @notifiers = options[:notifiers] || [Notifiers::ScreenNotifier.new]
13
29
  @heroku = options[:heroku] || HerokuWrapper.new(app_name, options)
14
30
  @tag_name = options[:tag]
15
31
  @match_tag = options[:match_tag_to] || 'master'
16
32
  @system_caller = options[:system_caller] || SystemCaller.new
17
33
  end
18
34
 
35
+ def setup
36
+ notify(:setup)
37
+ end
38
+
39
+ def teardown
40
+ notify(:teardown)
41
+ end
42
+
43
+ def notify(step, options={})
44
+ notifiers.each do |notifier|
45
+ notifier.notify(step, default_payload.merge(options))
46
+ end
47
+ end
48
+
49
+ # Public: Activates Heroku maintenance mode.
50
+ #
19
51
  def activate_maintenance_mode
20
- notify_screen("Activating Maintenance Mode")
52
+ notify(:activate_maintenance_mode)
21
53
  heroku.app_maintenance_on
22
54
  end
23
55
 
56
+ # Public: Deactivates Heroku maintenance mode.
57
+ #
24
58
  def deactivate_maintenance_mode
25
- notify_screen("Deactivating Maintenance Mode")
59
+ notify(:deactivate_maintenance_mode)
26
60
  heroku.app_maintenance_off
27
61
  end
28
62
 
63
+ # Public: Creates a git tag and pushes it to repository.
64
+ #
29
65
  def update_repo_tag
30
66
  unless tag_name.nil? || tag_name.empty?
31
- notify_screen("Updating Repo Tag: #{tag_name}")
67
+ notify(:update_repo_tag)
32
68
  system_call "git tag #{tag_name} #{match_tag} -f"
33
69
  system_call "git push -f origin #{tag_name}"
34
70
  end
35
71
  end
36
72
 
73
+ # Public: Pushes repository to Heroku.
74
+ #
37
75
  def push_repo
38
76
  reference_point = tag_name || 'master'
39
- notify_screen("Pushing #{reference_point} to Heroku")
77
+ notify(:push_repo, reference_point: reference_point)
40
78
  system_call "git push -f #{git_remote} #{reference_point}:master"
41
79
  end
42
80
 
81
+ # Public: Runs rails database migrations on your application.
82
+ #
43
83
  def run_migrations
44
- notify_screen("Running database migrations")
84
+ notify(:run_migrations)
45
85
  system_call "heroku run rake db:migrate --app #{app_name}"
46
86
  end
47
87
 
88
+ # Public: Restarts application on Heroku.
89
+ #
48
90
  def app_restart
49
- notify_screen("Restarting application")
91
+ notify(:app_restart)
50
92
  heroku.app_restart
51
93
  end
52
94
 
95
+ # Public: cURL for application URL to start your Heroku dyno.
96
+ #
53
97
  def warm_instance(wait_time = 3)
54
98
  sleep wait_time
55
- notify_screen("Accessing #{app_url} to warm up your application")
99
+ notify(:warm_instance)
56
100
  system_call "curl -Il http://#{app_url}"
57
101
  end
58
102
 
103
+ # Public: Execute common deploy steps.
104
+ #
105
+ # Default deploy consists of:
106
+ # * Activating maintenance page
107
+ # * Updating repository tag
108
+ # * Pushing repository to Heroku
109
+ # * Running database migrations
110
+ # * Restarting application on Heroku
111
+ # * Deactivating maintenance page
112
+ # * cURL'ing application URL to warm Heroku dyno
113
+ #
114
+ # Alias: #deploy
59
115
  def default_deploy
116
+ setup
60
117
  activate_maintenance_mode
61
118
  update_repo_tag
62
119
  push_repo
@@ -64,6 +121,7 @@ module Paratrooper
64
121
  app_restart
65
122
  deactivate_maintenance_mode
66
123
  warm_instance
124
+ teardown
67
125
  end
68
126
  alias_method :deploy, :default_deploy
69
127
 
@@ -72,14 +130,23 @@ module Paratrooper
72
130
  heroku.app_url
73
131
  end
74
132
 
75
- def git_remote
76
- "git@heroku.com:#{app_name}.git"
133
+ def default_payload
134
+ {
135
+ app_name: app_name,
136
+ app_url: app_url,
137
+ git_remote: git_remote,
138
+ tag_name: tag_name,
139
+ match_tag: match_tag
140
+ }
77
141
  end
78
142
 
79
- def notify_screen(message)
80
- formatter.display(message)
143
+ def git_remote
144
+ "git@heroku.com:#{app_name}.git"
81
145
  end
82
146
 
147
+ # Internal: Calls commands meant to go to system
148
+ #
149
+ # call - String version of system command
83
150
  def system_call(call)
84
151
  system_caller.execute(call)
85
152
  end
@@ -0,0 +1,17 @@
1
+ module Paratrooper
2
+ class Notifier
3
+ def notify(step_name, options = {})
4
+ self.send(step_name, options)
5
+ end
6
+
7
+ def activate_maintenance_mode(options = {}); end
8
+ def deactivate_maintenance_mode(options = {}); end
9
+ def update_repo_tag(options = {}); end
10
+ def push_repo(options = {}); end
11
+ def run_migrations(options = {}); end
12
+ def app_restart(options = {}); end
13
+ def warm_instance(options = {}); end
14
+ def setup(options = {}); end
15
+ def teardown(options = {}); end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ require 'paratrooper/notifier'
2
+
3
+ module Paratrooper
4
+ module Notifiers
5
+ class AirbrakeNotifier
6
+ def setup
7
+ `airbrake deploy`
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ require 'paratrooper/notifier'
2
+
3
+ module Paratrooper
4
+ module Notifiers
5
+
6
+ # Public: Sends notification to NewRelic to stop monitoring while deploy is
7
+ # happening
8
+ #
9
+ class NewRelicNotifier < Notifier
10
+ attr_reader :account_id, :api_key, :application_id
11
+
12
+ # Public: Initializes NewRelicNotifier
13
+ #
14
+ # api_key - String api key from NewRelic
15
+ # account_id - String NewRelic account id
16
+ # application_id - String NewRelic id of application
17
+ def initialize(api_key, account_id, application_id)
18
+ @api_key = api_key
19
+ @account_id = account_id
20
+ @application_id = application_id
21
+ end
22
+
23
+ def setup
24
+ %x[curl https://heroku.newrelic.com/accounts/#{account_id}/applications/#{application_id}/ping_targets/disable -X POST -H "X-Api-Key: #{api_key}"]
25
+ end
26
+
27
+ def teardown
28
+ %x[curl https://heroku.newrelic.com/accounts/#{account_id}/applications/#{application_id}/ping_targets/enable -X POST -H "X-Api-Key: #{api_key}"]
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,67 @@
1
+ require 'paratrooper/notifier'
2
+
3
+ module Paratrooper
4
+ module Notifiers
5
+
6
+ # Public: Default notifier for outputting messages to screen.
7
+ #
8
+ class ScreenNotifier < Notifier
9
+ attr_reader :output
10
+
11
+ # Public: Initializes ScreenNotifier
12
+ #
13
+ # output - IO object (default: STDOUT)
14
+ def initialize(output = STDOUT)
15
+ @output = output
16
+ end
17
+
18
+ # Public: Displays message with decoration
19
+ #
20
+ # message - String message to be displayed
21
+ #
22
+ # Examples
23
+ #
24
+ # display("Excellent Message")
25
+ # # =>
26
+ # # => ==========================================================================
27
+ # # => >> Excellent Message
28
+ # # => ==========================================================================
29
+ # # =>
30
+ def display(message)
31
+ output.puts
32
+ output.puts "=" * 80
33
+ output.puts ">> #{message}"
34
+ output.puts "=" * 80
35
+ output.puts
36
+ end
37
+
38
+ def activate_maintenance_mode(options = {})
39
+ display("Activating Maintenance Mode")
40
+ end
41
+
42
+ def deactivate_maintenance_mode(options = {})
43
+ display("Deactivating Maintenance Mode")
44
+ end
45
+
46
+ def update_repo_tag(options = {})
47
+ display("Updating Repo Tag: #{options[:tag_name]}")
48
+ end
49
+
50
+ def push_repo(options = {})
51
+ display("Pushing #{options[:reference_point]} to Heroku")
52
+ end
53
+
54
+ def run_migrations(options = {})
55
+ display("Running database migrations")
56
+ end
57
+
58
+ def app_restart(options = {})
59
+ display("Restarting application")
60
+ end
61
+
62
+ def warm_instance(options = {})
63
+ display("Accessing #{options[:app_url]} to warm up your application")
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module Paratrooper
2
- VERSION = "1.1.3"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -9,7 +9,7 @@ describe Paratrooper::Deploy do
9
9
  let(:default_options) do
10
10
  {
11
11
  heroku: heroku,
12
- formatter: formatter,
12
+ notifiers: [],
13
13
  system_caller: system_caller
14
14
  }
15
15
  end
@@ -22,7 +22,6 @@ describe Paratrooper::Deploy do
22
22
  app_maintenance_off: true,
23
23
  )
24
24
  end
25
- let(:formatter) { double(:formatter, puts: '') }
26
25
  let(:system_caller) { double(:system_caller) }
27
26
  let(:domain_response) do
28
27
  double(:domain_response, body: [{'domain' => 'application_url'}])
@@ -46,26 +45,19 @@ describe Paratrooper::Deploy do
46
45
  end
47
46
  end
48
47
 
49
- context "accepts :formatter" do
50
- let(:options) { { formatter: formatter } }
51
- let(:formatter) { double(:formatter) }
48
+ context "accepts :notifiers" do
49
+ let(:options) { { notifiers: [notifiers] } }
50
+ let(:notifiers) { double(:notifier) }
52
51
 
53
- it "and responds to #formatter" do
54
- expect(deployer.formatter).to eq(formatter)
52
+ it "and responds to #notifiers" do
53
+ expect(deployer.notifiers).to eq([notifiers])
55
54
  end
56
55
  end
57
56
  end
58
57
 
59
58
  describe "#activate_maintenance_mode" do
60
- let(:options) { { formatter: formatter } }
61
- let(:formatter) { double(:formatter, puts: true) }
62
-
63
- before do
64
- formatter.stub(:display)
65
- end
66
-
67
- it "displays message" do
68
- formatter.should_receive(:display).with('Activating Maintenance Mode')
59
+ it 'sends notification' do
60
+ deployer.should_receive(:notify).with(:activate_maintenance_mode).once
69
61
  deployer.activate_maintenance_mode
70
62
  end
71
63
 
@@ -76,12 +68,8 @@ describe Paratrooper::Deploy do
76
68
  end
77
69
 
78
70
  describe "#deactivate_maintenance_mode" do
79
- before do
80
- formatter.stub(:display)
81
- end
82
-
83
- it "displays message" do
84
- formatter.should_receive(:display).with('Deactivating Maintenance Mode')
71
+ it 'sends notification' do
72
+ deployer.should_receive(:notify).with(:deactivate_maintenance_mode).once
85
73
  deployer.deactivate_maintenance_mode
86
74
  end
87
75
 
@@ -97,11 +85,10 @@ describe Paratrooper::Deploy do
97
85
 
98
86
  before do
99
87
  system_caller.stub(:execute)
100
- formatter.stub(:display)
101
88
  end
102
89
 
103
- it 'displays message' do
104
- formatter.should_receive(:display).with('Updating Repo Tag: awesome')
90
+ it 'sends notification' do
91
+ deployer.should_receive(:notify).with(:update_repo_tag).once
105
92
  deployer.update_repo_tag
106
93
  end
107
94
 
@@ -142,11 +129,11 @@ describe Paratrooper::Deploy do
142
129
  describe "#push_repo" do
143
130
  before do
144
131
  system_caller.stub(:execute)
145
- formatter.stub(:display)
146
132
  end
147
133
 
148
- it 'displays message' do
149
- formatter.should_receive(:display).with('Pushing master to Heroku')
134
+ it 'sends notification' do
135
+ deployer.should_receive(:notify)
136
+ .with(:push_repo, reference_point: 'master').once
150
137
  deployer.push_repo
151
138
  end
152
139
 
@@ -160,11 +147,10 @@ describe Paratrooper::Deploy do
160
147
  describe "#run_migrations" do
161
148
  before do
162
149
  system_caller.stub(:execute)
163
- formatter.stub(:display)
164
150
  end
165
151
 
166
- it 'displays message' do
167
- formatter.should_receive(:display).with('Running database migrations')
152
+ it 'sends notification' do
153
+ deployer.should_receive(:notify).with(:run_migrations).once
168
154
  deployer.run_migrations
169
155
  end
170
156
 
@@ -176,12 +162,8 @@ describe Paratrooper::Deploy do
176
162
  end
177
163
 
178
164
  describe "#app_restart" do
179
- before do
180
- formatter.stub(:display)
181
- end
182
-
183
- it 'displays message' do
184
- formatter.should_receive(:display).with('Restarting application')
165
+ it 'sends notification' do
166
+ deployer.should_receive(:notify).with(:app_restart).once
185
167
  deployer.app_restart
186
168
  end
187
169
 
@@ -194,12 +176,10 @@ describe Paratrooper::Deploy do
194
176
  describe "#warm_instance" do
195
177
  before do
196
178
  system_caller.stub(:execute)
197
- formatter.stub(:display)
198
179
  end
199
180
 
200
- it 'displays message' do
201
- expected_notice = 'Accessing application_url to warm up your application'
202
- formatter.should_receive(:display).with(expected_notice)
181
+ it 'sends notification' do
182
+ deployer.should_receive(:notify).with(:warm_instance).once
203
183
  deployer.warm_instance(0)
204
184
  end
205
185
 
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'paratrooper/notifier'
3
+
4
+ describe Paratrooper::Notifier do
5
+ let(:notifier) { described_class.new }
6
+ describe '#notify' do
7
+ it 'sends correct method options' do
8
+ notifier.should_receive(:update_repo_tag).with(test: 'blah')
9
+ notifier.notify(:update_repo_tag, test: 'blah')
10
+ end
11
+ end
12
+ end
@@ -1,7 +1,8 @@
1
1
  require 'spec_helper'
2
- require 'paratrooper/default_formatter'
2
+ require 'paratrooper/notifiers/screen_notifier'
3
+ require 'stringio'
3
4
 
4
- describe Paratrooper::DefaultFormatter do
5
+ describe Paratrooper::Notifiers::ScreenNotifier do
5
6
  let(:formatter) { described_class.new(output_stub) }
6
7
  let(:output_stub) { StringIO.new }
7
8
 
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: 1.1.3
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-20 00:00:00.000000000 Z
13
+ date: 2013-03-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
@@ -107,18 +107,22 @@ files:
107
107
  - README.md
108
108
  - Rakefile
109
109
  - lib/paratrooper.rb
110
- - lib/paratrooper/default_formatter.rb
111
110
  - lib/paratrooper/deploy.rb
112
111
  - lib/paratrooper/heroku_wrapper.rb
113
112
  - lib/paratrooper/local_api_key_extractor.rb
113
+ - lib/paratrooper/notifier.rb
114
+ - lib/paratrooper/notifiers/airbrake_notifier.rb
115
+ - lib/paratrooper/notifiers/new_relic_notifier.rb.rb
116
+ - lib/paratrooper/notifiers/screen_notifier.rb
114
117
  - lib/paratrooper/system_caller.rb
115
118
  - lib/paratrooper/version.rb
116
119
  - paratrooper.gemspec
117
120
  - spec/fixtures/netrc
118
- - spec/paratrooper/default_formatter_spec.rb
119
121
  - spec/paratrooper/deploy_spec.rb
120
122
  - spec/paratrooper/heroku_wrapper_spec.rb
121
123
  - spec/paratrooper/local_api_key_extractor_spec.rb
124
+ - spec/paratrooper/notifier_spec.rb
125
+ - spec/paratrooper/notifiers/screen_notifier_spec.rb
122
126
  - spec/spec_helper.rb
123
127
  homepage: http://github.com/mattpolito/paratrooper
124
128
  licenses: []
@@ -146,9 +150,10 @@ specification_version: 3
146
150
  summary: Library to create task for deployment to Heroku
147
151
  test_files:
148
152
  - spec/fixtures/netrc
149
- - spec/paratrooper/default_formatter_spec.rb
150
153
  - spec/paratrooper/deploy_spec.rb
151
154
  - spec/paratrooper/heroku_wrapper_spec.rb
152
155
  - spec/paratrooper/local_api_key_extractor_spec.rb
156
+ - spec/paratrooper/notifier_spec.rb
157
+ - spec/paratrooper/notifiers/screen_notifier_spec.rb
153
158
  - spec/spec_helper.rb
154
159
  has_rdoc:
@@ -1,19 +0,0 @@
1
- require 'stringio'
2
-
3
- module Paratrooper
4
- class DefaultFormatter
5
- attr_reader :output
6
-
7
- def initialize(output = STDOUT)
8
- @output = output
9
- end
10
-
11
- def display(message)
12
- output.puts
13
- output.puts "=" * 80
14
- output.puts ">> #{message}"
15
- output.puts "=" * 80
16
- output.puts
17
- end
18
- end
19
- end