pogo 2.32.14 → 2.39.2

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.
Files changed (63) hide show
  1. data/README.md +0 -2
  2. data/lib/heroku/auth.rb +3 -1
  3. data/lib/heroku/client.rb +8 -5
  4. data/lib/heroku/client/cisaurus.rb +25 -0
  5. data/lib/heroku/client/heroku_postgresql.rb +0 -3
  6. data/lib/heroku/client/rendezvous.rb +2 -1
  7. data/lib/heroku/command.rb +1 -1
  8. data/lib/heroku/command/addons.rb +11 -2
  9. data/lib/heroku/command/apps.rb +105 -20
  10. data/lib/heroku/command/base.rb +1 -1
  11. data/lib/heroku/command/certs.rb +95 -34
  12. data/lib/heroku/command/config.rb +5 -5
  13. data/lib/heroku/command/domains.rb +4 -4
  14. data/lib/heroku/command/fork.rb +160 -0
  15. data/lib/heroku/command/git.rb +19 -20
  16. data/lib/heroku/command/help.rb +18 -2
  17. data/lib/heroku/command/keys.rb +1 -1
  18. data/lib/heroku/command/labs.rb +1 -1
  19. data/lib/heroku/command/logs.rb +3 -56
  20. data/lib/heroku/command/maintenance.rb +2 -2
  21. data/lib/heroku/command/pg.rb +7 -16
  22. data/lib/heroku/command/pgbackups.rb +37 -17
  23. data/lib/heroku/command/ps.rb +82 -35
  24. data/lib/heroku/command/regions.rb +23 -0
  25. data/lib/heroku/command/releases.rb +3 -3
  26. data/lib/heroku/command/run.rb +40 -27
  27. data/lib/heroku/command/sharing.rb +4 -4
  28. data/lib/heroku/command/ssl.rb +7 -25
  29. data/lib/heroku/command/stack.rb +1 -1
  30. data/lib/heroku/helpers/heroku_postgresql.rb +13 -17
  31. data/lib/heroku/helpers/log_displayer.rb +70 -0
  32. data/lib/heroku/plugin.rb +3 -0
  33. data/lib/heroku/updater.rb +11 -2
  34. data/lib/heroku/version.rb +1 -1
  35. data/spec/heroku/auth_spec.rb +10 -0
  36. data/spec/heroku/client/ssl_endpoint_spec.rb +12 -12
  37. data/spec/heroku/client_spec.rb +100 -100
  38. data/spec/heroku/command/addons_spec.rb +63 -59
  39. data/spec/heroku/command/apps_spec.rb +68 -65
  40. data/spec/heroku/command/base_spec.rb +21 -21
  41. data/spec/heroku/command/certs_spec.rb +31 -31
  42. data/spec/heroku/command/config_spec.rb +18 -18
  43. data/spec/heroku/command/db_spec.rb +3 -3
  44. data/spec/heroku/command/domains_spec.rb +13 -13
  45. data/spec/heroku/command/drains_spec.rb +3 -3
  46. data/spec/heroku/command/fork_spec.rb +56 -0
  47. data/spec/heroku/command/git_spec.rb +57 -29
  48. data/spec/heroku/command/labs_spec.rb +8 -8
  49. data/spec/heroku/command/logs_spec.rb +3 -3
  50. data/spec/heroku/command/maintenance_spec.rb +5 -5
  51. data/spec/heroku/command/pg_spec.rb +11 -25
  52. data/spec/heroku/command/pgbackups_spec.rb +13 -8
  53. data/spec/heroku/command/ps_spec.rb +23 -23
  54. data/spec/heroku/command/releases_spec.rb +22 -24
  55. data/spec/heroku/command/run_spec.rb +12 -15
  56. data/spec/heroku/command/sharing_spec.rb +9 -9
  57. data/spec/heroku/command/stack_spec.rb +4 -4
  58. data/spec/heroku/command_spec.rb +12 -12
  59. data/spec/heroku/helpers/heroku_postgresql_spec.rb +35 -14
  60. data/spec/spec_helper.rb +17 -2
  61. data/spec/support/openssl_mock_helper.rb +1 -1
  62. metadata +11 -6
  63. data/spec/heroku/command/ssl_spec.rb +0 -32
data/README.md CHANGED
@@ -68,6 +68,4 @@ Released under the MIT license; see the file License.
68
68
 
69
69
  Created by Adam Wiggins
70
70
 
71
- Maintained by Wesley Beary
72
-
73
71
  [Other Contributors](https://github.com/heroku/heroku/contributors)
@@ -305,7 +305,9 @@ class Heroku::Auth
305
305
  end
306
306
 
307
307
  def base_host(host)
308
- URI.parse(full_host(host)).host.split(".")[-2..-1].join(".")
308
+ parts = URI.parse(full_host(host)).host.split(".")
309
+ return parts.first if parts.size == 1
310
+ parts[-2..-1].join(".")
309
311
  end
310
312
 
311
313
  def full_host(host)
@@ -14,7 +14,7 @@ require 'heroku/client/ssl_endpoint'
14
14
  #
15
15
  # require 'heroku'
16
16
  # heroku = Heroku::Client.new('me@example.com', 'mypass')
17
- # heroku.create('myapp')
17
+ # heroku.create()
18
18
  #
19
19
  class Heroku::Client
20
20
 
@@ -249,13 +249,13 @@ class Heroku::Client
249
249
  doc.elements["//app/workers"].text.to_i
250
250
  end
251
251
 
252
- # Scales the web processes.
252
+ # Scales the web dynos.
253
253
  def set_dynos(app_name, qty)
254
254
  deprecate # 07/31/2012
255
255
  put("/apps/#{app_name}/dynos", :dynos => qty).to_s
256
256
  end
257
257
 
258
- # Scales the background processes.
258
+ # Scales the background dynos.
259
259
  def set_workers(app_name, qty)
260
260
  deprecate # 07/31/2012
261
261
  put("/apps/#{app_name}/workers", :workers => qty).to_s
@@ -546,8 +546,11 @@ Check the output of "heroku ps" and "heroku logs" for more information.
546
546
  delete("/apps/#{app_name}/logs/drains?url=#{URI.escape(url)}").to_s
547
547
  end
548
548
 
549
- def addons
550
- json_decode get("/addons", :accept => 'application/json').to_s
549
+ def addons(filters = {})
550
+ url = "/addons"
551
+ params = filters.map{|k,v| "#{k}=#{v}"}.join("&")
552
+ params = nil if params.empty?
553
+ json_decode get([url,params].compact.join("?"), :accept => 'application/json').to_s
551
554
  end
552
555
 
553
556
  def installed_addons(app_name)
@@ -0,0 +1,25 @@
1
+ require "heroku/client"
2
+
3
+ class Heroku::Client::Cisaurus
4
+
5
+ include Heroku::Helpers
6
+
7
+ def initialize(uri)
8
+ require 'rest_client'
9
+ @uri = URI.parse(uri)
10
+ end
11
+
12
+ def authenticated_resource(path)
13
+ host = "#{@uri.scheme}://#{@uri.host}"
14
+ host += ":#{@uri.port}" if @uri.port
15
+ RestClient::Resource.new("#{host}#{path}", "", Heroku::Auth.api_key)
16
+ end
17
+
18
+ def copy_slug(from, to)
19
+ authenticated_resource("/v1/apps/#{from}/copy/#{to}").post(json_encode("description" => "Forked from #{from}"), :content_type => :json).headers[:location]
20
+ end
21
+
22
+ def job_done?(job_location)
23
+ 202 != authenticated_resource(job_location).get.code
24
+ end
25
+ end
@@ -18,9 +18,6 @@ class Heroku::Client::HerokuPostgresql
18
18
  attr_reader :attachment
19
19
  def initialize(attachment)
20
20
  @attachment = attachment
21
- if attachment.resource_name == 'SHARED_DATABASE'
22
- error('This command is not available for shared database')
23
- end
24
21
  require 'rest_client'
25
22
  end
26
23
 
@@ -30,7 +30,8 @@ class Heroku::Client::Rendezvous
30
30
 
31
31
  ssl_socket = Timeout.timeout(connect_timeout) do
32
32
  ssl_context = OpenSSL::SSL::SSLContext.new
33
-
33
+ ssl_context.ssl_version = :TLSv1
34
+
34
35
  if Heroku::Auth.verify_host?(host)
35
36
  ssl_context.ca_file = File.expand_path("../../../../data/cacert.pem", __FILE__)
36
37
  ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -107,7 +107,7 @@ module Heroku
107
107
 
108
108
  global_option :confirm, "--confirm APP"
109
109
  global_option :help, "-h", "--help"
110
- global_option :remote, "--remote REMOTE"
110
+ global_option :remote, "-r", "--remote REMOTE"
111
111
 
112
112
  def self.prepare_run(cmd, args=[])
113
113
  command = parse(cmd)
@@ -42,8 +42,17 @@ module Heroku::Command
42
42
  #
43
43
  # list all available addons
44
44
  #
45
+ # --region REGION # specify a region for addon availability
46
+ #
47
+ #Example:
48
+ #
49
+ # $ heroku addons:list --region eu
50
+ # === available
51
+ # adept-scale:battleship, corvette...
52
+ # adminium:enterprise, petproject...
53
+ #
45
54
  def list
46
- addons = heroku.addons
55
+ addons = heroku.addons(options)
47
56
  if addons.empty?
48
57
  display "No addons available currently"
49
58
  else
@@ -177,7 +186,7 @@ module Heroku::Command
177
186
  end
178
187
 
179
188
  def app_addon_url(addon)
180
- "https://api.#{heroku.host}/myapps/#{app}/addons/#{addon}"
189
+ "https://api.#{heroku.host}/apps/#{app}/addons/#{addon}"
181
190
  end
182
191
 
183
192
  def partition_addons(addons)
@@ -12,11 +12,11 @@ class Heroku::Command::Apps < Heroku::Command::Base
12
12
  #
13
13
  # $ heroku apps
14
14
  # === My Apps
15
- # myapp1
16
- # myapp2
15
+ # example
16
+ # example2
17
17
  #
18
18
  # === Collaborated Apps
19
- # theirapp1 other@owner.name
19
+ # theirapp other@owner.name
20
20
  #
21
21
  def index
22
22
  validate_arguments!
@@ -27,13 +27,33 @@ class Heroku::Command::Apps < Heroku::Command::Base
27
27
  end
28
28
 
29
29
  unless my_apps.empty?
30
- styled_header("My Apps")
31
- styled_array(my_apps.map { |app| app["name"] })
30
+ non_legacy_apps = my_apps.select do |app|
31
+ app["tier"] != "legacy"
32
+ end
33
+
34
+ unless non_legacy_apps.empty?
35
+ production_basic_apps, dev_legacy_apps = my_apps.partition do |app|
36
+ ["production", "basic"].include?(app["tier"])
37
+ end
38
+
39
+ unless production_basic_apps.empty?
40
+ styled_header("Basic & Production Apps")
41
+ styled_array(production_basic_apps.map { |app| regionized_app_name(app) })
42
+ end
43
+
44
+ unless dev_legacy_apps.empty?
45
+ styled_header("Dev & Legacy Apps")
46
+ styled_array(dev_legacy_apps.map { |app| regionized_app_name(app) })
47
+ end
48
+ else
49
+ styled_header("My Apps")
50
+ styled_array(my_apps.map { |app| regionized_app_name(app) })
51
+ end
32
52
  end
33
53
 
34
54
  unless collaborated_apps.empty?
35
55
  styled_header("Collaborated Apps")
36
- styled_array(collaborated_apps.map { |app| [app["name"], app["owner_email"]] })
56
+ styled_array(collaborated_apps.map { |app| [regionized_app_name(app), app["owner_email"]] })
37
57
  end
38
58
  else
39
59
  display("You have no apps.")
@@ -51,13 +71,13 @@ class Heroku::Command::Apps < Heroku::Command::Base
51
71
  #Examples:
52
72
  #
53
73
  # $ heroku apps:info
54
- # === myapp
55
- # Git URL: git@heroku.com:myapp.git
74
+ # === example
75
+ # Git URL: git@heroku.com:example.git
56
76
  # Repo Size: 5M
57
77
  # ...
58
78
  #
59
79
  # $ heroku apps:info --shell
60
- # git_url=git@heroku.com:myapp.git
80
+ # git_url=git@heroku.com:example.git
61
81
  # repo_size=5000000
62
82
  # ...
63
83
  #
@@ -125,6 +145,10 @@ class Heroku::Command::Apps < Heroku::Command::Base
125
145
 
126
146
  data["Owner Email"] = app_data["owner_email"]
127
147
 
148
+ if app_data["region"]
149
+ data["Region"] = app_data["region"]
150
+ end
151
+
128
152
  if app_data["repo_size"]
129
153
  data["Repo Size"] = format_bytes(app_data["repo_size"])
130
154
  end
@@ -140,6 +164,10 @@ class Heroku::Command::Apps < Heroku::Command::Base
140
164
 
141
165
  data["Web URL"] = app_data["web_url"]
142
166
 
167
+ if app_data["tier"]
168
+ data["Tier"] = app_data["tier"].capitalize
169
+ end
170
+
143
171
  styled_hash(data)
144
172
  end
145
173
  end
@@ -155,6 +183,8 @@ class Heroku::Command::Apps < Heroku::Command::Base
155
183
  # -n, --no-remote # don't create a git remote
156
184
  # -r, --remote REMOTE # the git remote to create, default "heroku"
157
185
  # -s, --stack STACK # the stack on which to create the app
186
+ # --region REGION # specify region for this app to run in
187
+ # -t, --tier TIER # HIDDEN: the tier for this app
158
188
  #
159
189
  #Examples:
160
190
  #
@@ -167,18 +197,26 @@ class Heroku::Command::Apps < Heroku::Command::Base
167
197
  # http://floating-dragon-42.herokuapp.com/ | git@heroku.com:floating-dragon-42.git
168
198
  #
169
199
  # # specify a name
170
- # $ heroku apps:create myapp
171
- # Creating myapp... done, stack is cedar
172
- # http://myapp.heroku.com/ | git@heroku.com:myapp.git
200
+ # $ heroku apps:create example
201
+ # Creating example... done, stack is cedar
202
+ # http://example.heroku.com/ | git@heroku.com:example.git
173
203
  #
174
204
  # # create a staging app
175
- # $ heroku apps:create myapp-staging --remote staging
205
+ # $ heroku apps:create example-staging --remote staging
206
+ #
207
+ # # create an app in the eu region
208
+ # $ heroku apps:create --region eu
176
209
  #
177
210
  def create
178
211
  name = shift_argument || options[:app] || ENV['HEROKU_APP']
179
212
  validate_arguments!
180
213
 
181
- info = api.post_app({ "name" => name, "stack" => options[:stack] }).body
214
+ info = api.post_app({
215
+ "name" => name,
216
+ "region" => options[:region],
217
+ "stack" => options[:stack],
218
+ "tier" => options[:tier]
219
+ }).body
182
220
  begin
183
221
  action("Creating #{info['name']}") do
184
222
  if info['create_status'] == 'creating'
@@ -189,7 +227,11 @@ class Heroku::Command::Apps < Heroku::Command::Base
189
227
  end
190
228
  end
191
229
  end
192
- status("stack is #{info['stack']}")
230
+ if info['region']
231
+ status("region is #{info['region']}")
232
+ else
233
+ status("stack is #{info['stack']}")
234
+ end
193
235
  end
194
236
 
195
237
  (options[:addons] || "").split(",").each do |addon|
@@ -222,8 +264,8 @@ class Heroku::Command::Apps < Heroku::Command::Base
222
264
  #
223
265
  #Example:
224
266
  #
225
- # $ heroku apps:rename myapp-newname
226
- # http://myapp-newname.herokuapp.com/ | git@heroku.com:myapp-newname.git
267
+ # $ heroku apps:rename example-newname
268
+ # http://example-newname.herokuapp.com/ | git@heroku.com:example-newname.git
227
269
  # Git remote heroku updated
228
270
  #
229
271
  def rename
@@ -261,7 +303,7 @@ class Heroku::Command::Apps < Heroku::Command::Base
261
303
  #Example:
262
304
  #
263
305
  # $ heroku apps:open
264
- # Opening myapp... done
306
+ # Opening example... done
265
307
  #
266
308
  def open
267
309
  validate_arguments!
@@ -278,8 +320,8 @@ class Heroku::Command::Apps < Heroku::Command::Base
278
320
  #
279
321
  #Example:
280
322
  #
281
- # $ heroku apps:destroy -a myapp --confirm myapp
282
- # Destroying myapp (including all add-ons)... done
323
+ # $ heroku apps:destroy -a example --confirm example
324
+ # Destroying example (including all add-ons)... done
283
325
  #
284
326
  def destroy
285
327
  @app = shift_argument || options[:app] || options[:confirm]
@@ -308,4 +350,47 @@ class Heroku::Command::Apps < Heroku::Command::Base
308
350
  alias_command "destroy", "apps:destroy"
309
351
  alias_command "apps:delete", "apps:destroy"
310
352
 
353
+ # apps:upgrade TIER
354
+ #
355
+ # HIDDEN: upgrade an app's pricing tier
356
+ #
357
+ def upgrade
358
+ tier = shift_argument
359
+ error("Usage: heroku apps:upgrade TIER\nMust specify TIER to upgrade.") if tier.nil? || tier.empty?
360
+ validate_arguments!
361
+
362
+ action("Upgrading #{app} to #{tier}") do
363
+ api.put_app(app, "tier" => tier)
364
+ end
365
+ end
366
+
367
+ alias_command "upgrade", "apps:upgrade"
368
+
369
+ # apps:downgrade TIER
370
+ #
371
+ # HIDDEN: downgrade an app's pricing tier
372
+ #
373
+ def downgrade
374
+ tier = shift_argument
375
+ error("Usage: heroku apps:downgrade TIER\nMust specify TIER to downgrade.") if tier.nil? || tier.empty?
376
+ validate_arguments!
377
+
378
+ action("Upgrading #{app} to #{tier}") do
379
+ api.put_app(app, "tier" => tier)
380
+ end
381
+ end
382
+
383
+ alias_command "downgrade", "apps:downgrade"
384
+
385
+ private
386
+
387
+ def regionized_app_name(app)
388
+ # temporary, show region for non-us apps
389
+ if app["region"] && app["region"] != 'us'
390
+ "#{app["name"]} (#{app["region"]})"
391
+ else
392
+ app["name"]
393
+ end
394
+ end
395
+
311
396
  end
@@ -205,7 +205,7 @@ protected
205
205
  return unless File.exists?(".git")
206
206
  git("remote -v").split("\n").each do |remote|
207
207
  name, url, method = remote.split(/\s/)
208
- if url =~ /^git@#{Heroku::Auth.git_host}:([\w\d-]+)\.git$/
208
+ if url =~ /^git@#{Heroku::Auth.git_host}(?:[\.\w]*):([\w\d-]+)\.git$/
209
209
  remotes[name] = $1
210
210
  end
211
211
  end
@@ -1,19 +1,23 @@
1
1
  require "heroku/command/base"
2
+ require "excon"
2
3
 
3
4
  # manage ssl endpoints for an app
4
5
  #
5
6
  class Heroku::Command::Certs < Heroku::Command::Base
7
+ SSL_DOCTOR = Excon.new(ENV["SSL_DOCTOR_URL"] || "https://ssl-doctor.herokuapp.com/")
8
+
9
+ class UsageError < StandardError; end
6
10
 
7
11
  # certs
8
12
  #
9
- # list ssl endpoints for an app
13
+ # List ssl endpoints for an app.
10
14
  #
11
15
  def index
12
16
  endpoints = heroku.ssl_endpoint_list(app)
13
17
 
14
18
  if endpoints.empty?
15
19
  display "#{app} has no SSL Endpoints."
16
- display "Use `heroku certs:add PEM KEY` to add one."
20
+ display "Use `heroku certs:add CRT KEY` to add one."
17
21
  else
18
22
  endpoints.map! do |endpoint|
19
23
  {
@@ -31,28 +35,70 @@ class Heroku::Command::Certs < Heroku::Command::Base
31
35
  end
32
36
  end
33
37
 
34
- # certs:add PEM KEY
38
+ # certs:chain CRT [CRT ...]
35
39
  #
36
- # add an ssl endpoint to an app
40
+ # Print the ordered and complete chain for the given certificate.
37
41
  #
38
- def add
39
- fail("Usage: heroku certs:add PEM KEY\nMust specify PEM and KEY to add cert.") if args.size < 2
40
- pem = File.read(args[0]) rescue error("Unable to read #{args[0]} PEM")
41
- key = File.read(args[1]) rescue error("Unable to read #{args[1]} KEY")
42
+ # Optional intermediate certificates may be given too, and will
43
+ # be used during chain resolution.
44
+ #
45
+ def chain
46
+ puts read_crt_through_ssl_doctor
47
+ rescue UsageError
48
+ fail("Usage: heroku certs:chain CRT [CRT ...]\nMust specify at least one certificate file.")
49
+ end
42
50
 
43
- endpoint = action("Adding SSL Endpoint to #{app}") do
44
- heroku.ssl_endpoint_add(app, pem, key)
45
- end
51
+ # certs:key CRT KEY [KEY ...]
52
+ #
53
+ # Print the correct key for the given certificate.
54
+ #
55
+ # You must pass one single certificate, and one or more keys.
56
+ # The first key that signs the certificate will be printed back.
57
+ #
58
+ def key
59
+ crt, key = read_crt_and_key_through_ssl_doctor("Testing for signing key")
60
+ puts key
61
+ rescue UsageError
62
+ fail("Usage: heroku certs:key CRT KEY [KEY ...]\nMust specify one certificate file and at least one key file.")
63
+ end
46
64
 
65
+ # certs:add CRT KEY
66
+ #
67
+ # Add an ssl endpoint to an app.
68
+ #
69
+ # --bypass # bypass the trust chain completion step
70
+ #
71
+ def add
72
+ crt, key = read_crt_and_key
73
+ endpoint = action("Adding SSL Endpoint to #{app}") { heroku.ssl_endpoint_add(app, crt, key) }
47
74
  display_warnings(endpoint)
48
75
  display "#{app} now served by #{endpoint['cname']}"
49
76
  display "Certificate details:"
50
77
  display_certificate_info(endpoint)
78
+ rescue UsageError
79
+ fail("Usage: heroku certs:add CRT KEY\nMust specify CRT and KEY to add cert.")
80
+ end
81
+
82
+ # certs:update CRT KEY
83
+ #
84
+ # Update an SSL Endpoint on an app.
85
+ #
86
+ # --bypass # bypass the trust chain completion step
87
+ #
88
+ def update
89
+ crt, key = read_crt_and_key
90
+ cname = options[:endpoint] || current_endpoint
91
+ endpoint = action("Updating SSL Endpoint #{cname} for #{app}") { heroku.ssl_endpoint_update(app, cname, crt, key) }
92
+ display_warnings(endpoint)
93
+ display "Updated certificate details:"
94
+ display_certificate_info(endpoint)
95
+ rescue UsageError
96
+ fail("Usage: heroku certs:update CRT KEY\nMust specify CRT and KEY to update cert.")
51
97
  end
52
98
 
53
99
  # certs:info
54
100
  #
55
- # show certificate information for an ssl endpoint
101
+ # Show certificate information for an ssl endpoint.
56
102
  #
57
103
  def info
58
104
  cname = options[:endpoint] || current_endpoint
@@ -66,7 +112,7 @@ class Heroku::Command::Certs < Heroku::Command::Base
66
112
 
67
113
  # certs:remove
68
114
  #
69
- # remove an SSL Endpoint from an app
115
+ # Remove an SSL Endpoint from an app.
70
116
  #
71
117
  def remove
72
118
  cname = options[:endpoint] || current_endpoint
@@ -76,29 +122,9 @@ class Heroku::Command::Certs < Heroku::Command::Base
76
122
  display "NOTE: Billing is still active. Remove SSL Endpoint add-on to stop billing."
77
123
  end
78
124
 
79
- # certs:update PEM KEY
80
- #
81
- # update an SSL Endpoint on an app
82
- #
83
- def update
84
- fail("Usage: heroku certs:update PEM KEY\nMust specify PEM and KEY to update cert.") if args.size < 2
85
- pem = File.read(args[0]) rescue error("Unable to read #{args[0]} PEM")
86
- key = File.read(args[1]) rescue error("Unable to read #{args[1]} KEY")
87
- app = self.app
88
- cname = options[:endpoint] || current_endpoint
89
-
90
- endpoint = action("Updating SSL Endpoint #{cname} for #{app}") do
91
- heroku.ssl_endpoint_update(app, cname, pem, key)
92
- end
93
-
94
- display_warnings(endpoint)
95
- display "Updated certificate details:"
96
- display_certificate_info(endpoint)
97
- end
98
-
99
125
  # certs:rollback
100
126
  #
101
- # rollback an SSL Endpoint for an app
127
+ # Rollback an SSL Endpoint for an app.
102
128
  #
103
129
  def rollback
104
130
  cname = options[:endpoint] || current_endpoint
@@ -145,4 +171,39 @@ class Heroku::Command::Certs < Heroku::Command::Base
145
171
  end
146
172
  end
147
173
 
174
+ def display(msg = "", new_line = true)
175
+ super if $stdout.tty?
176
+ end
177
+
178
+ def post_to_ssl_doctor(path, action_text = nil)
179
+ raise UsageError if args.size < 1
180
+ action_text ||= "Resolving trust chain"
181
+ action(action_text) do
182
+ input = args.map { |arg| File.read(arg) rescue error("Unable to read #{args[0]} file") }.join("\n")
183
+ SSL_DOCTOR.post(:path => path, :body => input, :headers => {'Content-Type' => 'application/octet-stream'}, :expects => 200).body
184
+ end
185
+ rescue Excon::Errors::BadRequest, Excon::Errors::UnprocessableEntity => e
186
+ error(e.response.body)
187
+ end
188
+
189
+ def read_crt_and_key_through_ssl_doctor(action_text = nil)
190
+ crt_and_key = post_to_ssl_doctor("resolve-chain-and-key", action_text)
191
+ Heroku::OkJson.decode(crt_and_key).values_at("pem", "key")
192
+ end
193
+
194
+ def read_crt_through_ssl_doctor(action_text = nil)
195
+ post_to_ssl_doctor("resolve-chain", action_text)
196
+ end
197
+
198
+ def read_crt_and_key_bypassing_ssl_doctor
199
+ raise UsageError if args.size != 2
200
+ crt = File.read(args[0]) rescue error("Unable to read #{args[0]} CRT")
201
+ key = File.read(args[1]) rescue error("Unable to read #{args[1]} KEY")
202
+ [crt, key]
203
+ end
204
+
205
+ def read_crt_and_key
206
+ options[:bypass] ? read_crt_and_key_bypassing_ssl_doctor : read_crt_and_key_through_ssl_doctor
207
+ end
208
+
148
209
  end