shelly 0.2.28 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ class Shelly::Client
2
+ def app_configs(cloud)
3
+ get("/apps/#{cloud}/configs")
4
+ end
5
+
6
+ def app_config(cloud, path)
7
+ get("/apps/#{cloud}/configs/#{CGI.escape(path)}")
8
+ end
9
+
10
+ def app_create_config(cloud, path, content)
11
+ post("/apps/#{cloud}/configs", :config => {:path => path, :content => content})
12
+ end
13
+
14
+ def app_update_config(cloud, path, content)
15
+ put("/apps/#{cloud}/configs/#{CGI.escape(path)}", :config => {:content => content})
16
+ end
17
+
18
+ def app_delete_config(cloud, path)
19
+ delete("/apps/#{cloud}/configs/#{CGI.escape(path)}")
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ class Shelly::Client
2
+ def database_backups(code_name)
3
+ get("/apps/#{code_name}/database_backups")
4
+ end
5
+
6
+ def database_backup(code_name, handler)
7
+ get("/apps/#{code_name}/database_backups/#{handler}")
8
+ end
9
+
10
+ def restore_backup(code_name, filename)
11
+ put("/apps/#{code_name}/database_backups/#{filename}/restore")
12
+ end
13
+
14
+ def request_backup(code_name, kind = nil)
15
+ post("/apps/#{code_name}/database_backups", :kind => kind)
16
+ end
17
+
18
+ def download_backup_url(code_name, filename)
19
+ get("/apps/#{code_name}/database_backups/#{filename}/download_url")["url"]
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ class Shelly::Client
2
+ def deploy_logs(cloud)
3
+ get("/apps/#{cloud}/deployment_logs")
4
+ end
5
+
6
+ def deploy_log(cloud, log)
7
+ get("/apps/#{cloud}/deployment_logs/#{log}")
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Shelly::Client
2
+ def redeploy(cloud)
3
+ post("/apps/#{cloud}/deploys")
4
+ end
5
+
6
+ def deployment(cloud, deployment_id)
7
+ get("/apps/#{cloud}/deploys/#{deployment_id}")
8
+ end
9
+ end
@@ -0,0 +1,49 @@
1
+ class Shelly::Client
2
+ class APIException < Exception
3
+ attr_reader :status_code, :body, :request_id
4
+
5
+ def initialize(body = {}, status_code = nil, request_id = nil)
6
+ @status_code = status_code
7
+ @body = body
8
+ @request_id = request_id
9
+ end
10
+
11
+ def [](key)
12
+ body[key.to_s]
13
+ end
14
+ end
15
+
16
+ class UnauthorizedException < APIException; end
17
+
18
+ class ForbiddenException < APIException; end
19
+
20
+ class ConflictException < APIException; end
21
+
22
+ class GemVersionException < APIException; end
23
+
24
+ class GatewayTimeoutException < APIException; end
25
+
26
+ class LockedException < APIException; end
27
+
28
+ class ValidationException < APIException
29
+ def errors
30
+ self[:errors]
31
+ end
32
+
33
+ def each_error
34
+ errors.each do |field, message|
35
+ yield [field.gsub('_',' ').capitalize, message].join(" ")
36
+ end
37
+ end
38
+ end
39
+
40
+ class NotFoundException < APIException
41
+ def resource
42
+ self[:resource].to_sym
43
+ end
44
+
45
+ def id
46
+ self[:id]
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ class Shelly::Client
2
+ def organizations
3
+ get("/organizations")
4
+ end
5
+
6
+ def organization(name)
7
+ get("/organizations/#{name}")
8
+ end
9
+
10
+ def members(name)
11
+ get("/organizations/#{name}/memberships")
12
+ end
13
+
14
+ def send_invitation(name, email, owner = false)
15
+ post("/organizations/#{name}/memberships", :email => email, :owner => owner)
16
+ end
17
+
18
+ def delete_member(name, email)
19
+ delete("/organizations/#{name}/memberships/#{email}")
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ class Shelly::Client
2
+ def shellyapp_url
3
+ get("/shellyapp")["url"]
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class Shelly::Client
2
+ def add_ssh_key(ssh_key)
3
+ post("/ssh_keys", :ssh_key => ssh_key)
4
+ end
5
+
6
+ def delete_ssh_key(ssh_key)
7
+ delete("/ssh_keys", :ssh_key => ssh_key)
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class Shelly::Client
2
+ def register_user(email, password, ssh_key)
3
+ post("/users", :user => {:email => email, :password => password, :ssh_key => ssh_key})
4
+ end
5
+ end
@@ -74,8 +74,7 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository}
74
74
 
75
75
  def logged_in?
76
76
  user = Shelly::User.new
77
- user.token
78
- user
77
+ user.authorize!
79
78
  rescue Client::UnauthorizedException
80
79
  say_error "You are not logged in. To log in use: `shelly login`"
81
80
  end
data/lib/shelly/model.rb CHANGED
@@ -1,13 +1,11 @@
1
1
  module Shelly
2
2
  class Model
3
3
  def current_user
4
- @user = User.new
5
- @user.load_credentials
6
- @user
4
+ @current_user ||= User.new
7
5
  end
8
6
 
9
7
  def shelly
10
- @shelly ||= Client.new(current_user.email, current_user.password)
8
+ @shelly ||= Client.new
11
9
  end
12
10
  end
13
11
  end
data/lib/shelly/user.rb CHANGED
@@ -2,13 +2,6 @@ require 'shelly/organization'
2
2
 
3
3
  module Shelly
4
4
  class User < Model
5
- attr_accessor :email, :password
6
-
7
- def initialize(email = nil, password = nil)
8
- @email = email
9
- @password = password
10
- end
11
-
12
5
  def apps
13
6
  shelly.apps.map do |attributes|
14
7
  Shelly::App.from_attributes(attributes)
@@ -21,33 +14,34 @@ module Shelly
21
14
  end
22
15
  end
23
16
 
24
- def register
17
+ def email
18
+ shelly.user_email
19
+ end
20
+
21
+ def register(email, password)
25
22
  ssh_key = File.read(ssh_key_path) if ssh_key_exists?
26
23
  shelly.register_user(email, password, ssh_key)
27
- save_credentials
28
24
  end
29
25
 
30
- def login
31
- client = Client.new(email, password)
32
- # test if credentials are valid
33
- # if not RestClient::Unauthorized will be raised
34
- client.token
35
- save_credentials
26
+ def authorize!
27
+ if credentials_exists?
28
+ email, password = File.read(credentials_path).split("\n")
29
+ shelly.authorize_with_email_and_password(email, password)
30
+ delete_credentials
31
+ else
32
+ shelly.authorize!
33
+ end
36
34
  end
37
35
 
38
- def token
39
- shelly.token["token"]
40
- end
36
+ def login(email, password)
37
+ delete_credentials # clean up previous auth storage
41
38
 
42
- def load_credentials
43
- return unless credentials_exists?
44
- @email, @password = File.read(credentials_path).split("\n")
39
+ shelly.authorize_with_email_and_password(email, password)
45
40
  end
46
41
 
47
- def save_credentials
48
- FileUtils.mkdir_p(config_dir) unless credentials_exists?
49
- File.open(credentials_path, 'w') { |file| file << "#{email}\n#{password}" }
50
- set_credentials_permissions
42
+ def logout
43
+ delete_credentials # clean up previous auth storage
44
+ shelly.forget_authorization
51
45
  end
52
46
 
53
47
  def delete_credentials
@@ -55,8 +49,8 @@ module Shelly
55
49
  end
56
50
 
57
51
  def delete_ssh_key
58
- shelly.logout(File.read(dsa_key)) if File.exists?(dsa_key)
59
- shelly.logout(File.read(rsa_key)) if File.exists?(rsa_key)
52
+ shelly.delete_ssh_key(File.read(dsa_key)) if File.exists?(dsa_key)
53
+ shelly.delete_ssh_key(File.read(rsa_key)) if File.exists?(rsa_key)
60
54
  end
61
55
 
62
56
  def ssh_key_exists?
@@ -97,11 +91,6 @@ module Shelly
97
91
  def credentials_exists?
98
92
  File.exists?(credentials_path)
99
93
  end
100
-
101
- def set_credentials_permissions
102
- FileUtils.chmod(0700, config_dir)
103
- FileUtils.chmod(0600, credentials_path)
104
- end
105
94
  end
106
95
  end
107
96
 
@@ -1,3 +1,3 @@
1
1
  module Shelly
2
- VERSION = "0.2.28"
2
+ VERSION = "0.3.0"
3
3
  end
data/shelly.gemspec CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.add_runtime_dependency "json"
29
29
  s.add_runtime_dependency "progressbar"
30
30
  s.add_runtime_dependency "launchy"
31
+ s.add_runtime_dependency "netrc"
31
32
 
32
33
  s.files = `git ls-files`.split("\n")
33
34
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -8,7 +8,7 @@ describe Shelly::CLI::Backup do
8
8
  @backup = Shelly::CLI::Backup.new
9
9
  Shelly::CLI::Backup.stub(:new).and_return(@backup)
10
10
  @client = mock
11
- @client.stub(:token).and_return("abc")
11
+ @client.stub(:authorize!)
12
12
  Shelly::Client.stub(:new).and_return(@client)
13
13
  FileUtils.mkdir_p("/projects/foo")
14
14
  Dir.chdir("/projects/foo")
@@ -13,7 +13,7 @@ describe Shelly::CLI::Config do
13
13
  $stdout.stub(:print)
14
14
  FileUtils.mkdir_p("/projects/foo")
15
15
  Dir.chdir("/projects/foo")
16
- @client.stub(:token).and_return("abc")
16
+ @client.stub(:authorize!)
17
17
  File.open("Cloudfile", 'w') {|f| f.write("foo-production:\n") }
18
18
  FileUtils.mkdir_p("/tmp")
19
19
  Dir.stub(:tmpdir).and_return("/tmp")
@@ -18,7 +18,7 @@ describe Shelly::CLI::Deploy do
18
18
  FileUtils.mkdir_p("/projects/foo")
19
19
  Dir.chdir("/projects/foo")
20
20
  File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
21
- @client.stub(:token).and_return("abc")
21
+ @client.stub(:authorize!)
22
22
  end
23
23
 
24
24
  it "should ensure user has logged in" do
@@ -55,7 +55,7 @@ describe Shelly::CLI::Deploy do
55
55
  FileUtils.mkdir_p("/projects/foo")
56
56
  Dir.chdir("/projects/foo")
57
57
  File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
58
- @client.stub(:token).and_return("abc")
58
+ @client.stub(:authorize!)
59
59
  end
60
60
 
61
61
  it "should ensure user has logged in" do
@@ -8,7 +8,7 @@ describe Shelly::CLI::File do
8
8
  Shelly::CLI::File.stub(:new).and_return(@cli_files)
9
9
  @client = mock
10
10
  Shelly::Client.stub(:new).and_return(@client)
11
- @client.stub(:token).and_return("abc")
11
+ @client.stub(:authorize!)
12
12
  FileUtils.mkdir_p("/projects/foo")
13
13
  Dir.chdir("/projects/foo")
14
14
  @app = Shelly::App.new("foo-production")
@@ -8,7 +8,7 @@ describe Shelly::CLI::Logs do
8
8
  Shelly::CLI::Logs.stub(:new).and_return(@cli_logs)
9
9
  @client = mock
10
10
  Shelly::Client.stub(:new).and_return(@client)
11
- @client.stub(:token).and_return("abc")
11
+ @client.stub(:authorize!)
12
12
  FileUtils.mkdir_p("/projects/foo")
13
13
  Dir.chdir("/projects/foo")
14
14
  @app = Shelly::App.new("foo-production")
@@ -3,17 +3,20 @@ require "spec_helper"
3
3
  require "shelly/cli/main"
4
4
 
5
5
  describe Shelly::CLI::Main do
6
+ let(:user) { Shelly::User.new }
6
7
  before do
8
+ FileUtils.mkpath(File.expand_path("~"))
7
9
  FileUtils.stub(:chmod)
8
10
  @main = Shelly::CLI::Main.new
9
11
  Shelly::CLI::Main.stub(:new).and_return(@main)
10
12
  @client = mock
11
- @client.stub(:token).and_return("abc")
13
+ @client.stub(:authorize!)
12
14
  @client.stub(:shellyapp_url).and_return("https://example.com")
13
15
  Shelly::Client.stub(:new).and_return(@client)
14
16
  Shelly::User.stub(:guess_email).and_return("")
15
17
  $stdout.stub(:puts)
16
18
  $stdout.stub(:print)
19
+ Shelly::User.stub(:new => user)
17
20
  end
18
21
 
19
22
  describe "#version" do
@@ -67,13 +70,10 @@ describe Shelly::CLI::Main do
67
70
 
68
71
  describe "#register" do
69
72
  before do
70
- @client.stub(:register_user)
71
73
  @key_path = File.expand_path("~/.ssh/id_rsa.pub")
72
- @user = Shelly::User.new
73
74
  FileUtils.mkdir_p("~/.ssh")
74
75
  File.open("~/.ssh/id_rsa.pub", "w") { |f| f << "ssh-key AAbbcc" }
75
- @client.stub(:ssh_key_available?)
76
- Shelly::User.stub(:new).and_return(@user)
76
+ user.stub(:register).with("better@example.com", "secret") { true }
77
77
  end
78
78
 
79
79
  it "should register user without local SSH Key and show message to create SSH Key" do
@@ -96,22 +96,16 @@ describe Shelly::CLI::Main do
96
96
  end
97
97
 
98
98
  it "should suggest email and use it if user enters blank email" do
99
+ user.should_receive(:register).with("kate@example.com", "secret")
99
100
  Shelly::User.stub(:guess_email).and_return("kate@example.com")
100
101
  $stdout.should_receive(:print).with("Email (kate@example.com - default): ")
101
- @client.should_receive(:register_user).with("kate@example.com", "secret", "ssh-key AAbbcc")
102
102
  fake_stdin(["", "secret", "secret", "yes"]) do
103
103
  invoke(@main, :register)
104
104
  end
105
105
  end
106
106
 
107
- it "should use email provided by user" do
108
- @client.should_receive(:register_user).with("better@example.com", "secret", "ssh-key AAbbcc")
109
- fake_stdin(["better@example.com", "secret", "secret", "yes"]) do
110
- invoke(@main, :register)
111
- end
112
- end
113
-
114
107
  it "should not ask about email if it's provided as argument" do
108
+ user.should_receive(:register).with("kate@example.com", "secret")
115
109
  $stdout.should_receive(:puts).with("Registering with email: kate@example.com")
116
110
  fake_stdin(["secret", "secret", "yes"]) do
117
111
  invoke(@main, :register, "kate@example.com")
@@ -135,7 +129,7 @@ describe Shelly::CLI::Main do
135
129
  FileUtils.mkdir_p("~/.ssh")
136
130
  File.open(@key_path, "w") { |f| f << "key" }
137
131
  $stdout.should_receive(:puts).with("Uploading your public SSH key from #{@key_path}")
138
- fake_stdin(["kate@example.com", "secret", "secret", "yes"]) do
132
+ fake_stdin(["better@example.com", "secret", "secret", "yes"]) do
139
133
  invoke(@main, :register)
140
134
  end
141
135
  end
@@ -143,10 +137,10 @@ describe Shelly::CLI::Main do
143
137
 
144
138
  context "public SSH key doesn't exist" do
145
139
  it "should register user without the public SSH key" do
146
- @user.stub(:ssh_key_registered?)
140
+ user.stub(:ssh_key_registered?)
147
141
  FileUtils.rm_rf(@key_path)
148
142
  $stdout.should_not_receive(:puts).with("Uploading your public SSH key from #{@key_path}")
149
- fake_stdin(["kate@example.com", "secret", "secret", "yes"]) do
143
+ fake_stdin(["better@example.com", "secret", "secret", "yes"]) do
150
144
  invoke(@main, :register)
151
145
  end
152
146
  end
@@ -154,10 +148,9 @@ describe Shelly::CLI::Main do
154
148
 
155
149
  context "on successful registration" do
156
150
  it "should display message about registration and email address confirmation" do
157
- @client.stub(:register_user).and_return(true)
158
151
  $stdout.should_receive(:puts).with(green "Successfully registered!")
159
152
  $stdout.should_receive(:puts).with(green "Check you mailbox for email address confirmation")
160
- fake_stdin(["kate@example.com", "pass", "pass", "yes"]) do
153
+ fake_stdin(["better@example.com", "secret", "secret", "yes"]) do
161
154
  invoke(@main, :register)
162
155
  end
163
156
  end
@@ -167,10 +160,10 @@ describe Shelly::CLI::Main do
167
160
  it "should display errors and exit with 1" do
168
161
  body = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
169
162
  exception = Shelly::Client::ValidationException.new(body)
170
- @client.stub(:register_user).and_raise(exception)
163
+ user.stub(:register).and_raise(exception)
171
164
  $stdout.should_receive(:puts).with("\e[31mEmail has been already taken\e[0m")
172
165
  lambda {
173
- fake_stdin(["kate@example.com", "pass", "pass", "yes"]) do
166
+ fake_stdin(["better@example.com", "secret", "secret", "yes"]) do
174
167
  invoke(@main, :register)
175
168
  end
176
169
  }.should raise_error(SystemExit)
@@ -191,27 +184,22 @@ describe Shelly::CLI::Main do
191
184
 
192
185
  describe "#login" do
193
186
  before do
194
- @user = Shelly::User.new
187
+ user.stub(:upload_ssh_key)
195
188
  @key_path = File.expand_path("~/.ssh/id_rsa.pub")
196
189
  FileUtils.mkdir_p("~/.ssh")
197
190
  File.open("~/.ssh/id_rsa.pub", "w") { |f| f << "ssh-key AAbbcc" }
198
- @user.stub(:upload_ssh_key)
199
- @client.stub(:token).and_return("abc")
200
191
  @client.stub(:apps).and_return([
201
192
  {"code_name" => "abc", "state" => "running",
202
193
  "state_description" => "running"},
203
194
  {"code_name" => "fooo", "state" => "no_code",
204
195
  "state_description" => "turned off (no code pushed)"},])
205
- Shelly::User.stub(:new).and_return(@user)
206
196
  end
207
197
 
208
- it "should ask about email and password" do
209
- fake_stdin(["megan@example.com", "secret"]) do
210
- invoke(@main, :login)
198
+ context "on successful login" do
199
+ before do
200
+ user.stub(:login).with("megan@example.com", "secret") { true }
211
201
  end
212
- end
213
202
 
214
- context "on successful login" do
215
203
  it "should display message about successful login" do
216
204
  $stdout.should_receive(:puts).with(green "Login successful")
217
205
  fake_stdin(["megan@example.com", "secret"]) do
@@ -227,7 +215,7 @@ describe Shelly::CLI::Main do
227
215
  end
228
216
 
229
217
  it "should upload user's public SSH key" do
230
- @user.should_receive(:upload_ssh_key)
218
+ user.should_receive(:upload_ssh_key)
231
219
  $stdout.should_receive(:puts).with("Uploading your public SSH key")
232
220
  fake_stdin(["megan@example.com", "secret"]) do
233
221
  invoke(@main, :login)
@@ -260,7 +248,7 @@ describe Shelly::CLI::Main do
260
248
  it "should exit with 1 and display error message" do
261
249
  response = {"message" => "Unauthorized", "url" => "https://admin.winniecloud.com/users/password/new"}
262
250
  exception = Shelly::Client::UnauthorizedException.new(response)
263
- @client.stub(:token).and_raise(exception)
251
+ @client.stub(:authorize_with_email_and_password).and_raise(exception)
264
252
  $stdout.should_receive(:puts).with("\e[31mWrong email or password\e[0m")
265
253
  $stdout.should_receive(:puts).with("\e[31mYou can reset password by using link:\e[0m")
266
254
  $stdout.should_receive(:puts).with("\e[31mhttps://admin.winniecloud.com/users/password/new\e[0m")
@@ -308,7 +296,7 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
308
296
  # This spec tests logged_in? hook
309
297
  it "should exit with message if user is not logged in" do
310
298
  exception = Shelly::Client::UnauthorizedException.new
311
- @client.stub(:token).and_raise(exception)
299
+ @client.stub(:authorize!).and_raise(exception)
312
300
  $stdout.should_receive(:puts).with(red "You are not logged in. To log in use: `shelly login`")
313
301
  lambda {
314
302
  fake_stdin(["", ""]) do
@@ -1209,16 +1197,8 @@ Wait until cloud is in 'turned off' state and try again.")
1209
1197
 
1210
1198
  describe "#logout" do
1211
1199
  before do
1212
- @user = Shelly::User.new
1213
- @client.stub(:token).and_return("abc")
1214
- Shelly::User.stub(:new).and_return(@user)
1215
- FileUtils.mkdir_p("~/.ssh")
1216
- FileUtils.mkdir_p("~/.shelly")
1217
- File.open("Cloudfile", 'w') { |f| f.write("foo-production:\n") }
1218
- File.open("~/.ssh/id_rsa.pub", "w") { |f| f << "ssh-key AAbbcc" }
1219
- @key_path = File.expand_path("~/.ssh/id_rsa.pub")
1220
- File.open("~/.shelly/credentials", "w") { |f| f << "megan@fox.pl\nsecret" }
1221
- @client.stub(:logout).and_return(true)
1200
+ user.stub(:logout => true)
1201
+ user.stub(:delete_ssh_key => false)
1222
1202
  end
1223
1203
 
1224
1204
  it "should ensure user has logged in" do
@@ -1226,17 +1206,16 @@ Wait until cloud is in 'turned off' state and try again.")
1226
1206
  end
1227
1207
 
1228
1208
  it "should logout from shelly cloud and show message" do
1229
- $stdout.should_receive(:puts).with("Your public SSH key has been removed from Shelly Cloud")
1230
1209
  $stdout.should_receive(:puts).with("You have been successfully logged out")
1210
+ user.should_receive(:logout)
1231
1211
  invoke(@main, :logout)
1232
- File.exists?("~/.shelly/credentials").should be_false
1233
1212
  end
1234
1213
 
1235
- it "should remove only credentiales when local ssh key doesn't exist" do
1236
- FileUtils.rm_rf(@key_path)
1237
- $stdout.should_receive(:puts).with("You have been successfully logged out")
1214
+ it "should notify user that ssh key was removed" do
1215
+ user.stub(:delete_ssh_key => true)
1216
+ $stdout.should_receive(:puts).with("Your public SSH key has been removed from Shelly Cloud")
1217
+ user.should_receive(:delete_ssh_key)
1238
1218
  invoke(@main, :logout)
1239
- File.exists?("~/.shelly/credentials").should be_false
1240
1219
  end
1241
1220
  end
1242
1221