shelly 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/shelly/app.rb +5 -1
- data/lib/shelly/cli/main.rb +130 -6
- data/lib/shelly/client.rb +11 -10
- data/lib/shelly/user.rb +13 -0
- data/lib/shelly/version.rb +1 -1
- data/spec/shelly/app_spec.rb +13 -0
- data/spec/shelly/cli/main_spec.rb +354 -20
- data/spec/shelly/client_spec.rb +14 -33
- data/spec/shelly/user_spec.rb +35 -0
- metadata +111 -169
- data/lib/shelly/cli/account.rb +0 -61
- data/lib/shelly/cli/apps.rb +0 -90
- data/spec/shelly/cli/account_spec.rb +0 -128
- data/spec/shelly/cli/apps_spec.rb +0 -192
data/lib/shelly/cli/account.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
require "shelly/user"
|
2
|
-
|
3
|
-
module Shelly
|
4
|
-
module CLI
|
5
|
-
class Account < Thor
|
6
|
-
namespace :account
|
7
|
-
include Helpers
|
8
|
-
|
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)
|
13
|
-
user.register
|
14
|
-
if user.ssh_key_exists?
|
15
|
-
say "Uploading your public SSH key from #{user.ssh_key_path}"
|
16
|
-
end
|
17
|
-
say "Successfully registered!"
|
18
|
-
say "Check you mailbox for email address confirmation"
|
19
|
-
rescue Client::APIError => e
|
20
|
-
if e.message == "Validation Failed"
|
21
|
-
e.errors.each { |error| say "#{error.first} #{error.last}" }
|
22
|
-
exit 1
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Fix for bug with displaying help for subcommands
|
27
|
-
# http://stackoverflow.com/questions/5663519/namespacing-thor-commands-in-a-standalone-ruby-executable
|
28
|
-
def self.banner(task, namespace = true, subcommand = false)
|
29
|
-
"#{basename} #{task.formatted_usage(self, true, subcommand)}"
|
30
|
-
end
|
31
|
-
|
32
|
-
# FIXME: move to helpers
|
33
|
-
no_tasks do
|
34
|
-
def ask_for_email
|
35
|
-
email_question = User.guess_email.blank? ? "Email:" : "Email (#{User.guess_email} - default):"
|
36
|
-
email = ask(email_question)
|
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"
|
40
|
-
end
|
41
|
-
|
42
|
-
def ask_for_password
|
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
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/shelly/cli/apps.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require "shelly/app"
|
2
|
-
|
3
|
-
module Shelly
|
4
|
-
module CLI
|
5
|
-
class Apps < Thor
|
6
|
-
include Helpers
|
7
|
-
namespace :apps
|
8
|
-
|
9
|
-
desc "add", "Adds new application to Shelly Cloud"
|
10
|
-
def add
|
11
|
-
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
12
|
-
|
13
|
-
@app = Shelly::App.new
|
14
|
-
@app.purpose = ask_for_purpose
|
15
|
-
@app.code_name = ask_for_code_name
|
16
|
-
@app.databases = ask_for_databases
|
17
|
-
@app.create
|
18
|
-
|
19
|
-
unless @app.remote_exists?
|
20
|
-
say "Adding remote #{@app.purpose} #{@app.git_url}", :green
|
21
|
-
@app.add_git_remote
|
22
|
-
else
|
23
|
-
say "Remote #{@app.purpose} already exists"
|
24
|
-
if yes?("Would you like to overwrite remote #{@app.purpose} with #{@app.git_url} (Y/N)?:")
|
25
|
-
@app.add_git_remote(true)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
say "Creating Cloudfile", :green
|
30
|
-
@app.create_cloudfile
|
31
|
-
|
32
|
-
say "Provide billing details. Opening browser...", :green
|
33
|
-
@app.open_billing_page
|
34
|
-
|
35
|
-
info_adding_cloudfile_to_repository
|
36
|
-
info_deploying_to_shellycloud
|
37
|
-
rescue Client::APIError => e
|
38
|
-
if e.message == "Validation Failed"
|
39
|
-
e.errors.each { |error| say "#{error.first} #{error.last}" }
|
40
|
-
exit 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
no_tasks do
|
45
|
-
def ask_for_purpose
|
46
|
-
purpose = ask("How will you use this system (production - default,staging):")
|
47
|
-
purpose.blank? ? "production" : purpose
|
48
|
-
end
|
49
|
-
|
50
|
-
def ask_for_code_name
|
51
|
-
default_code_name = "#{Shelly::App.guess_code_name}-#{@app.purpose}"
|
52
|
-
code_name = ask("Application code name (#{default_code_name} - default):")
|
53
|
-
code_name.blank? ? default_code_name : code_name
|
54
|
-
end
|
55
|
-
|
56
|
-
def ask_for_databases
|
57
|
-
kinds = Shelly::App::DATABASE_KINDS
|
58
|
-
databases = ask("Which database do you want to use #{kinds.join(", ")} (postgresql - default):")
|
59
|
-
begin
|
60
|
-
databases = databases.split(/[\s,]/)
|
61
|
-
valid = databases.all? { |kind| kinds.include?(kind) }
|
62
|
-
break if valid
|
63
|
-
databases = ask("Unknown database kind. Supported are: #{kinds.join(", ")}:")
|
64
|
-
end while not valid
|
65
|
-
|
66
|
-
databases.empty? ? ["postgresql"] : databases
|
67
|
-
end
|
68
|
-
|
69
|
-
def info_adding_cloudfile_to_repository
|
70
|
-
say_new_line
|
71
|
-
say "Project is now configured for use with Shell Cloud:", :green
|
72
|
-
say "You can review changes using", :green
|
73
|
-
say " git diff"
|
74
|
-
end
|
75
|
-
|
76
|
-
def info_deploying_to_shellycloud
|
77
|
-
say_new_line
|
78
|
-
say "When you make sure all settings are correct please issue following commands:", :green
|
79
|
-
say " git add ."
|
80
|
-
say ' git commit -m "Application added to Shelly Cloud"'
|
81
|
-
say " git push"
|
82
|
-
say_new_line
|
83
|
-
say "Deploy to #{@app.purpose} using:", :green
|
84
|
-
say " git push #{@app.purpose} master"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
@@ -1,128 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "shelly/cli/account"
|
3
|
-
|
4
|
-
describe Shelly::CLI::Account do
|
5
|
-
before do
|
6
|
-
FileUtils.stub(:chmod)
|
7
|
-
@client = mock
|
8
|
-
@account = Shelly::CLI::Account.new
|
9
|
-
Shelly::Client.stub(:new).and_return(@client)
|
10
|
-
$stdout.stub(:puts)
|
11
|
-
$stdout.stub(:print)
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#register" do
|
15
|
-
before do
|
16
|
-
Shelly::User.stub(:guess_email).and_return("")
|
17
|
-
@client.stub(:register_user)
|
18
|
-
@key_path = File.expand_path("~/.ssh/id_rsa.pub")
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should ask for email, password and password confirmation" do
|
22
|
-
$stdout.should_receive(:print).with("Email: ")
|
23
|
-
$stdout.should_receive(:print).with("Password: ")
|
24
|
-
$stdout.should_receive(:print).with("Password confirmation: ")
|
25
|
-
fake_stdin(["better@example.com", "secret", "secret"]) do
|
26
|
-
@account.register
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should suggest email and use it if user enters blank email" do
|
31
|
-
Shelly::User.stub(:guess_email).and_return("kate@example.com")
|
32
|
-
$stdout.should_receive(:print).with("Email (kate@example.com - default): ")
|
33
|
-
@client.should_receive(:register_user).with("kate@example.com", "secret", nil)
|
34
|
-
fake_stdin(["", "secret", "secret"]) do
|
35
|
-
@account.register
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should use email provided by user" do
|
40
|
-
@client.should_receive(:register_user).with("better@example.com", "secret", nil)
|
41
|
-
fake_stdin(["better@example.com", "secret", "secret"]) do
|
42
|
-
@account.register
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
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
|
69
|
-
@account.register
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
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
|
78
|
-
@account.register
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "public SSH key exists" do
|
84
|
-
it "should register with the public SSH key" do
|
85
|
-
FileUtils.mkdir_p("~/.ssh")
|
86
|
-
File.open(@key_path, "w") { |f| f << "key" }
|
87
|
-
$stdout.should_receive(:puts).with("Uploading your public SSH key from #{@key_path}")
|
88
|
-
fake_stdin(["kate@example.com", "secret", "secret"]) do
|
89
|
-
@account.register
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
context "public SSH key doesn't exist" do
|
95
|
-
it "should register user without the public SSH key" do
|
96
|
-
$stdout.should_not_receive(:puts).with("Uploading your public SSH key from #{@key_path}")
|
97
|
-
fake_stdin(["kate@example.com", "secret", "secret"]) do
|
98
|
-
@account.register
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
context "on successful registration" do
|
104
|
-
it "should display message about registration and email address confirmation" do
|
105
|
-
@client.stub(:register_user).and_return(true)
|
106
|
-
$stdout.should_receive(:puts).with("Successfully registered!")
|
107
|
-
$stdout.should_receive(:puts).with("Check you mailbox for email address confirmation")
|
108
|
-
fake_stdin(["kate@example.com", "pass", "pass"]) do
|
109
|
-
@account.register
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
context "on unsuccessful registration" do
|
115
|
-
it "should display errors and exit with 1" do
|
116
|
-
response = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
|
117
|
-
exception = Shelly::Client::APIError.new(response)
|
118
|
-
@client.stub(:register_user).and_raise(exception)
|
119
|
-
$stdout.should_receive(:puts).with("email has been already taken")
|
120
|
-
lambda {
|
121
|
-
fake_stdin(["kate@example.com", "pass", "pass"]) do
|
122
|
-
@account.register
|
123
|
-
end
|
124
|
-
}.should raise_error(SystemExit)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
@@ -1,192 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "shelly/cli/apps"
|
3
|
-
|
4
|
-
describe Shelly::CLI::Apps do
|
5
|
-
before do
|
6
|
-
@apps = Shelly::CLI::Apps.new
|
7
|
-
$stdout.stub(:print)
|
8
|
-
$stdout.stub(:puts)
|
9
|
-
end
|
10
|
-
|
11
|
-
describe "#add" do
|
12
|
-
before do
|
13
|
-
FileUtils.mkdir_p("/projects/foo")
|
14
|
-
Dir.chdir("/projects/foo")
|
15
|
-
@app = Shelly::App.new
|
16
|
-
@app.stub(:add_git_remote)
|
17
|
-
@app.stub(:create)
|
18
|
-
@app.stub(:generate_cloudfile).and_return("Example Cloudfile")
|
19
|
-
@app.stub(:open_billing_page)
|
20
|
-
@app.stub(:remote_exists?).and_return(false)
|
21
|
-
Shelly::App.stub(:inside_git_repository?).and_return(true)
|
22
|
-
Shelly::App.stub(:new).and_return(@app)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should exit with message if command run outside git repository" do
|
26
|
-
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
27
|
-
$stdout.should_receive(:puts).with("Must be run inside your project git repository")
|
28
|
-
lambda {
|
29
|
-
fake_stdin(["staging", "", ""]) do
|
30
|
-
@apps.add
|
31
|
-
end
|
32
|
-
}.should raise_error(SystemExit)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should ask user how he will use application" do
|
36
|
-
$stdout.should_receive(:print).with("How will you use this system (production - default,staging): ")
|
37
|
-
@app.should_receive(:purpose=).with("staging")
|
38
|
-
fake_stdin(["staging", "", ""]) do
|
39
|
-
@apps.add
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context "when user provided empty purpose" do
|
44
|
-
it "should use 'production' as default" do
|
45
|
-
$stdout.should_receive(:print).with("How will you use this system (production - default,staging): ")
|
46
|
-
@app.should_receive(:purpose=).with("production")
|
47
|
-
fake_stdin(["", "", ""]) do
|
48
|
-
@apps.add
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should use code name provided by user" do
|
54
|
-
$stdout.should_receive(:print).with("How will you use this system (production - default,staging): ")
|
55
|
-
$stdout.should_receive(:print).with("Application code name (foo-staging - default): ")
|
56
|
-
@app.should_receive(:code_name=).with("mycodename")
|
57
|
-
fake_stdin(["staging", "mycodename", ""]) do
|
58
|
-
@apps.add
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context "when user provided empty code name" do
|
63
|
-
it "should use 'current_dirname-purpose' as default" do
|
64
|
-
$stdout.should_receive(:print).with("How will you use this system (production - default,staging): ")
|
65
|
-
$stdout.should_receive(:print).with("Application code name (foo-staging - default): ")
|
66
|
-
fake_stdin(["staging", "", ""]) do
|
67
|
-
@apps.add
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should use database provided by user (separated by comma or space)" do
|
73
|
-
$stdout.should_receive(:print).with("Which database do you want to use postgresql, mongodb, redis, none (postgresql - default): ")
|
74
|
-
@app.should_receive(:databases=).with(["postgresql", "mongodb", "redis"])
|
75
|
-
fake_stdin(["staging", "", "postgresql,mongodb redis"]) do
|
76
|
-
@apps.add
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should ask again for databases if unsupported kind typed" do
|
81
|
-
$stdout.should_receive(:print).with("Which database do you want to use postgresql, mongodb, redis, none (postgresql - default): ")
|
82
|
-
$stdout.should_receive(:print).with("Unknown database kind. Supported are: postgresql, mongodb, redis, none: ")
|
83
|
-
fake_stdin(["staging", "", "postgresql,doesnt-exist", "none"]) do
|
84
|
-
@apps.add
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context "when user provided empty database" do
|
89
|
-
it "should use 'postgresql' database as default" do
|
90
|
-
@app.should_receive(:databases=).with(["postgresql"])
|
91
|
-
fake_stdin(["staging", "", ""]) do
|
92
|
-
@apps.add
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
it "should create the app on shelly cloud" do
|
98
|
-
@app.should_receive(:create)
|
99
|
-
fake_stdin(["", "", ""]) do
|
100
|
-
@apps.add
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
it "should display validation errors if they are any" do
|
105
|
-
response = {"message" => "Validation Failed", "errors" => [["code_name", "has been already taken"]]}
|
106
|
-
exception = Shelly::Client::APIError.new(response)
|
107
|
-
@app.should_receive(:create).and_raise(exception)
|
108
|
-
$stdout.should_receive(:puts).with("code_name has been already taken")
|
109
|
-
lambda {
|
110
|
-
fake_stdin(["", "", ""]) do
|
111
|
-
@apps.add
|
112
|
-
end
|
113
|
-
}.should raise_error(SystemExit)
|
114
|
-
end
|
115
|
-
|
116
|
-
context "git remote doesn't exist" do
|
117
|
-
it "should add git remote" do
|
118
|
-
$stdout.should_receive(:puts).with("\e[32mAdding remote staging git@git.shellycloud.com:foooo.git\e[0m")
|
119
|
-
@app.should_receive(:add_git_remote)
|
120
|
-
fake_stdin(["staging", "foooo", ""]) do
|
121
|
-
@apps.add
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context "git remote exist" do
|
127
|
-
before do
|
128
|
-
@app.stub(:remote_exists?).and_return(true)
|
129
|
-
end
|
130
|
-
|
131
|
-
it "should ask user if he wants to overwrite existing git remote" do
|
132
|
-
$stdout.should_receive(:puts).with("Remote staging already exists")
|
133
|
-
$stdout.should_receive(:print).with("Would you like to overwrite remote staging with git@git.shellycloud.com:foooo.git (Y/N)?: ")
|
134
|
-
fake_stdin(["staging", "foooo", "", "y"]) do
|
135
|
-
@apps.add
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
it "should overwrite existing git remote on 'yes' from user" do
|
140
|
-
@app.should_receive(:add_git_remote).with(true)
|
141
|
-
fake_stdin(["staging", "foooo", "", "y"]) do
|
142
|
-
@apps.add
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
it "should not overwrite existing git remote on 'no' from user" do
|
147
|
-
@app.should_not_receive(:add_git_remote).with(true)
|
148
|
-
fake_stdin(["staging", "foooo", "", "n"]) do
|
149
|
-
@apps.add
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
it "should create Cloudfile" do
|
155
|
-
File.exists?("/projects/foo/Cloudfile").should be_false
|
156
|
-
fake_stdin(["staging", "foooo", ""]) do
|
157
|
-
@apps.add
|
158
|
-
end
|
159
|
-
File.read("/projects/foo/Cloudfile").should == "Example Cloudfile"
|
160
|
-
end
|
161
|
-
|
162
|
-
it "should browser window with link to edit billing information" do
|
163
|
-
$stdout.should_receive(:puts).with("\e[32mProvide billing details. Opening browser...\e[0m")
|
164
|
-
@app.should_receive(:open_billing_page)
|
165
|
-
fake_stdin(["staging", "foooo", ""]) do
|
166
|
-
@apps.add
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
it "should display info about adding Cloudfile to repository" do
|
171
|
-
$stdout.should_receive(:puts).with("\e[32mProject is now configured for use with Shell Cloud:\e[0m")
|
172
|
-
$stdout.should_receive(:puts).with("\e[32mYou can review changes using\e[0m")
|
173
|
-
$stdout.should_receive(:puts).with(" git diff")
|
174
|
-
fake_stdin(["staging", "foooo", "none"]) do
|
175
|
-
@apps.add
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
it "should display info on how to deploy to ShellyCloud" do
|
180
|
-
$stdout.should_receive(:puts).with("\e[32mWhen you make sure all settings are correct please issue following commands:\e[0m")
|
181
|
-
$stdout.should_receive(:puts).with(" git add .")
|
182
|
-
$stdout.should_receive(:puts).with(' git commit -m "Application added to Shelly Cloud"')
|
183
|
-
$stdout.should_receive(:puts).with(" git push")
|
184
|
-
$stdout.should_receive(:puts).with("\e[32mDeploy to staging using:\e[0m")
|
185
|
-
$stdout.should_receive(:puts).with(" git push staging master")
|
186
|
-
fake_stdin(["staging", "foooo", "none"]) do
|
187
|
-
@apps.add
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|