shelly 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/core_ext/object.rb +4 -0
- data/lib/shelly/base.rb +15 -1
- data/lib/shelly/cli/account.rb +23 -18
- data/lib/shelly/cli/apps.rb +6 -2
- data/lib/shelly/cli/main.rb +3 -3
- data/lib/shelly/client.rb +3 -2
- data/lib/shelly/helpers.rb +11 -3
- data/lib/shelly/templates/Cloudfile.erb +8 -9
- data/lib/shelly/user.rb +5 -4
- data/lib/shelly/version.rb +1 -1
- data/spec/shelly/app_spec.rb +10 -11
- data/spec/shelly/base_spec.rb +35 -0
- data/spec/shelly/cli/account_spec.rb +49 -28
- data/spec/shelly/cli/apps_spec.rb +1 -0
- data/spec/shelly/cli/main_spec.rb +3 -5
- data/spec/shelly/client_spec.rb +7 -0
- metadata +6 -4
data/lib/core_ext/object.rb
CHANGED
data/lib/shelly/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
1
3
|
module Shelly
|
2
4
|
class Base
|
3
5
|
def current_user
|
@@ -6,8 +8,20 @@ module Shelly
|
|
6
8
|
@user
|
7
9
|
end
|
8
10
|
|
11
|
+
def config
|
12
|
+
@config ||= if File.exists?(config_file_path)
|
13
|
+
YAML::load(File.read(config_file_path))
|
14
|
+
else
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def config_file_path
|
20
|
+
File.join(current_user.config_dir, "config.yml")
|
21
|
+
end
|
22
|
+
|
9
23
|
def shelly
|
10
|
-
@shelly ||= Client.new(current_user.email, current_user.password)
|
24
|
+
@shelly ||= Client.new(current_user.email, current_user.password, config)
|
11
25
|
end
|
12
26
|
end
|
13
27
|
end
|
data/lib/shelly/cli/account.rb
CHANGED
@@ -6,26 +6,20 @@ module Shelly
|
|
6
6
|
namespace :account
|
7
7
|
include Helpers
|
8
8
|
|
9
|
-
desc "register", "Registers new user account on Shelly Cloud"
|
10
|
-
def register
|
11
|
-
email
|
12
|
-
|
13
|
-
|
14
|
-
# FIXME: ask user in loop, until he enters valid values
|
15
|
-
if email.blank? or password.blank?
|
16
|
-
say "Email and password can't be blank" and exit 1
|
17
|
-
end
|
18
|
-
|
19
|
-
user = User.new(email, password)
|
9
|
+
desc "register [EMAIL]", "Registers new user account on Shelly Cloud"
|
10
|
+
def register(email = nil)
|
11
|
+
say "Registering with email: #{email}" if email
|
12
|
+
user = User.new(email || ask_for_email, ask_for_password)
|
20
13
|
user.register
|
21
14
|
if user.ssh_key_exists?
|
22
15
|
say "Uploading your public SSH key from #{user.ssh_key_path}"
|
23
16
|
end
|
24
17
|
say "Successfully registered!"
|
25
|
-
say "Check you mailbox for email confirmation"
|
18
|
+
say "Check you mailbox for email address confirmation"
|
26
19
|
rescue Client::APIError => e
|
27
20
|
if e.message == "Validation Failed"
|
28
21
|
e.errors.each { |error| say "#{error.first} #{error.last}" }
|
22
|
+
exit 1
|
29
23
|
end
|
30
24
|
end
|
31
25
|
|
@@ -40,15 +34,26 @@ module Shelly
|
|
40
34
|
def ask_for_email
|
41
35
|
email_question = User.guess_email.blank? ? "Email:" : "Email (#{User.guess_email} - default):"
|
42
36
|
email = ask(email_question)
|
43
|
-
email.blank? ? User.guess_email : email
|
37
|
+
email = email.blank? ? User.guess_email : email
|
38
|
+
return email if email.present?
|
39
|
+
say_error "Email can't be blank, please try again"
|
44
40
|
end
|
45
41
|
|
46
42
|
def ask_for_password
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
loop do
|
44
|
+
say "Password: "
|
45
|
+
password = echo_disabled { $stdin.gets.strip }
|
46
|
+
say_new_line
|
47
|
+
say "Password confirmation: "
|
48
|
+
password_confirmation = echo_disabled { $stdin.gets.strip }
|
49
|
+
say_new_line
|
50
|
+
if password.present?
|
51
|
+
return password if password == password_confirmation
|
52
|
+
say "Password and password confirmation don't match, please type them again"
|
53
|
+
else
|
54
|
+
say "Password can't be blank"
|
55
|
+
end
|
56
|
+
end
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
data/lib/shelly/cli/apps.rb
CHANGED
@@ -13,13 +13,17 @@ module Shelly
|
|
13
13
|
@app.databases = ask_for_databases
|
14
14
|
@app.add_git_remote
|
15
15
|
@app.create_cloudfile
|
16
|
-
|
17
|
-
|
16
|
+
open_billing_page
|
18
17
|
info_adding_cloudfile_to_repository
|
19
18
|
info_deploying_to_shellycloud
|
20
19
|
end
|
21
20
|
|
22
21
|
no_tasks do
|
22
|
+
def open_billing_page
|
23
|
+
say "Provide billing details. Opening browser..."
|
24
|
+
@app.open_billing_page
|
25
|
+
end
|
26
|
+
|
23
27
|
def ask_for_purpose
|
24
28
|
purpose = ask("How will you use this system (production - default,staging):")
|
25
29
|
purpose.blank? ? "production" : purpose
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -16,9 +16,9 @@ module Shelly
|
|
16
16
|
say "shelly version #{Shelly::VERSION}"
|
17
17
|
end
|
18
18
|
|
19
|
-
desc "register", "Registers new user account on Shelly Cloud"
|
20
|
-
def register
|
21
|
-
invoke "account:register"
|
19
|
+
desc "register [EMAIL]", "Registers new user account on Shelly Cloud"
|
20
|
+
def register(email = nil)
|
21
|
+
invoke "account:register", email
|
22
22
|
end
|
23
23
|
|
24
24
|
desc "add", "Adds new application to Shelly Cloud"
|
data/lib/shelly/client.rb
CHANGED
@@ -19,13 +19,14 @@ module Shelly
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def initialize(email = nil, password = nil)
|
22
|
+
def initialize(email = nil, password = nil, options = {})
|
23
23
|
@email = email
|
24
24
|
@password = password
|
25
|
+
@options = options
|
25
26
|
end
|
26
27
|
|
27
28
|
def api_url
|
28
|
-
ENV["SHELLY_URL"] || "https://admin.winniecloud.com/apiv2"
|
29
|
+
@options["shelly_url"] || ENV["SHELLY_URL"] || "https://admin.winniecloud.com/apiv2"
|
29
30
|
end
|
30
31
|
|
31
32
|
def register_user(email, password, ssh_key)
|
data/lib/shelly/helpers.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
module Shelly
|
2
2
|
module Helpers
|
3
|
-
def
|
3
|
+
def echo_disabled
|
4
4
|
system "stty -echo"
|
5
|
+
value = yield
|
6
|
+
system "stty echo"
|
7
|
+
value
|
5
8
|
end
|
6
9
|
|
7
|
-
def
|
8
|
-
|
10
|
+
def say_new_line
|
11
|
+
say "\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
def say_error(message)
|
15
|
+
say message
|
16
|
+
exit 1
|
9
17
|
end
|
10
18
|
end
|
11
19
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
<%= @code_name %>:
|
2
|
-
ruby: 1.9.2
|
2
|
+
ruby: 1.9.2 # 1.9.2 or ree
|
3
|
+
environment: production # RAILS_ENV
|
3
4
|
monitoring_email:
|
4
5
|
- <%= @email %>
|
5
6
|
domains:
|
@@ -7,14 +8,12 @@
|
|
7
8
|
servers:
|
8
9
|
app1:
|
9
10
|
size: large
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
<%- @databases.each_with_index do |kind, index| -%>
|
16
|
-
<%= "#{kind}#{index}" %>:
|
11
|
+
thin: 4
|
12
|
+
# whenever: on
|
13
|
+
# delayed_job: 1
|
14
|
+
<%- @databases.each do |kind| -%>
|
15
|
+
<%= kind %>:
|
17
16
|
size: large
|
18
17
|
database:
|
19
|
-
|
18
|
+
- <%= kind %>
|
20
19
|
<%- end -%>
|
data/lib/shelly/user.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Shelly
|
2
2
|
class User < Base
|
3
3
|
attr_reader :email, :password
|
4
|
+
|
4
5
|
def initialize(email = nil, password = nil)
|
5
6
|
@email = email
|
6
7
|
@password = password
|
@@ -39,11 +40,11 @@ module Shelly
|
|
39
40
|
@@guess_email ||= IO.popen("git config --get user.email").read.strip
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
43
|
+
def config_dir
|
44
|
+
File.expand_path("~/.shelly")
|
45
|
+
end
|
46
46
|
|
47
|
+
protected
|
47
48
|
def credentials_path
|
48
49
|
File.join(config_dir, "credentials")
|
49
50
|
end
|
data/lib/shelly/version.rb
CHANGED
data/spec/shelly/app_spec.rb
CHANGED
@@ -31,7 +31,8 @@ describe Shelly::App do
|
|
31
31
|
FakeFS.deactivate!
|
32
32
|
expected = <<-config
|
33
33
|
foo-staging:
|
34
|
-
ruby: 1.9.2
|
34
|
+
ruby: 1.9.2 # 1.9.2 or ree
|
35
|
+
environment: production # RAILS_ENV
|
35
36
|
monitoring_email:
|
36
37
|
- bob@example.com
|
37
38
|
domains:
|
@@ -39,19 +40,17 @@ foo-staging:
|
|
39
40
|
servers:
|
40
41
|
app1:
|
41
42
|
size: large
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
type: cron
|
47
|
-
postgresql0:
|
43
|
+
thin: 4
|
44
|
+
# whenever: on
|
45
|
+
# delayed_job: 1
|
46
|
+
postgresql:
|
48
47
|
size: large
|
49
48
|
database:
|
50
|
-
|
51
|
-
|
49
|
+
- postgresql
|
50
|
+
mongodb:
|
52
51
|
size: large
|
53
52
|
database:
|
54
|
-
|
53
|
+
- mongodb
|
55
54
|
config
|
56
55
|
@app.generate_cloudfile.should == expected
|
57
56
|
end
|
@@ -83,7 +82,7 @@ config
|
|
83
82
|
|
84
83
|
describe "#open_billing_page" do
|
85
84
|
it "should open browser window" do
|
86
|
-
user = mock(:token => "abc", :email => nil, :password => nil)
|
85
|
+
user = mock(:token => "abc", :email => nil, :password => nil, :config_dir => "~/.shelly")
|
87
86
|
@app.stub(:current_user).and_return(user)
|
88
87
|
url = "#{@app.shelly.api_url}/apps/foo-staging/edit_billing?api_key=abc"
|
89
88
|
Launchy.should_receive(:open).with(url)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shelly::Base do
|
4
|
+
before do
|
5
|
+
config_dir = File.expand_path("~/.shelly")
|
6
|
+
FileUtils.mkdir_p(config_dir)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#current_user" do
|
10
|
+
it "should return user with loaded credentials" do
|
11
|
+
File.open(File.join("~/.shelly/credentials"), "w") { |f| f << "superman@example.com\nthe-kal-el" }
|
12
|
+
base = Shelly::Base.new
|
13
|
+
user = base.current_user
|
14
|
+
user.email.should == "superman@example.com"
|
15
|
+
user.password.should == "the-kal-el"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#config" do
|
20
|
+
context "config file exists" do
|
21
|
+
it "should return loaded config as a Hash" do
|
22
|
+
File.open("~/.shelly/config.yml", "w") { |f| f << "shelly_url: http://api.example.com/v4/\n" }
|
23
|
+
base = Shelly::Base.new
|
24
|
+
base.config.should == {"shelly_url" => "http://api.example.com/v4/"}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "config file doesn't exist" do
|
29
|
+
it "should return an empty Hash" do
|
30
|
+
base = Shelly::Base.new
|
31
|
+
base.config.should == {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -18,10 +18,11 @@ describe Shelly::CLI::Account do
|
|
18
18
|
@key_path = File.expand_path("~/.ssh/id_rsa.pub")
|
19
19
|
end
|
20
20
|
|
21
|
-
it "should ask for email and password" do
|
21
|
+
it "should ask for email, password and password confirmation" do
|
22
22
|
$stdout.should_receive(:print).with("Email: ")
|
23
23
|
$stdout.should_receive(:print).with("Password: ")
|
24
|
-
|
24
|
+
$stdout.should_receive(:print).with("Password confirmation: ")
|
25
|
+
fake_stdin(["better@example.com", "secret", "secret"]) do
|
25
26
|
@account.register
|
26
27
|
end
|
27
28
|
end
|
@@ -30,77 +31,97 @@ describe Shelly::CLI::Account do
|
|
30
31
|
Shelly::User.stub(:guess_email).and_return("kate@example.com")
|
31
32
|
$stdout.should_receive(:print).with("Email (kate@example.com - default): ")
|
32
33
|
@client.should_receive(:register_user).with("kate@example.com", "secret", nil)
|
33
|
-
fake_stdin(["", "secret"]) do
|
34
|
+
fake_stdin(["", "secret", "secret"]) do
|
34
35
|
@account.register
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
it "should use email provided by user" do
|
39
40
|
@client.should_receive(:register_user).with("better@example.com", "secret", nil)
|
40
|
-
fake_stdin(["better@example.com", "secret"]) do
|
41
|
+
fake_stdin(["better@example.com", "secret", "secret"]) do
|
41
42
|
@account.register
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
it "should
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
it "should not ask about email if it's provided as argument" do
|
47
|
+
$stdout.should_receive(:puts).with("Registering with email: kate@example.com")
|
48
|
+
fake_stdin(["secret", "secret"]) do
|
49
|
+
@account.register("kate@example.com")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when user enters blank email" do
|
54
|
+
it "should show error message and exit with 1" do
|
55
|
+
Shelly::User.stub(:guess_email).and_return("")
|
56
|
+
$stdout.should_receive(:puts).with("Email can't be blank, please try again")
|
57
|
+
lambda {
|
58
|
+
fake_stdin(["", "bob@example.com", "only-pass", "only-pass"]) do
|
59
|
+
@account.register
|
60
|
+
end
|
61
|
+
}.should raise_error(SystemExit)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when user enters blank password" do
|
66
|
+
it "should ask for it again" do
|
67
|
+
$stdout.should_receive(:puts).with("Password can't be blank")
|
68
|
+
fake_stdin(["better@example.com", "", "", "secret", "secret"]) do
|
50
69
|
@account.register
|
51
70
|
end
|
52
|
-
end
|
71
|
+
end
|
53
72
|
end
|
54
73
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
fake_stdin(["better@example.com", ""]) do
|
74
|
+
context "when user enters password and password confirmation which don't match each other" do
|
75
|
+
it "should ask for them again" do
|
76
|
+
$stdout.should_receive(:puts).with("Password and password confirmation don't match, please type them again")
|
77
|
+
fake_stdin(["better@example.com", "secret", "sec-TYPO-ret", "secret", "secret"]) do
|
59
78
|
@account.register
|
60
79
|
end
|
61
|
-
end
|
80
|
+
end
|
62
81
|
end
|
63
82
|
|
64
|
-
context "
|
65
|
-
it "should register with
|
83
|
+
context "public SSH key exists" do
|
84
|
+
it "should register with the public SSH key" do
|
66
85
|
FileUtils.mkdir_p("~/.ssh")
|
67
86
|
File.open(@key_path, "w") { |f| f << "key" }
|
68
87
|
$stdout.should_receive(:puts).with("Uploading your public SSH key from #{@key_path}")
|
69
|
-
fake_stdin(["kate@example.com", "secret"]) do
|
88
|
+
fake_stdin(["kate@example.com", "secret", "secret"]) do
|
70
89
|
@account.register
|
71
90
|
end
|
72
91
|
end
|
73
92
|
end
|
74
93
|
|
75
|
-
context "
|
76
|
-
it "should register user without the
|
94
|
+
context "public SSH key doesn't exist" do
|
95
|
+
it "should register user without the public SSH key" do
|
77
96
|
$stdout.should_not_receive(:puts).with("Uploading your public SSH key from #{@key_path}")
|
78
|
-
fake_stdin(["kate@example.com", "secret"]) do
|
97
|
+
fake_stdin(["kate@example.com", "secret", "secret"]) do
|
79
98
|
@account.register
|
80
99
|
end
|
81
100
|
end
|
82
101
|
end
|
83
102
|
|
84
103
|
context "on successful registration" do
|
85
|
-
it "should display message about registration and email confirmation" do
|
104
|
+
it "should display message about registration and email address confirmation" do
|
86
105
|
@client.stub(:register_user).and_return(true)
|
87
106
|
$stdout.should_receive(:puts).with("Successfully registered!")
|
88
|
-
$stdout.should_receive(:puts).with("Check you mailbox for email confirmation")
|
89
|
-
fake_stdin(["kate@example.com", "pass"]) do
|
107
|
+
$stdout.should_receive(:puts).with("Check you mailbox for email address confirmation")
|
108
|
+
fake_stdin(["kate@example.com", "pass", "pass"]) do
|
90
109
|
@account.register
|
91
110
|
end
|
92
111
|
end
|
93
112
|
end
|
94
113
|
|
95
114
|
context "on unsuccessful registration" do
|
96
|
-
it "should display errors" do
|
115
|
+
it "should display errors and exit with 1" do
|
97
116
|
response = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
|
98
117
|
exception = Shelly::Client::APIError.new(response)
|
99
118
|
@client.stub(:register_user).and_raise(exception)
|
100
119
|
$stdout.should_receive(:puts).with("email has been already taken")
|
101
|
-
|
102
|
-
@
|
103
|
-
|
120
|
+
lambda {
|
121
|
+
fake_stdin(["kate@example.com", "pass", "pass"]) do
|
122
|
+
@account.register
|
123
|
+
end
|
124
|
+
}.should raise_error(SystemExit)
|
104
125
|
end
|
105
126
|
end
|
106
127
|
end
|
@@ -97,6 +97,7 @@ describe Shelly::CLI::Apps do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
it "should browser window with link to edit billing information" do
|
100
|
+
$stdout.should_receive(:puts).with("Provide billing details. Opening browser...")
|
100
101
|
@app.should_receive(:open_billing_page)
|
101
102
|
fake_stdin(["staging", "foooo", ""]) do
|
102
103
|
@apps.add
|
@@ -15,8 +15,8 @@ describe Shelly::CLI::Main do
|
|
15
15
|
|
16
16
|
describe "#register" do
|
17
17
|
it "should invoke account:register command" do
|
18
|
-
@main.should_receive(:invoke).with("account:register")
|
19
|
-
@main.register
|
18
|
+
@main.should_receive(:invoke).with("account:register", "kate@example.com")
|
19
|
+
@main.register("kate@example.com")
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -27,8 +27,6 @@ describe Shelly::CLI::Main do
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
30
|
describe "#help" do
|
33
31
|
it "should display available commands" do
|
34
32
|
expected = <<-OUT
|
@@ -37,7 +35,7 @@ Tasks:
|
|
37
35
|
shelly add # Adds new application to Shelly Cloud
|
38
36
|
shelly apps <command> # Manages your applications
|
39
37
|
shelly help [TASK] # Describe available tasks or one specific task
|
40
|
-
shelly register
|
38
|
+
shelly register [EMAIL] # Registers new user account on Shelly Cloud
|
41
39
|
shelly version # Displays shelly version
|
42
40
|
OUT
|
43
41
|
out = IO.popen("bin/shelly").read.strip
|
data/spec/shelly/client_spec.rb
CHANGED
@@ -8,6 +8,13 @@ describe Shelly::Client do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "#api_url" do
|
11
|
+
context "API URL passed with options hash" do
|
12
|
+
it "should use provided value" do
|
13
|
+
client = Shelly::Client.new("bob@example.com", "secret", "shelly_url" => "https://api2.example.com")
|
14
|
+
client.api_url.should == "https://api2.example.com"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
11
18
|
context "env SHELLY_URL is not set" do
|
12
19
|
it "should return default API URL" do
|
13
20
|
ENV['SHELLY_URL'].should be_nil
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shelly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Shelly Cloud team
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-10-03 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -205,6 +205,7 @@ files:
|
|
205
205
|
- spec/helpers.rb
|
206
206
|
- spec/input_faker.rb
|
207
207
|
- spec/shelly/app_spec.rb
|
208
|
+
- spec/shelly/base_spec.rb
|
208
209
|
- spec/shelly/cli/account_spec.rb
|
209
210
|
- spec/shelly/cli/apps_spec.rb
|
210
211
|
- spec/shelly/cli/main_spec.rb
|
@@ -249,6 +250,7 @@ test_files:
|
|
249
250
|
- spec/helpers.rb
|
250
251
|
- spec/input_faker.rb
|
251
252
|
- spec/shelly/app_spec.rb
|
253
|
+
- spec/shelly/base_spec.rb
|
252
254
|
- spec/shelly/cli/account_spec.rb
|
253
255
|
- spec/shelly/cli/apps_spec.rb
|
254
256
|
- spec/shelly/cli/main_spec.rb
|