shelly 0.2.28 → 0.3.0

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.
@@ -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