shelly 0.0.49 → 0.0.50.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/shelly/app.rb +32 -7
- data/lib/shelly/cli/main.rb +15 -9
- data/lib/shelly/cli/runner.rb +5 -0
- data/lib/shelly/cli/user.rb +5 -1
- data/lib/shelly/client.rb +2 -2
- data/lib/shelly/version.rb +1 -1
- data/shelly.gemspec +1 -1
- data/spec/shelly/app_spec.rb +29 -9
- data/spec/shelly/cli/main_spec.rb +51 -16
- data/spec/shelly/cli/runner_spec.rb +33 -0
- data/spec/shelly/cli/user_spec.rb +18 -7
- data/spec/shelly/client_spec.rb +7 -5
- metadata +150 -164
data/Rakefile
CHANGED
data/lib/shelly/app.rb
CHANGED
@@ -13,12 +13,16 @@ module Shelly
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def add_git_remote
|
16
|
-
system("git remote rm
|
17
|
-
system("git remote add
|
16
|
+
system("git remote rm #{code_name} > /dev/null 2>&1")
|
17
|
+
system("git remote add #{code_name} #{git_url}")
|
18
|
+
end
|
19
|
+
|
20
|
+
def git_remote_exist?
|
21
|
+
IO.popen("git remote").read.include?(code_name)
|
18
22
|
end
|
19
23
|
|
20
24
|
def remove_git_remote
|
21
|
-
system("git remote rm
|
25
|
+
system("git remote rm #{code_name} > /dev/null 2>&1")
|
22
26
|
end
|
23
27
|
|
24
28
|
def generate_cloudfile
|
@@ -33,7 +37,7 @@ module Shelly
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def create
|
36
|
-
attributes = {:
|
40
|
+
attributes = {:code_name => code_name, :domains => domains}
|
37
41
|
response = shelly.create_app(attributes)
|
38
42
|
self.git_url = response["git_url"]
|
39
43
|
self.domains = response["domains"]
|
@@ -102,11 +106,32 @@ module Shelly
|
|
102
106
|
end
|
103
107
|
|
104
108
|
def self.guess_code_name
|
105
|
-
|
109
|
+
guessed = nil
|
110
|
+
if Cloudfile.present?
|
111
|
+
clouds = Cloudfile.new.clouds
|
112
|
+
if clouds.grep(/staging/)
|
113
|
+
guessed = "production"
|
114
|
+
production_clouds = clouds.grep(/production/)
|
115
|
+
production_clouds.sort.each do |cloud|
|
116
|
+
cloud =~ /production(\d*)/
|
117
|
+
guessed = "production#{$1.to_i+1}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
"#{File.basename(Dir.pwd)}-#{guessed || 'staging'}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def collaborations
|
125
|
+
@collaborations ||= Array(shelly.collaborations(code_name)).
|
126
|
+
sort_by { |c| c["email"] }
|
127
|
+
end
|
128
|
+
|
129
|
+
def active_collaborations
|
130
|
+
collaborations.select { |c| c["active"] }
|
106
131
|
end
|
107
132
|
|
108
|
-
def
|
109
|
-
|
133
|
+
def inactive_collaborations
|
134
|
+
collaborations.select { |c| !c["active"] }
|
110
135
|
end
|
111
136
|
|
112
137
|
def configs
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -16,7 +16,7 @@ module Shelly
|
|
16
16
|
check_unknown_options!(:except => :rake)
|
17
17
|
|
18
18
|
# FIXME: it should be possible to pass single symbol, instead of one element array
|
19
|
-
before_hook :logged_in?, :only => [:add, :list, :start, :stop, :logs, :delete, :ip, :logout, :execute, :rake]
|
19
|
+
before_hook :logged_in?, :only => [:add, :status, :list, :start, :stop, :logs, :delete, :ip, :logout, :execute, :rake]
|
20
20
|
before_hook :inside_git_repository?, :only => [:add]
|
21
21
|
before_hook :cloudfile_present?, :only => [:logs, :stop, :start, :ip, :execute, :rake]
|
22
22
|
|
@@ -85,8 +85,14 @@ module Shelly
|
|
85
85
|
@app.domains = options["domains"] || ["#{@app.code_name}.shellyapp.com"]
|
86
86
|
@app.create
|
87
87
|
|
88
|
-
|
89
|
-
@app
|
88
|
+
git_remote = @app.git_remote_exist?
|
89
|
+
if !git_remote or (git_remote and yes?("Git remote #{@app} exists, overwrite (yes/no): "))
|
90
|
+
say "Adding remote #{@app} #{@app.git_url}", :green
|
91
|
+
@app.add_git_remote
|
92
|
+
else
|
93
|
+
say "You have to manually add git remote:"
|
94
|
+
say "`git remote add NAME #{@app.git_url}`"
|
95
|
+
end
|
90
96
|
|
91
97
|
say "Creating Cloudfile", :green
|
92
98
|
@app.create_cloudfile
|
@@ -100,7 +106,7 @@ module Shelly
|
|
100
106
|
end
|
101
107
|
|
102
108
|
info_adding_cloudfile_to_repository
|
103
|
-
info_deploying_to_shellycloud
|
109
|
+
info_deploying_to_shellycloud(@app)
|
104
110
|
|
105
111
|
rescue Client::ValidationException => e
|
106
112
|
e.each_error { |error| say_error error, :with_exit => false }
|
@@ -344,8 +350,8 @@ module Shelly
|
|
344
350
|
end
|
345
351
|
|
346
352
|
def ask_for_code_name
|
347
|
-
default_code_name =
|
348
|
-
code_name = ask("Cloud code name (#{
|
353
|
+
default_code_name = Shelly::App.guess_code_name
|
354
|
+
code_name = ask("Cloud code name (#{Shelly::App.guess_code_name} - default):")
|
349
355
|
code_name.blank? ? default_code_name : code_name
|
350
356
|
end
|
351
357
|
|
@@ -369,15 +375,15 @@ module Shelly
|
|
369
375
|
say " git status"
|
370
376
|
end
|
371
377
|
|
372
|
-
def info_deploying_to_shellycloud
|
378
|
+
def info_deploying_to_shellycloud(remote)
|
373
379
|
say_new_line
|
374
380
|
say "When you make sure all settings are correct please issue following commands:", :green
|
375
381
|
say " git add ."
|
376
382
|
say ' git commit -m "Application added to Shelly Cloud"'
|
377
383
|
say " git push"
|
378
384
|
say_new_line
|
379
|
-
say "Deploy to
|
380
|
-
say " git push
|
385
|
+
say "Deploy to your cloud using:", :green
|
386
|
+
say " git push #{remote} master"
|
381
387
|
say_new_line
|
382
388
|
end
|
383
389
|
end
|
data/lib/shelly/cli/runner.rb
CHANGED
@@ -18,11 +18,16 @@ module Shelly
|
|
18
18
|
def start
|
19
19
|
Shelly::CLI::Main.start(args)
|
20
20
|
rescue SystemExit; raise
|
21
|
+
rescue Client::UnauthorizedException
|
22
|
+
raise if debug?
|
23
|
+
say_error "You are not logged in. To log in use: `shelly login`"
|
21
24
|
rescue Client::GemVersionException => e
|
25
|
+
raise if debug?
|
22
26
|
say "Required shelly gem version: #{e.body["required_version"]}"
|
23
27
|
say "Your version: #{VERSION}"
|
24
28
|
say_error "Update shelly gem with `gem install shelly`"
|
25
29
|
rescue Interrupt
|
30
|
+
raise if debug?
|
26
31
|
say_new_line
|
27
32
|
say_error "[canceled]"
|
28
33
|
rescue Exception
|
data/lib/shelly/cli/user.rb
CHANGED
@@ -16,7 +16,9 @@ module Shelly
|
|
16
16
|
begin
|
17
17
|
@app = App.new(cloud)
|
18
18
|
say "Cloud #{cloud}:"
|
19
|
-
@app.
|
19
|
+
@app.active_collaborations.each { |c| say " #{c["email"]}" }
|
20
|
+
@app.inactive_collaborations.each { |c|
|
21
|
+
say " #{c["email"]} (invited)" }
|
20
22
|
rescue Client::NotFoundException => e
|
21
23
|
raise unless e.resource == :cloud
|
22
24
|
say_error "You have no access to '#{cloud}' cloud defined in Cloudfile"
|
@@ -56,6 +58,8 @@ module Shelly
|
|
56
58
|
begin
|
57
59
|
@user.delete_collaboration(cloud, user_email)
|
58
60
|
say "User #{user_email} deleted from cloud #{cloud}"
|
61
|
+
rescue Client::ConflictException => e
|
62
|
+
say_error e[:message]
|
59
63
|
rescue Client::NotFoundException => e
|
60
64
|
case e.resource
|
61
65
|
when :cloud
|
data/lib/shelly/client.rb
CHANGED
@@ -152,8 +152,8 @@ module Shelly
|
|
152
152
|
post("/apps/#{code_name}/database_backups", :kind => kind)
|
153
153
|
end
|
154
154
|
|
155
|
-
def
|
156
|
-
get("/apps/#{cloud}/
|
155
|
+
def collaborations(cloud)
|
156
|
+
get("/apps/#{cloud}/collaborations")
|
157
157
|
end
|
158
158
|
|
159
159
|
def redeploy(cloud)
|
data/lib/shelly/version.rb
CHANGED
data/shelly.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = %q{Tool for managing applications and clouds at shellycloud.com}
|
13
13
|
|
14
14
|
s.rubyforge_project = "shelly"
|
15
|
-
s.add_development_dependency "rspec"
|
15
|
+
s.add_development_dependency "rspec", "~> 2.8.0"
|
16
16
|
s.add_development_dependency "rake"
|
17
17
|
s.add_development_dependency "guard"
|
18
18
|
s.add_development_dependency "guard-rspec"
|
data/spec/shelly/app_spec.rb
CHANGED
@@ -12,15 +12,29 @@ describe Shelly::App do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
describe ".guess_code_name" do
|
15
|
-
|
16
|
-
|
15
|
+
context "no Cloudfile" do
|
16
|
+
it "should return name of current working directory" do
|
17
|
+
Shelly::App.guess_code_name.should == "foo-staging"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with Cloudfile" do
|
22
|
+
it "should return production" do
|
23
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
|
24
|
+
Shelly::App.guess_code_name.should == "foo-production"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return productionNUMBER" do
|
28
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
29
|
+
Shelly::App.guess_code_name.should == "foo-production1"
|
30
|
+
end
|
17
31
|
end
|
18
32
|
end
|
19
33
|
|
20
|
-
describe "#
|
34
|
+
describe "#collaborations" do
|
21
35
|
it "should fetch app's users" do
|
22
|
-
@client.should_receive(:
|
23
|
-
@app.
|
36
|
+
@client.should_receive(:collaborations).with("foo-staging")
|
37
|
+
@app.collaborations
|
24
38
|
end
|
25
39
|
end
|
26
40
|
|
@@ -31,16 +45,24 @@ describe Shelly::App do
|
|
31
45
|
end
|
32
46
|
|
33
47
|
it "should try to remove existing git remote" do
|
34
|
-
@app.should_receive(:system).with("git remote rm
|
48
|
+
@app.should_receive(:system).with("git remote rm foo-staging > /dev/null 2>&1")
|
35
49
|
@app.add_git_remote
|
36
50
|
end
|
37
51
|
|
38
52
|
it "should add git remote with proper name and git repository" do
|
39
|
-
@app.should_receive(:system).with("git remote add
|
53
|
+
@app.should_receive(:system).with("git remote add foo-staging git@git.shellycloud.com:foo-staging.git")
|
40
54
|
@app.add_git_remote
|
41
55
|
end
|
42
56
|
end
|
43
57
|
|
58
|
+
describe "git_remote_exist" do
|
59
|
+
it "should return true if git remote exist" do
|
60
|
+
io = mock(:read => "origin\nfoo-staging")
|
61
|
+
IO.should_receive(:popen).with("git remote").and_return(io)
|
62
|
+
@app.git_remote_exist?.should be_true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
44
66
|
describe "#configs" do
|
45
67
|
it "should get configs from client" do
|
46
68
|
@client.should_receive(:app_configs).with("foo-staging").and_return(config_response)
|
@@ -229,7 +251,6 @@ config
|
|
229
251
|
@app.code_name = "fooo"
|
230
252
|
attributes = {
|
231
253
|
:code_name => "fooo",
|
232
|
-
:name => "fooo",
|
233
254
|
:domains => nil
|
234
255
|
}
|
235
256
|
@client.should_receive(:create_app).with(attributes).and_return("git_url" => "git@git.shellycloud.com:fooo.git",
|
@@ -254,7 +275,6 @@ config
|
|
254
275
|
@app.domains = ["boo.shellyapp.com", "boo.example.com"]
|
255
276
|
attributes = {
|
256
277
|
:code_name => "boo",
|
257
|
-
:name => "boo",
|
258
278
|
:domains => %w(boo.shellyapp.com boo.example.com)
|
259
279
|
}
|
260
280
|
@client.should_receive(:create_app).with(attributes).and_return("git_url" => "git@git.shellycloud.com:fooo.git",
|
@@ -274,6 +274,7 @@ OUT
|
|
274
274
|
Shelly::App.stub(:new).and_return(@app)
|
275
275
|
@client.stub(:token).and_return("abc")
|
276
276
|
@app.stub(:attributes).and_return({"trial" => false})
|
277
|
+
@app.stub(:git_remote_exist?).and_return(false)
|
277
278
|
end
|
278
279
|
|
279
280
|
# This spec tests inside_git_repository? hook
|
@@ -328,7 +329,7 @@ OUT
|
|
328
329
|
end
|
329
330
|
|
330
331
|
it "should use code name provided by user" do
|
331
|
-
$stdout.should_receive(:print).with("Cloud code name (foo-
|
332
|
+
$stdout.should_receive(:print).with("Cloud code name (foo-staging - default): ")
|
332
333
|
@app.should_receive(:code_name=).with("mycodename")
|
333
334
|
fake_stdin(["mycodename", ""]) do
|
334
335
|
invoke(@main, :add)
|
@@ -337,8 +338,8 @@ OUT
|
|
337
338
|
|
338
339
|
context "when user provided empty code name" do
|
339
340
|
it "should use 'current_dirname-purpose' as default" do
|
340
|
-
$stdout.should_receive(:print).with("Cloud code name (foo-
|
341
|
-
@app.should_receive(:code_name=).with("foo-
|
341
|
+
$stdout.should_receive(:print).with("Cloud code name (foo-staging - default): ")
|
342
|
+
@app.should_receive(:code_name=).with("foo-staging")
|
342
343
|
fake_stdin(["", ""]) do
|
343
344
|
invoke(@main, :add)
|
344
345
|
end
|
@@ -393,7 +394,7 @@ OUT
|
|
393
394
|
$stdout.should_receive(:puts).with(green "Billing information")
|
394
395
|
$stdout.should_receive(:puts).with("Cloud created with 20 Euro credit.")
|
395
396
|
$stdout.should_receive(:puts).with("Remember to provide billing details before trial ends.")
|
396
|
-
$stdout.should_receive(:puts).with("http://example.com/apps/foo-
|
397
|
+
$stdout.should_receive(:puts).with("http://example.com/apps/foo-staging/billing/edit")
|
397
398
|
|
398
399
|
fake_stdin(["", ""]) do
|
399
400
|
invoke(@main, :add)
|
@@ -415,7 +416,7 @@ OUT
|
|
415
416
|
@app.should_receive(:create).and_raise(exception)
|
416
417
|
$stdout.should_receive(:puts).with("\e[31mCode name has been already taken\e[0m")
|
417
418
|
$stdout.should_receive(:puts).with("\e[31mFix erros in the below command and type it again to create your cloud\e[0m")
|
418
|
-
$stdout.should_receive(:puts).with("\e[31mshelly add --code-name=foo-
|
419
|
+
$stdout.should_receive(:puts).with("\e[31mshelly add --code-name=foo-staging --databases=postgresql --domains=foo-staging.shellyapp.com\e[0m")
|
419
420
|
lambda {
|
420
421
|
fake_stdin(["", ""]) do
|
421
422
|
invoke(@main, :add)
|
@@ -436,11 +437,39 @@ OUT
|
|
436
437
|
}.should raise_error(SystemExit)
|
437
438
|
end
|
438
439
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
440
|
+
context "git remote" do
|
441
|
+
it "should add one if it doesn't exist" do
|
442
|
+
$stdout.should_receive(:puts).with("\e[32mAdding remote foooo git@git.shellycloud.com:foooo.git\e[0m")
|
443
|
+
@app.should_receive(:add_git_remote)
|
444
|
+
fake_stdin(["foooo", ""]) do
|
445
|
+
invoke(@main, :add)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
context "does exist" do
|
450
|
+
before do
|
451
|
+
@app.stub(:git_remote_exist?).and_return(true)
|
452
|
+
end
|
453
|
+
|
454
|
+
it "should ask if one exist and overwrite" do
|
455
|
+
$stdout.should_receive(:print).with("Git remote foooo exists, overwrite (yes/no): ")
|
456
|
+
$stdout.should_receive(:puts).with(green "Adding remote foooo git@git.shellycloud.com:foooo.git")
|
457
|
+
@app.should_receive(:add_git_remote)
|
458
|
+
fake_stdin(["foooo", "", "yes"]) do
|
459
|
+
invoke(@main, :add)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should ask if one exist and not overwrite" do
|
464
|
+
$stdout.should_receive(:print).with("Git remote foooo exists, overwrite (yes/no): ")
|
465
|
+
$stdout.should_receive(:puts).with("You have to manually add git remote:")
|
466
|
+
$stdout.should_receive(:puts).with("`git remote add NAME git@git.shellycloud.com:foooo.git`")
|
467
|
+
@app.should_not_receive(:add_git_remote)
|
468
|
+
fake_stdin(["foooo", "", "no"]) do
|
469
|
+
invoke(@main, :add)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
444
473
|
end
|
445
474
|
end
|
446
475
|
|
@@ -466,8 +495,8 @@ OUT
|
|
466
495
|
$stdout.should_receive(:puts).with(" git add .")
|
467
496
|
$stdout.should_receive(:puts).with(' git commit -m "Application added to Shelly Cloud"')
|
468
497
|
$stdout.should_receive(:puts).with(" git push")
|
469
|
-
$stdout.should_receive(:puts).with("\e[32mDeploy to
|
470
|
-
$stdout.should_receive(:puts).with(" git push
|
498
|
+
$stdout.should_receive(:puts).with("\e[32mDeploy to your cloud using:\e[0m")
|
499
|
+
$stdout.should_receive(:puts).with(" git push foooo master")
|
471
500
|
fake_stdin(["foooo", "none"]) do
|
472
501
|
invoke(@main, :add)
|
473
502
|
end
|
@@ -500,10 +529,16 @@ OUT
|
|
500
529
|
invoke(@main, :list)
|
501
530
|
end
|
502
531
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
532
|
+
context "#status" do
|
533
|
+
it "should ensure user has logged in" do
|
534
|
+
hooks(@main, :status).should include(:logged_in?)
|
535
|
+
end
|
536
|
+
|
537
|
+
it "should have a 'status' alias" do
|
538
|
+
@client.stub(:apps).and_return([])
|
539
|
+
$stdout.should_receive(:puts).with("\e[32mYou have no clouds yet\e[0m")
|
540
|
+
invoke(@main, :status)
|
541
|
+
end
|
507
542
|
end
|
508
543
|
end
|
509
544
|
|
@@ -64,6 +64,18 @@ describe Shelly::CLI::Runner do
|
|
64
64
|
}.should raise_error(SystemExit)
|
65
65
|
end
|
66
66
|
|
67
|
+
it "should rescue unauthorized exception and display message" do
|
68
|
+
@client = mock
|
69
|
+
runner = Shelly::CLI::Runner.new(%w(status))
|
70
|
+
Shelly::Client.stub(:new).and_return(@client)
|
71
|
+
@client.stub(:token).and_return("abc")
|
72
|
+
@client.stub(:apps).and_raise(Shelly::Client::UnauthorizedException.new)
|
73
|
+
$stdout.should_receive(:puts).with("You are not logged in. To log in use: `shelly login`")
|
74
|
+
lambda {
|
75
|
+
runner.start
|
76
|
+
}.should raise_error(SystemExit)
|
77
|
+
end
|
78
|
+
|
67
79
|
context "with --debug option (debug mode)" do
|
68
80
|
it "should re-raise caught exception to the console" do
|
69
81
|
Shelly::CLI::Main.stub(:start).and_raise(RuntimeError.new)
|
@@ -71,6 +83,27 @@ describe Shelly::CLI::Runner do
|
|
71
83
|
@runner.start
|
72
84
|
}.should raise_error(RuntimeError)
|
73
85
|
end
|
86
|
+
|
87
|
+
it "should re-raise unauthorized exception" do
|
88
|
+
Shelly::CLI::Main.stub(:start).and_raise(Shelly::Client::UnauthorizedException.new)
|
89
|
+
lambda {
|
90
|
+
@runner.start
|
91
|
+
}.should raise_error(Shelly::Client::UnauthorizedException)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should re-raise gem version exception" do
|
95
|
+
Shelly::CLI::Main.stub(:start).and_raise(Shelly::Client::GemVersionException.new)
|
96
|
+
lambda {
|
97
|
+
@runner.start
|
98
|
+
}.should raise_error(Shelly::Client::GemVersionException)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should re-raise interupt exception" do
|
102
|
+
Shelly::CLI::Main.stub(:start).and_raise(Interrupt.new)
|
103
|
+
lambda {
|
104
|
+
@runner.start
|
105
|
+
}.should raise_error(Interrupt)
|
106
|
+
end
|
74
107
|
end
|
75
108
|
|
76
109
|
context "without --debug option (normal mode)" do
|
@@ -27,6 +27,10 @@ describe Shelly::CLI::User do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
describe "#list" do
|
30
|
+
let(:response) {
|
31
|
+
[{'email' => 'user@example.com', 'active' => true},
|
32
|
+
{'email' => 'auser2@example2.com', 'active' => false}]
|
33
|
+
}
|
30
34
|
before do
|
31
35
|
@cloudfile = Shelly::Cloudfile.new
|
32
36
|
Shelly::Cloudfile.stub(:new).and_return(@cloudfile)
|
@@ -42,27 +46,24 @@ describe Shelly::CLI::User do
|
|
42
46
|
|
43
47
|
context "on success" do
|
44
48
|
it "should receive clouds from the Cloudfile" do
|
45
|
-
@client.stub(:
|
49
|
+
@client.stub(:collaborations).and_return(response)
|
46
50
|
@cloudfile.should_receive(:clouds).and_return(["foo-staging", "foo-production"])
|
47
51
|
invoke(@cli_user, :list)
|
48
52
|
end
|
49
53
|
|
50
54
|
it "should display clouds and users" do
|
51
|
-
@client.stub(:
|
55
|
+
@client.stub(:collaborations).and_return(response)
|
52
56
|
$stdout.should_receive(:puts).with("Cloud foo-production:")
|
53
57
|
$stdout.should_receive(:puts).with(" user@example.com")
|
58
|
+
$stdout.should_receive(:puts).with(" auser2@example2.com (invited)")
|
54
59
|
invoke(@cli_user, :list)
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
58
|
-
def response
|
59
|
-
[{'email' => 'user@example.com'}]
|
60
|
-
end
|
61
|
-
|
62
63
|
context "on failure" do
|
63
64
|
it "should exit with 1 if user does not have access to cloud" do
|
64
65
|
exception = Shelly::Client::NotFoundException.new("resource" => "cloud")
|
65
|
-
@client.stub(:
|
66
|
+
@client.stub(:collaborations).and_raise(exception)
|
66
67
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
67
68
|
lambda { invoke(@cli_user, :list) }.should raise_error(SystemExit)
|
68
69
|
end
|
@@ -175,6 +176,16 @@ describe Shelly::CLI::User do
|
|
175
176
|
invoke(@cli_user, :delete, "megan@example.com")
|
176
177
|
}.should raise_error(SystemExit)
|
177
178
|
end
|
179
|
+
|
180
|
+
it "should show that user can't delete own collaboration" do
|
181
|
+
exception = Shelly::Client::ConflictException.new("message" =>
|
182
|
+
"Can't remove own collaboration")
|
183
|
+
@client.stub(:delete_collaboration).and_raise(exception)
|
184
|
+
$stdout.should_receive(:puts).with(red "Can't remove own collaboration")
|
185
|
+
lambda {
|
186
|
+
invoke(@cli_user, :delete, "megan@example.com")
|
187
|
+
}.should raise_error(SystemExit)
|
188
|
+
end
|
178
189
|
end
|
179
190
|
end
|
180
191
|
end
|
data/spec/shelly/client_spec.rb
CHANGED
@@ -170,12 +170,14 @@ describe Shelly::Client do
|
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
|
-
describe "#
|
173
|
+
describe "#collaborations" do
|
174
174
|
it "should send get request with app code_names" do
|
175
|
-
FakeWeb.register_uri(:get, api_url("apps/staging-foo/
|
176
|
-
{:email => "
|
177
|
-
|
178
|
-
response
|
175
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/collaborations"),
|
176
|
+
:body => [{:email => "test@example.com", :active => true},
|
177
|
+
{:email => "test2@example.com", :active => false}].to_json)
|
178
|
+
response = @client.collaborations("staging-foo")
|
179
|
+
response.should == [{"email" => "test@example.com", 'active' => true},
|
180
|
+
{"email" => "test2@example.com", 'active' => false}]
|
179
181
|
end
|
180
182
|
end
|
181
183
|
|
metadata
CHANGED
@@ -1,188 +1,167 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: shelly
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 49
|
10
|
-
version: 0.0.49
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.50.pre
|
5
|
+
prerelease: 7
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Shelly Cloud team
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
21
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
22
|
-
none: false
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
hash: 3
|
27
|
-
segments:
|
28
|
-
- 0
|
29
|
-
version: "0"
|
30
|
-
requirement: *id001
|
31
|
-
prerelease: false
|
32
|
-
type: :development
|
12
|
+
date: 2012-02-28 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
33
15
|
name: rspec
|
34
|
-
|
35
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70352069078820 !ruby/object:Gem::Requirement
|
36
17
|
none: false
|
37
|
-
requirements:
|
38
|
-
- -
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
|
41
|
-
segments:
|
42
|
-
- 0
|
43
|
-
version: "0"
|
44
|
-
requirement: *id002
|
45
|
-
prerelease: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.8.0
|
46
22
|
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70352069078820
|
25
|
+
- !ruby/object:Gem::Dependency
|
47
26
|
name: rake
|
48
|
-
|
49
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
27
|
+
requirement: &70352069078400 !ruby/object:Gem::Requirement
|
50
28
|
none: false
|
51
|
-
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
|
55
|
-
segments:
|
56
|
-
- 0
|
57
|
-
version: "0"
|
58
|
-
requirement: *id003
|
59
|
-
prerelease: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
60
33
|
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70352069078400
|
36
|
+
- !ruby/object:Gem::Dependency
|
61
37
|
name: guard
|
62
|
-
|
63
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
38
|
+
requirement: &70352069077940 !ruby/object:Gem::Requirement
|
64
39
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
segments:
|
70
|
-
- 0
|
71
|
-
version: "0"
|
72
|
-
requirement: *id004
|
73
|
-
prerelease: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
74
44
|
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70352069077940
|
47
|
+
- !ruby/object:Gem::Dependency
|
75
48
|
name: guard-rspec
|
76
|
-
|
77
|
-
version_requirements: &id005 !ruby/object:Gem::Requirement
|
49
|
+
requirement: &70352069077520 !ruby/object:Gem::Requirement
|
78
50
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
version: "0"
|
86
|
-
requirement: *id005
|
87
|
-
prerelease: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
88
55
|
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70352069077520
|
58
|
+
- !ruby/object:Gem::Dependency
|
89
59
|
name: simplecov
|
90
|
-
|
91
|
-
|
60
|
+
requirement: &70352069077100 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70352069077100
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby_gntp
|
71
|
+
requirement: &70352069076580 !ruby/object:Gem::Requirement
|
92
72
|
none: false
|
93
|
-
requirements:
|
94
|
-
- -
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
|
97
|
-
|
98
|
-
- 0
|
99
|
-
version: "0"
|
100
|
-
requirement: *id006
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
101
78
|
prerelease: false
|
79
|
+
version_requirements: *70352069076580
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rb-fsevent
|
82
|
+
requirement: &70352069076120 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
102
88
|
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70352069076120
|
91
|
+
- !ruby/object:Gem::Dependency
|
103
92
|
name: fakefs
|
104
|
-
|
105
|
-
version_requirements: &id007 !ruby/object:Gem::Requirement
|
93
|
+
requirement: &70352069075600 !ruby/object:Gem::Requirement
|
106
94
|
none: false
|
107
|
-
requirements:
|
108
|
-
- -
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
|
111
|
-
segments:
|
112
|
-
- 0
|
113
|
-
version: "0"
|
114
|
-
requirement: *id007
|
115
|
-
prerelease: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
116
99
|
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70352069075600
|
102
|
+
- !ruby/object:Gem::Dependency
|
117
103
|
name: fakeweb
|
118
|
-
|
119
|
-
version_requirements: &id008 !ruby/object:Gem::Requirement
|
104
|
+
requirement: &70352069075060 !ruby/object:Gem::Requirement
|
120
105
|
none: false
|
121
|
-
requirements:
|
122
|
-
- -
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
|
125
|
-
|
126
|
-
- 0
|
127
|
-
- 14
|
128
|
-
- 7
|
129
|
-
version: 0.14.7
|
130
|
-
requirement: *id008
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
131
111
|
prerelease: false
|
132
|
-
|
112
|
+
version_requirements: *70352069075060
|
113
|
+
- !ruby/object:Gem::Dependency
|
133
114
|
name: wijet-thor
|
134
|
-
|
135
|
-
version_requirements: &id009 !ruby/object:Gem::Requirement
|
115
|
+
requirement: &70352069074100 !ruby/object:Gem::Requirement
|
136
116
|
none: false
|
137
|
-
requirements:
|
138
|
-
- -
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
|
141
|
-
segments:
|
142
|
-
- 0
|
143
|
-
version: "0"
|
144
|
-
requirement: *id009
|
145
|
-
prerelease: false
|
117
|
+
requirements:
|
118
|
+
- - ~>
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 0.14.7
|
146
121
|
type: :runtime
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70352069074100
|
124
|
+
- !ruby/object:Gem::Dependency
|
147
125
|
name: rest-client
|
148
|
-
|
149
|
-
version_requirements: &id010 !ruby/object:Gem::Requirement
|
126
|
+
requirement: &70352069073660 !ruby/object:Gem::Requirement
|
150
127
|
none: false
|
151
|
-
requirements:
|
152
|
-
- -
|
153
|
-
- !ruby/object:Gem::Version
|
154
|
-
|
155
|
-
segments:
|
156
|
-
- 0
|
157
|
-
version: "0"
|
158
|
-
requirement: *id010
|
159
|
-
prerelease: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
160
132
|
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *70352069073660
|
135
|
+
- !ruby/object:Gem::Dependency
|
161
136
|
name: json
|
162
|
-
|
163
|
-
version_requirements: &id011 !ruby/object:Gem::Requirement
|
137
|
+
requirement: &70352069073200 !ruby/object:Gem::Requirement
|
164
138
|
none: false
|
165
|
-
requirements:
|
166
|
-
- -
|
167
|
-
- !ruby/object:Gem::Version
|
168
|
-
|
169
|
-
segments:
|
170
|
-
- 0
|
171
|
-
version: "0"
|
172
|
-
requirement: *id011
|
173
|
-
prerelease: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
174
143
|
type: :runtime
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *70352069073200
|
146
|
+
- !ruby/object:Gem::Dependency
|
175
147
|
name: progressbar
|
148
|
+
requirement: &70352069072600 !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
type: :runtime
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: *70352069072600
|
176
157
|
description: Tool for managing applications and clouds at shellycloud.com
|
177
|
-
email:
|
158
|
+
email:
|
178
159
|
- support@shellycloud.com
|
179
|
-
executables:
|
160
|
+
executables:
|
180
161
|
- shelly
|
181
162
|
extensions: []
|
182
|
-
|
183
163
|
extra_rdoc_files: []
|
184
|
-
|
185
|
-
files:
|
164
|
+
files:
|
186
165
|
- .gitignore
|
187
166
|
- .travis.yml
|
188
167
|
- Gemfile
|
@@ -234,36 +213,43 @@ files:
|
|
234
213
|
- spec/thor/options_spec.rb
|
235
214
|
homepage: http://shellycloud.com
|
236
215
|
licenses: []
|
237
|
-
|
238
216
|
post_install_message:
|
239
217
|
rdoc_options: []
|
240
|
-
|
241
|
-
require_paths:
|
218
|
+
require_paths:
|
242
219
|
- lib
|
243
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
220
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
244
221
|
none: false
|
245
|
-
requirements:
|
246
|
-
- -
|
247
|
-
- !ruby/object:Gem::Version
|
248
|
-
|
249
|
-
|
250
|
-
- 0
|
251
|
-
version: "0"
|
252
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
222
|
+
requirements:
|
223
|
+
- - ! '>='
|
224
|
+
- !ruby/object:Gem::Version
|
225
|
+
version: '0'
|
226
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
253
227
|
none: false
|
254
|
-
requirements:
|
255
|
-
- -
|
256
|
-
- !ruby/object:Gem::Version
|
257
|
-
|
258
|
-
segments:
|
259
|
-
- 0
|
260
|
-
version: "0"
|
228
|
+
requirements:
|
229
|
+
- - ! '>'
|
230
|
+
- !ruby/object:Gem::Version
|
231
|
+
version: 1.3.1
|
261
232
|
requirements: []
|
262
|
-
|
263
233
|
rubyforge_project: shelly
|
264
234
|
rubygems_version: 1.8.10
|
265
235
|
signing_key:
|
266
236
|
specification_version: 3
|
267
237
|
summary: Shelly Cloud command line tool
|
268
|
-
test_files:
|
269
|
-
|
238
|
+
test_files:
|
239
|
+
- spec/helpers.rb
|
240
|
+
- spec/input_faker.rb
|
241
|
+
- spec/shelly/app_spec.rb
|
242
|
+
- spec/shelly/backup_spec.rb
|
243
|
+
- spec/shelly/cli/backup_spec.rb
|
244
|
+
- spec/shelly/cli/config_spec.rb
|
245
|
+
- spec/shelly/cli/deploys_spec.rb
|
246
|
+
- spec/shelly/cli/main_spec.rb
|
247
|
+
- spec/shelly/cli/runner_spec.rb
|
248
|
+
- spec/shelly/cli/user_spec.rb
|
249
|
+
- spec/shelly/client_spec.rb
|
250
|
+
- spec/shelly/cloudfile_spec.rb
|
251
|
+
- spec/shelly/download_progress_bar_spec.rb
|
252
|
+
- spec/shelly/model_spec.rb
|
253
|
+
- spec/shelly/user_spec.rb
|
254
|
+
- spec/spec_helper.rb
|
255
|
+
- spec/thor/options_spec.rb
|