shelly 0.0.6 → 0.0.7
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/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
|