shelly 0.0.16 → 0.0.17
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/core_ext/hash.rb +17 -0
- data/lib/shelly.rb +4 -0
- data/lib/shelly/app.rb +6 -6
- data/lib/shelly/cli/main.rb +37 -44
- data/lib/shelly/cli/users.rb +18 -8
- data/lib/shelly/client.rb +21 -1
- data/lib/shelly/cloudfile.rb +45 -0
- data/lib/shelly/helpers.rb +11 -0
- data/lib/shelly/user.rb +6 -1
- data/lib/shelly/version.rb +1 -1
- data/lib/thor/options.rb +12 -0
- data/spec/shelly/app_spec.rb +46 -20
- data/spec/shelly/cli/main_spec.rb +58 -47
- data/spec/shelly/cli/users_spec.rb +62 -10
- data/spec/shelly/client_spec.rb +37 -4
- data/spec/shelly/cloudfile_spec.rb +38 -0
- data/spec/shelly/user_spec.rb +9 -1
- metadata +31 -26
@@ -0,0 +1,17 @@
|
|
1
|
+
class Hash
|
2
|
+
def deep_stringify_keys
|
3
|
+
new_hash = {}
|
4
|
+
self.each do |key, value|
|
5
|
+
new_hash.merge!(key.to_s => (value.is_a?(Hash) ? value.deep_stringify_keys : value))
|
6
|
+
end
|
7
|
+
new_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def deep_symbolize_keys
|
11
|
+
new_hash = {}
|
12
|
+
self.each do |key, value|
|
13
|
+
new_hash.merge!(key.to_sym => (value.is_a?(Hash) ? value.deep_symbolize_keys : value))
|
14
|
+
end
|
15
|
+
new_hash
|
16
|
+
end
|
17
|
+
end
|
data/lib/shelly.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "thor"
|
3
3
|
require "core_ext/object"
|
4
|
+
require "core_ext/hash"
|
4
5
|
require "shelly/helpers"
|
5
6
|
require "shelly/base"
|
7
|
+
require "thor/options"
|
6
8
|
|
7
9
|
module Shelly
|
8
10
|
autoload :App, "shelly/app"
|
11
|
+
autoload :Cloudfile, "shelly/cloudfile"
|
9
12
|
autoload :Client, "shelly/client"
|
10
13
|
autoload :User, "shelly/user"
|
11
14
|
autoload :VERSION, "shelly/version"
|
12
15
|
end
|
16
|
+
|
data/lib/shelly/app.rb
CHANGED
@@ -4,7 +4,7 @@ require 'launchy'
|
|
4
4
|
module Shelly
|
5
5
|
class App < Base
|
6
6
|
DATABASE_KINDS = %w(postgresql mongodb redis none)
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :code_name, :databases, :ruby_version, :environment, :git_url, :domains
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
@ruby_version = "MRI-1.9.2"
|
@@ -12,14 +12,14 @@ module Shelly
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def add_git_remote
|
15
|
-
system("git remote rm
|
16
|
-
system("git remote add
|
15
|
+
system("git remote rm production &> /dev/null")
|
16
|
+
system("git remote add production #{git_url}")
|
17
17
|
end
|
18
18
|
|
19
19
|
def generate_cloudfile
|
20
20
|
@email = current_user.email
|
21
21
|
@databases = databases
|
22
|
-
@domains = domains
|
22
|
+
@domains = domains
|
23
23
|
template = File.read(cloudfile_template_path)
|
24
24
|
cloudfile = ERB.new(template, 0, "%<>-")
|
25
25
|
cloudfile.result(binding)
|
@@ -35,10 +35,11 @@ module Shelly
|
|
35
35
|
:code_name => code_name,
|
36
36
|
:environment => environment,
|
37
37
|
:ruby_version => ruby_version,
|
38
|
-
:domain_name =>
|
38
|
+
:domain_name => domains
|
39
39
|
}
|
40
40
|
response = shelly.create_app(attributes)
|
41
41
|
self.git_url = response["git_url"]
|
42
|
+
self.domains = response["domain_name"].split if domains.nil?
|
42
43
|
end
|
43
44
|
|
44
45
|
def create_cloudfile
|
@@ -68,4 +69,3 @@ module Shelly
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
end
|
71
|
-
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -8,6 +8,7 @@ module Shelly
|
|
8
8
|
include Thor::Actions
|
9
9
|
include Helpers
|
10
10
|
register(Users, "users", "users <command>", "Manages users using this app")
|
11
|
+
check_unknown_options!
|
11
12
|
|
12
13
|
map %w(-v --version) => :version
|
13
14
|
desc "version", "Displays shelly version"
|
@@ -30,15 +31,16 @@ module Shelly
|
|
30
31
|
say "Check you mailbox for email address confirmation"
|
31
32
|
rescue Client::APIError => e
|
32
33
|
if e.validation?
|
33
|
-
e.
|
34
|
-
say_error "#{error.first} #{error.last}", :with_exit => false
|
35
|
-
end
|
34
|
+
e.each_error { |error| say_error "#{error}", :with_exit => false }
|
36
35
|
exit 1
|
37
36
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
rescue RestClient::Conflict
|
38
|
+
say_error "User with your ssh key already exists.", :with_exit => false
|
39
|
+
say_error "You can login using: shelly login [EMAIL]", :with_exit => false
|
40
|
+
exit 1
|
41
|
+
rescue Errno::ENOENT => e
|
42
|
+
say_error e, :with_exit => false
|
43
|
+
say_error "Use ssh-keygen to generate ssh key pair"
|
42
44
|
end
|
43
45
|
|
44
46
|
desc "login [EMAIL]", "Logins user to Shelly Cloud"
|
@@ -52,40 +54,38 @@ module Shelly
|
|
52
54
|
user.apps.each do |app|
|
53
55
|
say " #{app["code_name"]}"
|
54
56
|
end
|
55
|
-
rescue RestClient::Unauthorized
|
56
|
-
say_error "Wrong email or password", :with_exit => false
|
57
|
-
say_error "You can reset password by using link:", :with_exit => false
|
58
|
-
say_error "https://admin.winniecloud.com/users/password/new", :with_exit => false
|
59
|
-
exit 1
|
60
57
|
rescue Client::APIError => e
|
61
58
|
if e.validation?
|
62
|
-
e.
|
59
|
+
e.each_error { |error| say_error "#{error}", :with_exit => false }
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
if e.unauthorized?
|
63
|
+
say_error "Wrong email or password", :with_exit => false
|
64
|
+
say_error "You can reset password by using link:", :with_exit => false
|
65
|
+
say_error "#{e.url}", :with_exit => false
|
63
66
|
exit 1
|
64
67
|
end
|
65
68
|
end
|
66
69
|
|
67
|
-
method_option
|
70
|
+
method_option "code-name", :type => :string, :aliases => "-c",
|
68
71
|
:desc => "Unique code_name of your application"
|
69
|
-
method_option :environment, :type => :string, :aliases => "-e",
|
70
|
-
:desc => "Environment that your application will be running"
|
71
72
|
method_option :databases, :type => :array, :aliases => "-d",
|
72
73
|
:banner => "#{Shelly::App::DATABASE_KINDS.join(' ')}",
|
73
74
|
:desc => "Array of databases of your choice"
|
74
75
|
method_option :domains, :type => :array,
|
75
|
-
:banner => "
|
76
|
+
:banner => "CODE-NAME.shellyapp.com YOUR-DOMAIN.com",
|
76
77
|
:desc => "Array of your domains"
|
77
78
|
desc "add", "Adds new application to Shelly Cloud"
|
78
79
|
def add
|
79
80
|
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
80
81
|
check_options(options)
|
81
82
|
@app = Shelly::App.new
|
82
|
-
@app.
|
83
|
-
@app.code_name = options["code_name"] || ask_for_code_name
|
83
|
+
@app.code_name = options["code-name"] || ask_for_code_name
|
84
84
|
@app.databases = options["databases"] || ask_for_databases
|
85
85
|
@app.domains = options["domains"]
|
86
86
|
@app.create
|
87
87
|
|
88
|
-
say "Adding remote
|
88
|
+
say "Adding remote production #{@app.git_url}", :green
|
89
89
|
@app.add_git_remote
|
90
90
|
|
91
91
|
say "Creating Cloudfile", :green
|
@@ -96,22 +96,28 @@ module Shelly
|
|
96
96
|
|
97
97
|
info_adding_cloudfile_to_repository
|
98
98
|
info_deploying_to_shellycloud
|
99
|
+
|
99
100
|
rescue Client::APIError => e
|
100
101
|
if e.validation?
|
101
|
-
e.
|
102
|
-
|
102
|
+
e.each_error { |error| say_error "#{error}", :with_exit => false }
|
103
|
+
say_new_line
|
104
|
+
say_error "Fix erros in the below command and type it again to create your application" , :with_exit => false
|
105
|
+
say_error "shelly add --code-name=#{@app.code_name} --databases=#{@app.databases.join} --domains=#{@app.code_name}.shellyapp.com"
|
103
106
|
end
|
104
107
|
end
|
105
108
|
|
106
109
|
# FIXME: move to helpers
|
107
110
|
no_tasks do
|
108
111
|
def check_options(options)
|
109
|
-
unless
|
110
|
-
options.
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
unless options.empty?
|
113
|
+
options["domains"].map! {|domain| domain.gsub(",", "") } if options["domains"]
|
114
|
+
options["databases"].map! {|kind| kind.gsub(",", "") } if options["databases"]
|
115
|
+
unless ["code-name", "databases", "domains"].all? do |option|
|
116
|
+
options.include?(option.to_s) && options[option.to_s] != option.to_s
|
117
|
+
end && valid_databases?(options["databases"])
|
118
|
+
say_error "Try 'shelly help add' for more information"
|
119
|
+
end
|
120
|
+
end
|
115
121
|
end
|
116
122
|
|
117
123
|
def valid_databases?(databases)
|
@@ -119,14 +125,6 @@ module Shelly
|
|
119
125
|
databases.all? { |kind| kinds.include?(kind) }
|
120
126
|
end
|
121
127
|
|
122
|
-
def ask_for_email
|
123
|
-
email_question = User.guess_email.blank? ? "Email:" : "Email (#{User.guess_email} - default):"
|
124
|
-
email = ask(email_question)
|
125
|
-
email = email.blank? ? User.guess_email : email
|
126
|
-
return email if email.present?
|
127
|
-
say_error "Email can't be blank, please try again"
|
128
|
-
end
|
129
|
-
|
130
128
|
def ask_for_password(options = {})
|
131
129
|
options = {:with_confirmation => true}.merge(options)
|
132
130
|
loop do
|
@@ -146,13 +144,8 @@ module Shelly
|
|
146
144
|
end
|
147
145
|
end
|
148
146
|
|
149
|
-
def ask_for_purpose
|
150
|
-
purpose = ask("How will you use this system (production - default,staging):")
|
151
|
-
purpose.blank? ? "production" : purpose
|
152
|
-
end
|
153
|
-
|
154
147
|
def ask_for_code_name
|
155
|
-
default_code_name = "#{Shelly::App.guess_code_name}
|
148
|
+
default_code_name = "#{Shelly::App.guess_code_name}-production"
|
156
149
|
code_name = ask("Application code name (#{default_code_name} - default):")
|
157
150
|
code_name.blank? ? default_code_name : code_name
|
158
151
|
end
|
@@ -184,8 +177,8 @@ module Shelly
|
|
184
177
|
say ' git commit -m "Application added to Shelly Cloud"'
|
185
178
|
say " git push"
|
186
179
|
say_new_line
|
187
|
-
say "Deploy to
|
188
|
-
say " git push
|
180
|
+
say "Deploy to production using:", :green
|
181
|
+
say " git push production master"
|
189
182
|
say_new_line
|
190
183
|
end
|
191
184
|
end
|
data/lib/shelly/cli/users.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "yaml"
|
2
2
|
require "shelly/user"
|
3
|
+
require "shelly/cloudfile"
|
3
4
|
|
4
5
|
module Shelly
|
5
6
|
module CLI
|
@@ -10,20 +11,29 @@ module Shelly
|
|
10
11
|
desc "list", "List users who have access to current application"
|
11
12
|
def list
|
12
13
|
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
13
|
-
|
14
|
-
@app
|
15
|
-
|
16
|
-
|
17
|
-
say "Cloud #{app['code_name']}:"
|
18
|
-
app['users'].each do |user|
|
19
|
-
say " #{user['email']} (#{user['name']})"
|
20
|
-
end
|
14
|
+
@cloudfile = Shelly::Cloudfile.new
|
15
|
+
@cloudfile.fetch_users.each do |app, users|
|
16
|
+
say "Cloud #{app}:"
|
17
|
+
users.each { |user| say " #{user}" }
|
21
18
|
end
|
22
19
|
rescue Client::APIError => e
|
23
20
|
say e.message
|
24
21
|
exit 1
|
25
22
|
end
|
26
23
|
|
24
|
+
desc "add [EMAIL]", "Add new developer to applications defined in Cloudfile"
|
25
|
+
def add(email = nil)
|
26
|
+
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
27
|
+
user_email = email || ask_for_email({:guess_email => false})
|
28
|
+
@cloudfile = Shelly::Cloudfile.new
|
29
|
+
@user = Shelly::User.new
|
30
|
+
@user.send_invitation(@cloudfile.clouds, user_email)
|
31
|
+
say "Sending invitation to #{user_email}"
|
32
|
+
rescue Client::APIError => e
|
33
|
+
say e.message
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
|
27
37
|
end
|
28
38
|
end
|
29
39
|
end
|
data/lib/shelly/client.rb
CHANGED
@@ -16,9 +16,23 @@ module Shelly
|
|
16
16
|
@response["errors"]
|
17
17
|
end
|
18
18
|
|
19
|
+
def url
|
20
|
+
@response["url"]
|
21
|
+
end
|
22
|
+
|
19
23
|
def validation?
|
20
24
|
message == "Validation Failed"
|
21
25
|
end
|
26
|
+
|
27
|
+
def unauthorized?
|
28
|
+
message == "Unauthorized"
|
29
|
+
end
|
30
|
+
|
31
|
+
def each_error
|
32
|
+
@response["errors"].each do |index,message|
|
33
|
+
yield index.gsub('_',' ').capitalize + " " + message
|
34
|
+
end
|
35
|
+
end
|
22
36
|
end
|
23
37
|
|
24
38
|
def initialize(email = nil, password = nil)
|
@@ -42,6 +56,12 @@ module Shelly
|
|
42
56
|
get("/token")
|
43
57
|
end
|
44
58
|
|
59
|
+
def send_invitation(apps, email)
|
60
|
+
apps.map do |app|
|
61
|
+
post("/apps/#{app}/collaborations", :email => email)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
45
65
|
def create_app(attributes)
|
46
66
|
post("/apps", :app => attributes)
|
47
67
|
end
|
@@ -102,7 +122,7 @@ module Shelly
|
|
102
122
|
end
|
103
123
|
|
104
124
|
def process_response(response)
|
105
|
-
if [404, 422, 500].include?(response.code)
|
125
|
+
if [401, 404, 422, 500].include?(response.code)
|
106
126
|
raise APIError.new(response.body)
|
107
127
|
end
|
108
128
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Shelly
|
2
|
+
class Cloudfile < Base
|
3
|
+
attr_accessor :content
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
open if File.exists?(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
File.join(Dir.pwd, "Cloudfile")
|
11
|
+
end
|
12
|
+
|
13
|
+
def open
|
14
|
+
@content = YAML.load(File.open(path))
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(hash)
|
18
|
+
@content = hash
|
19
|
+
File.open(path, "w") do |f|
|
20
|
+
f.write(yaml(hash))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def clouds
|
25
|
+
@content.keys.sort
|
26
|
+
end
|
27
|
+
|
28
|
+
def yaml(hash)
|
29
|
+
string = hash.deep_stringify_keys.to_yaml
|
30
|
+
# FIXME: check if it possible to remove sub("---", "") by passing options to_yaml
|
31
|
+
string.sub("---","").split("\n").map(&:rstrip).join("\n").strip
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_users
|
35
|
+
response = shelly.app_users(clouds)
|
36
|
+
response.inject({}) do |result, app|
|
37
|
+
result[app['code_name']] = app['users'].map do |user|
|
38
|
+
"#{user['email']} (#{user['name']})"
|
39
|
+
end
|
40
|
+
result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
data/lib/shelly/helpers.rb
CHANGED
@@ -16,5 +16,16 @@ module Shelly
|
|
16
16
|
say message, :red
|
17
17
|
exit 1 if options[:with_exit]
|
18
18
|
end
|
19
|
+
|
20
|
+
def ask_for_email(options = {})
|
21
|
+
options = {:guess_email => true}.merge(options)
|
22
|
+
email_question = options[:guess_email] && !User.guess_email.blank? ? "Email (#{User.guess_email} - default):" : "Email:"
|
23
|
+
email = ask(email_question)
|
24
|
+
email = email.blank? ? User.guess_email : email
|
25
|
+
return email if email.present?
|
26
|
+
say_error "Email can't be blank, please try again"
|
27
|
+
end
|
28
|
+
|
19
29
|
end
|
20
30
|
end
|
31
|
+
|
data/lib/shelly/user.rb
CHANGED
@@ -29,6 +29,10 @@ module Shelly
|
|
29
29
|
shelly.token["token"]
|
30
30
|
end
|
31
31
|
|
32
|
+
def send_invitation(apps, email)
|
33
|
+
shelly.send_invitation(apps, email)
|
34
|
+
end
|
35
|
+
|
32
36
|
def load_credentials
|
33
37
|
return unless credentials_exists?
|
34
38
|
@email, @password = File.read(credentials_path).split("\n")
|
@@ -47,7 +51,7 @@ module Shelly
|
|
47
51
|
def ssh_key_path
|
48
52
|
File.expand_path("~/.ssh/id_rsa.pub")
|
49
53
|
end
|
50
|
-
|
54
|
+
|
51
55
|
def ssh_key_registered?
|
52
56
|
ssh_key = File.read(ssh_key_path).strip
|
53
57
|
shelly.ssh_key_available?(ssh_key)
|
@@ -81,3 +85,4 @@ module Shelly
|
|
81
85
|
end
|
82
86
|
end
|
83
87
|
end
|
88
|
+
|
data/lib/shelly/version.rb
CHANGED
data/lib/thor/options.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class Thor
|
2
|
+
class Options < Arguments
|
3
|
+
|
4
|
+
def check_unknown!
|
5
|
+
raise UnknownArgumentError, "shelly: unrecognized option '#{@unknown.join(', ')}'\n" +
|
6
|
+
"Usage: shelly [COMMAND]... [OPTIONS]\n" +
|
7
|
+
"Try 'shelly --help' for more information" unless @unknown.empty?
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
data/spec/shelly/app_spec.rb
CHANGED
@@ -8,7 +8,6 @@ describe Shelly::App do
|
|
8
8
|
@client = mock(:api_url => "https://api.example.com", :shellyapp_url => "http://shellyapp.example.com")
|
9
9
|
Shelly::Client.stub(:new).and_return(@client)
|
10
10
|
@app = Shelly::App.new
|
11
|
-
@app.purpose = "staging"
|
12
11
|
@app.code_name = "foo-staging"
|
13
12
|
end
|
14
13
|
|
@@ -42,12 +41,12 @@ describe Shelly::App do
|
|
42
41
|
end
|
43
42
|
|
44
43
|
it "should try to remove existing git remote" do
|
45
|
-
@app.should_receive(:system).with("git remote rm
|
44
|
+
@app.should_receive(:system).with("git remote rm production &> /dev/null")
|
46
45
|
@app.add_git_remote
|
47
46
|
end
|
48
47
|
|
49
48
|
it "should add git remote with proper name and git repository" do
|
50
|
-
@app.should_receive(:system).with("git remote add
|
49
|
+
@app.should_receive(:system).with("git remote add production git@git.shellycloud.com:foo-staging.git")
|
51
50
|
@app.add_git_remote
|
52
51
|
end
|
53
52
|
end
|
@@ -122,25 +121,52 @@ config
|
|
122
121
|
end
|
123
122
|
|
124
123
|
describe "#create" do
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
124
|
+
context "without providing domain" do
|
125
|
+
it "should create the app on shelly cloud via API client" do
|
126
|
+
@app.code_name = "fooo"
|
127
|
+
attributes = {
|
128
|
+
:code_name => "fooo",
|
129
|
+
:name => "fooo",
|
130
|
+
:environment => "production",
|
131
|
+
:ruby_version => "MRI-1.9.2",
|
132
|
+
:domain_name => nil
|
133
|
+
}
|
134
|
+
@client.should_receive(:create_app).with(attributes).and_return("git_url" => "git@git.shellycloud.com:fooo.git",
|
135
|
+
"domain_name" => "fooo.shellyapp.com")
|
136
|
+
@app.create
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should assign returned git_url and domain" do
|
140
|
+
@client.stub(:create_app).and_return("git_url" => "git@git.example.com:fooo.git",
|
141
|
+
"domain_name" => "fooo.shellyapp.com")
|
142
|
+
@app.create
|
143
|
+
@app.git_url.should == "git@git.example.com:fooo.git"
|
144
|
+
@app.domains.should == ["fooo.shellyapp.com"]
|
145
|
+
end
|
137
146
|
end
|
138
147
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
148
|
+
context "with providing domain" do
|
149
|
+
it "should create the app on shelly cloud via API client" do
|
150
|
+
@app.code_name = "boo"
|
151
|
+
@app.domains = ["boo.shellyapp.com", "boo.example.com"]
|
152
|
+
attributes = {
|
153
|
+
:code_name => "boo",
|
154
|
+
:name => "boo",
|
155
|
+
:environment => "production",
|
156
|
+
:ruby_version => "MRI-1.9.2",
|
157
|
+
:domain_name => ["boo.shellyapp.com", "boo.example.com"]
|
158
|
+
}
|
159
|
+
@client.should_receive(:create_app).with(attributes).and_return("git_url" => "git@git.shellycloud.com:fooo.git",
|
160
|
+
"domain_name" => "boo.shellyapp.com boo.example.com")
|
161
|
+
@app.create
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should assign returned git_url and domain" do
|
165
|
+
@client.stub(:create_app).and_return("git_url" => "git@git.example.com:fooo.git",
|
166
|
+
"domain_name" => "boo.shellyapp.com boo.example.com")
|
167
|
+
@app.create
|
168
|
+
@app.domains.should == ["boo.shellyapp.com", "boo.example.com"]
|
169
|
+
end
|
143
170
|
end
|
144
171
|
end
|
145
172
|
end
|
146
|
-
|
@@ -3,7 +3,6 @@ require "shelly/cli/main"
|
|
3
3
|
|
4
4
|
describe Shelly::CLI::Main do
|
5
5
|
before do
|
6
|
-
ENV['SHELLY_GIT_HOST'] = nil
|
7
6
|
FileUtils.stub(:chmod)
|
8
7
|
@main = Shelly::CLI::Main.new
|
9
8
|
@client = mock
|
@@ -45,6 +44,16 @@ OUT
|
|
45
44
|
Shelly::User.stub(:new).and_return(@user)
|
46
45
|
end
|
47
46
|
|
47
|
+
it "should return false if ssh key don't exist on local hard drive" do
|
48
|
+
@user.stub(:ssh_key_registered?).and_raise(Errno::ENOENT)
|
49
|
+
File.exists?(File.expand_path("~/.ssh/id_rsa.pub")).should be_false
|
50
|
+
$stdout.should_receive(:puts).with("\e[31mNo such file or directory\e[0m")
|
51
|
+
$stdout.should_receive(:puts).with("\e[31mUse ssh-keygen to generate ssh key pair\e[0m")
|
52
|
+
lambda {
|
53
|
+
@main.register
|
54
|
+
}.should raise_error(SystemExit)
|
55
|
+
end
|
56
|
+
|
48
57
|
it "should check ssh key in database" do
|
49
58
|
@user.stub(:ssh_key_registered?).and_raise(RestClient::Conflict)
|
50
59
|
$stdout.should_receive(:puts).with("\e[31mUser with your ssh key already exists.\e[0m")
|
@@ -134,7 +143,7 @@ OUT
|
|
134
143
|
response = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
|
135
144
|
exception = Shelly::Client::APIError.new(response.to_json)
|
136
145
|
@client.stub(:register_user).and_raise(exception)
|
137
|
-
$stdout.should_receive(:puts).with("\e[
|
146
|
+
$stdout.should_receive(:puts).with("\e[31mEmail has been already taken\e[0m")
|
138
147
|
lambda {
|
139
148
|
fake_stdin(["kate@example.com", "pass", "pass"]) do
|
140
149
|
@main.register
|
@@ -187,7 +196,8 @@ OUT
|
|
187
196
|
|
188
197
|
context "on unauthorized user" do
|
189
198
|
it "should exit with 1 and display error message" do
|
190
|
-
|
199
|
+
response = {"message" => "Unauthorized", "url" => "https://admin.winniecloud.com/users/password/new"}
|
200
|
+
exception = Shelly::Client::APIError.new(response.to_json)
|
191
201
|
@client.stub(:token).and_raise(exception)
|
192
202
|
$stdout.should_receive(:puts).with("\e[31mWrong email or password\e[0m")
|
193
203
|
$stdout.should_receive(:puts).with("\e[31mYou can reset password by using link:\e[0m")
|
@@ -219,68 +229,67 @@ OUT
|
|
219
229
|
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
220
230
|
$stdout.should_receive(:puts).with("\e[31mMust be run inside your project git repository\e[0m")
|
221
231
|
lambda {
|
222
|
-
fake_stdin(["
|
232
|
+
fake_stdin(["", ""]) do
|
223
233
|
@main.add
|
224
234
|
end
|
225
235
|
}.should raise_error(SystemExit)
|
226
236
|
end
|
227
237
|
|
228
|
-
it "should ask user how he will use application" do
|
229
|
-
$stdout.should_receive(:print).with("How will you use this system (production - default,staging): ")
|
230
|
-
@app.should_receive(:purpose=).with("staging")
|
231
|
-
fake_stdin(["staging", "", ""]) do
|
232
|
-
@main.add
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
238
|
context "command line options" do
|
237
239
|
context "invalid params" do
|
238
240
|
it "should show help and exit if not all options are passed" do
|
239
|
-
$stdout.should_receive(:puts).with("
|
240
|
-
@main.options = {"
|
241
|
+
$stdout.should_receive(:puts).with("\e[31mTry 'shelly help add' for more information\e[0m")
|
242
|
+
@main.options = {"code-name" => "foo"}
|
241
243
|
lambda { @main.add }.should raise_error(SystemExit)
|
242
244
|
end
|
243
245
|
|
244
246
|
it "should exit if databases are not valid" do
|
245
|
-
$stdout.should_receive(:puts).with("
|
246
|
-
@main.options = {"
|
247
|
+
$stdout.should_receive(:puts).with("\e[31mTry 'shelly help add' for more information\e[0m")
|
248
|
+
@main.options = {"code-name" => "foo", "databases" => ["not existing"], "domains" => ["foo.example.com"]}
|
247
249
|
lambda { @main.add }.should raise_error(SystemExit)
|
248
250
|
end
|
249
|
-
end
|
250
251
|
|
251
|
-
|
252
|
-
|
253
|
-
@app.should_receive(:
|
254
|
-
@main.options = {"code_name" => "foo", "environment" => "production", "databases" => ["postgresql"], "domains" => ["foo.example.com"]}
|
252
|
+
it "should accept databases separated by comma" do
|
253
|
+
@main.options = {"code-name" => "foo", "databases" => ["postgresql,", "mongodb"], "domains" => ["foo.example.com"]}
|
254
|
+
@app.should_receive(:databases=).with(["postgresql", "mongodb"])
|
255
255
|
@main.add
|
256
256
|
end
|
257
|
+
|
258
|
+
it "should display which parameter was wrong" do
|
259
|
+
expected = "shelly: unrecognized option '--unknown=param'\n" +
|
260
|
+
"Usage: shelly [COMMAND]... [OPTIONS]\n" +
|
261
|
+
"Try 'shelly --help' for more information"
|
262
|
+
|
263
|
+
Open3.popen3("bin/shelly add --unknown=param") do |stdin, stdout, stderr, wait_thr|
|
264
|
+
out = stderr.read.strip
|
265
|
+
out.should == expected
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
257
269
|
end
|
258
|
-
end
|
259
270
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
fake_stdin(["", "", ""]) do
|
271
|
+
context "valid params" do
|
272
|
+
it "should create app on shelly cloud" do
|
273
|
+
@app.should_receive(:create)
|
274
|
+
@main.options = {"code-name" => "foo", "databases" => ["postgresql"], "domains" => ["foo.example.com"]}
|
265
275
|
@main.add
|
266
276
|
end
|
267
277
|
end
|
268
278
|
end
|
269
279
|
|
270
280
|
it "should use code name provided by user" do
|
271
|
-
$stdout.should_receive(:print).with("
|
272
|
-
$stdout.should_receive(:print).with("Application code name (foo-staging - default): ")
|
281
|
+
$stdout.should_receive(:print).with("Application code name (foo-production - default): ")
|
273
282
|
@app.should_receive(:code_name=).with("mycodename")
|
274
|
-
fake_stdin(["
|
283
|
+
fake_stdin(["mycodename", ""]) do
|
275
284
|
@main.add
|
276
285
|
end
|
277
286
|
end
|
278
287
|
|
279
288
|
context "when user provided empty code name" do
|
280
289
|
it "should use 'current_dirname-purpose' as default" do
|
281
|
-
$stdout.should_receive(:print).with("
|
282
|
-
|
283
|
-
fake_stdin(["
|
290
|
+
$stdout.should_receive(:print).with("Application code name (foo-production - default): ")
|
291
|
+
@app.should_receive(:code_name=).with("foo-production")
|
292
|
+
fake_stdin(["", ""]) do
|
284
293
|
@main.add
|
285
294
|
end
|
286
295
|
end
|
@@ -289,7 +298,7 @@ OUT
|
|
289
298
|
it "should use database provided by user (separated by comma or space)" do
|
290
299
|
$stdout.should_receive(:print).with("Which database do you want to use postgresql, mongodb, redis, none (postgresql - default): ")
|
291
300
|
@app.should_receive(:databases=).with(["postgresql", "mongodb", "redis"])
|
292
|
-
fake_stdin(["
|
301
|
+
fake_stdin(["", "postgresql ,mongodb redis"]) do
|
293
302
|
@main.add
|
294
303
|
end
|
295
304
|
end
|
@@ -297,7 +306,7 @@ OUT
|
|
297
306
|
it "should ask again for databases if unsupported kind typed" do
|
298
307
|
$stdout.should_receive(:print).with("Which database do you want to use postgresql, mongodb, redis, none (postgresql - default): ")
|
299
308
|
$stdout.should_receive(:print).with("Unknown database kind. Supported are: postgresql, mongodb, redis, none: ")
|
300
|
-
fake_stdin(["
|
309
|
+
fake_stdin(["", "postgresql,doesnt-exist", "none"]) do
|
301
310
|
@main.add
|
302
311
|
end
|
303
312
|
end
|
@@ -305,7 +314,7 @@ OUT
|
|
305
314
|
context "when user provided empty database" do
|
306
315
|
it "should use 'postgresql' database as default" do
|
307
316
|
@app.should_receive(:databases=).with(["postgresql"])
|
308
|
-
fake_stdin(["
|
317
|
+
fake_stdin(["", ""]) do
|
309
318
|
@main.add
|
310
319
|
end
|
311
320
|
end
|
@@ -313,7 +322,7 @@ OUT
|
|
313
322
|
|
314
323
|
it "should create the app on shelly cloud" do
|
315
324
|
@app.should_receive(:create)
|
316
|
-
fake_stdin(["", ""
|
325
|
+
fake_stdin(["", ""]) do
|
317
326
|
@main.add
|
318
327
|
end
|
319
328
|
end
|
@@ -322,25 +331,27 @@ OUT
|
|
322
331
|
response = {"message" => "Validation Failed", "errors" => [["code_name", "has been already taken"]]}
|
323
332
|
exception = Shelly::Client::APIError.new(response.to_json)
|
324
333
|
@app.should_receive(:create).and_raise(exception)
|
325
|
-
$stdout.should_receive(:puts).with("\e[
|
334
|
+
$stdout.should_receive(:puts).with("\e[31mCode name has been already taken\e[0m")
|
335
|
+
$stdout.should_receive(:puts).with("\e[31mFix erros in the below command and type it again to create your application\e[0m")
|
336
|
+
$stdout.should_receive(:puts).with("\e[31mshelly add --code-name=foo-production --databases=postgresql --domains=foo-production.shellyapp.com\e[0m")
|
326
337
|
lambda {
|
327
|
-
fake_stdin(["", ""
|
338
|
+
fake_stdin(["", ""]) do
|
328
339
|
@main.add
|
329
340
|
end
|
330
341
|
}.should raise_error(SystemExit)
|
331
342
|
end
|
332
343
|
|
333
344
|
it "should add git remote" do
|
334
|
-
$stdout.should_receive(:puts).with("\e[32mAdding remote
|
345
|
+
$stdout.should_receive(:puts).with("\e[32mAdding remote production git@git.shellycloud.com:foooo.git\e[0m")
|
335
346
|
@app.should_receive(:add_git_remote)
|
336
|
-
fake_stdin(["
|
347
|
+
fake_stdin(["foooo", ""]) do
|
337
348
|
@main.add
|
338
349
|
end
|
339
350
|
end
|
340
351
|
|
341
352
|
it "should create Cloudfile" do
|
342
353
|
File.exists?("/projects/foo/Cloudfile").should be_false
|
343
|
-
fake_stdin(["
|
354
|
+
fake_stdin(["foooo", ""]) do
|
344
355
|
@main.add
|
345
356
|
end
|
346
357
|
File.read("/projects/foo/Cloudfile").should == "Example Cloudfile"
|
@@ -349,7 +360,7 @@ OUT
|
|
349
360
|
it "should browser window with link to edit billing information" do
|
350
361
|
$stdout.should_receive(:puts).with("\e[32mProvide billing details. Opening browser...\e[0m")
|
351
362
|
@app.should_receive(:open_billing_page)
|
352
|
-
fake_stdin(["
|
363
|
+
fake_stdin(["foooo", ""]) do
|
353
364
|
@main.add
|
354
365
|
end
|
355
366
|
end
|
@@ -358,7 +369,7 @@ OUT
|
|
358
369
|
$stdout.should_receive(:puts).with("\e[32mProject is now configured for use with Shell Cloud:\e[0m")
|
359
370
|
$stdout.should_receive(:puts).with("\e[32mYou can review changes using\e[0m")
|
360
371
|
$stdout.should_receive(:puts).with(" git status")
|
361
|
-
fake_stdin(["
|
372
|
+
fake_stdin(["foooo", "none"]) do
|
362
373
|
@main.add
|
363
374
|
end
|
364
375
|
end
|
@@ -368,9 +379,9 @@ OUT
|
|
368
379
|
$stdout.should_receive(:puts).with(" git add .")
|
369
380
|
$stdout.should_receive(:puts).with(' git commit -m "Application added to Shelly Cloud"')
|
370
381
|
$stdout.should_receive(:puts).with(" git push")
|
371
|
-
$stdout.should_receive(:puts).with("\e[32mDeploy to
|
372
|
-
$stdout.should_receive(:puts).with(" git push
|
373
|
-
fake_stdin(["
|
382
|
+
$stdout.should_receive(:puts).with("\e[32mDeploy to production using:\e[0m")
|
383
|
+
$stdout.should_receive(:puts).with(" git push production master")
|
384
|
+
fake_stdin(["foooo", "none"]) do
|
374
385
|
@main.add
|
375
386
|
end
|
376
387
|
end
|
@@ -12,17 +12,25 @@ describe Shelly::CLI::Users do
|
|
12
12
|
$stdout.stub(:print)
|
13
13
|
end
|
14
14
|
|
15
|
+
describe "#help" do
|
16
|
+
it "should show help" do
|
17
|
+
$stdout.should_receive(:puts).with("Tasks:")
|
18
|
+
$stdout.should_receive(:puts).with(/add \[EMAIL\]\s+# Add new developer to applications defined in Cloudfile/)
|
19
|
+
$stdout.should_receive(:puts).with(/list\s+# List users who have access to current application/)
|
20
|
+
@users.help
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
describe "#list" do
|
16
25
|
before do
|
17
26
|
FileUtils.mkdir_p("/projects/foo")
|
18
27
|
Dir.chdir("/projects/foo")
|
19
28
|
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
20
|
-
@app = mock
|
21
|
-
Shelly::App.stub(:new).and_return(@app)
|
22
29
|
Shelly::App.stub(:inside_git_repository?).and_return(true)
|
23
30
|
end
|
24
31
|
|
25
32
|
it "should exit with message if command run outside git repository" do
|
33
|
+
@client.stub(:app_users).and_return(response)
|
26
34
|
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
27
35
|
$stdout.should_receive(:puts).with("\e[31mMust be run inside your project git repository\e[0m")
|
28
36
|
lambda {
|
@@ -32,35 +40,79 @@ describe Shelly::CLI::Users do
|
|
32
40
|
|
33
41
|
context "on success" do
|
34
42
|
it "should receive clouds from the Cloudfile" do
|
35
|
-
@
|
43
|
+
@client.should_receive(:app_users).with(["foo-production", "foo-staging"]).
|
36
44
|
and_return(response)
|
37
45
|
@users.list
|
38
46
|
end
|
39
47
|
|
40
48
|
it "should display clouds and users" do
|
41
|
-
@
|
49
|
+
@client.stub(:app_users).and_return(response)
|
42
50
|
$stdout.should_receive(:puts).with("Cloud foo-staging:")
|
43
51
|
$stdout.should_receive(:puts).with(" user@example.com (username)")
|
44
52
|
$stdout.should_receive(:puts).with("Cloud foo-production:")
|
45
53
|
$stdout.should_receive(:puts).with(" user2@example.com (username2)")
|
46
54
|
@users.list
|
47
55
|
end
|
56
|
+
end
|
48
57
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
58
|
+
def response
|
59
|
+
[{'code_name' => 'foo-staging','users' => [{'name' => 'username','email' => 'user@example.com'}]},
|
60
|
+
{'code_name' => 'foo-production','users' => [{'name' => 'username2','email' => 'user2@example.com'}]}]
|
53
61
|
end
|
54
62
|
|
55
63
|
context "on failure" do
|
56
|
-
it "should raise an error if user does not have to any app" do
|
64
|
+
it "should raise an error if user does not have access to any app" do
|
57
65
|
response = {"message" => "You do not have access to this app"}
|
58
66
|
exception = Shelly::Client::APIError.new(response.to_json)
|
59
|
-
@
|
67
|
+
@client.stub(:app_users).and_raise(exception)
|
60
68
|
$stdout.should_receive(:puts).with("You do not have access to this app")
|
61
69
|
lambda { @users.list }.should raise_error(SystemExit)
|
62
70
|
end
|
63
71
|
end
|
64
72
|
end
|
73
|
+
|
74
|
+
describe "#add" do
|
75
|
+
before do
|
76
|
+
FileUtils.mkdir_p("/projects/foo")
|
77
|
+
Dir.chdir("/projects/foo")
|
78
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
79
|
+
Shelly::App.stub(:inside_git_repository?).and_return(true)
|
80
|
+
@client.stub(:token).and_return("abc")
|
81
|
+
@user = Shelly::User.new
|
82
|
+
@client.stub(:apps).and_return([{"code_name" => "abc"}, {"code_name" => "fooo"}])
|
83
|
+
Shelly::User.stub(:new).and_return(@user)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should exit with message if command run outside git repository" do
|
87
|
+
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
88
|
+
$stdout.should_receive(:puts).with("\e[31mMust be run inside your project git repository\e[0m")
|
89
|
+
lambda {
|
90
|
+
@users.add
|
91
|
+
}.should raise_error(SystemExit)
|
92
|
+
end
|
93
|
+
|
94
|
+
context "on success" do
|
95
|
+
before do
|
96
|
+
@client.should_receive(:send_invitation).with(["foo-production", "foo-staging"], "megan@example.com")
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should ask about email" do
|
100
|
+
fake_stdin(["megan@example.com"]) do
|
101
|
+
@users.add
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should receive clouds from the Cloudfile" do
|
106
|
+
@users.add("megan@example.com")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should receive clouds from the Cloudfile" do
|
110
|
+
$stdout.should_receive(:puts).with("Sending invitation to megan@example.com")
|
111
|
+
@users.add("megan@example.com")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
65
117
|
end
|
66
118
|
|
data/spec/shelly/client_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Shelly::Client::APIError do
|
4
4
|
before do
|
5
|
-
body = {"message" => "something went wrong", "errors" => [
|
5
|
+
body = {"message" => "something went wrong", "errors" => [["first", "foo"]], "url" => "https://foo.bar"}
|
6
6
|
@error = Shelly::Client::APIError.new(body.to_json)
|
7
7
|
end
|
8
8
|
|
@@ -10,8 +10,16 @@ describe Shelly::Client::APIError do
|
|
10
10
|
@error.message.should == "something went wrong"
|
11
11
|
end
|
12
12
|
|
13
|
-
it "should return
|
14
|
-
@error.errors.should == [
|
13
|
+
it "should return array of errors" do
|
14
|
+
@error.errors.should == [["first", "foo"]]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return url" do
|
18
|
+
@error.url.should == "https://foo.bar"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return user friendly string" do
|
22
|
+
@error.each_error{|error| error.should == "First foo"}
|
15
23
|
end
|
16
24
|
|
17
25
|
describe "#validation?" do
|
@@ -29,6 +37,22 @@ describe Shelly::Client::APIError do
|
|
29
37
|
end
|
30
38
|
end
|
31
39
|
end
|
40
|
+
|
41
|
+
describe "#unauthorized?" do
|
42
|
+
context "when error is caused by unauthorized error" do
|
43
|
+
it "should return true" do
|
44
|
+
body = {"message" => "Unauthorized"}
|
45
|
+
error = Shelly::Client::APIError.new(body.to_json)
|
46
|
+
error.should be_unauthorized
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when error is not caused by unauthorized" do
|
51
|
+
it "should return false" do
|
52
|
+
@error.should_not be_unauthorized
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
32
56
|
end
|
33
57
|
|
34
58
|
describe Shelly::Client do
|
@@ -93,6 +117,15 @@ describe Shelly::Client do
|
|
93
117
|
end
|
94
118
|
end
|
95
119
|
|
120
|
+
describe "#send_invitation" do
|
121
|
+
it "should send post with developer's email" do
|
122
|
+
FakeWeb.register_uri(:post, @url + "/apps/staging-foo/collaborations", :body => {}.to_json)
|
123
|
+
FakeWeb.register_uri(:post, @url + "/apps/production-foo/collaborations", :body => {}.to_json)
|
124
|
+
response = @client.send_invitation(["staging-foo", "production-foo"], "megan@example.com")
|
125
|
+
response.should == [{}, {}]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
96
129
|
describe "#update_ssh_key" do
|
97
130
|
it "should send put with give SSH key" do
|
98
131
|
@client.should_receive(:put).with("/ssh_key", {:ssh_key => "abc"})
|
@@ -169,7 +202,7 @@ describe Shelly::Client do
|
|
169
202
|
@client.get('/account')
|
170
203
|
end
|
171
204
|
|
172
|
-
%w(404 422 500).each do |code|
|
205
|
+
%w(401, 404 422 500).each do |code|
|
173
206
|
context "on #{code} response code" do
|
174
207
|
it "should raise APIError" do
|
175
208
|
@response.stub(:code).and_return(code.to_i)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "shelly/cloudfile"
|
3
|
+
|
4
|
+
describe Shelly::Cloudfile do
|
5
|
+
before do
|
6
|
+
FileUtils.mkdir_p("/projects/foo")
|
7
|
+
Dir.chdir("/projects/foo")
|
8
|
+
@hash = {:code_name => {:code => "test"}}
|
9
|
+
@client = mock
|
10
|
+
Shelly::Client.stub(:new).and_return(@client)
|
11
|
+
@cloudfile = Shelly::Cloudfile.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#hash converting" do
|
15
|
+
it "should convert hash to proper string" do
|
16
|
+
@cloudfile.yaml(@hash).should == "code_name:\n code: test"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should conver a hash to yaml format" do
|
20
|
+
@cloudfile.write(@hash)
|
21
|
+
@cloudfile.open.should == {"code_name" => {"code" => "test"}}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#fetch_users" do
|
26
|
+
it "should return array to display with clouds and users" do
|
27
|
+
@cloudfile.write(@hash)
|
28
|
+
@client.should_receive(:app_users).and_return(response)
|
29
|
+
response = @cloudfile.fetch_users
|
30
|
+
response.should == {"foo-staging" => ["user@example.com (username)"]}
|
31
|
+
end
|
32
|
+
|
33
|
+
def response
|
34
|
+
[{'code_name' => 'foo-staging','users' => [{'name' => 'username','email' => 'user@example.com'}]}]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/spec/shelly/user_spec.rb
CHANGED
@@ -92,6 +92,13 @@ describe Shelly::User do
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
+
describe "#send_invitation" do
|
96
|
+
it "should send invitation" do
|
97
|
+
@client.should_receive(:send_invitation).with(["foo-staging"], "megan@example.com")
|
98
|
+
@user.send_invitation(["foo-staging"], "megan@example.com")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
95
102
|
describe "#ssh_key_path" do
|
96
103
|
it "should return path to public ssh key file" do
|
97
104
|
@user.ssh_key_path.should == File.expand_path("~/.ssh/id_rsa.pub")
|
@@ -105,7 +112,7 @@ describe Shelly::User do
|
|
105
112
|
@user.should_not be_ssh_key_exists
|
106
113
|
end
|
107
114
|
end
|
108
|
-
|
115
|
+
|
109
116
|
describe "#ssh_key_registered?" do
|
110
117
|
it "should read and check if ssh key exists in database" do
|
111
118
|
@client.should_receive(:ssh_key_available?).with('ssh-key AAbbcc')
|
@@ -155,3 +162,4 @@ describe Shelly::User do
|
|
155
162
|
end
|
156
163
|
end
|
157
164
|
end
|
165
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shelly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.17
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-11-03 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156677640 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156677640
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156677220 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156677220
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: guard
|
38
|
-
requirement: &
|
38
|
+
requirement: &2156676800 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2156676800
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: guard-rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &2156676380 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2156676380
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: growl_notify
|
60
|
-
requirement: &
|
60
|
+
requirement: &2156675920 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2156675920
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rb-fsevent
|
71
|
-
requirement: &
|
71
|
+
requirement: &2156675500 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2156675500
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: fakefs
|
82
|
-
requirement: &
|
82
|
+
requirement: &2156675080 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *2156675080
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: fakeweb
|
93
|
-
requirement: &
|
93
|
+
requirement: &2156674660 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *2156674660
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: thor
|
104
|
-
requirement: &
|
104
|
+
requirement: &2156674240 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *2156674240
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rest-client
|
115
|
-
requirement: &
|
115
|
+
requirement: &2156673780 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :runtime
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *2156673780
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: json
|
126
|
-
requirement: &
|
126
|
+
requirement: &2156673340 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *2156673340
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: launchy
|
137
|
-
requirement: &
|
137
|
+
requirement: &2156672840 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,7 +142,7 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :runtime
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *2156672840
|
146
146
|
description: Tool for managing applications and clouds at shellycloud.com
|
147
147
|
email:
|
148
148
|
- support@shellycloud.com
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- README.md
|
159
159
|
- Rakefile
|
160
160
|
- bin/shelly
|
161
|
+
- lib/core_ext/hash.rb
|
161
162
|
- lib/core_ext/object.rb
|
162
163
|
- lib/shelly.rb
|
163
164
|
- lib/shelly/app.rb
|
@@ -165,10 +166,12 @@ files:
|
|
165
166
|
- lib/shelly/cli/main.rb
|
166
167
|
- lib/shelly/cli/users.rb
|
167
168
|
- lib/shelly/client.rb
|
169
|
+
- lib/shelly/cloudfile.rb
|
168
170
|
- lib/shelly/helpers.rb
|
169
171
|
- lib/shelly/templates/Cloudfile.erb
|
170
172
|
- lib/shelly/user.rb
|
171
173
|
- lib/shelly/version.rb
|
174
|
+
- lib/thor/options.rb
|
172
175
|
- shelly.gemspec
|
173
176
|
- spec/helpers.rb
|
174
177
|
- spec/input_faker.rb
|
@@ -177,6 +180,7 @@ files:
|
|
177
180
|
- spec/shelly/cli/main_spec.rb
|
178
181
|
- spec/shelly/cli/users_spec.rb
|
179
182
|
- spec/shelly/client_spec.rb
|
183
|
+
- spec/shelly/cloudfile_spec.rb
|
180
184
|
- spec/shelly/user_spec.rb
|
181
185
|
- spec/spec_helper.rb
|
182
186
|
homepage: http://shellycloud.com
|
@@ -211,5 +215,6 @@ test_files:
|
|
211
215
|
- spec/shelly/cli/main_spec.rb
|
212
216
|
- spec/shelly/cli/users_spec.rb
|
213
217
|
- spec/shelly/client_spec.rb
|
218
|
+
- spec/shelly/cloudfile_spec.rb
|
214
219
|
- spec/shelly/user_spec.rb
|
215
220
|
- spec/spec_helper.rb
|