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 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
@@ -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.unauthorized?
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
- say_error e.message
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
- if e.not_found?
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.unauthorized?
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
@@ -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.unauthorized?
38
- say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
37
+ if e.resource_not_found == :cloud
38
+ say_error "You have no access to '#{@app}' cloud defined in Cloudfile"
39
39
  else
40
- say_error e.message
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
- if e.unauthorized?
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.unauthorized?
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.unauthorized?
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.unauthorized?
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
@@ -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.unauthorized?
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
- say_error e.message
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.unauthorized?
60
- say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
61
- elsif e.message == "Log not found"
62
- say_error "Log not found, list all deploy logs using:", :with_exit => false
63
- say " shelly deploys list #{cloud}"
64
- exit 1
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
 
@@ -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
- ips = @app.ips
152
- print_wrapped "Web server IP: #{ips['web_server_ip']}", :ident => 2
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.unauthorized?
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.unauthorized?
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.unauthorized?
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
- say_error e.message
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.unauthorized?
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
@@ -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.unauthorized?
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.unauthorized?
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(response_body, status_code)
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
- @response["message"]
16
+ body["message"]
17
17
  end
18
18
 
19
19
  def errors
20
- @response["errors"]
20
+ body["errors"]
21
21
  end
22
22
 
23
23
  def url
24
- @response["url"]
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
- # FIXME: Return unauthorized if user has no access to cloud, checked by 401 status code
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
- @response["errors"].each do |index,message|
43
- yield index.gsub('_',' ').capitalize + " " + message
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
- if [401, 404, 422, 500].include?(response.code)
215
- raise APIError.new(response.body, response.code)
216
- end
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
- JSON.parse(response.body)
221
+ body
220
222
  end
221
223
  end
222
224
  end
@@ -1,3 +1,3 @@
1
1
  module Shelly
2
- VERSION = "0.0.40"
2
+ VERSION = "0.0.41.pre"
3
3
  end
@@ -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
- response = {"message" => "Cloud foo-staging not found"}
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({}.to_json, 404)
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({}.to_json, 500)
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
- response = {"message" => "Cloud foo-staging not found"}
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(response.to_json, 422)
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 not found"}
38
- exception = Shelly::Client::APIError.new(response.to_json, 404)
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
- response = {"message" => "Cloud foo-staging not found"}
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
- it "should exit if user doesn't have access to cloud in Cloudfile" do
92
- response = {"message" => "Cloud foo-staging not found"}
93
- exception = Shelly::Client::APIError.new(response.to_json, 404)
94
- @client.stub(:deploy_log).and_raise(exception)
95
- $stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
96
- lambda { invoke(@deploys, :show, "last") }.should raise_error(SystemExit)
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(response.to_json, 422)
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(response.to_json, 401)
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(response.to_json, 422)
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
- body = {"message" => "Unauthorized"}
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" => "Cloud foo-production not found"}
506
- exception = Shelly::Client::APIError.new(response.to_json, 404)
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
- response = {"message" => "Unauthorized"}
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
- response = {"message" => "Cloud foo-production not found"}
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
- response = {"message" => "Unauthorized"}
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(:app_ips).and_return(response)
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
- response = {"message" => "Cloud foo-staging not found"}
715
- exception = Shelly::Client::APIError.new(response.to_json, 404)
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
- invoke(@main, :delete, "--cloud", "foo-staging")
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
- invoke(@main, :delete, "--cloud", "foo-staging")
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
- response = {:message => "Application not found"}
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("\e[31mApplication not found\e[0m")
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
- invoke(@main, :delete, "--cloud", "foo-bar")
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(response.to_json, 404)
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
- response = {"message" => "Unauthorized"}
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(response.to_json, 404)
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 not found"}
85
- exception = Shelly::Client::APIError.new(response.to_json, 404)
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(response.to_json, 404)
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")
@@ -2,12 +2,13 @@ require "spec_helper"
2
2
 
3
3
  describe Shelly::Client::APIError do
4
4
  before do
5
- body = {"message" => "something went wrong", "errors" => [["first", "foo"]], "url" => "https://foo.bar"}
6
- @error = Shelly::Client::APIError.new(body.to_json, 404)
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 == "something went wrong"
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({}.to_json, 500)
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(body.to_json, 422)
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
- body = {"message" => "Unauthorized"}
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 "#app_ips" do
172
- it "should send get request with app code_name" do
173
- FakeWeb.register_uri(:get, api_url("apps/staging-foo/ips"), :body => {:mail_server_ip => "10.0.1.1", :web_server_ip => "88.198.21.187"}.to_json)
174
- response = @client.app_ips("staging-foo")
175
- response.should == {"mail_server_ip" => "10.0.1.1", "web_server_ip" => "88.198.21.187"}
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.40
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: 2011-12-30 00:00:00.000000000 Z
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: &70136906680620 !ruby/object:Gem::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: *70136906680620
24
+ version_requirements: *70129852876100
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70136906696580 !ruby/object:Gem::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: *70136906696580
35
+ version_requirements: *70129852875680
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: guard
38
- requirement: &70136906696160 !ruby/object:Gem::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: *70136906696160
46
+ version_requirements: *70129852875260
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: guard-rspec
49
- requirement: &70136906695740 !ruby/object:Gem::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: *70136906695740
57
+ version_requirements: *70129852874840
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: growl_notify
60
- requirement: &70136906695280 !ruby/object:Gem::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: *70136906695280
68
+ version_requirements: *70129852890740
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rb-fsevent
71
- requirement: &70136906694860 !ruby/object:Gem::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: *70136906694860
79
+ version_requirements: *70129852890320
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: fakefs
82
- requirement: &70136906694440 !ruby/object:Gem::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: *70136906694440
90
+ version_requirements: *70129852889900
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: fakeweb
93
- requirement: &70136906694020 !ruby/object:Gem::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: *70136906694020
101
+ version_requirements: *70129852889480
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: wijet-thor
104
- requirement: &70136906693520 !ruby/object:Gem::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: *70136906693520
112
+ version_requirements: *70129852888980
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rest-client
115
- requirement: &70136906693100 !ruby/object:Gem::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: *70136906693100
123
+ version_requirements: *70129852888560
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: json
126
- requirement: &70136906692640 !ruby/object:Gem::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: *70136906692640
134
+ version_requirements: *70129852888100
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: wijet-launchy
137
- requirement: &70136906692220 !ruby/object:Gem::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: *70136906692220
145
+ version_requirements: *70129852887680
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: progressbar
148
- requirement: &70136906691800 !ruby/object:Gem::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: *70136906691800
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: '0'
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.11
234
+ rubygems_version: 1.8.10
241
235
  signing_key:
242
236
  specification_version: 3
243
237
  summary: Shelly Cloud command line tool