shelly 0.0.32 → 0.0.33
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/lib/shelly/app.rb +16 -0
- data/lib/shelly/cli/backup.rb +5 -3
- data/lib/shelly/cli/config.rb +117 -2
- data/lib/shelly/cli/deploys.rb +8 -4
- data/lib/shelly/cli/main.rb +32 -31
- data/lib/shelly/client.rb +16 -0
- data/lib/shelly/helpers.rb +1 -1
- data/lib/shelly/version.rb +1 -1
- data/spec/shelly/cli/backup_spec.rb +4 -3
- data/spec/shelly/cli/config_spec.rb +193 -7
- data/spec/shelly/cli/deploys_spec.rb +6 -4
- data/spec/shelly/cli/main_spec.rb +65 -29
- metadata +4 -4
data/.gitignore
CHANGED
data/lib/shelly/app.rb
CHANGED
@@ -106,6 +106,22 @@ module Shelly
|
|
106
106
|
configs.find_all { |config| config["created_by_user"] == false }
|
107
107
|
end
|
108
108
|
|
109
|
+
def config(id)
|
110
|
+
shelly.app_config(code_name, id)
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_config(path, content)
|
114
|
+
shelly.app_create_config(code_name, path, content)
|
115
|
+
end
|
116
|
+
|
117
|
+
def update_config(id, content)
|
118
|
+
shelly.app_update_config(code_name, id, content)
|
119
|
+
end
|
120
|
+
|
121
|
+
def delete_config(id)
|
122
|
+
shelly.app_delete_config(code_name, id)
|
123
|
+
end
|
124
|
+
|
109
125
|
def open_billing_page
|
110
126
|
url = "#{shelly.shellyapp_url}/login?api_key=#{current_user.token}&return_to=/apps/#{code_name}/edit_billing"
|
111
127
|
Launchy.open(url)
|
data/lib/shelly/cli/backup.rb
CHANGED
@@ -6,12 +6,14 @@ module Shelly
|
|
6
6
|
namespace :backup
|
7
7
|
include Helpers
|
8
8
|
|
9
|
-
desc "list", "List database
|
10
|
-
|
9
|
+
desc "list", "List database backups"
|
10
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
11
|
+
:desc => "Specify which cloud to list backups for"
|
12
|
+
def list
|
11
13
|
logged_in?
|
12
14
|
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
13
15
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
14
|
-
multiple_clouds(cloud, "backup list", "Select cloud to view database backups using:")
|
16
|
+
multiple_clouds(options[:cloud], "backup list", "Select cloud to view database backups for using:")
|
15
17
|
backups = @app.database_backups
|
16
18
|
unless backups.empty?
|
17
19
|
backups.unshift({"filename" => "Filename", "size" => "Size"})
|
data/lib/shelly/cli/config.rb
CHANGED
@@ -20,14 +20,14 @@ module Shelly
|
|
20
20
|
user_configs = @app.user_configs
|
21
21
|
unless user_configs.empty?
|
22
22
|
say "Custom configuration files:"
|
23
|
-
user_configs
|
23
|
+
print_configs(user_configs)
|
24
24
|
else
|
25
25
|
say "You have no custom configuration files."
|
26
26
|
end
|
27
27
|
shelly_configs = @app.shelly_generated_configs
|
28
28
|
unless shelly_configs.empty?
|
29
29
|
say "Following files are created by Shelly Cloud:"
|
30
|
-
shelly_configs
|
30
|
+
print_configs(shelly_configs)
|
31
31
|
end
|
32
32
|
else
|
33
33
|
say "Cloud #{cloud} has no configuration files"
|
@@ -42,6 +42,121 @@ module Shelly
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
46
|
+
:desc => "Specify which cloud to show configuration file for"
|
47
|
+
desc "show CONFIG_ID", "View configuration file"
|
48
|
+
def show(id = nil)
|
49
|
+
logged_in?
|
50
|
+
say_error "No Cloudfile found" unless Cloudfile.present?
|
51
|
+
say_error "No configuration file specified" unless id
|
52
|
+
multiple_clouds(options[:cloud], "show #{id}", "Specify cloud using:")
|
53
|
+
config = @app.config(id)
|
54
|
+
say "Content of #{config["path"]}:", :green
|
55
|
+
say config["content"]
|
56
|
+
end
|
57
|
+
|
58
|
+
map "new" => :create
|
59
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
60
|
+
:desc => "Specify for which cloud create configuration file"
|
61
|
+
desc "create PATH", "Create configuration file"
|
62
|
+
def create(path = nil)
|
63
|
+
logged_in?
|
64
|
+
say_error "No Cloudfile found" unless Cloudfile.present?
|
65
|
+
say_error "No path specified" unless path
|
66
|
+
output = open_editor(path)
|
67
|
+
multiple_clouds(options[:cloud], "create #{path}", "Specify cloud using:")
|
68
|
+
@app.create_config(path, output)
|
69
|
+
say "File '#{path}' created, it will be used after next code deploy", :green
|
70
|
+
rescue Client::APIError => e
|
71
|
+
if e.unauthorized?
|
72
|
+
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
73
|
+
elsif e.validation?
|
74
|
+
e.each_error { |error| say_error error, :with_exit => false }
|
75
|
+
exit 1
|
76
|
+
else
|
77
|
+
say_error e.message
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
map "update" => :edit
|
82
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
83
|
+
:desc => "Specify for which cloud edit configuration file"
|
84
|
+
desc "edit CONFIG_ID", "Edit configuration file"
|
85
|
+
def edit(id = nil)
|
86
|
+
logged_in?
|
87
|
+
say_error "No Cloudfile found" unless Cloudfile.present?
|
88
|
+
say_error "No configuration file specified" unless id
|
89
|
+
multiple_clouds(options[:cloud], "edit #{id}", "Specify cloud using:")
|
90
|
+
config = @app.config(id)
|
91
|
+
content = open_editor(config["path"], config["content"])
|
92
|
+
@app.update_config(id, content)
|
93
|
+
say "File '#{config["path"]}' updated, it will be used after next code deploy", :green
|
94
|
+
rescue Client::APIError => e
|
95
|
+
if e.unauthorized?
|
96
|
+
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
97
|
+
elsif e.validation?
|
98
|
+
e.each_error { |error| say_error error, :with_exit => false }
|
99
|
+
exit 1
|
100
|
+
else
|
101
|
+
say_error e.message
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
106
|
+
:desc => "Specify for which cloud delete configuration file"
|
107
|
+
desc "delete CONFIG_ID", "Delete configuration file"
|
108
|
+
def delete(id = nil)
|
109
|
+
logged_in?
|
110
|
+
say_error "No Cloudfile found" unless Cloudfile.present?
|
111
|
+
say_error "No configuration file specified" unless id
|
112
|
+
multiple_clouds(options[:cloud], "delete #{id}", "Specify cloud using:")
|
113
|
+
config = @app.config(id)
|
114
|
+
answer = ask("Are you sure you want to delete '#{config["path"]}' [y/n]: ")
|
115
|
+
if answer =~ /yes|YES|y|Y/
|
116
|
+
@app.delete_config(id)
|
117
|
+
say "File deleted, redeploy your cloud to make changes", :green
|
118
|
+
else
|
119
|
+
say "File not deleted"
|
120
|
+
end
|
121
|
+
rescue Client::APIError => e
|
122
|
+
if e.unauthorized?
|
123
|
+
say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
|
124
|
+
elsif e.validation?
|
125
|
+
e.each_error { |error| say_error error, :with_exit => false }
|
126
|
+
exit 1
|
127
|
+
else
|
128
|
+
say_error e.message
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
no_tasks do
|
133
|
+
def print_configs(configs)
|
134
|
+
print_table(configs.map { |config|
|
135
|
+
[" * ", config["id"], config["path"]] })
|
136
|
+
end
|
137
|
+
|
138
|
+
def open_editor(path, output = "")
|
139
|
+
filename = "shelly-edit-"
|
140
|
+
0.upto(20) { filename += rand(9).to_s }
|
141
|
+
filename << File.extname(path)
|
142
|
+
filename = File.join(Dir.tmpdir, filename)
|
143
|
+
tf = File.open(filename, "w")
|
144
|
+
tf.sync = true
|
145
|
+
tf.puts output
|
146
|
+
tf.close
|
147
|
+
no_editor unless system("#{ENV['EDITOR']} #{tf.path}")
|
148
|
+
tf = File.open(filename, "r")
|
149
|
+
output = tf.gets(nil)
|
150
|
+
tf.close
|
151
|
+
File.unlink(filename)
|
152
|
+
output
|
153
|
+
end
|
154
|
+
|
155
|
+
def no_editor
|
156
|
+
say_error "Please set EDITOR environment variable"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
45
160
|
end
|
46
161
|
end
|
47
162
|
end
|
data/lib/shelly/cli/deploys.rb
CHANGED
@@ -8,10 +8,12 @@ module Shelly
|
|
8
8
|
include Helpers
|
9
9
|
|
10
10
|
desc "list", "Lists deploy logs"
|
11
|
-
|
11
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
12
|
+
:desc => "Specify which cloud to show deploy logs for"
|
13
|
+
def list
|
12
14
|
logged_in?
|
13
15
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
14
|
-
multiple_clouds(cloud, "deploys list", "Select cloud to view deploy logs using:")
|
16
|
+
multiple_clouds(options[:cloud], "deploys list", "Select cloud to view deploy logs using:")
|
15
17
|
logs = @app.deploy_logs
|
16
18
|
unless logs.empty?
|
17
19
|
say "Available deploy logs", :green
|
@@ -30,10 +32,12 @@ module Shelly
|
|
30
32
|
end
|
31
33
|
|
32
34
|
desc "show LOG", "Show specific deploy log"
|
33
|
-
|
35
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
36
|
+
:desc => "Specify which cloud to show deploy logs for"
|
37
|
+
def show(log = nil)
|
34
38
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
35
39
|
specify_log(log)
|
36
|
-
multiple_clouds(cloud, "deploys show #{log}", "Select log and cloud to view deploy logs using:")
|
40
|
+
multiple_clouds(options[:cloud], "deploys show #{log}", "Select log and cloud to view deploy logs using:")
|
37
41
|
content = @app.deploy_log(log)
|
38
42
|
say "Log for deploy done on #{content["created_at"]}", :green
|
39
43
|
if content["bundle_install"]
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -161,11 +161,13 @@ module Shelly
|
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
|
-
desc "start
|
165
|
-
|
164
|
+
desc "start", "Starts the cloud"
|
165
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
166
|
+
:desc => "Specify which cloud to start"
|
167
|
+
def start
|
166
168
|
logged_in?
|
167
169
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
168
|
-
multiple_clouds(cloud, "start", "Select
|
170
|
+
multiple_clouds(options[:cloud], "start", "Select cloud to start using:")
|
169
171
|
@app.start
|
170
172
|
say "Starting cloud #{@app.code_name}. Check status with:", :green
|
171
173
|
say " shelly list"
|
@@ -195,11 +197,13 @@ module Shelly
|
|
195
197
|
end
|
196
198
|
end
|
197
199
|
|
198
|
-
desc "stop
|
199
|
-
|
200
|
+
desc "stop", "Stops the cloud"
|
201
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
202
|
+
:desc => "Specify which cloud to stop"
|
203
|
+
def stop
|
200
204
|
logged_in?
|
201
205
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
202
|
-
multiple_clouds(cloud, "stop", "Select
|
206
|
+
multiple_clouds(options[:cloud], "stop", "Select cloud to stop using:")
|
203
207
|
@app.stop
|
204
208
|
say "Cloud '#{@app.code_name}' stopped"
|
205
209
|
rescue Client::APIError => e
|
@@ -208,31 +212,28 @@ module Shelly
|
|
208
212
|
end
|
209
213
|
end
|
210
214
|
|
211
|
-
desc "delete
|
212
|
-
|
215
|
+
desc "delete", "Delete cloud from Shelly Cloud"
|
216
|
+
method_option :cloud, :type => :string, :aliases => "-c",
|
217
|
+
:desc => "Specify which cloud to delete"
|
218
|
+
def delete
|
213
219
|
user = Shelly::User.new
|
214
220
|
user.token
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
say "Removing git remote - done"
|
230
|
-
else
|
231
|
-
say "Missing git remote"
|
232
|
-
end
|
221
|
+
multiple_clouds(options[:cloud], "delete", "Select cloud to delete using:")
|
222
|
+
say "You are about to delete application: #{@app.code_name}."
|
223
|
+
say "Press Control-C at any moment to cancel."
|
224
|
+
say "Please confirm each question by typing yes and pressing Enter."
|
225
|
+
say_new_line
|
226
|
+
ask_to_delete_files
|
227
|
+
ask_to_delete_database
|
228
|
+
ask_to_delete_application
|
229
|
+
@app.delete
|
230
|
+
say_new_line
|
231
|
+
say "Scheduling application delete - done"
|
232
|
+
if App.inside_git_repository?
|
233
|
+
@app.remove_git_remote
|
234
|
+
say "Removing git remote - done"
|
233
235
|
else
|
234
|
-
|
235
|
-
say_error "Use: shelly delete CODE-NAME"
|
236
|
+
say "Missing git remote"
|
236
237
|
end
|
237
238
|
rescue Client::APIError => e
|
238
239
|
say_error e.message
|
@@ -245,13 +246,13 @@ module Shelly
|
|
245
246
|
cloud = options[:cloud]
|
246
247
|
logged_in?
|
247
248
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
248
|
-
multiple_clouds(cloud, "logs
|
249
|
+
multiple_clouds(cloud, "logs", "Select which to show logs for using:")
|
249
250
|
begin
|
250
251
|
logs = @app.application_logs
|
251
252
|
say "Cloud #{@app.code_name}:", :green
|
252
253
|
logs.each_with_index do |log, i|
|
253
|
-
say "Instance #{i+1}:"
|
254
|
-
|
254
|
+
say "Instance #{i+1}:", :green
|
255
|
+
say log
|
255
256
|
end
|
256
257
|
rescue Client::APIError => e
|
257
258
|
if e.unauthorized?
|
data/lib/shelly/client.rb
CHANGED
@@ -62,6 +62,22 @@ module Shelly
|
|
62
62
|
get("/apps/#{cloud}/configs")
|
63
63
|
end
|
64
64
|
|
65
|
+
def app_config(cloud, id)
|
66
|
+
get("/apps/#{cloud}/configs/#{id}")
|
67
|
+
end
|
68
|
+
|
69
|
+
def app_create_config(cloud, path, content)
|
70
|
+
post("/apps/#{cloud}/configs", :config => {:path => path, :content => content})
|
71
|
+
end
|
72
|
+
|
73
|
+
def app_update_config(cloud, id, content)
|
74
|
+
put("/apps/#{cloud}/configs/#{id}", :config => {:content => content})
|
75
|
+
end
|
76
|
+
|
77
|
+
def app_delete_config(cloud, id)
|
78
|
+
delete("/apps/#{cloud}/configs/#{id}")
|
79
|
+
end
|
80
|
+
|
65
81
|
def send_invitation(cloud, email)
|
66
82
|
post("/apps/#{cloud}/collaborations", :email => email)
|
67
83
|
end
|
data/lib/shelly/helpers.rb
CHANGED
@@ -61,7 +61,7 @@ module Shelly
|
|
61
61
|
clouds = Cloudfile.new.clouds
|
62
62
|
if clouds.count > 1 && cloud.nil?
|
63
63
|
say "You have multiple clouds in Cloudfile. #{message}"
|
64
|
-
say " shelly #{action} #{clouds.first}"
|
64
|
+
say " shelly #{action} --cloud #{clouds.first}"
|
65
65
|
say "Available clouds:"
|
66
66
|
clouds.each do |cloud|
|
67
67
|
say " * #{cloud}"
|
data/lib/shelly/version.rb
CHANGED
@@ -38,8 +38,8 @@ describe Shelly::CLI::Backup do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should show information to select specific cloud and exit" do
|
41
|
-
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to view database backups using:")
|
42
|
-
$stdout.should_receive(:puts).with(" shelly backup list foo-production")
|
41
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to view database backups for using:")
|
42
|
+
$stdout.should_receive(:puts).with(" shelly backup list --cloud foo-production")
|
43
43
|
$stdout.should_receive(:puts).with("Available clouds:")
|
44
44
|
$stdout.should_receive(:puts).with(" * foo-production")
|
45
45
|
$stdout.should_receive(:puts).with(" * foo-staging")
|
@@ -53,7 +53,8 @@ describe Shelly::CLI::Backup do
|
|
53
53
|
$stdout.should_receive(:puts).with(" Filename | Size")
|
54
54
|
$stdout.should_receive(:puts).with(" backup.postgre.tar.gz | 10kb")
|
55
55
|
$stdout.should_receive(:puts).with(" backup.mongo.tar.gz | 22kb")
|
56
|
-
@backup.
|
56
|
+
@backup.options = {:cloud => 'foo-staging'}
|
57
|
+
@backup.list
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
@@ -10,14 +10,18 @@ describe Shelly::CLI::Config do
|
|
10
10
|
Shelly::Client.stub(:new).and_return(@client)
|
11
11
|
$stdout.stub(:puts)
|
12
12
|
$stdout.stub(:print)
|
13
|
+
FileUtils.mkdir_p("/projects/foo")
|
14
|
+
Dir.chdir("/projects/foo")
|
15
|
+
@client.stub(:token).and_return("abc")
|
16
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
|
17
|
+
FileUtils.mkdir_p("/tmp")
|
18
|
+
Dir.stub(:tmpdir).and_return("/tmp")
|
19
|
+
ENV["EDITOR"] = "vim"
|
13
20
|
end
|
14
21
|
|
15
22
|
describe "#list" do
|
16
23
|
before do
|
17
|
-
FileUtils.mkdir_p("/projects/foo")
|
18
|
-
Dir.chdir("/projects/foo")
|
19
24
|
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
20
|
-
@client.stub(:token).and_return("abc")
|
21
25
|
end
|
22
26
|
|
23
27
|
it "should exit with message if there is no Cloudfile" do
|
@@ -37,19 +41,201 @@ describe Shelly::CLI::Config do
|
|
37
41
|
end
|
38
42
|
|
39
43
|
it "should list available configuration files for clouds" do
|
40
|
-
@client.should_receive(:app_configs).with("foo-staging").and_return([{"created_by_user" => true, "path" => "config/settings.yml"}])
|
41
|
-
@client.should_receive(:app_configs).with("foo-production").and_return([{"created_by_user" => false, "path" => "config/app.yml"}])
|
44
|
+
@client.should_receive(:app_configs).with("foo-staging").and_return([{"id" => 1, "created_by_user" => true, "path" => "config/settings.yml"}])
|
45
|
+
@client.should_receive(:app_configs).with("foo-production").and_return([{"id" => 2, "created_by_user" => false, "path" => "config/app.yml"}])
|
42
46
|
$stdout.should_receive(:puts).with(green "Configuration files for foo-production")
|
43
47
|
$stdout.should_receive(:puts).with("You have no custom configuration files.")
|
44
48
|
$stdout.should_receive(:puts).with("Following files are created by Shelly Cloud:")
|
45
|
-
$stdout.should_receive(:puts).with(
|
49
|
+
$stdout.should_receive(:puts).with(/ * 2\s+config\/app.yml/)
|
46
50
|
$stdout.should_receive(:puts).with(green "Configuration files for foo-staging")
|
47
51
|
$stdout.should_receive(:puts).with("Custom configuration files:")
|
48
|
-
$stdout.should_receive(:puts).with(
|
52
|
+
$stdout.should_receive(:puts).with(/ * 1\s+config\/settings.yml/)
|
49
53
|
|
50
54
|
@config.list
|
51
55
|
end
|
52
56
|
|
53
57
|
end
|
54
58
|
|
59
|
+
describe "#show" do
|
60
|
+
it "should exit with message if there is no Cloudfile" do
|
61
|
+
File.delete("Cloudfile")
|
62
|
+
$stdout.should_receive(:puts).with(red "No Cloudfile found")
|
63
|
+
lambda { @config.show(1) }.should raise_error(SystemExit)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should exit if no id was specified" do
|
67
|
+
$stdout.should_receive(:puts).with(red "No configuration file specified")
|
68
|
+
lambda { @config.show }.should raise_error(SystemExit)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should show config" do
|
72
|
+
@client.should_receive(:app_config).with("foo-staging", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
73
|
+
$stdout.should_receive(:puts).with(green "Content of test.rb:")
|
74
|
+
$stdout.should_receive(:puts).with("example content")
|
75
|
+
@config.show(1)
|
76
|
+
end
|
77
|
+
|
78
|
+
context "multiple clouds" do
|
79
|
+
before do
|
80
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should show info to select cloud and exit" do
|
84
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Specify cloud using:")
|
85
|
+
lambda { @config.show(1) }.should raise_error(SystemExit)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should use cloud specified by parameter" do
|
89
|
+
@client.should_receive(:app_config).with("foo-production", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
90
|
+
@config.options = {:cloud => "foo-production"}
|
91
|
+
@config.show(1)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#create" do
|
97
|
+
it "should exit with message if there is no Cloudfile" do
|
98
|
+
File.delete("Cloudfile")
|
99
|
+
$stdout.should_receive(:puts).with(red "No Cloudfile found")
|
100
|
+
lambda { @config.create("path") }.should raise_error(SystemExit)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should exit if no id was specified" do
|
104
|
+
$stdout.should_receive(:puts).with(red "No path specified")
|
105
|
+
lambda { @config.create }.should raise_error(SystemExit)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should ask to set EDITOR environment variable if not set" do
|
109
|
+
@config.stub(:system) {false}
|
110
|
+
$stdout.should_receive(:puts).with(red "Please set EDITOR environment variable")
|
111
|
+
lambda { @config.create("path") }.should raise_error(SystemExit)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should create file" do
|
115
|
+
@config.should_receive(:system).with(/vim \/tmp\/shelly-edit/).and_return(true)
|
116
|
+
@client.should_receive(:app_create_config).with("foo-staging", "path", "\n").and_return({})
|
117
|
+
$stdout.should_receive(:puts).with(green "File 'path' created, it will be used after next code deploy")
|
118
|
+
@config.create("path")
|
119
|
+
end
|
120
|
+
|
121
|
+
context "multiple clouds" do
|
122
|
+
before do
|
123
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should show info to select cloud and exit" do
|
127
|
+
@config.stub(:system) {true}
|
128
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Specify cloud using:")
|
129
|
+
lambda { @config.create("path") }.should raise_error(SystemExit)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should use cloud specified by parameter" do
|
133
|
+
@config.should_receive(:system).with(/vim \/tmp\/shelly-edit/).and_return(true)
|
134
|
+
@client.should_receive(:app_create_config).with("foo-production", "path", "\n").and_return({})
|
135
|
+
@config.options = {:cloud => "foo-production"}
|
136
|
+
@config.create("path")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
describe "#edit" do
|
143
|
+
it "should exit with message if there is no Cloudfile" do
|
144
|
+
File.delete("Cloudfile")
|
145
|
+
$stdout.should_receive(:puts).with(red "No Cloudfile found")
|
146
|
+
lambda { @config.edit(1) }.should raise_error(SystemExit)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should exit if no path was specified" do
|
150
|
+
$stdout.should_receive(:puts).with(red "No configuration file specified")
|
151
|
+
lambda { @config.edit }.should raise_error(SystemExit)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should ask to set EDITOR environment variable if not set" do
|
155
|
+
@client.should_receive(:app_config).with("foo-staging", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
156
|
+
@config.stub(:system) {false}
|
157
|
+
$stdout.should_receive(:puts).with(red "Please set EDITOR environment variable")
|
158
|
+
lambda { @config.edit(1) }.should raise_error(SystemExit)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should create file" do
|
162
|
+
@client.should_receive(:app_config).with("foo-staging", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
163
|
+
@config.should_receive(:system).with(/vim \/tmp\/shelly-edit/).and_return(true)
|
164
|
+
@client.should_receive(:app_update_config).with("foo-staging", 1, "example content\n").and_return({"path" => "test.rb", "content" => "example content"})
|
165
|
+
$stdout.should_receive(:puts).with(green "File 'test.rb' updated, it will be used after next code deploy")
|
166
|
+
@config.edit(1)
|
167
|
+
end
|
168
|
+
|
169
|
+
context "multiple clouds" do
|
170
|
+
before do
|
171
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should show info to select cloud and exit" do
|
175
|
+
@config.stub(:system) {true}
|
176
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Specify cloud using:")
|
177
|
+
lambda { @config.edit(1) }.should raise_error(SystemExit)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should use cloud specified by parameter" do
|
181
|
+
@client.should_receive(:app_config).with("foo-production", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
182
|
+
@config.should_receive(:system).with(/vim \/tmp\/shelly-edit/).and_return(true)
|
183
|
+
@client.should_receive(:app_update_config).with("foo-production", 1, "example content\n").and_return({"path" => "test.rb", "content" => "example content"})
|
184
|
+
@config.options = {:cloud => "foo-production"}
|
185
|
+
@config.edit(1)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#delete" do
|
191
|
+
it "should exit with message if there is no Cloudfile" do
|
192
|
+
File.delete("Cloudfile")
|
193
|
+
$stdout.should_receive(:puts).with(red "No Cloudfile found")
|
194
|
+
lambda { @config.delete(1) }.should raise_error(SystemExit)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should exit if no path was specified" do
|
198
|
+
$stdout.should_receive(:puts).with(red "No configuration file specified")
|
199
|
+
lambda { @config.delete }.should raise_error(SystemExit)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should delete configuration file" do
|
203
|
+
@client.should_receive(:app_config).with("foo-staging", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
204
|
+
@client.should_receive(:app_delete_config).with("foo-staging", 1).and_return({})
|
205
|
+
$stdout.should_receive(:puts).with(green "File deleted, redeploy your cloud to make changes")
|
206
|
+
fake_stdin(["y"]) do
|
207
|
+
@config.delete(1)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should not delete file if user answered other than yes/y" do
|
212
|
+
@client.should_receive(:app_config).with("foo-staging", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
213
|
+
@client.should_not_receive(:app_delete_config)
|
214
|
+
$stdout.should_receive(:puts).with("File not deleted")
|
215
|
+
fake_stdin(["n"]) do
|
216
|
+
@config.delete(1)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context "multiple clouds" do
|
221
|
+
before do
|
222
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should show info to select cloud and exit" do
|
226
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Specify cloud using:")
|
227
|
+
lambda { @config.delete(1) }.should raise_error(SystemExit)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should use cloud specified by parameter" do
|
231
|
+
@client.should_receive(:app_config).with("foo-production", 1).and_return({"path" => "test.rb", "content" => "example content"})
|
232
|
+
@client.should_receive(:app_delete_config).with("foo-production", 1).and_return({})
|
233
|
+
$stdout.should_receive(:puts).with(green "File deleted, redeploy your cloud to make changes")
|
234
|
+
@config.options = {:cloud => "foo-production"}
|
235
|
+
fake_stdin(["y"]) do
|
236
|
+
@config.delete(1)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
55
241
|
end
|
@@ -42,7 +42,7 @@ describe Shelly::CLI::Deploys do
|
|
42
42
|
|
43
43
|
it "should show information to select specific cloud and exit" do
|
44
44
|
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to view deploy logs using:")
|
45
|
-
$stdout.should_receive(:puts).with(" shelly deploys list foo-production")
|
45
|
+
$stdout.should_receive(:puts).with(" shelly deploys list --cloud foo-production")
|
46
46
|
$stdout.should_receive(:puts).with("Available clouds:")
|
47
47
|
$stdout.should_receive(:puts).with(" * foo-production")
|
48
48
|
$stdout.should_receive(:puts).with(" * foo-staging")
|
@@ -53,7 +53,8 @@ describe Shelly::CLI::Deploys do
|
|
53
53
|
@client.should_receive(:deploy_logs).with("foo-staging").and_return([{"failed" => false, "created_at" => "2011-12-12-14-14-59"}])
|
54
54
|
$stdout.should_receive(:puts).with(green "Available deploy logs")
|
55
55
|
$stdout.should_receive(:puts).with(" * 2011-12-12-14-14-59")
|
56
|
-
@deploys.
|
56
|
+
@deploys.options = {:cloud => "foo-staging"}
|
57
|
+
@deploys.list
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
@@ -99,7 +100,7 @@ describe Shelly::CLI::Deploys do
|
|
99
100
|
|
100
101
|
it "should show information to select specific cloud and exit" do
|
101
102
|
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select log and cloud to view deploy logs using:")
|
102
|
-
$stdout.should_receive(:puts).with(" shelly deploys show last foo-production")
|
103
|
+
$stdout.should_receive(:puts).with(" shelly deploys show last --cloud foo-production")
|
103
104
|
$stdout.should_receive(:puts).with("Available clouds:")
|
104
105
|
$stdout.should_receive(:puts).with(" * foo-production")
|
105
106
|
$stdout.should_receive(:puts).with(" * foo-staging")
|
@@ -109,7 +110,8 @@ describe Shelly::CLI::Deploys do
|
|
109
110
|
it "should render the logs" do
|
110
111
|
@client.should_receive(:deploy_log).with("foo-staging", "last").and_return(response)
|
111
112
|
expected_output
|
112
|
-
@deploys.
|
113
|
+
@deploys.options = {:cloud => "foo-staging"}
|
114
|
+
@deploys.show("last")
|
113
115
|
end
|
114
116
|
end
|
115
117
|
|
@@ -26,7 +26,7 @@ Tasks:
|
|
26
26
|
shelly add # Adds new cloud to Shelly Cloud
|
27
27
|
shelly backup <command> # Manages database backups from this cloud
|
28
28
|
shelly config <command> # Manages cloud configuration files
|
29
|
-
shelly delete
|
29
|
+
shelly delete # Delete cloud from Shelly Cloud
|
30
30
|
shelly deploys <command> # View cloud deploy logs
|
31
31
|
shelly help [TASK] # Describe available tasks or one specific task
|
32
32
|
shelly ip # Lists clouds IP's
|
@@ -34,8 +34,8 @@ Tasks:
|
|
34
34
|
shelly login [EMAIL] # Logs user in to Shelly Cloud
|
35
35
|
shelly logs # Show latest application logs from each instance
|
36
36
|
shelly register [EMAIL] # Registers new user account on Shelly Cloud
|
37
|
-
shelly start
|
38
|
-
shelly stop
|
37
|
+
shelly start # Starts the cloud
|
38
|
+
shelly stop # Stops the cloud
|
39
39
|
shelly user <command> # Manages users using this cloud
|
40
40
|
shelly version # Displays shelly version
|
41
41
|
|
@@ -538,8 +538,8 @@ OUT
|
|
538
538
|
end
|
539
539
|
|
540
540
|
it "should show information to start specific cloud and exit" do
|
541
|
-
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select
|
542
|
-
$stdout.should_receive(:puts).with(" shelly start foo-production")
|
541
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to start using:")
|
542
|
+
$stdout.should_receive(:puts).with(" shelly start --cloud foo-production")
|
543
543
|
$stdout.should_receive(:puts).with("Available clouds:")
|
544
544
|
$stdout.should_receive(:puts).with(" * foo-production")
|
545
545
|
$stdout.should_receive(:puts).with(" * foo-staging")
|
@@ -550,7 +550,8 @@ OUT
|
|
550
550
|
@client.should_receive(:start_cloud).with("foo-staging")
|
551
551
|
$stdout.should_receive(:puts).with(green "Starting cloud foo-staging. Check status with:")
|
552
552
|
$stdout.should_receive(:puts).with(" shelly list")
|
553
|
-
@main.
|
553
|
+
@main.options = {:cloud => "foo-staging"}
|
554
|
+
@main.start
|
554
555
|
end
|
555
556
|
end
|
556
557
|
|
@@ -654,8 +655,8 @@ OUT
|
|
654
655
|
end
|
655
656
|
|
656
657
|
it "should show information to start specific cloud and exit" do
|
657
|
-
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select
|
658
|
-
$stdout.should_receive(:puts).with(" shelly stop foo-production")
|
658
|
+
$stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to stop using:")
|
659
|
+
$stdout.should_receive(:puts).with(" shelly stop --cloud foo-production")
|
659
660
|
$stdout.should_receive(:puts).with("Available clouds:")
|
660
661
|
$stdout.should_receive(:puts).with(" * foo-production")
|
661
662
|
$stdout.should_receive(:puts).with(" * foo-staging")
|
@@ -665,7 +666,8 @@ OUT
|
|
665
666
|
it "should fetch from command line which cloud to start" do
|
666
667
|
@client.should_receive(:stop_cloud).with("foo-staging")
|
667
668
|
$stdout.should_receive(:puts).with("Cloud 'foo-staging' stopped")
|
668
|
-
@main.
|
669
|
+
@main.options = {:cloud => "foo-staging"}
|
670
|
+
@main.stop
|
669
671
|
end
|
670
672
|
end
|
671
673
|
end
|
@@ -734,9 +736,14 @@ OUT
|
|
734
736
|
Shelly::App.stub(:new).and_return(@app)
|
735
737
|
end
|
736
738
|
|
737
|
-
context "when
|
739
|
+
context "when cloud is given" do
|
740
|
+
before do
|
741
|
+
File.open("Cloudfile", 'w') {|f|
|
742
|
+
f.write("foo-staging:\nfoo-production:\n") }
|
743
|
+
end
|
744
|
+
|
738
745
|
it "should ask about delete application parts" do
|
739
|
-
$stdout.should_receive(:puts).with("You are about to delete application: foo-
|
746
|
+
$stdout.should_receive(:puts).with("You are about to delete application: foo-staging.")
|
740
747
|
$stdout.should_receive(:puts).with("Press Control-C at any moment to cancel.")
|
741
748
|
$stdout.should_receive(:puts).with("Please confirm each question by typing yes and pressing Enter.")
|
742
749
|
$stdout.should_receive(:puts).with("\n")
|
@@ -747,7 +754,8 @@ OUT
|
|
747
754
|
$stdout.should_receive(:puts).with("Scheduling application delete - done")
|
748
755
|
$stdout.should_receive(:puts).with("Removing git remote - done")
|
749
756
|
fake_stdin(["yes", "yes", "yes"]) do
|
750
|
-
@main.
|
757
|
+
@main.options = {:cloud => "foo-staging"}
|
758
|
+
@main.delete
|
751
759
|
end
|
752
760
|
end
|
753
761
|
|
@@ -755,23 +763,35 @@ OUT
|
|
755
763
|
@app.should_not_receive(:delete)
|
756
764
|
lambda{
|
757
765
|
fake_stdin(["yes", "yes", "no"]) do
|
758
|
-
@main.
|
766
|
+
@main.options = {:cloud => "foo-staging"}
|
767
|
+
@main.delete
|
759
768
|
end
|
760
769
|
}.should raise_error(SystemExit)
|
761
770
|
end
|
762
771
|
end
|
763
772
|
|
764
773
|
context "when git repository doesn't exist" do
|
774
|
+
before do
|
775
|
+
File.open("Cloudfile", 'w') {|f|
|
776
|
+
f.write("foo-staging:\n") }
|
777
|
+
end
|
778
|
+
|
765
779
|
it "should say that Git remote missing" do
|
766
780
|
Shelly::App.stub(:inside_git_repository?).and_return(false)
|
767
781
|
$stdout.should_receive(:puts).with("Missing git remote")
|
768
782
|
fake_stdin(["yes", "yes", "yes"]) do
|
769
|
-
@main.
|
783
|
+
@main.options = {:cloud => "foo-staging"}
|
784
|
+
@main.delete
|
770
785
|
end
|
771
786
|
end
|
772
787
|
end
|
773
788
|
|
774
|
-
context "when
|
789
|
+
context "when cloud given in option doesn't exist" do
|
790
|
+
before do
|
791
|
+
File.open("Cloudfile", 'w') {|f|
|
792
|
+
f.write("foo-staging:\n") }
|
793
|
+
end
|
794
|
+
|
775
795
|
it "should raise Client::APIError" do
|
776
796
|
response = {:message => "Application not found"}
|
777
797
|
exception = Shelly::Client::APIError.new(response.to_json)
|
@@ -779,17 +799,33 @@ OUT
|
|
779
799
|
$stdout.should_receive(:puts).with("\e[31mApplication not found\e[0m")
|
780
800
|
lambda{
|
781
801
|
fake_stdin(["yes", "yes", "yes"]) do
|
782
|
-
@main.
|
802
|
+
@main.options = {:cloud => "foo-bar"}
|
803
|
+
@main.delete
|
783
804
|
end
|
784
805
|
}.should raise_error(SystemExit)
|
785
806
|
end
|
786
807
|
end
|
787
808
|
|
788
|
-
context "when
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
809
|
+
context "when no cloud option is given" do
|
810
|
+
before do
|
811
|
+
File.open("Cloudfile", 'w') {|f|
|
812
|
+
f.write("foo-staging:\n") }
|
813
|
+
end
|
814
|
+
|
815
|
+
it "should take the cloud from Cloudfile" do
|
816
|
+
$stdout.should_receive(:puts).with("You are about to delete application: foo-staging.")
|
817
|
+
$stdout.should_receive(:puts).with("Press Control-C at any moment to cancel.")
|
818
|
+
$stdout.should_receive(:puts).with("Please confirm each question by typing yes and pressing Enter.")
|
819
|
+
$stdout.should_receive(:puts).with("\n")
|
820
|
+
$stdout.should_receive(:print).with("I want to delete all files stored on Shelly Cloud (yes/no): ")
|
821
|
+
$stdout.should_receive(:print).with("I want to delete all database data stored on Shelly Cloud (yes/no): ")
|
822
|
+
$stdout.should_receive(:print).with("I want to delete the application (yes/no): ")
|
823
|
+
$stdout.should_receive(:puts).with("\n")
|
824
|
+
$stdout.should_receive(:puts).with("Scheduling application delete - done")
|
825
|
+
$stdout.should_receive(:puts).with("Removing git remote - done")
|
826
|
+
fake_stdin(["yes", "yes", "yes"]) do
|
827
|
+
@main.delete
|
828
|
+
end
|
793
829
|
end
|
794
830
|
end
|
795
831
|
end
|
@@ -839,8 +875,8 @@ OUT
|
|
839
875
|
it "should show logs for the cloud" do
|
840
876
|
@client.stub(:application_logs).and_return(["log1"])
|
841
877
|
$stdout.should_receive(:puts).with(green "Cloud foo-production:")
|
842
|
-
$stdout.should_receive(:puts).with("Instance 1:")
|
843
|
-
$stdout.should_receive(:puts).with("
|
878
|
+
$stdout.should_receive(:puts).with(green "Instance 1:")
|
879
|
+
$stdout.should_receive(:puts).with("log1")
|
844
880
|
@main.logs
|
845
881
|
end
|
846
882
|
end
|
@@ -865,8 +901,8 @@ OUT
|
|
865
901
|
@client.should_receive(:application_logs).with("foo-staging").
|
866
902
|
and_return(["log1"])
|
867
903
|
$stdout.should_receive(:puts).with(green "Cloud foo-staging:")
|
868
|
-
$stdout.should_receive(:puts).with("Instance 1:")
|
869
|
-
$stdout.should_receive(:puts).with("
|
904
|
+
$stdout.should_receive(:puts).with(green "Instance 1:")
|
905
|
+
$stdout.should_receive(:puts).with("log1")
|
870
906
|
@main.options = {:cloud => "foo-staging"}
|
871
907
|
@main.logs
|
872
908
|
end
|
@@ -876,10 +912,10 @@ OUT
|
|
876
912
|
it "should show logs from each instance" do
|
877
913
|
@client.stub(:application_logs).and_return(["log1", "log2"])
|
878
914
|
$stdout.should_receive(:puts).with(green "Cloud foo-production:")
|
879
|
-
$stdout.should_receive(:puts).with("Instance 1:")
|
880
|
-
$stdout.should_receive(:puts).with("
|
881
|
-
$stdout.should_receive(:puts).with("Instance 2:")
|
882
|
-
$stdout.should_receive(:puts).with("
|
915
|
+
$stdout.should_receive(:puts).with(green "Instance 1:")
|
916
|
+
$stdout.should_receive(:puts).with("log1")
|
917
|
+
$stdout.should_receive(:puts).with(green "Instance 2:")
|
918
|
+
$stdout.should_receive(:puts).with("log2")
|
883
919
|
@main.logs
|
884
920
|
end
|
885
921
|
end
|
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: 93
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 33
|
10
|
+
version: 0.0.33
|
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-12-
|
18
|
+
date: 2011-12-26 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rspec
|