rhc 1.9.6 → 1.10.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/features/lib/rhc_helper.rb +0 -4
- data/features/lib/rhc_helper/app.rb +10 -10
- data/features/lib/rhc_helper/commandify.rb +6 -24
- data/features/support/before_hooks.rb +1 -1
- data/features/support/env.rb +9 -2
- data/features/support/platform_support.rb +11 -1
- data/lib/rhc/auth/basic.rb +4 -1
- data/lib/rhc/cartridge_helpers.rb +4 -8
- data/lib/rhc/commands.rb +6 -3
- data/lib/rhc/commands/alias.rb +1 -0
- data/lib/rhc/commands/app.rb +104 -67
- data/lib/rhc/commands/authorization.rb +2 -1
- data/lib/rhc/commands/base.rb +8 -1
- data/lib/rhc/commands/cartridge.rb +39 -16
- data/lib/rhc/commands/git_clone.rb +2 -1
- data/lib/rhc/commands/port_forward.rb +4 -6
- data/lib/rhc/commands/ssh.rb +54 -0
- data/lib/rhc/exceptions.rb +12 -7
- data/lib/rhc/git_helpers.rb +4 -5
- data/lib/rhc/help_formatter.rb +11 -6
- data/lib/rhc/helpers.rb +24 -3
- data/lib/rhc/highline_extensions.rb +31 -6
- data/lib/rhc/output_helpers.rb +0 -29
- data/lib/rhc/rest.rb +16 -1
- data/lib/rhc/rest/application.rb +7 -3
- data/lib/rhc/rest/base.rb +7 -2
- data/lib/rhc/rest/client.rb +7 -14
- data/lib/rhc/rest/gear_group.rb +10 -1
- data/lib/rhc/rest/mock.rb +34 -8
- data/lib/rhc/ssh_helpers.rb +144 -1
- data/lib/rhc/usage_templates/command_help.erb +16 -2
- data/spec/coverage_helper.rb +10 -7
- data/spec/rhc/commands/alias_spec.rb +28 -0
- data/spec/rhc/commands/app_spec.rb +64 -45
- data/spec/rhc/commands/authorization_spec.rb +16 -0
- data/spec/rhc/commands/cartridge_spec.rb +59 -3
- data/spec/rhc/commands/port_forward_spec.rb +6 -6
- data/spec/rhc/commands/ssh_spec.rb +125 -0
- data/spec/rhc/commands/tail_spec.rb +4 -3
- data/spec/rhc/helpers_spec.rb +70 -42
- data/spec/rhc/highline_extensions_spec.rb +23 -1
- data/spec/rhc/rest_client_spec.rb +6 -9
- data/spec/rhc/rest_spec.rb +41 -2
- data/spec/spec_helper.rb +38 -0
- metadata +336 -373
data/lib/rhc/rest.rb
CHANGED
@@ -97,7 +97,22 @@ module RHC
|
|
97
97
|
|
98
98
|
#I/O Exceptions Connection timeouts, etc
|
99
99
|
class ConnectionException < Exception; end
|
100
|
-
class TimeoutException < ConnectionException
|
100
|
+
class TimeoutException < ConnectionException
|
101
|
+
def initialize(message, nested=nil)
|
102
|
+
super(message)
|
103
|
+
@nested = nested
|
104
|
+
end
|
105
|
+
|
106
|
+
def on_receive?
|
107
|
+
@nested.is_a? HTTPClient::ReceiveTimeoutError
|
108
|
+
end
|
109
|
+
def on_connect?
|
110
|
+
@nested.is_a? HTTPClient::ConnectTimeoutError
|
111
|
+
end
|
112
|
+
def on_send?
|
113
|
+
@nested.is_a? HTTPClient::SendTimeoutError
|
114
|
+
end
|
115
|
+
end
|
101
116
|
|
102
117
|
class SSLConnectionFailed < ConnectionException
|
103
118
|
attr_reader :reason
|
data/lib/rhc/rest/application.rb
CHANGED
@@ -63,11 +63,15 @@ module RHC
|
|
63
63
|
rest_method "GET_GEAR_GROUPS"
|
64
64
|
end
|
65
65
|
|
66
|
+
def gears
|
67
|
+
gear_groups.map{ |group| group.gears }.flatten
|
68
|
+
end
|
69
|
+
|
66
70
|
def gear_ssh_url(gear_id)
|
67
|
-
gear =
|
71
|
+
gear = gears.find{ |g| g['id'] == gear_id }
|
68
72
|
|
69
|
-
raise ArgumentError
|
70
|
-
gear['ssh_url'] or raise
|
73
|
+
raise ArgumentError, "Gear #{gear_id} not found" if gear.nil?
|
74
|
+
gear['ssh_url'] or raise NoPerGearOperations
|
71
75
|
end
|
72
76
|
|
73
77
|
def tidy
|
data/lib/rhc/rest/base.rb
CHANGED
@@ -23,11 +23,16 @@ module RHC
|
|
23
23
|
url = url.gsub(/:\w+/) { |s| options[:params][s] } if options[:params]
|
24
24
|
method = options[:method] || link['method']
|
25
25
|
|
26
|
-
client.request(options.merge({
|
26
|
+
result = client.request(options.merge({
|
27
27
|
:url => url,
|
28
28
|
:method => method,
|
29
29
|
:payload => payload,
|
30
30
|
}))
|
31
|
+
if result.is_a?(Hash) && (result['messages'] || result['errors'])
|
32
|
+
attributes['messages'] = Array(result['messages'])
|
33
|
+
result = self
|
34
|
+
end
|
35
|
+
result
|
31
36
|
end
|
32
37
|
|
33
38
|
def links
|
@@ -60,4 +65,4 @@ module RHC
|
|
60
65
|
end
|
61
66
|
end
|
62
67
|
end
|
63
|
-
end
|
68
|
+
end
|
data/lib/rhc/rest/client.rb
CHANGED
@@ -175,7 +175,7 @@ module RHC
|
|
175
175
|
# The list may not necessarily be sorted; we will select the last
|
176
176
|
# matching one supported by the server.
|
177
177
|
# See #api_version_negotiated
|
178
|
-
CLIENT_API_VERSIONS = [1.1, 1.2, 1.3, 1.4]
|
178
|
+
CLIENT_API_VERSIONS = [1.1, 1.2, 1.3, 1.4, 1.5]
|
179
179
|
|
180
180
|
def initialize(*args)
|
181
181
|
options = args[0].is_a?(Hash) && args[0] || {}
|
@@ -207,8 +207,6 @@ module RHC
|
|
207
207
|
self.headers.merge!(options.delete(:headers)) if options[:headers]
|
208
208
|
self.options.merge!(options)
|
209
209
|
|
210
|
-
update_http_proxy_env
|
211
|
-
|
212
210
|
debug "Connecting to #{@end_point}"
|
213
211
|
end
|
214
212
|
|
@@ -262,7 +260,7 @@ module RHC
|
|
262
260
|
"Connection to server timed out. "\
|
263
261
|
"It is possible the operation finished without being able "\
|
264
262
|
"to report success. Use 'rhc domain show' or 'rhc app show' "\
|
265
|
-
"to see the status of your applications.")
|
263
|
+
"to see the status of your applications.", e)
|
266
264
|
rescue EOFError => e
|
267
265
|
raise ConnectionException.new(
|
268
266
|
"Connection to server got interrupted: #{e.message}")
|
@@ -306,6 +304,9 @@ module RHC
|
|
306
304
|
raise ConnectionException.new(
|
307
305
|
"Unable to connect to the server (#{e.message})."\
|
308
306
|
"#{client.proxy.present? ? " Check that you have correctly specified your proxy server '#{client.proxy}' as well as your OpenShift server '#{args[1]}'." : " Check that you have correctly specified your OpenShift server '#{args[1]}'."}")
|
307
|
+
rescue Errno::ECONNRESET => e
|
308
|
+
raise ConnectionException.new(
|
309
|
+
"The server has closed the connection unexpectedly (#{e.message}). Your last operation may still be running on the server; please check before retrying your last request.")
|
309
310
|
rescue RHC::Rest::Exception
|
310
311
|
raise
|
311
312
|
rescue => e
|
@@ -438,11 +439,11 @@ module RHC
|
|
438
439
|
def parse_response(response)
|
439
440
|
result = RHC::Json.decode(response)
|
440
441
|
type = result['type']
|
441
|
-
data = result['data']
|
442
|
+
data = result['data'] || {}
|
442
443
|
|
443
444
|
# Copy messages to each object
|
444
445
|
messages = Array(result['messages']).map do |m|
|
445
|
-
m['text'] if m['field'].nil? or m['field'] == 'result'
|
446
|
+
m['text'] if m['field'].nil? or m['field'] == 'result' or m['severity'] == 'result'
|
446
447
|
end.compact
|
447
448
|
data.each{ |d| d['messages'] = messages } if data.is_a?(Array)
|
448
449
|
data['messages'] = messages if data.is_a?(Hash)
|
@@ -559,14 +560,6 @@ module RHC
|
|
559
560
|
keys = messages.group_by{ |m| m['field'] }.keys.compact.sort.map(&:to_sym) rescue []
|
560
561
|
[messages_to_error(messages), keys]
|
561
562
|
end
|
562
|
-
|
563
|
-
def update_http_proxy_env
|
564
|
-
# Set the http_proxy env variable, read by
|
565
|
-
# HTTPClient, being sure to add the http protocol
|
566
|
-
# if not specified already
|
567
|
-
proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
|
568
|
-
ENV['http_proxy'] = "http://#{proxy}" if proxy.present? && proxy !~ /^(\w+):\/\//
|
569
|
-
end
|
570
563
|
end
|
571
564
|
end
|
572
565
|
end
|
data/lib/rhc/rest/gear_group.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
module RHC
|
2
2
|
module Rest
|
3
3
|
class GearGroup < Base
|
4
|
-
define_attr :gears, :cartridges, :gear_profile
|
4
|
+
define_attr :gears, :cartridges, :gear_profile, :additional_gear_storage, :base_gear_storage
|
5
|
+
|
6
|
+
def name(gear)
|
7
|
+
gear['name'] ||= "#{group.cartridges.collect{ |c| c['name'] }.join('+')}:#{gear['id']}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def quota
|
11
|
+
return nil unless base_gear_storage
|
12
|
+
((additional_gear_storage || 0) + base_gear_storage) * 1024 * 1024 * 1024
|
13
|
+
end
|
5
14
|
end
|
6
15
|
end
|
7
16
|
end
|
data/lib/rhc/rest/mock.rb
CHANGED
@@ -52,7 +52,7 @@ module RHC::Rest::Mock
|
|
52
52
|
to_return({
|
53
53
|
:body => {
|
54
54
|
:data => mock_response_links(authorizations ? mock_api_with_authorizations : mock_real_client_links),
|
55
|
-
:supported_api_versions => [1.0, 1.1, 1.2, 1.3, 1.4],
|
55
|
+
:supported_api_versions => [1.0, 1.1, 1.2, 1.3, 1.4, 1.5],
|
56
56
|
}.to_json
|
57
57
|
})
|
58
58
|
end
|
@@ -208,6 +208,21 @@ module RHC::Rest::Mock
|
|
208
208
|
})
|
209
209
|
end
|
210
210
|
|
211
|
+
def stub_application_cartridges(domain_name, app_name, cartridges, status = 200)
|
212
|
+
url = client_links['LIST_DOMAINS']['relative'] rescue "broker/rest/domains"
|
213
|
+
stub_api_request(:any, "#{url}/#{domain_name}/applications/#{app_name}/cartridges").
|
214
|
+
to_return({
|
215
|
+
:body => {
|
216
|
+
:type => 'cartridges',
|
217
|
+
:data => cartridges.map{ |c| c.is_a?(String) ? {:name => c} : c }.map do |cart|
|
218
|
+
cart[:links] ||= mock_response_links(mock_cart_links(domain_name,app_name, cart[:name]))
|
219
|
+
cart
|
220
|
+
end
|
221
|
+
}.to_json,
|
222
|
+
:status => status
|
223
|
+
})
|
224
|
+
end
|
225
|
+
|
211
226
|
def stub_simple_carts
|
212
227
|
stub_api_request(:get, 'broker/rest/cartridges', mock_user_auth).to_return(simple_carts)
|
213
228
|
end
|
@@ -324,7 +339,7 @@ module RHC::Rest::Mock
|
|
324
339
|
|
325
340
|
def mock_app_links(domain_id='test_domain',app_id='test_app')
|
326
341
|
[['ADD_CARTRIDGE', "domains/#{domain_id}/apps/#{app_id}/carts/add", 'post'],
|
327
|
-
['LIST_CARTRIDGES', "domains/#{domain_id}/
|
342
|
+
['LIST_CARTRIDGES', "broker/rest/domains/#{domain_id}/applications/#{app_id}/cartridges",'get' ],
|
328
343
|
['GET_GEAR_GROUPS', "domains/#{domain_id}/apps/#{app_id}/gear_groups", 'get' ],
|
329
344
|
['START', "domains/#{domain_id}/apps/#{app_id}/start", 'post'],
|
330
345
|
['STOP', "domains/#{domain_id}/apps/#{app_id}/stop", 'post'],
|
@@ -333,14 +348,14 @@ module RHC::Rest::Mock
|
|
333
348
|
['ADD_ALIAS', "domains/#{domain_id}/apps/#{app_id}/event", 'post'],
|
334
349
|
['REMOVE_ALIAS', "domains/#{domain_id}/apps/#{app_id}/event", 'post'],
|
335
350
|
['LIST_ALIASES', "domains/#{domain_id}/apps/#{app_id}/aliases", 'get'],
|
336
|
-
['DELETE', "domains/#{domain_id}/
|
351
|
+
['DELETE', "broker/rest/domains/#{domain_id}/applications/#{app_id}", 'DELETE']]
|
337
352
|
end
|
338
353
|
|
339
354
|
def mock_cart_links(domain_id='test_domain',app_id='test_app',cart_id='test_cart')
|
340
355
|
[['START', "domains/#{domain_id}/apps/#{app_id}/carts/#{cart_id}/start", 'post'],
|
341
356
|
['STOP', "domains/#{domain_id}/apps/#{app_id}/carts/#{cart_id}/stop", 'post'],
|
342
357
|
['RESTART', "domains/#{domain_id}/apps/#{app_id}/carts/#{cart_id}/restart", 'post'],
|
343
|
-
['DELETE', "domains/#{domain_id}/
|
358
|
+
['DELETE', "broker/rest/domains/#{domain_id}/applications/#{app_id}/cartridges/#{cart_id}", 'DELETE']]
|
344
359
|
end
|
345
360
|
|
346
361
|
def mock_client_links
|
@@ -487,6 +502,8 @@ module RHC::Rest::Mock
|
|
487
502
|
MockRestCartridge.new(self, "mock_cart-2", "embedded"),
|
488
503
|
MockRestCartridge.new(self, "unique_mock_cart-1", "embedded"),
|
489
504
|
MockRestCartridge.new(self, "jenkins-client-1.4", "embedded"),
|
505
|
+
MockRestCartridge.new(self, "embcart-1", "embedded"),
|
506
|
+
MockRestCartridge.new(self, "embcart-2", "embedded"),
|
490
507
|
premium_embedded
|
491
508
|
]
|
492
509
|
end
|
@@ -601,11 +618,14 @@ module RHC::Rest::Mock
|
|
601
618
|
|
602
619
|
class MockRestGearGroup < RHC::Rest::GearGroup
|
603
620
|
include Helpers
|
604
|
-
def initialize(client=nil)
|
621
|
+
def initialize(client=nil, carts=['name' => 'fake_geargroup_cart-0.1'], count=1)
|
605
622
|
super({}, client)
|
606
|
-
@cartridges =
|
607
|
-
@gears =
|
623
|
+
@cartridges = carts
|
624
|
+
@gears = count.times.map do |i|
|
625
|
+
{'state' => 'started', 'id' => "fakegearid#{i}", 'ssh_url' => "ssh://fakegearid#{i}@fakesshurl.com"}
|
626
|
+
end
|
608
627
|
@gear_profile = 'small'
|
628
|
+
@base_gear_storage = 1
|
609
629
|
end
|
610
630
|
end
|
611
631
|
|
@@ -710,7 +730,13 @@ module RHC::Rest::Mock
|
|
710
730
|
|
711
731
|
def gear_groups
|
712
732
|
# we don't have heavy interaction with gear groups yet so keep this simple
|
713
|
-
@gear_groups ||=
|
733
|
+
@gear_groups ||= begin
|
734
|
+
if @scalable
|
735
|
+
cartridges.map{ |c| MockRestGearGroup.new(client, [c.name], c.current_scale) if c.name != 'haproxy-1.4' }.compact
|
736
|
+
else
|
737
|
+
[MockRestGearGroup.new(client, cartridges.map{ |c| {'name' => c.name} }, 1)]
|
738
|
+
end
|
739
|
+
end
|
714
740
|
end
|
715
741
|
|
716
742
|
def cartridges
|
data/lib/rhc/ssh_helpers.rb
CHANGED
@@ -20,6 +20,134 @@ require 'rhc/vendor/sshkey'
|
|
20
20
|
|
21
21
|
module RHC
|
22
22
|
module SSHHelpers
|
23
|
+
|
24
|
+
class MultipleGearTask
|
25
|
+
def initialize(command, over, opts={})
|
26
|
+
requires_ssh_multi!
|
27
|
+
|
28
|
+
@command = command
|
29
|
+
@over = over
|
30
|
+
@opts = opts
|
31
|
+
end
|
32
|
+
|
33
|
+
def run(&block)
|
34
|
+
out = nil
|
35
|
+
|
36
|
+
Net::SSH::Multi.start(
|
37
|
+
:concurrent_connections => @opts[:limit],
|
38
|
+
:on_error => lambda{ |server| $stderr.puts "Unable to connect to gear #{server}" }
|
39
|
+
) do |session|
|
40
|
+
|
41
|
+
@over.each do |item|
|
42
|
+
case item
|
43
|
+
when RHC::Rest::GearGroup
|
44
|
+
item.gears.each do |gear|
|
45
|
+
session.use ssh_host_for(gear), :properties => {:gear => gear, :group => item}
|
46
|
+
end
|
47
|
+
#when RHC::Rest::Gear
|
48
|
+
# session.use ssh_host_for(item), :properties => {:gear => item}
|
49
|
+
#end
|
50
|
+
else
|
51
|
+
raise "Cannot establish an SSH session to this type"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
session.exec @command, &(
|
55
|
+
case
|
56
|
+
when @opts[:raw]
|
57
|
+
lambda { |ch, dest, data|
|
58
|
+
(dest == :stdout ? $stdout : $stderr).puts data
|
59
|
+
}
|
60
|
+
when @opts[:as] == :table
|
61
|
+
out = []
|
62
|
+
lambda { |ch, dest, data|
|
63
|
+
label = label_for(ch)
|
64
|
+
data.chomp.each_line do |line|
|
65
|
+
row = out.find{ |row| row[0] == label } || (out << [label, []])[-1]
|
66
|
+
row[1] << line
|
67
|
+
end
|
68
|
+
}
|
69
|
+
when @opts[:as] == :gear
|
70
|
+
lambda { |ch, dest, data| (ch.connection.properties[:gear]['data'] ||= "") << data }
|
71
|
+
else
|
72
|
+
width = 0
|
73
|
+
lambda { |ch, dest, data|
|
74
|
+
label = label_for(ch)
|
75
|
+
io = dest == :stdout ? $stdout : $stderr
|
76
|
+
data.chomp!
|
77
|
+
|
78
|
+
if data.each_line.to_a.count < 2
|
79
|
+
io.puts "[#{label}] #{data}"
|
80
|
+
elsif @opts[:always_prefix]
|
81
|
+
data.each_line do |line|
|
82
|
+
io.puts "[#{label}] #{line}"
|
83
|
+
end
|
84
|
+
else
|
85
|
+
io.puts "=== #{label}"
|
86
|
+
io.puts data
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end)
|
90
|
+
session.loop
|
91
|
+
end
|
92
|
+
|
93
|
+
if block_given? && !@opts[:raw]
|
94
|
+
case
|
95
|
+
when @opts[:as] == :gear
|
96
|
+
out = []
|
97
|
+
@over.each do |item|
|
98
|
+
case item
|
99
|
+
when RHC::Rest::GearGroup then item.gears.each{ |gear| out << yield(gear, gear['data'], item) }
|
100
|
+
#when RHC::Rest::Gear then out << yield(gear, gear['data'], nil)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
out
|
107
|
+
end
|
108
|
+
protected
|
109
|
+
def ssh_host_for(gear)
|
110
|
+
RHC::Helpers.ssh_string(gear['ssh_url']) or raise NoPerGearOperations
|
111
|
+
end
|
112
|
+
|
113
|
+
def label_for(channel)
|
114
|
+
channel.properties[:label] ||=
|
115
|
+
begin
|
116
|
+
group = channel.connection.properties[:group]
|
117
|
+
"#{key_for(channel)} #{group.cartridges.map{ |c| c['name'] }.join('+')}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def key_for(channel)
|
122
|
+
channel.connection.properties[:gear]['id']
|
123
|
+
end
|
124
|
+
|
125
|
+
def requires_ssh_multi!
|
126
|
+
begin
|
127
|
+
require 'net/ssh/multi'
|
128
|
+
rescue LoadError
|
129
|
+
raise RHC::OperationNotSupportedException, "You must install Net::SSH::Multi to use the --gears option. Most systems: 'gem install net-ssh-multi'"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def run_on_gears(command, gears, opts={}, &block)
|
135
|
+
debug "Executing #{command} on each of #{gears.inspect}"
|
136
|
+
MultipleGearTask.new(command, gears, {:limit => options.limit, :always_prefix => options.always_prefix, :raw => options.raw}.merge(opts)).run(&block)
|
137
|
+
end
|
138
|
+
|
139
|
+
def table_from_gears(command, groups, opts={}, &block)
|
140
|
+
cells = run_on_gears(command, groups, {:as => :table}.merge(opts), &block)
|
141
|
+
cells.each{ |r| r.concat(r.pop.first.split(opts[:split_cells_on])) } if !block_given? && opts[:split_cells_on]
|
142
|
+
say table cells, opts unless options.raw
|
143
|
+
end
|
144
|
+
|
145
|
+
def ssh_command_for_op(operation)
|
146
|
+
#case operation
|
147
|
+
raise RHC::OperationNotSupportedException, "The operation #{operation} is not supported."
|
148
|
+
#end
|
149
|
+
end
|
150
|
+
|
23
151
|
# Public: Run ssh command on remote host
|
24
152
|
#
|
25
153
|
# host - The String of the remote hostname to ssh to.
|
@@ -100,7 +228,6 @@ module RHC
|
|
100
228
|
end
|
101
229
|
end
|
102
230
|
|
103
|
-
|
104
231
|
# For Net::SSH versions (< 2.0.11) that does not have
|
105
232
|
# Net::SSH::KeyFactory.load_public_key, we drop to shell to get
|
106
233
|
# the key's fingerprint
|
@@ -147,6 +274,22 @@ module RHC
|
|
147
274
|
ssh_key_triple_for(RHC::Config.ssh_pub_key_file_path)
|
148
275
|
end
|
149
276
|
|
277
|
+
# check the version of SSH that is installed
|
278
|
+
def ssh_version
|
279
|
+
@ssh_version ||= `ssh -V 2>&1`.strip
|
280
|
+
end
|
281
|
+
|
282
|
+
# return whether or not SSH is installed
|
283
|
+
def has_ssh?
|
284
|
+
@has_ssh ||= begin
|
285
|
+
@ssh_version = nil
|
286
|
+
ssh_version
|
287
|
+
$?.success?
|
288
|
+
rescue
|
289
|
+
false
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
150
293
|
private
|
151
294
|
|
152
295
|
def ssh_add
|
@@ -1,7 +1,20 @@
|
|
1
1
|
Usage: <%= Array(program :name).first %> <%= @command.name %> <%= @command.syntax %>
|
2
2
|
|
3
3
|
<%= @command.description || @command.summary %>
|
4
|
-
<% if @actions.blank? -%>
|
4
|
+
<% if @actions.blank? or @command.root? and @command.info[:method].present? -%>
|
5
|
+
|
6
|
+
<% unless @command.info[:args].blank? or @command.options.all?{ |o| o[:hide] or o[:switches].present? } -%>
|
7
|
+
|
8
|
+
Arguments
|
9
|
+
<%= table(
|
10
|
+
@command.info[:args].select do |opt|
|
11
|
+
not opt[:hide] and not opt[:switches].present?
|
12
|
+
end.map do |opt|
|
13
|
+
[opt[:name], opt[:description]]
|
14
|
+
end,
|
15
|
+
table_args(' ', 25)
|
16
|
+
).join("\n") %>
|
17
|
+
<% end -%>
|
5
18
|
<% unless @command.options.blank? or @command.options.all?{ |o| o[:hide] } -%>
|
6
19
|
|
7
20
|
Options
|
@@ -26,7 +39,8 @@ Global Options
|
|
26
39
|
).join("\n") %>
|
27
40
|
|
28
41
|
See 'rhc help options' for a full list of global options.
|
29
|
-
<%
|
42
|
+
<% end -%>
|
43
|
+
<% if @actions.present? -%>
|
30
44
|
|
31
45
|
List of Actions
|
32
46
|
<%= table(@actions.map{ |a| [a[:name], a[:summary]] }, table_args(' ', 13)).join("\n") %>
|
data/spec/coverage_helper.rb
CHANGED
@@ -16,19 +16,22 @@ unless RUBY_VERSION < '1.9'
|
|
16
16
|
def print_missed_lines
|
17
17
|
@files.each do |file|
|
18
18
|
file.missed_lines.each do |line|
|
19
|
-
puts "MISSED #{file.filename}:#{line.number}"
|
19
|
+
STDERR.puts "MISSED #{file.filename}:#{line.number}"
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
original_stderr = $stderr # in case helpers don't properly cleanup
|
26
25
|
SimpleCov.at_exit do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
begin
|
27
|
+
SimpleCov.result.format!
|
28
|
+
if SimpleCov.result.covered_percent < 100.0
|
29
|
+
SimpleCov.result.print_missed_lines if SimpleCov.result.covered_percent > 98.0
|
30
|
+
STDERR.puts "Coverage not 100%, build failed."
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
rescue Exception => e
|
34
|
+
STDERR.puts "Exception at exit, #{e.message}"
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|