hr_deploy 0.0.6 → 0.0.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 269384c663c1693b844f227cbd8219d1e9e0ddaf
4
- data.tar.gz: 3f9c00a090f410433ea4949950032515eeaa7f76
3
+ metadata.gz: bce644d0caddde4560e698e8995029f32da4976d
4
+ data.tar.gz: aeb328b6b9cec1f7a210f95b4c9fb9b4b6069b3b
5
5
  SHA512:
6
- metadata.gz: d1a59907ccd34338cd0abf9fbaa37b57ad4368207e318918a494743718ad6a4910888923037a495d464bbc1a49654413fcd255003566caecac853928090e6a65
7
- data.tar.gz: b55cfd0cf957c4f195fb3511326dacaa3c2d67bb266a5d78020268b69d54b75670ca775e76d1e7d5aaaf30f8a1eabd4e37463052d45f774809c0391cb1f2671e
6
+ metadata.gz: 13eb8c7a328d864f9e8db2bb7827e4c59ccc0e5be946232c4131320c4fee275c472c37a89db5bf7be6f3b89bc32d700ff086dce86563e8eff0d19b81f7679d29
7
+ data.tar.gz: f8cca7377f6ffa1ad386a96acd9a859c1d76f8ddb1ba0ca1ac7fbf547c0b7e59bcfa5aee0041d8737f197ed741d26f8eb38830602b16a2c6b4fcb6660aadaed8
@@ -60,6 +60,13 @@ module HR_Deploy
60
60
  # when you execute 'hr_deploy deploy' without arguments.
61
61
  :default: true
62
62
 
63
+ # URL to open after deploy is complete. If a 503 (maintenance) or no
64
+ # response is returned for 5 seconds, URL will be retried for a total
65
+ # time of up to a minute. If this is set, user perceived downtime will
66
+ # be calculated. Wrap in quotes and provide the protocol, e.g. 'http://'
67
+ # or 'https://'. Optional, delete to skip opening the app after the deploy.
68
+ :app_url: 'http://app'
69
+
63
70
  # Example of another target, feel free to delete or modify.
64
71
  - :production:
65
72
  :description: Production
@@ -236,6 +243,12 @@ module HR_Deploy
236
243
  return false
237
244
  end
238
245
 
246
+ when :app_url
247
+ unless value.instance_of?(String)
248
+ self.error = 'App URL should be a string'
249
+ return false
250
+ end
251
+
239
252
  else
240
253
  self.error = "Option unknown: #{option}"
241
254
  return false
@@ -274,7 +287,8 @@ module HR_Deploy
274
287
  backup_db: options[:backup_db],
275
288
  maintenance: options[:maintenance],
276
289
  default: options[:default],
277
- s3_asset_sync: options[:s3_asset_sync])
290
+ s3_asset_sync: options[:s3_asset_sync],
291
+ app_url: options[:app_url])
278
292
  else
279
293
  # Only target name was given, 'options' hash is nil
280
294
  HR_Deploy::Target.new(name: name)
@@ -13,6 +13,7 @@ require 'hr_deploy/tasks/precompile_assets_task.rb'
13
13
  require 'hr_deploy/tasks/push_code_task.rb'
14
14
  require 'hr_deploy/tasks/migrate_db_task.rb'
15
15
  require 'hr_deploy/tasks/restart_task.rb'
16
+ require 'hr_deploy/tasks/open_app_task.rb'
16
17
 
17
18
  module HR_Deploy
18
19
 
@@ -196,6 +197,10 @@ module HR_Deploy
196
197
  tasks_to_run << HR_Deploy::DisableMaintenanceTask.new(target: target, confirm: confirm, dry_run: dry_run)
197
198
  end
198
199
 
200
+ if target.app_url
201
+ tasks_to_run << HR_Deploy::OpenAppTask.new(target: target, dry_run: dry_run)
202
+ end
203
+
199
204
  if target.pinging_interaction?
200
205
  tasks_to_run << HR_Deploy::EnablePingerTask.new(target: target, confirm: confirm, dry_run: dry_run)
201
206
  end
@@ -249,14 +254,36 @@ module HR_Deploy
249
254
  def deploy_succeeded
250
255
  if dry_run
251
256
  print_deploy_successful 'Dry run complete'
257
+
252
258
  else
253
- print_deploy_successful "Deploy complete in #{(Time.now - start_time).round} seconds"
259
+ print_deploy_successful "Deploy complete in #{human_time(Time.now - start_time)}"
260
+
261
+ downtime = calculate_downtime
262
+ print_deploy_successful "User perceived downtime was #{human_time(downtime)}" if downtime
254
263
  end
255
264
 
256
265
  # Execution is finished
257
266
  exit 0
258
267
  end
259
268
 
269
+ def calculate_downtime
270
+ open_app = finished_tasks.find { |task| task.class == HR_Deploy::OpenAppTask }
271
+
272
+ # Can't calculate user perceived downtime accurately if app was not opened
273
+ return nil unless open_app
274
+
275
+ enable_maintenance = finished_tasks.find { |task| task.class == HR_Deploy::EnableMaintenanceTask }
276
+ push_code = finished_tasks.find { |task| task.class == HR_Deploy::PushCodeTask }
277
+
278
+ if enable_maintenance
279
+ starting_time = enable_maintenance.start_time
280
+ else
281
+ starting_time = push_code.start_time
282
+ end
283
+
284
+ open_app.end_time - starting_time
285
+ end
286
+
260
287
  def application_state(failed_task)
261
288
 
262
289
  did_not_change = 'Application state did not change'
@@ -286,6 +313,8 @@ module HR_Deploy
286
313
  unknown
287
314
  when HR_Deploy::DisableMaintenanceTask
288
315
  deployed
316
+ when HR_Deploy::OpenAppTask
317
+ deployed
289
318
  when HR_Deploy::EnablePingerTask
290
319
  deployed
291
320
  when HR_Deploy::CleanNewAssetsTask
@@ -336,5 +365,41 @@ module HR_Deploy
336
365
  def print_app_status(msg)
337
366
  puts msg.yellow
338
367
  end
368
+
369
+ def human_time(seconds)
370
+ seconds = seconds.round
371
+ minutes = seconds / 60
372
+ seconds = seconds % 60
373
+
374
+ minute_string = nil
375
+ second_string = nil
376
+
377
+ unless minutes == 0
378
+ if minutes == 1
379
+ minute_string = 'minute'
380
+ else
381
+ minute_string = 'minutes'
382
+ end
383
+ end
384
+
385
+ unless seconds == 0
386
+ if seconds == 1
387
+ second_string = 'second'
388
+ else
389
+ second_string = 'seconds'
390
+ end
391
+ end
392
+
393
+ result = ''
394
+ result += "#{minutes} #{minute_string} " unless minutes == 0
395
+ result += "#{seconds} #{second_string}" unless seconds == 0
396
+ result.strip!
397
+
398
+ if result == ''
399
+ '0 seconds'
400
+ else
401
+ result
402
+ end
403
+ end
339
404
  end
340
405
  end
@@ -6,6 +6,7 @@ module HR_Deploy
6
6
  attr_reader :new_relic_disable_pinger_url
7
7
  attr_reader :new_relic_enable_pinger_url
8
8
  attr_reader :description
9
+ attr_reader :app_url
9
10
 
10
11
  def initialize(args)
11
12
 
@@ -14,6 +15,7 @@ module HR_Deploy
14
15
  @new_relic_enable_pinger_url = args[:new_relic_enable_pinger_url]
15
16
  @s3_asset_sync = args[:s3_asset_sync]
16
17
  @default = args[:default]
18
+ @app_url = args[:app_url]
17
19
 
18
20
  # Use name for description, if no description given
19
21
  @description = args[:description] || name
@@ -7,6 +7,7 @@ module HR_Deploy
7
7
  def run
8
8
  print_stage 'Enabling maintenance mode...'
9
9
 
10
+ set_start_time
10
11
  execute_system_command("heroku maintenance:on --remote #{target.name}")
11
12
 
12
13
  if dry_run? || !confirm?
@@ -0,0 +1,81 @@
1
+ require 'hr_deploy/tasks/task'
2
+ require 'timeout'
3
+ require 'net/http'
4
+
5
+ module HR_Deploy
6
+
7
+ class OpenAppTask < HR_Deploy::Task
8
+
9
+ ONE_TRY_TIME = 5
10
+ TOTAL_TRY_TIME = 60
11
+
12
+ def run
13
+ print_stage 'Opening app...'
14
+ open_command = "heroku open --remote #{target.name}"
15
+
16
+ if dry_run?
17
+ execute_system_command(open_command)
18
+ self.success = true
19
+ return
20
+ end
21
+
22
+ ending_time = Time.now + HR_Deploy::OpenAppTask::TOTAL_TRY_TIME
23
+
24
+ until success == true || success == false
25
+ status = try_status
26
+
27
+ if status == :ok
28
+ execute_system_command(open_command)
29
+ set_end_time
30
+ self.success = true
31
+
32
+ elsif status == :fail || (status == :retry && Time.now > ending_time)
33
+
34
+ self.success = false
35
+ self.error = "Could not open app\n" +
36
+ "To open manually: #{open_command}"
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # :ok -> app returned a status other than 503 before timeout
44
+ # :retry -> app did not return a status before timeout or returned 503
45
+ # :fail -> an error occurred
46
+ def try_status
47
+ starting_time = Time.now
48
+
49
+ begin
50
+ Timeout::timeout(HR_Deploy::OpenAppTask::ONE_TRY_TIME) do
51
+
52
+ url = target.app_url
53
+ unless url.start_with?('https://') || url.start_with?('http://')
54
+ url = 'http://' + url
55
+ end
56
+
57
+ uri = URI.parse(url)
58
+ http = Net::HTTP.new(uri.host, uri.port)
59
+
60
+ if url.start_with?('https://')
61
+ http.use_ssl = true
62
+ end
63
+
64
+ request = Net::HTTP::Get.new(uri.request_uri)
65
+ response = http.request(request)
66
+
67
+ if response.code == '503'
68
+ sleep(HR_Deploy::OpenAppTask::ONE_TRY_TIME - (starting_time - Time.now))
69
+ :retry
70
+ else
71
+ :ok
72
+ end
73
+ end
74
+ rescue Timeout::Error
75
+ :retry
76
+ rescue
77
+ :fail
78
+ end
79
+ end
80
+ end
81
+ end
@@ -7,6 +7,7 @@ module HR_Deploy
7
7
  def run
8
8
  print_stage 'Pushing new code...'
9
9
 
10
+ set_start_time
10
11
  execute_system_command("git push #{target.name} master")
11
12
 
12
13
  if dry_run? || !confirm?
@@ -6,6 +6,8 @@ module HR_Deploy
6
6
  class Task
7
7
 
8
8
  attr_reader :error
9
+ attr_reader :start_time
10
+ attr_reader :end_time
9
11
 
10
12
  def initialize(args = {})
11
13
  @target = args.fetch(:target, nil)
@@ -13,6 +15,8 @@ module HR_Deploy
13
15
  @dry_run = args.fetch(:dry_run, false)
14
16
  @success = nil
15
17
  @error = nil
18
+ @start_time = nil
19
+ @end_time = nil
16
20
  end
17
21
 
18
22
  def successful?
@@ -28,8 +32,18 @@ module HR_Deploy
28
32
 
29
33
  attr_reader :target
30
34
  attr_writer :error
35
+ attr_writer :start_time
36
+ attr_writer :end_time
31
37
  attr_accessor :success
32
38
 
39
+ def set_start_time
40
+ self.start_time = Time.now
41
+ end
42
+
43
+ def set_end_time
44
+ self.end_time = Time.now
45
+ end
46
+
33
47
  def confirm?
34
48
  !!@confirm
35
49
  end
@@ -64,7 +78,7 @@ module HR_Deploy
64
78
 
65
79
  def execute_system_command(cmd)
66
80
  if dry_run?
67
- puts "Executing command: #{cmd}"
81
+ puts cmd
68
82
  else
69
83
  system(cmd)
70
84
  end
@@ -1,3 +1,3 @@
1
1
  module HR_Deploy
2
- VERSION = '0.0.6'
2
+ VERSION = '0.0.7'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hr_deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Gubitskiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-30 00:00:00.000000000 Z
11
+ date: 2013-07-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Easily deploy your Rails apps to Heroku with one command, automatically
14
14
  taking care of things such as checking current Heroku status, enabling maintenance
@@ -40,6 +40,7 @@ files:
40
40
  - lib/hr_deploy/tasks/push_code_task.rb
41
41
  - lib/hr_deploy/tasks/migrate_db_task.rb
42
42
  - lib/hr_deploy/tasks/restart_task.rb
43
+ - lib/hr_deploy/tasks/open_app_task.rb
43
44
  - lib/hr_deploy/version.rb
44
45
  - bin/hr_deploy
45
46
  homepage: https://github.com/enthrops/hr_deploy