shelly 0.0.40 → 0.0.41.pre
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.
- data/lib/shelly/app.rb +18 -7
- data/lib/shelly/cli/backup.rb +8 -6
- data/lib/shelly/cli/config.rb +18 -7
- data/lib/shelly/cli/deploys.rb +11 -8
- data/lib/shelly/cli/main.rb +10 -8
- data/lib/shelly/cli/user.rb +3 -8
- data/lib/shelly/client.rb +23 -21
- data/lib/shelly/version.rb +1 -1
- data/spec/shelly/app_spec.rb +61 -13
- data/spec/shelly/cli/backup_spec.rb +5 -7
- data/spec/shelly/cli/config_spec.rb +82 -2
- data/spec/shelly/cli/deploys_spec.rb +17 -9
- data/spec/shelly/cli/main_spec.rb +22 -42
- data/spec/shelly/cli/user_spec.rb +4 -4
- data/spec/shelly/client_spec.rb +78 -23
- metadata +32 -38
data/lib/shelly/app.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'launchy'
|
3
|
+
require "shelly/backup"
|
3
4
|
|
4
5
|
module Shelly
|
5
6
|
class App < Model
|
6
7
|
DATABASE_KINDS = %w(postgresql mongodb redis none)
|
7
8
|
|
8
9
|
attr_accessor :code_name, :databases, :ruby_version, :environment,
|
9
|
-
:git_url, :domains
|
10
|
-
|
11
|
-
autoload :Backup, "shelly/backup"
|
10
|
+
:git_url, :domains, :web_server_ip, :mail_server_ip
|
12
11
|
|
13
12
|
def initialize(code_name = nil)
|
14
13
|
self.code_name = code_name
|
@@ -99,10 +98,6 @@ module Shelly
|
|
99
98
|
File.basename(Dir.pwd)
|
100
99
|
end
|
101
100
|
|
102
|
-
def ips
|
103
|
-
shelly.app_ips(code_name)
|
104
|
-
end
|
105
|
-
|
106
101
|
def users
|
107
102
|
shelly.app_users(code_name)
|
108
103
|
end
|
@@ -135,6 +130,18 @@ module Shelly
|
|
135
130
|
shelly.app_delete_config(code_name, path)
|
136
131
|
end
|
137
132
|
|
133
|
+
def attributes
|
134
|
+
@attributes ||= shelly.app(code_name)
|
135
|
+
end
|
136
|
+
|
137
|
+
def web_server_ip
|
138
|
+
attributes["web_server_ip"]
|
139
|
+
end
|
140
|
+
|
141
|
+
def mail_server_ip
|
142
|
+
attributes["mail_server_ip"]
|
143
|
+
end
|
144
|
+
|
138
145
|
def open_billing_page
|
139
146
|
url = "#{shelly.shellyapp_url}/login?api_key=#{current_user.token}&return_to=/apps/#{code_name}/edit_billing"
|
140
147
|
Launchy.open(url)
|
@@ -143,5 +150,9 @@ module Shelly
|
|
143
150
|
def self.inside_git_repository?
|
144
151
|
system("git status > /dev/null 2>&1")
|
145
152
|
end
|
153
|
+
|
154
|
+
def to_s
|
155
|
+
code_name
|
156
|
+
end
|
146
157
|
end
|
147
158
|
end
|
data/lib/shelly/cli/backup.rb
CHANGED
@@ -30,10 +30,10 @@ module Shelly
|
|
30
30
|
say "No database backups available"
|
31
31
|
end
|
32
32
|
rescue Client::APIError => e
|
33
|
-
if e.
|
33
|
+
if e.not_found?
|
34
34
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
35
35
|
else
|
36
|
-
|
36
|
+
raise e
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -49,11 +49,13 @@ module Shelly
|
|
49
49
|
say_new_line
|
50
50
|
say "Backup file saved to #{backup.filename}", :green
|
51
51
|
rescue Client::APIError => e
|
52
|
-
|
52
|
+
case e.resource_not_found
|
53
|
+
when :cloud
|
54
|
+
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
55
|
+
when :backup
|
53
56
|
say_error "Backup not found", :with_exit => false
|
54
57
|
say "You can list available backups with 'shelly backup list' command"
|
55
|
-
else
|
56
|
-
raise e
|
58
|
+
else; raise e
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
@@ -66,7 +68,7 @@ module Shelly
|
|
66
68
|
say "Backup requested. It can take up to several minutes for" +
|
67
69
|
"the backup process to finish and the backup to show up in backups list.", :green
|
68
70
|
rescue Client::APIError => e
|
69
|
-
if e.
|
71
|
+
if e.not_found?
|
70
72
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
71
73
|
else
|
72
74
|
say_error e.message
|
data/lib/shelly/cli/config.rb
CHANGED
@@ -34,10 +34,10 @@ module Shelly
|
|
34
34
|
say "Cloud #{cloud} has no configuration files"
|
35
35
|
end
|
36
36
|
rescue Client::APIError => e
|
37
|
-
if e.
|
38
|
-
say_error "You have no access to '#{@app
|
37
|
+
if e.resource_not_found == :cloud
|
38
|
+
say_error "You have no access to '#{@app}' cloud defined in Cloudfile"
|
39
39
|
else
|
40
|
-
|
40
|
+
raise e
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -53,8 +53,13 @@ module Shelly
|
|
53
53
|
say "Content of #{config["path"]}:", :green
|
54
54
|
say config["content"]
|
55
55
|
rescue Client::APIError => e
|
56
|
-
|
56
|
+
case e.resource_not_found
|
57
|
+
when :cloud
|
57
58
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
59
|
+
when :config
|
60
|
+
say_error "Config '#{path}' not found", :with_exit => false
|
61
|
+
say_error "You can list available config files with `shelly config list --cloud #{@app}`"
|
62
|
+
else; raise e
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
@@ -69,7 +74,7 @@ module Shelly
|
|
69
74
|
@app.create_config(path, output)
|
70
75
|
say "File '#{path}' created, it will be used after next code deploy", :green
|
71
76
|
rescue Client::APIError => e
|
72
|
-
if e.
|
77
|
+
if e.resource_not_found == :cloud
|
73
78
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
74
79
|
elsif e.validation?
|
75
80
|
e.each_error { |error| say_error error, :with_exit => false }
|
@@ -91,8 +96,11 @@ module Shelly
|
|
91
96
|
@app.update_config(path, content)
|
92
97
|
say "File '#{config["path"]}' updated, it will be used after next code deploy", :green
|
93
98
|
rescue Client::APIError => e
|
94
|
-
if e.
|
99
|
+
if e.resource_not_found == :cloud
|
95
100
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
101
|
+
elsif e.resource_not_found == :config
|
102
|
+
say_error "Config '#{path}' not found", :with_exit => false
|
103
|
+
say_error "You can list available config files with `shelly config list --cloud #{@app}`"
|
96
104
|
elsif e.validation?
|
97
105
|
e.each_error { |error| say_error error, :with_exit => false }
|
98
106
|
exit 1
|
@@ -115,8 +123,11 @@ module Shelly
|
|
115
123
|
say "File not deleted"
|
116
124
|
end
|
117
125
|
rescue Client::APIError => e
|
118
|
-
if e.
|
126
|
+
if e.resource_not_found == :cloud
|
119
127
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
128
|
+
elsif e.resource_not_found == :config
|
129
|
+
say_error "Config '#{path}' not found", :with_exit => false
|
130
|
+
say_error "You can list available config files with `shelly config list --cloud #{@app}`"
|
120
131
|
elsif e.validation?
|
121
132
|
e.each_error { |error| say_error error, :with_exit => false }
|
122
133
|
exit 1
|
data/lib/shelly/cli/deploys.rb
CHANGED
@@ -25,10 +25,10 @@ module Shelly
|
|
25
25
|
say "No deploy logs available"
|
26
26
|
end
|
27
27
|
rescue Client::APIError => e
|
28
|
-
if e.
|
28
|
+
if e.not_found?
|
29
29
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
30
30
|
else
|
31
|
-
|
31
|
+
raise e
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -56,12 +56,15 @@ module Shelly
|
|
56
56
|
say("Starting thin", :green); say(content["thin_restart"])
|
57
57
|
end
|
58
58
|
rescue Client::APIError => e
|
59
|
-
if e.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
if e.not_found?
|
60
|
+
case e.resource_not_found
|
61
|
+
when :cloud
|
62
|
+
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
63
|
+
when :log
|
64
|
+
say_error "Log not found, list all deploy logs using `shelly deploys list --cloud=#{@app.code_name}`"
|
65
|
+
end
|
66
|
+
else
|
67
|
+
raise e
|
65
68
|
end
|
66
69
|
end
|
67
70
|
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -143,16 +143,16 @@ module Shelly
|
|
143
143
|
|
144
144
|
desc "ip", "Lists clouds IP's"
|
145
145
|
def ip
|
146
|
+
say_error "No Cloudfile found" unless Cloudfile.present?
|
146
147
|
@cloudfile = Cloudfile.new
|
147
148
|
@cloudfile.clouds.each do |cloud|
|
148
149
|
begin
|
149
150
|
@app = App.new(cloud)
|
150
151
|
say "Cloud #{cloud}:", :green
|
151
|
-
|
152
|
-
print_wrapped "
|
153
|
-
print_wrapped "Mail server IP: #{ips['mail_server_ip']}", :ident => 2
|
152
|
+
print_wrapped "Web server IP: #{@app.web_server_ip}", :ident => 2
|
153
|
+
print_wrapped "Mail server IP: #{@app.mail_server_ip}", :ident => 2
|
154
154
|
rescue Client::APIError => e
|
155
|
-
if e.
|
155
|
+
if e.not_found?
|
156
156
|
say_error "You have no access to '#{cloud}' cloud defined in Cloudfile", :with_exit => false
|
157
157
|
else
|
158
158
|
say_error e.message, :with_exit => false
|
@@ -190,7 +190,7 @@ module Shelly
|
|
190
190
|
end
|
191
191
|
exit 1
|
192
192
|
rescue Client::APIError => e
|
193
|
-
if e.
|
193
|
+
if e.not_found?
|
194
194
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
195
195
|
end
|
196
196
|
end
|
@@ -203,7 +203,7 @@ module Shelly
|
|
203
203
|
@app.stop
|
204
204
|
say "Cloud '#{@app.code_name}' stopped"
|
205
205
|
rescue Client::APIError => e
|
206
|
-
if e.
|
206
|
+
if e.not_found?
|
207
207
|
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
208
208
|
end
|
209
209
|
end
|
@@ -230,7 +230,9 @@ module Shelly
|
|
230
230
|
say "Missing git remote"
|
231
231
|
end
|
232
232
|
rescue Client::APIError => e
|
233
|
-
|
233
|
+
if e.not_found?
|
234
|
+
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
235
|
+
end
|
234
236
|
end
|
235
237
|
|
236
238
|
desc "logs", "Show latest application logs from each instance"
|
@@ -247,7 +249,7 @@ module Shelly
|
|
247
249
|
say log
|
248
250
|
end
|
249
251
|
rescue Client::APIError => e
|
250
|
-
if e.
|
252
|
+
if e.not_found?
|
251
253
|
say_error "You have no access to cloud '#{cloud || @app.code_name}'"
|
252
254
|
end
|
253
255
|
end
|
data/lib/shelly/cli/user.rb
CHANGED
@@ -19,7 +19,7 @@ module Shelly
|
|
19
19
|
say "Cloud #{cloud}:"
|
20
20
|
@app.users.each { |user| say " #{user["email"]}" }
|
21
21
|
rescue Client::APIError => e
|
22
|
-
if e.
|
22
|
+
if e.not_found?
|
23
23
|
say_error "You have no access to '#{cloud}' cloud defined in Cloudfile", :with_exit => false
|
24
24
|
else
|
25
25
|
say_error e.message, :with_exit => false
|
@@ -39,7 +39,7 @@ module Shelly
|
|
39
39
|
rescue Client::APIError => e
|
40
40
|
if e.validation? && e.errors.include?(["email", "#{email} has already been taken"])
|
41
41
|
say_error "User #{email} is already in the cloud #{cloud}", :with_exit => false
|
42
|
-
elsif e.
|
42
|
+
elsif e.not_found?
|
43
43
|
say_error "You have no access to '#{cloud}' cloud defined in Cloudfile", :with_exit => false
|
44
44
|
elsif e.validation?
|
45
45
|
e.each_error { |error| say_error error, :with_exit => false }
|
@@ -51,12 +51,7 @@ module Shelly
|
|
51
51
|
say "Sending invitation to #{user_email} to work on #{cloud}", :green
|
52
52
|
end
|
53
53
|
end
|
54
|
-
rescue Client::APIError => e
|
55
|
-
if e.unauthorized?
|
56
|
-
e.errors.each { |error| say_error error, :with_exit => false}
|
57
|
-
exit 1
|
58
|
-
end
|
59
54
|
end
|
60
55
|
end
|
61
56
|
end
|
62
|
-
end
|
57
|
+
end
|
data/lib/shelly/client.rb
CHANGED
@@ -5,42 +5,45 @@ require "cgi"
|
|
5
5
|
module Shelly
|
6
6
|
class Client
|
7
7
|
class APIError < Exception
|
8
|
-
attr_reader :status_code
|
8
|
+
attr_reader :status_code, :body
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@response = JSON.parse(response_body)
|
10
|
+
def initialize(status_code, body = {})
|
12
11
|
@status_code = status_code
|
12
|
+
@body = body
|
13
13
|
end
|
14
14
|
|
15
15
|
def message
|
16
|
-
|
16
|
+
body["message"]
|
17
17
|
end
|
18
18
|
|
19
19
|
def errors
|
20
|
-
|
20
|
+
body["errors"]
|
21
21
|
end
|
22
22
|
|
23
23
|
def url
|
24
|
-
|
24
|
+
body["url"]
|
25
25
|
end
|
26
26
|
|
27
27
|
def validation?
|
28
28
|
message == "Validation Failed"
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def not_found?
|
32
32
|
status_code == 404
|
33
33
|
end
|
34
34
|
|
35
|
+
def resource_not_found
|
36
|
+
return unless not_found?
|
37
|
+
message =~ /Couldn't find (.*) with/ && $1.downcase.to_sym
|
38
|
+
end
|
39
|
+
|
35
40
|
def unauthorized?
|
36
|
-
|
37
|
-
# Return 404 if child of app doesn't exist, should be fixed in API
|
38
|
-
message == "Unauthorized" || message =~ /Cloud .+ not found/
|
41
|
+
status_code == 401
|
39
42
|
end
|
40
43
|
|
41
44
|
def each_error
|
42
|
-
|
43
|
-
yield
|
45
|
+
errors.each do |field, message|
|
46
|
+
yield [field.gsub('_',' ').capitalize, message].join(" ")
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
@@ -115,6 +118,10 @@ module Shelly
|
|
115
118
|
def apps
|
116
119
|
get("/apps")
|
117
120
|
end
|
121
|
+
|
122
|
+
def app(code_name)
|
123
|
+
get("/apps/#{code_name}")
|
124
|
+
end
|
118
125
|
|
119
126
|
def deploy_logs(cloud)
|
120
127
|
get("/apps/#{cloud}/deploys")
|
@@ -148,10 +155,6 @@ module Shelly
|
|
148
155
|
get("/apps/#{cloud}/users")
|
149
156
|
end
|
150
157
|
|
151
|
-
def app_ips(cloud)
|
152
|
-
get("/apps/#{cloud}/ips")
|
153
|
-
end
|
154
|
-
|
155
158
|
def post(path, params = {})
|
156
159
|
request(path, :post, params)
|
157
160
|
end
|
@@ -211,12 +214,11 @@ module Shelly
|
|
211
214
|
end
|
212
215
|
|
213
216
|
def process_response(response)
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
217
|
+
body = JSON.parse(response.body) rescue JSON::ParserError && {}
|
218
|
+
code = response.code
|
219
|
+
raise APIError.new(code, body) if (400..599).include?(code)
|
218
220
|
response.return!
|
219
|
-
|
221
|
+
body
|
220
222
|
end
|
221
223
|
end
|
222
224
|
end
|
data/lib/shelly/version.rb
CHANGED
data/spec/shelly/app_spec.rb
CHANGED
@@ -24,13 +24,6 @@ describe Shelly::App do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
describe "#ips" do
|
28
|
-
it "should get app's ips" do
|
29
|
-
@client.should_receive(:app_ips).with("foo-staging")
|
30
|
-
@app.ips
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
27
|
describe "#add_git_remote" do
|
35
28
|
before do
|
36
29
|
@app.stub(:git_url).and_return("git@git.shellycloud.com:foo-staging.git")
|
@@ -50,18 +43,67 @@ describe Shelly::App do
|
|
50
43
|
|
51
44
|
describe "#configs" do
|
52
45
|
it "should get configs from client" do
|
53
|
-
@client.should_receive(:app_configs).with("foo-staging")
|
54
|
-
@app.configs
|
46
|
+
@client.should_receive(:app_configs).with("foo-staging").and_return(config_response)
|
47
|
+
@app.configs.should == config_response
|
55
48
|
end
|
56
49
|
|
57
50
|
it "should return only user config files" do
|
58
|
-
@client.should_receive(:app_configs).with("foo-staging").and_return(
|
59
|
-
@app.user_configs
|
51
|
+
@client.should_receive(:app_configs).with("foo-staging").and_return(config_response)
|
52
|
+
@app.user_configs.should == [{"path" => "user_created", "created_by_user" => true}]
|
60
53
|
end
|
61
54
|
|
62
55
|
it "should return only shelly genereted config files" do
|
63
|
-
@client.should_receive(:app_configs).with("foo-staging").and_return(
|
64
|
-
@app.shelly_generated_configs
|
56
|
+
@client.should_receive(:app_configs).with("foo-staging").and_return(config_response)
|
57
|
+
@app.shelly_generated_configs.should == [{"path" => "shelly_created", "created_by_user" => false}]
|
58
|
+
end
|
59
|
+
|
60
|
+
def config_response
|
61
|
+
[{"path" => "user_created", "created_by_user" => true},
|
62
|
+
{"path" => "shelly_created", "created_by_user" => false}]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should get config from client" do
|
66
|
+
@client.should_receive(:app_config).with("foo-staging", "path")
|
67
|
+
@app.config("path")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should create config using client" do
|
71
|
+
@client.should_receive(:app_create_config).with("foo-staging", "path", "content")
|
72
|
+
@app.create_config("path", "content")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should update config using client" do
|
76
|
+
@client.should_receive(:app_update_config).with("foo-staging", "path", "content")
|
77
|
+
@app.update_config("path", "content")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should delete config using client" do
|
81
|
+
@client.should_receive(:app_delete_config).with("foo-staging", "path")
|
82
|
+
@app.delete_config("path")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#attributes" do
|
87
|
+
before do
|
88
|
+
@response = {"web_server_ip" => "192.0.2.1", "mail_server_ip" => "192.0.2.3"}
|
89
|
+
@client.stub(:app).and_return(@response)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should fetch app attributes from API and cache them" do
|
93
|
+
@client.should_receive(:app).with("foo-staging").exactly(:once).and_return(@response)
|
94
|
+
2.times { @app.attributes }
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#web_server_ip" do
|
98
|
+
it "should return web server ip address" do
|
99
|
+
@app.web_server_ip.should == "192.0.2.1"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#mail_server_ip" do
|
104
|
+
it "should return mail server ip address" do
|
105
|
+
@app.mail_server_ip.should == "192.0.2.3"
|
106
|
+
end
|
65
107
|
end
|
66
108
|
end
|
67
109
|
|
@@ -238,5 +280,11 @@ config
|
|
238
280
|
end
|
239
281
|
end
|
240
282
|
end
|
283
|
+
|
284
|
+
describe "#to_s" do
|
285
|
+
it "should return code_name" do
|
286
|
+
@app.to_s.should == "foo-staging"
|
287
|
+
end
|
288
|
+
end
|
241
289
|
end
|
242
290
|
|
@@ -30,8 +30,7 @@ describe Shelly::CLI::Backup do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
33
|
-
|
34
|
-
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
33
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Cloud with"})
|
35
34
|
@client.stub(:database_backups).and_raise(exception)
|
36
35
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
37
36
|
lambda { invoke(@backup, :list) }.should raise_error(SystemExit)
|
@@ -104,7 +103,7 @@ describe Shelly::CLI::Backup do
|
|
104
103
|
|
105
104
|
context "on backup not found" do
|
106
105
|
it "it should display error message" do
|
107
|
-
exception = Shelly::Client::APIError.new({}
|
106
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Backup with"})
|
108
107
|
@client.stub(:database_backup).and_raise(exception)
|
109
108
|
$stdout.should_receive(:puts).with(red "Backup not found")
|
110
109
|
$stdout.should_receive(:puts).with("You can list available backups with 'shelly backup list' command")
|
@@ -114,7 +113,7 @@ describe Shelly::CLI::Backup do
|
|
114
113
|
|
115
114
|
context "on unsupported exception" do
|
116
115
|
it "should re-raise it" do
|
117
|
-
exception = Shelly::Client::APIError.new(
|
116
|
+
exception = Shelly::Client::APIError.new(500)
|
118
117
|
@client.stub(:database_backup).and_raise(exception)
|
119
118
|
$stdout.should_not_receive(:puts).with(red "Backup not found")
|
120
119
|
$stdout.should_not_receive(:puts).with("You can list available backups with 'shelly backup list' command")
|
@@ -134,8 +133,7 @@ describe Shelly::CLI::Backup do
|
|
134
133
|
end
|
135
134
|
|
136
135
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
137
|
-
|
138
|
-
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
136
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Cloud foo-staging not found"})
|
139
137
|
@client.stub(:request_backup).and_raise(exception)
|
140
138
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
141
139
|
lambda { invoke(@backup, :create) }.should raise_error(SystemExit)
|
@@ -143,7 +141,7 @@ describe Shelly::CLI::Backup do
|
|
143
141
|
|
144
142
|
it "should display errors and exit 1 when kind is not valid" do
|
145
143
|
response = {"message" => "Wrong KIND argument. User one of following: postgresql, mongodb, redis"}
|
146
|
-
exception = Shelly::Client::APIError.new(
|
144
|
+
exception = Shelly::Client::APIError.new(422, response)
|
147
145
|
@client.should_receive(:request_backup).and_raise(exception)
|
148
146
|
$stdout.should_receive(:puts).with(red response["message"])
|
149
147
|
lambda { invoke(@backup, :create) }.should raise_error(SystemExit)
|
@@ -34,8 +34,8 @@ describe Shelly::CLI::Config do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
37
|
-
response = {"message" => "Cloud foo-staging
|
38
|
-
exception = Shelly::Client::APIError.new(
|
37
|
+
response = {"message" => "Couldn't find Cloud with code_name = foo-staging"}
|
38
|
+
exception = Shelly::Client::APIError.new(404, response)
|
39
39
|
@client.stub(:app_configs).and_raise(exception)
|
40
40
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
41
41
|
lambda { invoke(@config, :list) }.should raise_error(SystemExit)
|
@@ -76,6 +76,31 @@ describe Shelly::CLI::Config do
|
|
76
76
|
invoke(@config, :show, "path")
|
77
77
|
end
|
78
78
|
|
79
|
+
describe "on failure" do
|
80
|
+
context "when config doesn't exist" do
|
81
|
+
it "should display error message and exit with 1" do
|
82
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Config with"})
|
83
|
+
@client.should_receive(:app_config).and_raise(exception)
|
84
|
+
$stdout.should_receive(:puts).with(red "Config 'config/app.yml' not found")
|
85
|
+
$stdout.should_receive(:puts).with(red "You can list available config files with `shelly config list --cloud foo-staging`")
|
86
|
+
lambda {
|
87
|
+
invoke(@config, :show, "config/app.yml")
|
88
|
+
}.should raise_error(SystemExit)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when user doesn't have access to cloud" do
|
93
|
+
it "should display error message and exit with 1" do
|
94
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Cloud with"})
|
95
|
+
@client.should_receive(:app_config).and_raise(exception)
|
96
|
+
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
97
|
+
lambda {
|
98
|
+
invoke(@config, :show, "config/app.yml")
|
99
|
+
}.should raise_error(SystemExit)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
79
104
|
context "multiple clouds" do
|
80
105
|
before do
|
81
106
|
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
@@ -167,6 +192,31 @@ describe Shelly::CLI::Config do
|
|
167
192
|
invoke(@config, :edit, "path")
|
168
193
|
end
|
169
194
|
|
195
|
+
describe "on failure" do
|
196
|
+
context "when config doesn't exist" do
|
197
|
+
it "should display error message and exit with 1" do
|
198
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Config with"})
|
199
|
+
@client.should_receive(:app_config).and_raise(exception)
|
200
|
+
$stdout.should_receive(:puts).with(red "Config 'config/app.yml' not found")
|
201
|
+
$stdout.should_receive(:puts).with(red "You can list available config files with `shelly config list --cloud foo-staging`")
|
202
|
+
lambda {
|
203
|
+
invoke(@config, :edit, "config/app.yml")
|
204
|
+
}.should raise_error(SystemExit)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "when user doesn't have access to cloud" do
|
209
|
+
it "should display error message and exit with 1" do
|
210
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Cloud with"})
|
211
|
+
@client.should_receive(:app_config).and_raise(exception)
|
212
|
+
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
213
|
+
lambda {
|
214
|
+
invoke(@config, :edit, "config/app.yml")
|
215
|
+
}.should raise_error(SystemExit)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
170
220
|
context "multiple clouds" do
|
171
221
|
before do
|
172
222
|
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
@@ -235,5 +285,35 @@ describe Shelly::CLI::Config do
|
|
235
285
|
end
|
236
286
|
end
|
237
287
|
end
|
288
|
+
|
289
|
+
describe "on failure" do
|
290
|
+
context "when config doesn't exist" do
|
291
|
+
it "should display error message and exit with 1" do
|
292
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Config with"})
|
293
|
+
@client.should_receive(:app_delete_config).and_raise(exception)
|
294
|
+
$stdout.should_receive(:puts).with(red "Config 'config/app.yml' not found")
|
295
|
+
$stdout.should_receive(:puts).with(red "You can list available config files with `shelly config list --cloud foo-staging`")
|
296
|
+
fake_stdin(["y"]) do
|
297
|
+
lambda {
|
298
|
+
invoke(@config, :delete, "config/app.yml")
|
299
|
+
}.should raise_error(SystemExit)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context "when user doesn't have access to cloud" do
|
305
|
+
it "should display error message and exit with 1" do
|
306
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Cloud with"})
|
307
|
+
@client.should_receive(:app_delete_config).and_raise(exception)
|
308
|
+
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
309
|
+
fake_stdin(["y"]) do
|
310
|
+
lambda {
|
311
|
+
invoke(@config, :delete, "config/app.yml")
|
312
|
+
}.should raise_error(SystemExit)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
238
318
|
end
|
239
319
|
end
|
@@ -29,9 +29,7 @@ describe Shelly::CLI::Deploys do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
32
|
-
|
33
|
-
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
34
|
-
@client.stub(:deploy_logs).and_raise(exception)
|
32
|
+
@client.stub(:deploy_logs).and_raise(Shelly::Client::APIError.new(404))
|
35
33
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
36
34
|
lambda { invoke(@deploys, :list) }.should raise_error(SystemExit)
|
37
35
|
end
|
@@ -88,12 +86,22 @@ describe Shelly::CLI::Deploys do
|
|
88
86
|
}.should raise_error(SystemExit)
|
89
87
|
end
|
90
88
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
89
|
+
context "user doesn't have access to cloud" do
|
90
|
+
it "should exit 1 with message" do
|
91
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Cloud with"})
|
92
|
+
@client.stub(:deploy_log).and_raise(exception)
|
93
|
+
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
94
|
+
lambda { @deploys.show("last") }.should raise_error(SystemExit)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "log not found" do
|
99
|
+
it "should exit 1 with message" do
|
100
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Couldn't find Log with"})
|
101
|
+
@client.stub(:deploy_log).and_raise(exception)
|
102
|
+
$stdout.should_receive(:puts).with(red "Log not found, list all deploy logs using `shelly deploys list --cloud=foo-staging`")
|
103
|
+
lambda { @deploys.show("last") }.should raise_error(SystemExit)
|
104
|
+
end
|
97
105
|
end
|
98
106
|
|
99
107
|
context "multiple clouds" do
|
@@ -173,7 +173,7 @@ OUT
|
|
173
173
|
context "on unsuccessful registration" do
|
174
174
|
it "should display errors and exit with 1" do
|
175
175
|
response = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
|
176
|
-
exception = Shelly::Client::APIError.new(
|
176
|
+
exception = Shelly::Client::APIError.new(422, response)
|
177
177
|
@client.stub(:register_user).and_raise(exception)
|
178
178
|
$stdout.should_receive(:puts).with("\e[31mEmail has been already taken\e[0m")
|
179
179
|
lambda {
|
@@ -260,7 +260,7 @@ OUT
|
|
260
260
|
context "on unauthorized user" do
|
261
261
|
it "should exit with 1 and display error message" do
|
262
262
|
response = {"message" => "Unauthorized", "url" => "https://admin.winniecloud.com/users/password/new"}
|
263
|
-
exception = Shelly::Client::APIError.new(
|
263
|
+
exception = Shelly::Client::APIError.new(401, response)
|
264
264
|
@client.stub(:token).and_raise(exception)
|
265
265
|
$stdout.should_receive(:puts).with("\e[31mWrong email or password\e[0m")
|
266
266
|
$stdout.should_receive(:puts).with("\e[31mYou can reset password by using link:\e[0m")
|
@@ -380,7 +380,7 @@ OUT
|
|
380
380
|
|
381
381
|
it "should display validation errors if they are any" do
|
382
382
|
response = {"message" => "Validation Failed", "errors" => [["code_name", "has been already taken"]]}
|
383
|
-
exception = Shelly::Client::APIError.new(
|
383
|
+
exception = Shelly::Client::APIError.new(422, response)
|
384
384
|
@app.should_receive(:create).and_raise(exception)
|
385
385
|
$stdout.should_receive(:puts).with("\e[31mCode name has been already taken\e[0m")
|
386
386
|
$stdout.should_receive(:puts).with("\e[31mFix erros in the below command and type it again to create your cloud\e[0m")
|
@@ -468,8 +468,7 @@ OUT
|
|
468
468
|
|
469
469
|
context "on failure" do
|
470
470
|
it "should display info that user is not logged in" do
|
471
|
-
|
472
|
-
error = Shelly::Client::APIError.new(body.to_json, 401)
|
471
|
+
error = Shelly::Client::APIError.new(401)
|
473
472
|
@client.stub(:token).and_raise(error)
|
474
473
|
$stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
|
475
474
|
$stdout.should_receive(:puts).with(" shelly login")
|
@@ -502,16 +501,15 @@ OUT
|
|
502
501
|
end
|
503
502
|
|
504
503
|
it "should exit if user doesn't have access to clouds in Cloudfile" do
|
505
|
-
response = {"message" => "
|
506
|
-
exception = Shelly::Client::APIError.new(
|
504
|
+
response = {"message" => "Couldn't find Cloud with"}
|
505
|
+
exception = Shelly::Client::APIError.new(404, response)
|
507
506
|
@client.stub(:start_cloud).and_raise(exception)
|
508
507
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
509
508
|
lambda { invoke(@main, :start) }.should raise_error(SystemExit)
|
510
509
|
end
|
511
510
|
|
512
511
|
it "should exit if user is not logged in" do
|
513
|
-
|
514
|
-
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
512
|
+
exception = Shelly::Client::APIError.new(401)
|
515
513
|
@client.stub(:token).and_raise(exception)
|
516
514
|
$stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
|
517
515
|
$stdout.should_receive(:puts).with(" shelly login")
|
@@ -620,17 +618,13 @@ OUT
|
|
620
618
|
end
|
621
619
|
|
622
620
|
it "should exit if user doesn't have access to clouds in Cloudfile" do
|
623
|
-
|
624
|
-
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
625
|
-
@client.stub(:stop_cloud).and_raise(exception)
|
621
|
+
@client.stub(:stop_cloud).and_raise(Shelly::Client::APIError.new(404))
|
626
622
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
627
623
|
lambda { invoke(@main, :stop) }.should raise_error(SystemExit)
|
628
624
|
end
|
629
625
|
|
630
626
|
it "should exit if user is not logged in" do
|
631
|
-
|
632
|
-
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
633
|
-
@client.stub(:token).and_raise(exception)
|
627
|
+
@client.stub(:token).and_raise(Shelly::Client::APIError.new(401))
|
634
628
|
$stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
|
635
629
|
$stdout.should_receive(:puts).with(" shelly login")
|
636
630
|
lambda { invoke(@main, :stop) }.should raise_error(SystemExit)
|
@@ -673,14 +667,6 @@ OUT
|
|
673
667
|
Shelly::App.stub(:inside_git_repository?).and_return(true)
|
674
668
|
end
|
675
669
|
|
676
|
-
it "should exit with message if command run outside git repository" do
|
677
|
-
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
678
|
-
$stdout.should_receive(:puts).with("\e[31mMust be run inside your project git repository\e[0m")
|
679
|
-
lambda {
|
680
|
-
invoke(@main, :ip)
|
681
|
-
}.should raise_error(SystemExit)
|
682
|
-
end
|
683
|
-
|
684
670
|
it "should exit with message if there is no Cloudfile" do
|
685
671
|
File.delete("Cloudfile")
|
686
672
|
$stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
|
@@ -691,7 +677,7 @@ OUT
|
|
691
677
|
|
692
678
|
context "on success" do
|
693
679
|
it "should display mail and web server ip's" do
|
694
|
-
@client.stub(:
|
680
|
+
@client.stub(:app).and_return(response)
|
695
681
|
$stdout.should_receive(:puts).with("\e[32mCloud foo-production:\e[0m")
|
696
682
|
$stdout.should_receive(:puts).with(" Web server IP: 22.22.22.22")
|
697
683
|
$stdout.should_receive(:puts).with(" Mail server IP: 11.11.11.11")
|
@@ -704,16 +690,9 @@ OUT
|
|
704
690
|
end
|
705
691
|
|
706
692
|
context "on failure" do
|
707
|
-
it "should raise an error if user is not in git repository" do
|
708
|
-
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
709
|
-
$stdout.should_receive(:puts).with("\e[31mMust be run inside your project git repository\e[0m")
|
710
|
-
lambda { invoke(@main, :ip) }.should raise_error(SystemExit)
|
711
|
-
end
|
712
|
-
|
713
693
|
it "should raise an error if user does not have access to cloud" do
|
714
|
-
|
715
|
-
|
716
|
-
@client.stub(:app_ips).and_raise(exception)
|
694
|
+
exception = Shelly::Client::APIError.new(404, {"message" => "Cloud foo-staging not found"})
|
695
|
+
@client.stub(:app).and_raise(exception)
|
717
696
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
718
697
|
invoke(@main, :ip)
|
719
698
|
end
|
@@ -758,7 +737,8 @@ OUT
|
|
758
737
|
@app.should_not_receive(:delete)
|
759
738
|
lambda{
|
760
739
|
fake_stdin(["yes", "yes", "no"]) do
|
761
|
-
|
740
|
+
@main.options = {:cloud => "foo-staging"}
|
741
|
+
invoke(@main, :delete)
|
762
742
|
end
|
763
743
|
}.should raise_error(SystemExit)
|
764
744
|
end
|
@@ -774,7 +754,8 @@ OUT
|
|
774
754
|
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
775
755
|
$stdout.should_receive(:puts).with("Missing git remote")
|
776
756
|
fake_stdin(["yes", "yes", "yes"]) do
|
777
|
-
|
757
|
+
@main.options = {:cloud => "foo-staging"}
|
758
|
+
invoke(@main, :delete)
|
778
759
|
end
|
779
760
|
end
|
780
761
|
end
|
@@ -786,13 +767,13 @@ OUT
|
|
786
767
|
end
|
787
768
|
|
788
769
|
it "should raise Client::APIError" do
|
789
|
-
|
790
|
-
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
770
|
+
exception = Shelly::Client::APIError.new(404)
|
791
771
|
@app.stub(:delete).and_raise(exception)
|
792
|
-
$stdout.should_receive(:puts).with("
|
772
|
+
$stdout.should_receive(:puts).with(red "You have no access to 'foo-bar' cloud defined in Cloudfile")
|
793
773
|
lambda{
|
794
774
|
fake_stdin(["yes", "yes", "yes"]) do
|
795
|
-
|
775
|
+
@main.options = {:cloud => "foo-bar"}
|
776
|
+
invoke(@main, :delete)
|
796
777
|
end
|
797
778
|
}.should raise_error(SystemExit)
|
798
779
|
end
|
@@ -846,7 +827,7 @@ OUT
|
|
846
827
|
|
847
828
|
it "should exit if user doesn't have access to clouds in Cloudfile" do
|
848
829
|
response = {"message" => "Cloud foo-production not found"}
|
849
|
-
exception = Shelly::Client::APIError.new(
|
830
|
+
exception = Shelly::Client::APIError.new(404, response)
|
850
831
|
@client.stub(:application_logs).and_raise(exception)
|
851
832
|
$stdout.should_receive(:puts).
|
852
833
|
with(red "You have no access to cloud 'foo-production'")
|
@@ -854,8 +835,7 @@ OUT
|
|
854
835
|
end
|
855
836
|
|
856
837
|
it "should exit if user is not logged in" do
|
857
|
-
|
858
|
-
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
838
|
+
exception = Shelly::Client::APIError.new(401)
|
859
839
|
@client.stub(:token).and_raise(exception)
|
860
840
|
$stdout.should_receive(:puts).
|
861
841
|
with(red "You are not logged in. To log in use:")
|
@@ -51,7 +51,7 @@ describe Shelly::CLI::User do
|
|
51
51
|
|
52
52
|
it "should exit if user is not logged in" do
|
53
53
|
response = {"message" => "Unauthorized", "url" => "https://admin.winniecloud.com/users/password/new"}
|
54
|
-
exception = Shelly::Client::APIError.new(
|
54
|
+
exception = Shelly::Client::APIError.new(401, response)
|
55
55
|
@client.stub(:token).and_raise(exception)
|
56
56
|
$stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
|
57
57
|
$stdout.should_receive(:puts).with(" shelly login")
|
@@ -81,8 +81,8 @@ describe Shelly::CLI::User do
|
|
81
81
|
|
82
82
|
context "on failure" do
|
83
83
|
it "should raise an error if user does not have access to cloud" do
|
84
|
-
response = {"message" => "Cloud foo-staging
|
85
|
-
exception = Shelly::Client::APIError.new(
|
84
|
+
response = {"message" => "Couldn't find Cloud with code_name = foo-staging"}
|
85
|
+
exception = Shelly::Client::APIError.new(404, response)
|
86
86
|
@client.stub(:app_users).and_raise(exception)
|
87
87
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
88
88
|
invoke(@cli_user, :list)
|
@@ -143,7 +143,7 @@ describe Shelly::CLI::User do
|
|
143
143
|
context "on failure" do
|
144
144
|
it "should raise error if user doesnt have access to cloud" do
|
145
145
|
response = {"message" => "Cloud foo-staging not found"}
|
146
|
-
exception = Shelly::Client::APIError.new(
|
146
|
+
exception = Shelly::Client::APIError.new(404, response)
|
147
147
|
@client.stub(:send_invitation).and_raise(exception)
|
148
148
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
149
149
|
invoke(@cli_user, :add, "megan@example.com")
|
data/spec/shelly/client_spec.rb
CHANGED
@@ -2,12 +2,13 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Shelly::Client::APIError do
|
4
4
|
before do
|
5
|
-
body = {"message" => "
|
6
|
-
|
5
|
+
body = {"message" => "Couldn't find Cloud with code_name = fooo",
|
6
|
+
"errors" => [["first", "foo"]], "url" => "https://foo.bar"}
|
7
|
+
@error = Shelly::Client::APIError.new(404, body)
|
7
8
|
end
|
8
9
|
|
9
10
|
it "should return error message" do
|
10
|
-
@error.message.should == "
|
11
|
+
@error.message.should == "Couldn't find Cloud with code_name = fooo"
|
11
12
|
end
|
12
13
|
|
13
14
|
it "should return array of errors" do
|
@@ -19,16 +20,31 @@ describe Shelly::Client::APIError do
|
|
19
20
|
end
|
20
21
|
|
21
22
|
it "should return user friendly string" do
|
22
|
-
@error.each_error{|error| error.should == "First foo"}
|
23
|
+
@error.each_error { |error| error.should == "First foo" }
|
23
24
|
end
|
24
|
-
|
25
|
+
|
26
|
+
describe "#resource_not_found?" do
|
27
|
+
context "on 404 response" do
|
28
|
+
it "should return which resource was not found" do
|
29
|
+
@error.resource_not_found.should == :cloud
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "on non 404 response" do
|
34
|
+
it "should return nil" do
|
35
|
+
error = Shelly::Client::APIError.new(401)
|
36
|
+
error.resource_not_found.should be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
25
41
|
describe "#not_found?" do
|
26
42
|
it "should return true if response status code is 404" do
|
27
43
|
@error.should be_not_found
|
28
44
|
end
|
29
|
-
|
45
|
+
|
30
46
|
it "should return false if response status code is not 404" do
|
31
|
-
error = Shelly::Client::APIError.new(
|
47
|
+
error = Shelly::Client::APIError.new(500)
|
32
48
|
error.should_not be_not_found
|
33
49
|
end
|
34
50
|
end
|
@@ -37,7 +53,7 @@ describe Shelly::Client::APIError do
|
|
37
53
|
context "when error is caused by validation errors" do
|
38
54
|
it "should return true" do
|
39
55
|
body = {"message" => "Validation Failed"}
|
40
|
-
error = Shelly::Client::APIError.new(
|
56
|
+
error = Shelly::Client::APIError.new(422, body)
|
41
57
|
error.should be_validation
|
42
58
|
end
|
43
59
|
end
|
@@ -52,8 +68,7 @@ describe Shelly::Client::APIError do
|
|
52
68
|
describe "#unauthorized?" do
|
53
69
|
context "when error is caused by unauthorized error" do
|
54
70
|
it "should return true" do
|
55
|
-
|
56
|
-
error = Shelly::Client::APIError.new(body.to_json, 401)
|
71
|
+
error = Shelly::Client::APIError.new(401)
|
57
72
|
error.should be_unauthorized
|
58
73
|
end
|
59
74
|
end
|
@@ -71,7 +86,7 @@ describe Shelly::Client do
|
|
71
86
|
ENV['SHELLY_URL'] = nil
|
72
87
|
@client = Shelly::Client.new("bob@example.com", "secret")
|
73
88
|
end
|
74
|
-
|
89
|
+
|
75
90
|
def api_url(resource = "")
|
76
91
|
auth = "#{CGI.escape(@client.email)}:#{@client.password}@"
|
77
92
|
"https://#{auth}admin.winniecloud.com/apiv2/#{resource}"
|
@@ -142,6 +157,38 @@ describe Shelly::Client do
|
|
142
157
|
end
|
143
158
|
end
|
144
159
|
|
160
|
+
describe "#app_config" do
|
161
|
+
it "should send get request" do
|
162
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/configs/path"), :body => [{:content => "content", :path => "path"}].to_json)
|
163
|
+
response = @client.app_config("staging-foo", "path")
|
164
|
+
response.should == [{"content" => "content", "path" => "path"}]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#app_create_config" do
|
169
|
+
it "should send post request" do
|
170
|
+
FakeWeb.register_uri(:post, api_url("apps/staging-foo/configs"), :body => {}.to_json, :status => 201)
|
171
|
+
response = @client.app_create_config("staging-foo", "path", "content")
|
172
|
+
response.should == {}
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#app_update_config" do
|
177
|
+
it "should send put request" do
|
178
|
+
FakeWeb.register_uri(:put, api_url("apps/staging-foo/configs/path"), :body => {}.to_json)
|
179
|
+
response = @client.app_update_config("staging-foo", "path", "content")
|
180
|
+
response.should == {}
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#app_delete_config" do
|
185
|
+
it "should send delete request" do
|
186
|
+
FakeWeb.register_uri(:delete, api_url("apps/staging-foo/configs/path"), :body => {}.to_json)
|
187
|
+
response = @client.app_delete_config("staging-foo", "path")
|
188
|
+
response.should == {}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
145
192
|
describe "#application_logs" do
|
146
193
|
it "should send get request" do
|
147
194
|
time = Time.now
|
@@ -167,12 +214,13 @@ describe Shelly::Client do
|
|
167
214
|
response.should == [{"email" => "test@example.com"}, {"email" => "test2@example.com"}]
|
168
215
|
end
|
169
216
|
end
|
170
|
-
|
171
|
-
describe "#
|
172
|
-
it "should
|
173
|
-
FakeWeb.register_uri(:get, api_url("apps/staging-foo
|
174
|
-
|
175
|
-
response
|
217
|
+
|
218
|
+
describe "#app" do
|
219
|
+
it "should fetch app from API" do
|
220
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo"),
|
221
|
+
:body => {:web_server_ip => "192.0.2.1", :mail_server_ip => "192.0.2.3"}.to_json)
|
222
|
+
response = @client.app("staging-foo")
|
223
|
+
response.should == {"web_server_ip" => "192.0.2.1", "mail_server_ip" => "192.0.2.3"}
|
176
224
|
end
|
177
225
|
end
|
178
226
|
|
@@ -221,7 +269,7 @@ describe Shelly::Client do
|
|
221
269
|
@client.ssh_key_available?("ssh-key Abb")
|
222
270
|
end
|
223
271
|
end
|
224
|
-
|
272
|
+
|
225
273
|
describe "#database_backup" do
|
226
274
|
it "should fetch backup description from API" do
|
227
275
|
expected = {
|
@@ -232,11 +280,11 @@ describe Shelly::Client do
|
|
232
280
|
filename = "2011.11.26.04.00.10.foo.postgres.tar.gz"
|
233
281
|
url = api_url("apps/foo/database_backups/#{filename}")
|
234
282
|
FakeWeb.register_uri(:get, url, :body => expected.to_json)
|
235
|
-
|
283
|
+
|
236
284
|
@client.database_backup("foo", filename).should == expected
|
237
285
|
end
|
238
286
|
end
|
239
|
-
|
287
|
+
|
240
288
|
describe "#download_backup" do
|
241
289
|
before do
|
242
290
|
@filename = "2011.11.26.04.00.10.foo.postgres.tar.gz"
|
@@ -246,18 +294,18 @@ describe Shelly::Client do
|
|
246
294
|
response.stub(:read_body).and_yield("aaa").and_yield("bbbbb").and_yield("dddf")
|
247
295
|
FakeWeb.register_uri(:get, url, :response => response)
|
248
296
|
end
|
249
|
-
|
297
|
+
|
250
298
|
it "should write streamed database backup to file" do
|
251
299
|
@client.download_backup("foo", @filename)
|
252
300
|
File.read(@filename).should == %w(aaa bbbbb dddf).join
|
253
301
|
end
|
254
|
-
|
302
|
+
|
255
303
|
it "should execute progress_callback with size of every chunk" do
|
256
304
|
progress = mock(:update => true)
|
257
305
|
progress.should_receive(:update).with(3)
|
258
306
|
progress.should_receive(:update).with(5)
|
259
307
|
progress.should_receive(:update).with(4)
|
260
|
-
|
308
|
+
|
261
309
|
callback = lambda { |size| progress.update(size) }
|
262
310
|
|
263
311
|
@client.download_backup("foo", @filename, callback)
|
@@ -331,6 +379,13 @@ describe Shelly::Client do
|
|
331
379
|
end
|
332
380
|
end
|
333
381
|
end
|
382
|
+
|
383
|
+
it "should return empty hash if response is not a valid JSON" do
|
384
|
+
JSON.should_receive(:parse).with("").and_raise(JSON::ParserError)
|
385
|
+
@response.stub(:code).and_return("204")
|
386
|
+
@response.stub(:body).and_return("")
|
387
|
+
@client.post("/api/apps/flower").should == {}
|
388
|
+
end
|
334
389
|
end
|
335
390
|
|
336
391
|
describe "#headers" do
|
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shelly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.41.pre
|
5
|
+
prerelease: 7
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Shelly Cloud team
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70129852876100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70129852876100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &70129852875680 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70129852875680
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: guard
|
38
|
-
requirement: &
|
38
|
+
requirement: &70129852875260 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70129852875260
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: guard-rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70129852874840 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70129852874840
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: growl_notify
|
60
|
-
requirement: &
|
60
|
+
requirement: &70129852890740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70129852890740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rb-fsevent
|
71
|
-
requirement: &
|
71
|
+
requirement: &70129852890320 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70129852890320
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: fakefs
|
82
|
-
requirement: &
|
82
|
+
requirement: &70129852889900 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70129852889900
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: fakeweb
|
93
|
-
requirement: &
|
93
|
+
requirement: &70129852889480 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70129852889480
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: wijet-thor
|
104
|
-
requirement: &
|
104
|
+
requirement: &70129852888980 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: 0.14.7
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70129852888980
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rest-client
|
115
|
-
requirement: &
|
115
|
+
requirement: &70129852888560 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :runtime
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70129852888560
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: json
|
126
|
-
requirement: &
|
126
|
+
requirement: &70129852888100 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70129852888100
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: wijet-launchy
|
137
|
-
requirement: &
|
137
|
+
requirement: &70129852887680 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :runtime
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *70129852887680
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: progressbar
|
148
|
-
requirement: &
|
148
|
+
requirement: &70129852887260 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ! '>='
|
@@ -153,7 +153,7 @@ dependencies:
|
|
153
153
|
version: '0'
|
154
154
|
type: :runtime
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *70129852887260
|
157
157
|
description: Tool for managing applications and clouds at shellycloud.com
|
158
158
|
email:
|
159
159
|
- support@shellycloud.com
|
@@ -223,21 +223,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
223
223
|
- - ! '>='
|
224
224
|
- !ruby/object:Gem::Version
|
225
225
|
version: '0'
|
226
|
-
segments:
|
227
|
-
- 0
|
228
|
-
hash: 2595737964624093032
|
229
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
230
227
|
none: false
|
231
228
|
requirements:
|
232
|
-
- - ! '
|
229
|
+
- - ! '>'
|
233
230
|
- !ruby/object:Gem::Version
|
234
|
-
version:
|
235
|
-
segments:
|
236
|
-
- 0
|
237
|
-
hash: 2595737964624093032
|
231
|
+
version: 1.3.1
|
238
232
|
requirements: []
|
239
233
|
rubyforge_project: shelly
|
240
|
-
rubygems_version: 1.8.
|
234
|
+
rubygems_version: 1.8.10
|
241
235
|
signing_key:
|
242
236
|
specification_version: 3
|
243
237
|
summary: Shelly Cloud command line tool
|