shelly 0.4.42 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd0f3635267e3be6e9d6fbff86054582b6ac3b9f
4
- data.tar.gz: 63d62d167f8245525f44a317e39d72529f1a0037
3
+ metadata.gz: 4b85bcd0e7111d1a7bdaf59a47384141a49fb347
4
+ data.tar.gz: c0279a7748d978b1cb427240b4b0c9a49dbbd039
5
5
  SHA512:
6
- metadata.gz: 7c4780ffcc4713f920354d5e7a4c9a8421b51382a956f3b0acea83023d28c016fe2a7cb1091093464ec8799d4963ed4c2a3b2f14a6d2d73233d85d332bb29593
7
- data.tar.gz: 7dee1731a302343f71c175fe6dc87695639d21e55f77ee1d8b8a77d95d7f75a65a3ff11ddf61b4d1822422cae98877194eb9de834d1d7fb5acf3c65c94f20b51
6
+ metadata.gz: 72a140d37c0f1027109b1a066e9ac6b9c4e8c785be895e46c3225b8b9c92f166b15ba72fc85439137bb3f0de2c18cfd0489d76b8a82085fe8d9bafd05a12409d
7
+ data.tar.gz: a9c4dc381a59cd781993d8a319767552ea013eea3aace1fead433a14a369cbe58f636baadc2db18cc5d3ce32ad156e2dce5868a62f49011ab5bed84e6165f6f5
@@ -1,4 +1,5 @@
1
1
  rvm:
2
+ - '2.2'
2
3
  - '2.1'
3
4
  - 2.0.0
4
5
  - 1.9.3
@@ -1,3 +1,12 @@
1
+ ## 0.5.0 / 2015-01-02
2
+
3
+ * [bugfix] Catch Conflict 409 when creating or updating endpoints
4
+ * [improvement] shelly info should print cloud region
5
+ * [improvement] shelly add should ask about organization name instead of number
6
+ from the list
7
+ * [improvement] Replaced zone with region
8
+ * [improvement] Allow user to choose region for the new cloud
9
+
1
10
  ## 0.4.42 / 2014-12-14
2
11
 
3
12
  * [improvement] Added --server / -s option for shelly rake command, so user
@@ -11,10 +11,11 @@ module Shelly
11
11
  DATABASE_KINDS = %w(postgresql mysql mongodb redis)
12
12
  DATABASE_CHOICES = DATABASE_KINDS + %w(none)
13
13
  SERVER_SIZES = %w(small large)
14
+ REGIONS = %w(EU NA)
14
15
 
15
16
  attr_accessor :code_name, :databases, :ruby_version, :environment,
16
17
  :git_url, :domains, :web_server_ip, :size, :thin,
17
- :organization_name, :zone, :usage, :traffic
18
+ :organization_name, :zone, :region, :usage, :traffic
18
19
 
19
20
  def initialize(code_name = nil)
20
21
  self.code_name = code_name
@@ -71,7 +72,8 @@ module Shelly
71
72
  def create
72
73
  attributes = {:code_name => code_name,
73
74
  :organization_name => organization_name,
74
- :zone => zone}
75
+ :zone => zone,
76
+ :region => @region}
75
77
  response = shelly.create_app(attributes)
76
78
  assign_attributes(response)
77
79
  end
@@ -279,6 +281,10 @@ module Shelly
279
281
  attributes["git_info"]
280
282
  end
281
283
 
284
+ def region
285
+ attributes['region'] || @region
286
+ end
287
+
282
288
  def state
283
289
  attributes["state"]
284
290
  end
@@ -52,7 +52,7 @@ module Shelly
52
52
  def create(path)
53
53
  app = multiple_clouds(options[:cloud], "create #{path}")
54
54
  if app.config_exists?(path)
55
- say "File '#{path}' already exists. Use `shelly config edit #{path} --cloud #{options[:cloud]}` to update it.", :red
55
+ say "File '#{path}' already exists. Use `shelly config edit #{path} --cloud #{app}` to update it.", :red
56
56
  else
57
57
  output = open_editor(path)
58
58
  app.create_config(path, output)
@@ -34,7 +34,6 @@ module Shelly
34
34
  end
35
35
 
36
36
  print_table(to_display, :ident => 2)
37
-
38
37
  else
39
38
  say "No HTTP endpoints available"
40
39
  end
@@ -81,6 +80,18 @@ module Shelly
81
80
  app = multiple_clouds(options[:cloud],
82
81
  "endpoint create [CERT_PATH] [KEY_PATH] [BUNDLE_PATH]")
83
82
 
83
+ say "Every unique IP address assigned to endpoint costs 10€/month"
84
+ say "It's required for SSL/TLS"
85
+ if cert_path == nil && key_path == nil
86
+ say "You didn't provide certificate but it can be added later"
87
+ say "Assigned IP address can be used to catch all domains pointing to that address, without SSL/TLS enabled"
88
+ exit(0) unless yes?("Are you sure you want to create endpoint without certificate (yes/no):")
89
+ elsif app.endpoints.count > 0
90
+ ask_if_endpoints_were_already_created(app)
91
+ else
92
+ exit(0) unless yes?("Are you sure you want to create endpoint? (yes/no):")
93
+ end
94
+
84
95
  certificate, key = read_certificate_components(cert_path, key_path,
85
96
  bundle_path)
86
97
 
@@ -94,6 +105,8 @@ module Shelly
94
105
  say "Private IP address was requested for your cloud."
95
106
  say "Support has been notified and will contact you shortly."
96
107
  end
108
+ rescue Client::ConflictException => e
109
+ say_error e['message']
97
110
  rescue Client::ValidationException => e
98
111
  e.each_error { |error| say_error error, :with_exit => false }
99
112
  exit 1
@@ -127,6 +140,8 @@ module Shelly
127
140
  rescue Client::ValidationException => e
128
141
  e.each_error { |error| say_error error, :with_exit => false }
129
142
  exit 1
143
+ rescue Client::ConflictException => e
144
+ say_error e['message']
130
145
  rescue Client::NotFoundException => e
131
146
  raise unless e.resource == :certificate
132
147
  say_error "Endpoint not found"
@@ -168,6 +183,16 @@ module Shelly
168
183
  [certificate, key]
169
184
  end
170
185
  end
186
+
187
+ def ask_if_endpoints_were_already_created(app)
188
+ cli = Shelly::CLI::Endpoint.new
189
+ cli.options = {:cloud => app}
190
+ cli.list
191
+ say_new_line
192
+ exit(0) unless yes?("You already have assigned endpoint(s). Are " \
193
+ "you sure you want to create another one with a new IP address? " \
194
+ "(yes/no):")
195
+ end
171
196
  end
172
197
  end
173
198
  end
@@ -111,6 +111,7 @@ module Shelly
111
111
  app = multiple_clouds(options[:cloud], "info")
112
112
  msg = info_show_last_deploy_logs(app)
113
113
  say "Cloud #{app}:", app.in_deploy_failed_state? ? :red : :green
114
+ print_wrapped "Region: #{app.region}", :ident => 2
114
115
  print_wrapped "State: #{app.state_description}#{msg}", :ident => 2
115
116
  say_new_line
116
117
  print_wrapped "Deployed commit sha: #{app.git_info["deployed_commit_sha"]}", :ident => 2
@@ -17,6 +17,8 @@ module Shelly
17
17
  :desc => "Skip Shelly Cloud requirements check"
18
18
  method_option "zone", :type => :string, :hide => true,
19
19
  :desc => "Create cloud in given zone"
20
+ method_option "region", :type => :string,
21
+ :desc => "Create cloud in given region"
20
22
  desc "add", "Add a new cloud"
21
23
  def add
22
24
  check_options(options)
@@ -27,8 +29,13 @@ module Shelly
27
29
  app.code_name = options["code-name"] || ask_for_code_name
28
30
  app.databases = options["databases"] || ask_for_databases
29
31
  app.size = options["size"] || "small"
30
- app.organization_name = options["organization"] || ask_for_organization(options)
31
- app.zone = options["zone"]
32
+ app.organization_name = options["organization"] ||
33
+ ask_for_organization(options)
34
+ if options["zone"].present?
35
+ app.zone = options["zone"]
36
+ else
37
+ app.region = options["region"] || ask_for_region
38
+ end
32
39
 
33
40
  app.create
34
41
  say "Cloud '#{app}' created in '#{app.organization_name}' organization", :green
@@ -60,7 +67,7 @@ module Shelly
60
67
  e.each_error { |error| say_error error, :with_exit => false }
61
68
  say_new_line
62
69
  say_error "Fix erros in the below command and type it again to create your cloud" , :with_exit => false
63
- say_error "shelly add --code-name=#{app.code_name.downcase.dasherize} --databases=#{app.databases.join(',')} --organization=#{app.organization_name} --size=#{app.size}"
70
+ say_error "shelly add --code-name=#{app.code_name.downcase.dasherize} --databases=#{app.databases.join(',')} --organization=#{app.organization_name} --size=#{app.size} --region=#{app.region}"
64
71
  rescue Client::ForbiddenException
65
72
  say_error "You have to be the owner of '#{app.organization_name}' organization to add clouds"
66
73
  rescue Client::NotFoundException => e
@@ -72,33 +79,33 @@ module Shelly
72
79
  no_tasks do
73
80
  def ask_for_organization(options)
74
81
  organizations = Shelly::User.new.organizations
82
+
75
83
  if organizations.blank?
76
84
  ask_for_new_organization(options)
77
85
  else
78
- count = organizations.count
79
- option_selected = 0
86
+ say "Select organization for this cloud:"
87
+ say_new_line
88
+
80
89
  loop do
81
- say "Select organization for this cloud:"
82
- say_new_line
83
90
  say "existing organizations:"
84
91
 
85
92
  organizations.each_with_index do |organization, i|
86
93
  print_wrapped "#{i + 1}) #{organization.name}", :ident => 2
87
94
  end
88
- say_new_line
89
-
90
- print_wrapped "#{count + 1}) provide name for new organization", :ident => 2
91
95
 
92
- option_selected = ask("Option:")
93
- break if ('1'..(count + 1).to_s).include?(option_selected)
94
- end
95
-
96
- if option_selected.to_i == count + 1
97
- return ask_for_new_organization(options)
98
- end
96
+ say green "Or leave empty to create a new organization"
97
+ say_new_line
99
98
 
100
- if (1..count).include?(option_selected.to_i)
101
- return organizations[option_selected.to_i - 1].name
99
+ selected = ask("Organization:")
100
+ if organizations.select { |o| o.name == selected }.present?
101
+ return selected
102
+ elsif selected.empty?
103
+ say_new_line
104
+ return ask_for_new_organization(options)
105
+ else
106
+ say_new_line
107
+ say_warning "#{selected} organization does not exist"
108
+ end
102
109
  end
103
110
  end
104
111
  end
@@ -113,6 +120,28 @@ module Shelly
113
120
  end
114
121
  end
115
122
 
123
+ def ask_for_region
124
+ regions = Shelly::App::REGIONS
125
+ say "Select region for this cloud:"
126
+ say_new_line
127
+
128
+ loop do
129
+ say "available regions:"
130
+
131
+ regions.each_with_index do |region, i|
132
+ print_wrapped "#{i + 1}) #{region}", :ident => 2
133
+ end
134
+ say_new_line
135
+
136
+ selected = ask("Region:").upcase
137
+ if regions.include?(selected)
138
+ return selected
139
+ else
140
+ say_new_line
141
+ say_warning "#{selected} region is not available"
142
+ end
143
+ end
144
+ end
116
145
  end
117
146
  end
118
147
  end
@@ -21,10 +21,10 @@ module Shelly
21
21
  say_new_line
22
22
 
23
23
  maintenances.each do |maintenance|
24
- started_at = Time.parse(maintenance['created_at']).
24
+ started_at = Time.parse(maintenance['created_at']).getlocal.
25
25
  strftime('%Y-%m-%d %H:%M:%S')
26
26
  finished_at = if maintenance['finished']
27
- Time.parse(maintenance['updated_at']).
27
+ Time.parse(maintenance['updated_at']).getlocal.
28
28
  strftime('%Y-%m-%d %H:%M:%S')
29
29
  else
30
30
  'in progress'
@@ -1,9 +1,10 @@
1
1
  class Shelly::Client
2
2
  def create_app(attributes)
3
3
  organization = attributes.delete(:organization_name)
4
+ region = attributes.delete(:region)
4
5
  zone = attributes.delete(:zone)
5
6
  post("/apps", :app => attributes, :organization_name => organization,
6
- :zone => zone)
7
+ :region => region, :zone => zone)
7
8
  end
8
9
 
9
10
  def delete_app(code_name)
@@ -1,3 +1,3 @@
1
1
  module Shelly
2
- VERSION = "0.4.42"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -153,6 +153,7 @@ describe Shelly::App do
153
153
  describe "#attributes" do
154
154
  before do
155
155
  @response = {"web_server_ip" => "192.0.2.1",
156
+ "region" => "EU",
156
157
  "state" => "running",
157
158
  "maintenance" => false,
158
159
  "organization" => {
@@ -190,6 +191,12 @@ describe Shelly::App do
190
191
  end
191
192
  end
192
193
 
194
+ describe "#region" do
195
+ it "should return cloud region" do
196
+ @app.region.should == "EU"
197
+ end
198
+ end
199
+
193
200
  describe "#state" do
194
201
  it "should return state of cloud" do
195
202
  @app.state.should == "running"
@@ -356,7 +363,8 @@ describe Shelly::App do
356
363
  attributes = {
357
364
  :code_name => "fooo",
358
365
  :organization_name => nil,
359
- :zone => nil
366
+ :zone => nil,
367
+ :region => nil
360
368
  }
361
369
  @client.should_receive(:create_app).with(attributes).and_return("git_url" => "git@git.shellycloud.com:fooo.git",
362
370
  "domains" => %w(fooo.shellyapp.com))
@@ -122,7 +122,7 @@ describe Shelly::CLI::Config do
122
122
  it "should warn that config file already exists in specified path" do
123
123
  Shelly::App.stub(:new).and_return(@app)
124
124
  @app.stub(:config_exists? => true)
125
- $stdout.should_receive(:puts).with(red "File 'new_config' already exists. Use `shelly config edit new_config --cloud ` to update it.")
125
+ $stdout.should_receive(:puts).with(red "File 'new_config' already exists. Use `shelly config edit new_config --cloud foo-production` to update it.")
126
126
  invoke(@config, :create, "new_config")
127
127
  end
128
128
 
@@ -29,31 +29,6 @@ describe Shelly::CLI::Endpoint do
29
29
  invoke(@cli, :list)
30
30
  end
31
31
 
32
- def endpoints_response
33
- [
34
- {'ip_address' => '10.0.0.1',
35
- 'sni' => true,
36
- 'uuid' => 'uuid1', 'info' => {
37
- 'domain' => 'example.com',
38
- 'issuer' => 'CA',
39
- 'subjcet' => 'organization info',
40
- 'since' => '2012-06-11 23:00:00 UTC',
41
- 'to' => '2015-06-11 23:00:00 UTC'
42
- }
43
- },
44
- {'ip_address' => '10.0.0.2',
45
- 'sni' => false,
46
- 'uuid' => 'uuid2', 'info' => {
47
- 'domain' => nil,
48
- 'issuer' => nil,
49
- 'subjcet' => nil,
50
- 'since' => nil,
51
- 'to' => nil
52
- }
53
- }
54
- ]
55
- end
56
-
57
32
  context "no endpoints" do
58
33
  it "should display information" do
59
34
  @app.should_receive(:endpoints).and_return([])
@@ -98,28 +73,86 @@ describe Shelly::CLI::Endpoint do
98
73
  File.stub(:read).with('crt_path').and_return('crt')
99
74
  File.stub(:read).with('key_path').and_return('key')
100
75
  File.stub(:read).with('bundle_path').and_return('bundle')
76
+ @app.stub(:endpoints).and_return([])
101
77
  end
102
78
 
103
- it "should create endpoint" do
79
+ it "should create endpoint with provided certificate" do
104
80
  @app.should_receive(:create_endpoint).with("crt\n", "key", true).
105
81
  and_return(endpoint_response('ip_address' => '10.0.0.1'))
106
82
 
83
+ $stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
84
+ $stdout.should_receive(:puts).with("It's required for SSL/TLS")
85
+ $stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
86
+
107
87
  $stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
108
88
  $stdout.should_receive(:puts).with("Deployed certificate on front end servers.")
109
89
  $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
110
90
 
111
91
  @cli.options = {"sni" => true}
112
- invoke(@cli, :create, "crt_path", "key_path")
92
+ fake_stdin(["yes"]) do
93
+ invoke(@cli, :create, "crt_path", "key_path")
94
+ end
95
+ end
96
+
97
+ context "without certificate" do
98
+ it "should create endpoint" do
99
+ @app.should_receive(:create_endpoint).with(nil, nil, true).
100
+ and_return(endpoint_response('ip_address' => '10.0.0.1'))
101
+
102
+ $stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
103
+ $stdout.should_receive(:puts).with("It's required for SSL/TLS")
104
+ $stdout.should_receive(:puts).with("You didn't provide certificate but it can be added later")
105
+ $stdout.should_receive(:puts).with("Assigned IP address can be used to catch all domains pointing to that address, without SSL/TLS enabled")
106
+ $stdout.should_receive(:print).with("Are you sure you want to create endpoint without certificate (yes/no): ")
107
+ $stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
108
+ $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
109
+
110
+ @cli.options = {"sni" => true}
111
+ fake_stdin(["yes"]) do
112
+ invoke(@cli, :create)
113
+ end
114
+ end
115
+ end
116
+
117
+ context "multiple endpoints" do
118
+ it "should create endpoint with provided certificate" do
119
+ @app.should_receive(:create_endpoint).with("crt\n", "key", nil).
120
+ and_return(endpoint_response('ip_address' => '10.0.0.1'))
121
+ @app.stub(:endpoints).and_return(endpoints_response)
122
+
123
+ $stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
124
+ $stdout.should_receive(:puts).with("It's required for SSL/TLS")
125
+ $stdout.should_receive(:puts).with(green "Available HTTP endpoints")
126
+ $stdout.should_receive(:puts).with("\n")
127
+ $stdout.should_receive(:puts).with(" UUID | IP address | Certificate | SNI")
128
+ $stdout.should_receive(:puts).with(" uuid1 | 10.0.0.1 | example.com | \u2713")
129
+ $stdout.should_receive(:puts).with(" uuid2 | 10.0.0.2 | \u2717 | \u2717")
130
+ $stdout.should_receive(:puts).with("\n")
131
+ $stdout.should_receive(:print).with("You already have assigned endpoint(s). Are you sure you want to create another one with a new IP address? (yes/no): ")
132
+ $stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
133
+ $stdout.should_receive(:puts).with("Deployed certificate on front end servers.")
134
+ $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
135
+
136
+ fake_stdin(["yes"]) do
137
+ invoke(@cli, :create, "crt_path", "key_path")
138
+ end
139
+ end
113
140
  end
114
141
 
115
142
  context "validation errors" do
116
143
  it "should show errors and exit" do
117
144
  exception = Shelly::Client::ValidationException.new({"errors" => [["key", "is invalid"]]})
118
145
  @app.should_receive(:create_endpoint).and_raise(exception)
146
+
147
+ $stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
148
+ $stdout.should_receive(:puts).with("It's required for SSL/TLS")
149
+ $stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
119
150
  $stdout.should_receive(:puts).with(red "Key is invalid")
120
151
 
121
152
  lambda {
122
- invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
153
+ fake_stdin(["yes"]) do
154
+ invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
155
+ end
123
156
  }.should raise_error(SystemExit)
124
157
  end
125
158
  end
@@ -127,10 +160,35 @@ describe Shelly::CLI::Endpoint do
127
160
  context "providing one only part of certificate" do
128
161
  it "should show error and exit" do
129
162
  @app.should_not_receive(:create_endpoint)
163
+
164
+ $stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
165
+ $stdout.should_receive(:puts).with("It's required for SSL/TLS")
166
+ $stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
130
167
  $stdout.should_receive(:puts).with(red "Provide both certificate and key")
131
168
 
132
169
  lambda {
133
- invoke(@cli, :create, "crt_path")
170
+ fake_stdin(["yes"]) do
171
+ invoke(@cli, :create, "crt_path")
172
+ end
173
+ }.should raise_error(SystemExit)
174
+ end
175
+ end
176
+
177
+ context "conflict error" do
178
+ it "should show errors and exit" do
179
+ exception = Shelly::Client::ConflictException.new("message" =>
180
+ "That's an error")
181
+ @app.should_receive(:create_endpoint).and_raise(exception)
182
+
183
+ $stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
184
+ $stdout.should_receive(:puts).with("It's required for SSL/TLS")
185
+ $stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
186
+ $stdout.should_receive(:puts).with(red "That's an error")
187
+
188
+ lambda {
189
+ fake_stdin(["yes"]) do
190
+ invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
191
+ end
134
192
  }.should raise_error(SystemExit)
135
193
  end
136
194
  end
@@ -164,6 +222,19 @@ describe Shelly::CLI::Endpoint do
164
222
  }.should raise_error(SystemExit)
165
223
  end
166
224
  end
225
+
226
+ context "conflict error" do
227
+ it "should show errors and exit" do
228
+ exception = Shelly::Client::ConflictException.new("message" =>
229
+ "That's an error")
230
+ @app.should_receive(:update_endpoint).and_raise(exception)
231
+ $stdout.should_receive(:puts).with(red "That's an error")
232
+
233
+ lambda {
234
+ invoke(@cli, :update, "crt_path", "key_path", "bundle_path")
235
+ }.should raise_error(SystemExit)
236
+ end
237
+ end
167
238
  end
168
239
 
169
240
  describe "#delete" do
@@ -183,6 +254,31 @@ describe Shelly::CLI::Endpoint do
183
254
  end
184
255
  end
185
256
 
257
+ def endpoints_response
258
+ [
259
+ { 'ip_address' => '10.0.0.1',
260
+ 'sni' => true,
261
+ 'uuid' => 'uuid1', 'info' => {
262
+ 'domain' => 'example.com',
263
+ 'issuer' => 'CA',
264
+ 'subjcet' => 'organization info',
265
+ 'since' => '2012-06-11 23:00:00 UTC',
266
+ 'to' => '2015-06-11 23:00:00 UTC'
267
+ }
268
+ },
269
+ { 'ip_address' => '10.0.0.2',
270
+ 'sni' => false,
271
+ 'uuid' => 'uuid2', 'info' => {
272
+ 'domain' => nil,
273
+ 'issuer' => nil,
274
+ 'subjcet' => nil,
275
+ 'since' => nil,
276
+ 'to' => nil
277
+ }
278
+ }
279
+ ]
280
+ end
281
+
186
282
  def endpoint_response(options = {})
187
283
  {'ip_address' => '10.0.0.1', 'sni' => true,
188
284
  'uuid' => 'uuid1', 'info' => {
@@ -317,6 +317,7 @@ describe Shelly::CLI::Main do
317
317
  @app.stub(:git_remote_exist?).and_return(false)
318
318
  @main.stub(:check => true)
319
319
  @main.stub(:ask_for_organization)
320
+ @main.stub(:ask_for_region).and_return('EU')
320
321
  end
321
322
 
322
323
  # This spec tests inside_git_repository? hook
@@ -370,9 +371,29 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
370
371
  invoke(@main, :add)
371
372
  end
372
373
 
373
- it "should use zone from option" do
374
- @app.should_receive(:zone=).with('eu1')
375
- @main.options = {"zone" => "eu1"}
374
+ context "for zone param" do
375
+ it "should use zone from option" do
376
+ @app.should_receive(:zone=).with('zone')
377
+ @main.options = {"zone" => "zone"}
378
+ fake_stdin(["mycodename", ""]) do
379
+ invoke(@main, :add)
380
+ end
381
+ end
382
+
383
+ it "should not ask about the region" do
384
+ @app.should_not_receive(:region=)
385
+ $stdout.should_not_receive(:puts).
386
+ with("Select region for this cloud:")
387
+ @main.options = {"zone" => "zone"}
388
+ fake_stdin(["mycodename", ""]) do
389
+ invoke(@main, :add)
390
+ end
391
+ end
392
+ end
393
+
394
+ it "should use region from option" do
395
+ @app.should_receive(:region=).with('eu1')
396
+ @main.options = {"region" => "eu1"}
376
397
  fake_stdin(["mycodename", ""]) do
377
398
  invoke(@main, :add)
378
399
  end
@@ -476,7 +497,7 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
476
497
  @app.should_receive(:create).and_raise(exception)
477
498
  $stdout.should_receive(:puts).with(red "Code name has been already taken")
478
499
  $stdout.should_receive(:puts).with(red "Fix erros in the below command and type it again to create your cloud")
479
- $stdout.should_receive(:puts).with(red "shelly add --code-name=big-letters --databases=postgresql --organization=org-name --size=small")
500
+ $stdout.should_receive(:puts).with(red "shelly add --code-name=big-letters --databases=postgresql --organization=org-name --size=small --region=EU")
480
501
  lambda {
481
502
  fake_stdin(["BiG_LETTERS", ""]) do
482
503
  invoke(@main, :add)
@@ -608,7 +629,7 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
608
629
  it "should use --organization option" do
609
630
  @main.options = {"organization" => "foo"}
610
631
  @app.should_receive(:organization_name=).with("foo")
611
- fake_stdin(["foooo", "none"]) do
632
+ fake_stdin(["foo", "none"]) do
612
633
  invoke(@main, :add)
613
634
  end
614
635
  end
@@ -618,46 +639,51 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
618
639
  @client.stub(:organizations).and_return([{"name" => "aaa"}])
619
640
  end
620
641
 
621
- it "should ask user to choose organization if present and use chosen organization" do
622
- @app.should_receive(:organization_name=).with("aaa")
623
- $stdout.should_receive(:puts).with("Select organization for this cloud:")
642
+ it "should ask user to choose organization" do
643
+ $stdout.should_receive(:puts).
644
+ with("Select organization for this cloud:")
624
645
  $stdout.should_receive(:puts).with("existing organizations:")
625
646
  $stdout.should_receive(:puts).with(" 1) aaa")
626
- $stdout.should_receive(:puts).with(" 2) provide name for new organization")
627
- $stdout.should_receive(:print).with("Option: ")
628
- fake_stdin(["foooo", "none", "1"]) do
647
+ $stdout.should_receive(:puts).
648
+ with(green "Or leave empty to create a new organization")
649
+ $stdout.should_receive(:print).with("Organization: ")
650
+ fake_stdin(["foo", "none", "aaa"]) do
629
651
  invoke(@main, :add)
630
652
  end
631
653
  end
632
654
 
633
- it "should ask user to create new organization" do
634
- @main.options = {'redeem-code' => 'discount'}
635
- @client.should_receive(:create_organization).
636
- with({:name => "org-name", :redeem_code => 'discount'})
637
- @app.should_receive(:organization_name=).with('org-name')
638
- $stdout.should_receive(:puts).with("Select organization for this cloud:")
639
- $stdout.should_receive(:puts).with("existing organizations:")
640
- $stdout.should_receive(:puts).with(" 1) aaa")
641
- $stdout.should_receive(:puts).with(" 2) provide name for new organization")
642
- $stdout.should_receive(:print).with("Option: ")
643
- $stdout.should_receive(:print).with("Organization name (foo - default): ")
644
- $stdout.should_receive(:puts).with(green "Organization 'org-name' created")
645
- fake_stdin(["foooo", "none", "2", "org-name"]) do
655
+ it "should keep asking until user will provide a valid option" do
656
+ $stdout.should_receive(:print).with("Organization: ").twice
657
+ fake_stdin(["foo", "none", "bbb", "aaa"]) do
658
+ invoke(@main, :add)
659
+ end
660
+ end
661
+
662
+ it "should use choosen organization" do
663
+ @app.should_receive(:organization_name=).with("aaa")
664
+ fake_stdin(["foo", "none", "aaa"]) do
646
665
  invoke(@main, :add)
647
666
  end
648
667
  end
649
668
 
650
- it "should use redeem-code option" do
669
+ it "should ask user to create a new organization" do
670
+ @app.should_receive(:organization_name=).with('org-name')
651
671
  @client.should_receive(:create_organization).
652
672
  with({:name => "org-name", :redeem_code => nil})
653
- $stdout.should_receive(:puts).with("Select organization for this cloud:")
654
- $stdout.should_receive(:puts).with("existing organizations:")
655
- $stdout.should_receive(:puts).with(" 1) aaa")
656
- $stdout.should_receive(:puts).with(" 2) provide name for new organization")
657
- $stdout.should_receive(:print).with("Option: ")
658
- $stdout.should_receive(:print).with("Organization name (foo - default): ")
659
- $stdout.should_receive(:puts).with(green "Organization 'org-name' created")
660
- fake_stdin(["foooo", "none", "2", "org-name"]) do
673
+ $stdout.should_receive(:print).
674
+ with("Organization name (foo - default): ")
675
+ $stdout.should_receive(:puts).
676
+ with(green "Organization 'org-name' created")
677
+ fake_stdin(["foo", "none", "", "org-name"]) do
678
+ invoke(@main, :add)
679
+ end
680
+ end
681
+
682
+ it "should use --redeem-code option" do
683
+ @main.options = {'redeem-code' => 'discount'}
684
+ @client.should_receive(:create_organization).
685
+ with({:name => "org-name", :redeem_code => 'discount'})
686
+ fake_stdin(["foo", "none", "", "org-name"]) do
661
687
  invoke(@main, :add)
662
688
  end
663
689
  end
@@ -668,8 +694,11 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
668
694
  response = {"resource" => "organization"}
669
695
  exception = Shelly::Client::NotFoundException.new(response)
670
696
  @app.should_receive(:create).and_raise(exception)
671
- $stdout.should_receive(:puts).with(red "Organization 'foo' not found")
672
- $stdout.should_receive(:puts).with(red "You can list organizations you have access to with `shelly organization list`")
697
+ $stdout.should_receive(:puts).
698
+ with(red "Organization 'foo' not found")
699
+ $stdout.should_receive(:puts).
700
+ with(red "You can list organizations you have access to with" \
701
+ " `shelly organization list`")
673
702
 
674
703
  expect do
675
704
  fake_stdin(["foooo", "none"]) do
@@ -678,6 +707,59 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
678
707
  end.to raise_error(SystemExit)
679
708
  end
680
709
  end
710
+
711
+ context "for region" do
712
+ before do
713
+ @main.unstub(:ask_for_region)
714
+ end
715
+
716
+ it "should use the value from the --region option" do
717
+ @main.options = {"region" => "EU"}
718
+ @app.should_receive(:region=).with("EU")
719
+ fake_stdin(["foo", "none"]) do
720
+ invoke(@main, :add)
721
+ end
722
+ end
723
+
724
+ it "should ask user to choose the region" do
725
+ @app.should_receive(:region=).with("NA")
726
+ $stdout.should_receive(:puts).with("Select region for this cloud:")
727
+ $stdout.should_receive(:puts).with("available regions:")
728
+ $stdout.should_receive(:puts).with(" 1) EU")
729
+ $stdout.should_receive(:puts).with(" 2) NA")
730
+ $stdout.should_receive(:print).with("Region: ")
731
+ fake_stdin(["foo", "none", "NA"]) do
732
+ invoke(@main, :add)
733
+ end
734
+ end
735
+
736
+ context "when given region is not available" do
737
+ it "should print a warning message and ask again" do
738
+ $stdout.should_receive(:puts).
739
+ with(yellow "ASIA region is not available")
740
+ $stdout.should_receive(:puts).with("available regions:").twice
741
+ fake_stdin(["foo", "none", "ASIA", "NA"]) do
742
+ invoke(@main, :add)
743
+ end
744
+ end
745
+ end
746
+
747
+ context "when given region does not accepts new apps" do
748
+ it "should show that it is not available" do
749
+ @main.options = {"region" => "NA"}
750
+ response = {"error" => "Given region is unavailable"}
751
+ exception = Shelly::Client::ConflictException.new(response)
752
+ @app.should_receive(:create).and_raise(exception)
753
+ $stdout.should_receive(:puts).with(red "Given region is unavailable")
754
+
755
+ expect do
756
+ fake_stdin(["foo", "none", "NA"]) do
757
+ invoke(@main, :add)
758
+ end
759
+ end.to raise_error(SystemExit)
760
+ end
761
+ end
762
+ end
681
763
  end
682
764
 
683
765
  describe "#list" do
@@ -1006,6 +1088,7 @@ Wait until cloud is in 'turned off' state and try again.")
1006
1088
  it "should display basic information about cloud" do
1007
1089
  @main.should_receive(:multiple_clouds).and_return(@app)
1008
1090
  $stdout.should_receive(:puts).with(green "Cloud foo-production:")
1091
+ $stdout.should_receive(:puts).with(" Region: EU")
1009
1092
  $stdout.should_receive(:puts).with(" State: running")
1010
1093
  $stdout.should_receive(:puts).with(" Deployed commit sha: 52e65ed2d085eaae560cdb81b2b56a7d76")
1011
1094
  $stdout.should_receive(:puts).with(" Deployed commit message: Commit message")
@@ -1068,6 +1151,7 @@ Wait until cloud is in 'turned off' state and try again.")
1068
1151
  "maintenance" => true}))
1069
1152
  @main.should_receive(:multiple_clouds).and_return(@app)
1070
1153
  $stdout.should_receive(:puts).with(red "Cloud foo-production:")
1154
+ $stdout.should_receive(:puts).with(" Region: EU")
1071
1155
  $stdout.should_receive(:puts).with(" State: admin maintenance in progress")
1072
1156
  $stdout.should_receive(:puts).with(" Deployed commit sha: 52e65ed2d085eaae560cdb81b2b56a7d76")
1073
1157
  $stdout.should_receive(:puts).with(" Deployed commit message: Commit message")
@@ -1101,6 +1185,7 @@ Wait until cloud is in 'turned off' state and try again.")
1101
1185
  "maintenance" => false}))
1102
1186
  @main.should_receive(:multiple_clouds).and_return(@app)
1103
1187
  $stdout.should_receive(:puts).with(red "Cloud foo-production:")
1188
+ $stdout.should_receive(:puts).with(" Region: EU")
1104
1189
  $stdout.should_receive(:puts).with(" State: running (last deployment failed) (deployment log: `shelly deploys show last -c foo-production`)")
1105
1190
  $stdout.should_receive(:puts).with(" Deployed commit sha: 52e65ed2d085eaae560cdb81b2b56a7d76")
1106
1191
  $stdout.should_receive(:puts).with(" Deployed commit message: Commit message")
@@ -1148,6 +1233,7 @@ Wait until cloud is in 'turned off' state and try again.")
1148
1233
 
1149
1234
  def response(options = {})
1150
1235
  { "code_name" => "foo-production",
1236
+ "region" => "EU",
1151
1237
  "state" => "running",
1152
1238
  "state_description" => "running",
1153
1239
  "git_info" => {
@@ -171,9 +171,10 @@ describe Shelly::Client do
171
171
  describe "#create_app" do
172
172
  it "should send post with app's attributes" do
173
173
  @client.should_receive(:post).with("/apps", :app => {:code_name => "foo",
174
- :ruby_version => "1.9.2"}, :organization_name => "foo", :zone => 'eu1')
174
+ :ruby_version => "1.9.2"}, :organization_name => "foo", :region => 'EU',
175
+ :zone => nil)
175
176
  @client.create_app(:code_name => "foo", :ruby_version => "1.9.2",
176
- :organization_name => "foo", :zone => "eu1")
177
+ :organization_name => "foo", :region => "EU", :zone => nil)
177
178
  end
178
179
  end
179
180
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shelly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.42
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shelly Cloud team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-14 00:00:00.000000000 Z
11
+ date: 2015-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec