vmc 0.4.2 → 0.4.3

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/lib/vmc.rb +2 -5
  2. data/lib/vmc/cli/app/apps.rb +4 -1
  3. data/lib/vmc/cli/app/push.rb +38 -221
  4. data/lib/vmc/cli/app/push/create.rb +125 -0
  5. data/lib/vmc/cli/app/push/interaction.rb +64 -0
  6. data/lib/vmc/cli/app/push/sync.rb +59 -0
  7. data/lib/vmc/cli/app/rename.rb +1 -1
  8. data/lib/vmc/cli/organization/base.rb +14 -0
  9. data/lib/vmc/cli/organization/create_org.rb +28 -0
  10. data/lib/vmc/cli/organization/delete_org.rb +65 -0
  11. data/lib/vmc/cli/organization/org.rb +46 -0
  12. data/lib/vmc/cli/organization/orgs.rb +35 -0
  13. data/lib/vmc/cli/organization/rename.rb +32 -0
  14. data/lib/vmc/cli/service/base.rb +8 -0
  15. data/lib/vmc/cli/service/binding.rb +66 -0
  16. data/lib/vmc/cli/service/create.rb +104 -0
  17. data/lib/vmc/cli/service/delete.rb +84 -0
  18. data/lib/vmc/cli/service/rename.rb +32 -0
  19. data/lib/vmc/cli/service/service.rb +45 -0
  20. data/lib/vmc/cli/service/services.rb +118 -0
  21. data/lib/vmc/cli/space/base.rb +21 -0
  22. data/lib/vmc/cli/space/create.rb +57 -0
  23. data/lib/vmc/cli/space/delete.rb +92 -0
  24. data/lib/vmc/cli/space/rename.rb +36 -0
  25. data/lib/vmc/cli/space/space.rb +67 -0
  26. data/lib/vmc/cli/space/spaces.rb +57 -0
  27. data/lib/vmc/cli/space/take.rb +18 -0
  28. data/lib/vmc/cli/start/base.rb +100 -0
  29. data/lib/vmc/cli/start/colors.rb +14 -0
  30. data/lib/vmc/cli/start/info.rb +124 -0
  31. data/lib/vmc/cli/start/login.rb +94 -0
  32. data/lib/vmc/cli/start/logout.rb +14 -0
  33. data/lib/vmc/cli/start/register.rb +38 -0
  34. data/lib/vmc/cli/start/target.rb +68 -0
  35. data/lib/vmc/cli/start/targets.rb +17 -0
  36. data/lib/vmc/version.rb +1 -1
  37. data/spec/factories/app_factory.rb +5 -0
  38. data/spec/factories/client_factory.rb +10 -1
  39. data/spec/factories/domain_factory.rb +2 -1
  40. data/spec/factories/factory.rb +1 -0
  41. data/spec/factories/framework_factory.rb +1 -0
  42. data/spec/factories/organization_factory.rb +18 -0
  43. data/spec/factories/route_factory.rb +1 -0
  44. data/spec/factories/runtime_factory.rb +10 -0
  45. data/spec/factories/service_binding_factory.rb +9 -0
  46. data/spec/factories/service_factory.rb +17 -0
  47. data/spec/factories/service_instance_factory.rb +10 -0
  48. data/spec/factories/service_plan_factory.rb +11 -0
  49. data/spec/factories/space_factory.rb +10 -0
  50. data/spec/support/interact_helpers.rb +7 -3
  51. data/spec/vmc/cli/app/push/create_spec.rb +450 -0
  52. data/spec/vmc/cli/app/push_spec.rb +303 -9
  53. data/spec/vmc/cli/app/rename_spec.rb +9 -4
  54. data/spec/vmc/cli/organization/rename_spec.rb +113 -0
  55. data/spec/vmc/cli/route/delete_route_spec.rb +2 -2
  56. data/spec/vmc/cli/service/rename_spec.rb +114 -0
  57. data/spec/vmc/cli/space/rename_spec.rb +114 -0
  58. metadata +109 -64
  59. data/lib/vmc/cli/organization.rb +0 -176
  60. data/lib/vmc/cli/service.rb +0 -387
  61. data/lib/vmc/cli/space.rb +0 -284
  62. data/lib/vmc/cli/start.rb +0 -432
  63. data/spec/assets/hello-sinatra/Gemfile.lock +0 -17
@@ -2,10 +2,12 @@ require 'spec_helper'
2
2
  require "vmc/cli/app/push"
3
3
 
4
4
  describe VMC::App::Push do
5
- let(:global_inputs) { { :color => false, :quiet => true } }
5
+ let(:global) { { :color => false, :quiet => true } }
6
6
  let(:inputs) { {} }
7
7
  let(:given) { {} }
8
+ let(:path) { "somepath" }
8
9
  let(:client) { FactoryGirl.build(:client) }
10
+ let(:push) { VMC::App::Push.new(Mothership.commands[:push]) }
9
11
 
10
12
  before do
11
13
  any_instance_of(VMC::CLI) do |cli|
@@ -14,21 +16,313 @@ describe VMC::App::Push do
14
16
  end
15
17
  end
16
18
 
17
- describe 'CLI' do
18
- subject { Mothership.new.invoke(:push, inputs, given, global_inputs) }
19
+ describe 'metadata' do
20
+ let(:command) { Mothership.commands[:push] }
19
21
 
20
- context 'when creating a new app' do
22
+ describe 'command' do
23
+ subject { command }
24
+ its(:description) { should eq "Push an application, syncing changes if it exists" }
25
+ it { expect(Mothership::Help.group(:apps, :manage)).to include(subject) }
21
26
  end
22
27
 
23
- context 'when syncing an existing app' do
28
+ describe 'inputs' do
29
+ subject { command.inputs }
30
+
31
+ it "is not missing any descriptions" do
32
+ subject.each do |input, attrs|
33
+ expect(attrs[:description]).to be
34
+ expect(attrs[:description].strip).to_not be_empty
35
+ end
36
+ end
24
37
  end
25
- end
26
38
 
27
- describe '#create_app' do
28
- xit 'should detect the correct framework'
39
+ describe 'arguments' do
40
+ subject { command.arguments }
41
+ it 'has the correct argument order' do
42
+ should eq([{ :type => :normal, :value => nil, :name => :name }])
43
+ end
44
+ end
29
45
  end
30
46
 
31
47
  describe '#sync_app' do
48
+ let(:app) { FactoryGirl.build(:app) }
49
+
50
+ before do
51
+ stub(app).upload
52
+ app.changes = {}
53
+ end
54
+
55
+ subject do
56
+ push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
57
+ push.sync_app(app, path)
58
+ end
59
+
60
+ shared_examples 'common tests for inputs' do |*args|
61
+ context 'when the new input is the same as the old' do
62
+ type, input = args
63
+ input ||= type
64
+
65
+ let(:inputs) { {input => old} }
66
+
67
+ it "does not update the app's #{type}" do
68
+ dont_allow(push).line
69
+ dont_allow(app).update!
70
+ expect { subject }.not_to change { app.send(type) }
71
+ end
72
+ end
73
+ end
74
+
75
+ it 'uploads the app' do
76
+ mock(app).upload(path)
77
+ subject
78
+ end
79
+
80
+ context 'when no inputs are given' do
81
+ let(:inputs) { {} }
82
+
83
+ it 'should not update the app' do
84
+ dont_allow(app).update!
85
+ subject
86
+ end
87
+
88
+ [:memory=, :framework=].each do |property|
89
+ it "should not set #{property} on the app" do
90
+ dont_allow(app).__send__(property)
91
+ subject
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'when memory is given' do
97
+ let(:old) { 1024 }
98
+ let(:new) { "2G" }
99
+ let(:app) { FactoryGirl.build(:app, :memory => old) }
100
+ let(:inputs) { { :memory => new } }
101
+
102
+ it 'updates the app memory, converting to megabytes' do
103
+ stub(push).line(anything)
104
+ mock(app).update!
105
+ expect { subject }.to change { app.memory }.from(old).to(2048)
106
+ end
107
+
108
+ it 'outputs the changed memory in human readable sizes' do
109
+ mock(push).line("Changes:")
110
+ mock(push).line("memory: 1G -> 2G")
111
+ stub(app).update!
112
+ subject
113
+ end
114
+
115
+ include_examples 'common tests for inputs', :memory
116
+ end
117
+
118
+ context 'when instances is given' do
119
+ let(:old) { 1 }
120
+ let(:new) { 2 }
121
+ let(:app) { FactoryGirl.build(:app, :total_instances => old) }
122
+ let(:inputs) { { :instances => new } }
123
+
124
+ it 'updates the app instances' do
125
+ stub(push).line(anything)
126
+ mock(app).update!
127
+ expect { subject }.to change { app.total_instances }.from(old).to(new)
128
+ end
129
+
130
+ it 'outputs the changed instances' do
131
+ mock(push).line("Changes:")
132
+ mock(push).line("instances: 1 -> 2")
133
+ stub(app).update!
134
+ subject
135
+ end
136
+
137
+ include_examples 'common tests for inputs', :total_instances, :instances
138
+ end
139
+
140
+ context 'when framework is given' do
141
+ let(:old) { FactoryGirl.build(:framework, :name => "Old Framework") }
142
+ let(:new) { FactoryGirl.build(:framework, :name => "New Framework") }
143
+ let(:app) { FactoryGirl.build(:app, :framework => old) }
144
+ let(:inputs) { { :framework => new } }
145
+
146
+ it 'updates the app framework' do
147
+ stub(push).line(anything)
148
+ mock(app).update!
149
+ expect { subject }.to change { app.framework }.from(old).to(new)
150
+ end
151
+
152
+ it 'outputs the changed framework using the name' do
153
+ mock(push).line("Changes:")
154
+ mock(push).line("framework: Old Framework -> New Framework")
155
+ stub(app).update!
156
+ subject
157
+ end
158
+
159
+ include_examples 'common tests for inputs', :framework
160
+ end
161
+
162
+ context 'when runtime is given' do
163
+ let(:old) { FactoryGirl.build(:runtime, :name => "Old Runtime") }
164
+ let(:new) { FactoryGirl.build(:runtime, :name => "New Runtime") }
165
+ let(:app) { FactoryGirl.build(:app, :runtime => old) }
166
+ let(:inputs) { { :runtime => new } }
167
+
168
+ it 'updates the app runtime' do
169
+ stub(push).line(anything)
170
+ mock(app).update!
171
+ expect { subject }.to change { app.runtime }.from(old).to(new)
172
+ end
32
173
 
174
+ it 'outputs the changed runtime using the name' do
175
+ mock(push).line("Changes:")
176
+ mock(push).line("runtime: Old Runtime -> New Runtime")
177
+ stub(app).update!
178
+ subject
179
+ end
180
+
181
+ include_examples 'common tests for inputs', :runtime
182
+ end
183
+
184
+ context 'when command is given' do
185
+ let(:old) { "./start" }
186
+ let(:new) { "./start foo " }
187
+ let(:app) { FactoryGirl.build(:app, :command => old) }
188
+ let(:inputs) { { :command => new } }
189
+
190
+ it 'updates the app command' do
191
+ stub(push).line(anything)
192
+ mock(app).update!
193
+ expect { subject }.to change { app.command }.from("./start").to("./start foo ")
194
+ end
195
+
196
+ it 'outputs the changed command in single quotes' do
197
+ mock(push).line("Changes:")
198
+ mock(push).line("command: './start' -> './start foo '")
199
+ stub(app).update!
200
+ subject
201
+ end
202
+
203
+ include_examples 'common tests for inputs', :command
204
+ end
205
+
206
+ context 'when plan is given' do
207
+ let(:old) { "d100" }
208
+ let(:new) { "p100" }
209
+ let(:inputs) { { :plan => new } }
210
+
211
+ include_examples 'common tests for inputs', :production, :plan
212
+
213
+ %w{p100 P100 P200}.each do |plan|
214
+ context "when the given plan is #{plan}" do
215
+ let(:inputs) { { :plan => plan } }
216
+
217
+ it 'sets production to true' do
218
+ stub(push).line(anything)
219
+ mock(app).update!
220
+ expect { subject }.to change { app.production }.from(false).to(true)
221
+ end
222
+
223
+ it 'outputs the changed plan in single quotes' do
224
+ mock(push).line("Changes:")
225
+ mock(push).line("production: false -> true")
226
+ stub(app).update!
227
+ subject
228
+ end
229
+ end
230
+ end
231
+
232
+ %w{d100 D100 D200 fizzbuzz}.each do |plan|
233
+ context "when the given plan is #{plan}" do
234
+ let(:app) { FactoryGirl.build(:app, :production => true) }
235
+
236
+ let(:inputs) { { :plan => plan } }
237
+
238
+ it 'sets production to false' do
239
+ stub(push).line(anything)
240
+ mock(app).update!
241
+ expect { subject }.to change { app.production }.from(true).to(false)
242
+ end
243
+
244
+ it 'outputs the changed plan in single quotes' do
245
+ mock(push).line("Changes:")
246
+ mock(push).line("production: true -> false")
247
+ stub(app).update!
248
+ subject
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ context 'when restart is given' do
255
+ let(:inputs) { { :restart => true, :memory => 4096 } }
256
+
257
+
258
+ context 'when the app is already started' do
259
+ let(:app) { FactoryGirl.build(:app, :state => "STARTED") }
260
+
261
+ it 'invokes the restart command' do
262
+ stub(push).line
263
+ mock(app).update!
264
+ mock(push).invoke(:restart, :app => app)
265
+ subject
266
+ end
267
+
268
+ context 'but there are no changes' do
269
+ let(:inputs) { { :restart => true} }
270
+
271
+ it 'does not restart' do
272
+ stub(push).line
273
+ dont_allow(app).update!
274
+ dont_allow(push).invoke
275
+ subject
276
+ end
277
+ end
278
+ end
279
+
280
+ context 'when the app is not already started' do
281
+ let(:app) { FactoryGirl.build(:app, :state => "STOPPED") }
282
+
283
+ it 'does not invoke the restart command' do
284
+ stub(push).line
285
+ mock(app).update!
286
+ dont_allow(push).invoke(:restart, :app => app)
287
+ subject
288
+ end
289
+ end
290
+ end
291
+ end
292
+
293
+ describe '#setup_new_app (integration spec!!)' do
294
+ let(:app) { FactoryGirl.build(:app, :guid => nil) }
295
+ let(:framework) { FactoryGirl.build(:framework) }
296
+ let(:runtime) { FactoryGirl.build(:runtime) }
297
+ let(:url) { "https://www.foobar.com" }
298
+ let(:inputs) do
299
+ { :name => "some-app",
300
+ :instances => 2,
301
+ :framework => framework,
302
+ :runtime => runtime,
303
+ :memory => 1024,
304
+ :url => url
305
+ }
306
+ end
307
+ let(:global) { {:quiet => true, :color => false, :force => true} }
308
+
309
+ before do
310
+ stub(client).app { app }
311
+ end
312
+
313
+ subject do
314
+ push.input = Mothership::Inputs.new(Mothership.commands[:push], push, inputs, global, global)
315
+ push.setup_new_app(path)
316
+ end
317
+
318
+ it 'creates the app' do
319
+ mock(app).create!
320
+ mock(app).upload(path)
321
+ mock(push).filter(:create_app, app) { app }
322
+ mock(push).filter(:push_app, app) { app }
323
+ mock(push).invoke :map, :app => app, :url => url
324
+ mock(push).invoke :start, :app => app
325
+ subject
326
+ end
33
327
  end
34
- end
328
+ end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require "vmc/cli/app/rename"
3
3
 
4
4
  describe VMC::App::Rename do
5
- let(:global_inputs) { { :color => false, :quiet => true } }
5
+ let(:global) { { :color => false, :quiet => true } }
6
6
  let(:inputs) { {} }
7
7
  let(:given) { {} }
8
8
  let(:client) { FactoryGirl.build(:client) }
@@ -16,7 +16,7 @@ describe VMC::App::Rename do
16
16
  end
17
17
  end
18
18
 
19
- subject { Mothership.new.invoke(:rename, inputs, given, global_inputs) }
19
+ subject { Mothership.new.invoke(:rename, inputs, given, global) }
20
20
 
21
21
  describe 'metadata' do
22
22
  let(:command) { Mothership.commands[:rename] }
@@ -29,8 +29,13 @@ describe VMC::App::Rename do
29
29
 
30
30
  describe 'inputs' do
31
31
  subject { command.inputs }
32
- it { expect(subject[:app][:description]).to eq "Application to rename" }
33
- it { expect(subject[:name][:description]).to eq "New application name" }
32
+
33
+ it "is not missing any descriptions" do
34
+ subject.each do |input, attrs|
35
+ expect(attrs[:description]).to be
36
+ expect(attrs[:description].strip).to_not be_empty
37
+ end
38
+ end
34
39
  end
35
40
 
36
41
  describe 'arguments' do
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+ require "vmc/cli/organization/rename"
3
+
4
+ describe VMC::Organization::Rename do
5
+ let(:global) { { :color => false, :quiet => true } }
6
+ let(:inputs) { {} }
7
+ let(:given) { {} }
8
+ let(:organizations) { FactoryGirl.build_list(:organization, 3) }
9
+ let(:client) { FactoryGirl.build(:client, :organizations => organizations) }
10
+ let(:new_name) { "some-new-name" }
11
+
12
+ before do
13
+ any_instance_of(VMC::CLI) do |cli|
14
+ stub(cli).client { client }
15
+ stub(cli).precondition { nil }
16
+ end
17
+ end
18
+
19
+ subject { Mothership.new.invoke(:rename_org, inputs, given, global) }
20
+
21
+ describe 'metadata' do
22
+ let(:command) { Mothership.commands[:rename_org] }
23
+
24
+ describe 'command' do
25
+ subject { command }
26
+ its(:description) { should eq "Rename an organization" }
27
+ it { expect(Mothership::Help.group(:organizations)).to include(subject) }
28
+ end
29
+
30
+ describe 'inputs' do
31
+ subject { command.inputs }
32
+
33
+ it "is not missing any descriptions" do
34
+ subject.each do |input, attrs|
35
+ expect(attrs[:description]).to be
36
+ expect(attrs[:description].strip).to_not be_empty
37
+ end
38
+ end
39
+ end
40
+
41
+ describe 'arguments' do
42
+ subject { command.arguments }
43
+ it 'has the correct argument order' do
44
+ should eq([
45
+ { :type => :optional, :value => nil, :name => :organization },
46
+ { :type => :optional, :value => nil, :name => :name }
47
+ ])
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'when there are no organizations' do
53
+ let(:organizations) { [] }
54
+
55
+ context 'and an organization is given' do
56
+ let(:given) { { :organization => "some-invalid-organization" } }
57
+ it { expect { subject }.to raise_error(VMC::UserError, "Unknown organization 'some-invalid-organization'.") }
58
+ end
59
+
60
+ context 'and an organization is not given' do
61
+ it { expect { subject }.to raise_error(VMC::UserError, "No organizations.") }
62
+ end
63
+ end
64
+
65
+ context 'when there are organizations' do
66
+ let(:renamed_organization) { organizations.first }
67
+
68
+ context 'when the defaults are used' do
69
+ it 'asks for the organization and new name and renames' do
70
+ mock_ask("Rename which organization?", anything) { renamed_organization }
71
+ mock_ask("New name") { new_name }
72
+ mock(renamed_organization).name=(new_name)
73
+ mock(renamed_organization).update!
74
+ subject
75
+ end
76
+ end
77
+
78
+ context 'when no name is provided, but an organization is' do
79
+ let(:given) { { :organization => renamed_organization.name } }
80
+
81
+ it 'asks for the new name and renames' do
82
+ dont_allow_ask("Rename which organization?", anything)
83
+ mock_ask("New name") { new_name }
84
+ mock(renamed_organization).name=(new_name)
85
+ mock(renamed_organization).update!
86
+ subject
87
+ end
88
+ end
89
+
90
+ context 'when an organization is provided and a name' do
91
+ let(:inputs) { { :organization => renamed_organization, :name => new_name } }
92
+
93
+ it 'renames the organization' do
94
+ mock(renamed_organization).update!
95
+ subject
96
+ end
97
+
98
+ it 'displays the progress' do
99
+ mock_with_progress("Renaming to #{new_name}")
100
+ mock(renamed_organization).update!
101
+
102
+ subject
103
+ end
104
+
105
+ context 'and the name already exists' do
106
+ it 'fails' do
107
+ mock(renamed_organization).update! { raise CFoundry::OrganizationNameTaken }
108
+ expect { subject }.to raise_error(CFoundry::OrganizationNameTaken)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end