shelly 0.0.33 → 0.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/shelly/app.rb +12 -4
- data/lib/shelly/backup.rb +16 -0
- data/lib/shelly/cli/backup.rb +29 -5
- data/lib/shelly/client.rb +34 -4
- data/lib/shelly/download_progress_bar.rb +14 -0
- data/lib/shelly/version.rb +1 -1
- data/shelly.gemspec +1 -0
- data/spec/shelly/app_spec.rb +24 -0
- data/spec/shelly/backup_spec.rb +34 -0
- data/spec/shelly/cli/backup_spec.rb +67 -9
- data/spec/shelly/cli/config_spec.rb +1 -1
- data/spec/shelly/cli/deploys_spec.rb +2 -2
- data/spec/shelly/cli/main_spec.rb +12 -12
- data/spec/shelly/cli/user_spec.rb +2 -2
- data/spec/shelly/client_spec.rb +71 -14
- data/spec/shelly/download_progress_bar_spec.rb +28 -0
- metadata +24 -4
data/lib/shelly/app.rb
CHANGED
|
@@ -8,6 +8,8 @@ module Shelly
|
|
|
8
8
|
attr_accessor :code_name, :databases, :ruby_version, :environment,
|
|
9
9
|
:git_url, :domains
|
|
10
10
|
|
|
11
|
+
autoload :Backup, "shelly/backup"
|
|
12
|
+
|
|
11
13
|
def initialize(code_name = nil)
|
|
12
14
|
self.code_name = code_name
|
|
13
15
|
end
|
|
@@ -59,15 +61,22 @@ module Shelly
|
|
|
59
61
|
end
|
|
60
62
|
|
|
61
63
|
def application_logs
|
|
62
|
-
shelly.application_logs(
|
|
64
|
+
shelly.application_logs(code_name)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
67
|
def database_backups
|
|
66
|
-
shelly.database_backups(code_name)
|
|
68
|
+
shelly.database_backups(code_name).map do |attributes|
|
|
69
|
+
Shelly::Backup.new(attributes.merge("code_name" => code_name))
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def database_backup(handler)
|
|
74
|
+
attributes = shelly.database_backup(code_name, handler)
|
|
75
|
+
Shelly::Backup.new(attributes.merge("code_name" => code_name))
|
|
67
76
|
end
|
|
68
77
|
|
|
69
78
|
def logs
|
|
70
|
-
shelly.cloud_logs(
|
|
79
|
+
shelly.cloud_logs(code_name)
|
|
71
80
|
end
|
|
72
81
|
|
|
73
82
|
def start
|
|
@@ -132,4 +141,3 @@ module Shelly
|
|
|
132
141
|
end
|
|
133
142
|
end
|
|
134
143
|
end
|
|
135
|
-
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Shelly
|
|
2
|
+
class Backup < Model
|
|
3
|
+
attr_reader :filename, :size, :human_size, :code_name
|
|
4
|
+
|
|
5
|
+
def initialize(attributes = {})
|
|
6
|
+
@filename = attributes["filename"]
|
|
7
|
+
@size = attributes["size"]
|
|
8
|
+
@human_size = attributes["human_size"]
|
|
9
|
+
@code_name = attributes["code_name"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def download(callback)
|
|
13
|
+
shelly.download_backup(code_name, filename, callback)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/shelly/cli/backup.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require "shelly/cli/command"
|
|
2
|
+
require "shelly/backup"
|
|
3
|
+
require "shelly/download_progress_bar"
|
|
2
4
|
|
|
3
5
|
module Shelly
|
|
4
6
|
module CLI
|
|
@@ -15,13 +17,15 @@ module Shelly
|
|
|
15
17
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
|
16
18
|
multiple_clouds(options[:cloud], "backup list", "Select cloud to view database backups for using:")
|
|
17
19
|
backups = @app.database_backups
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
if backups.present?
|
|
21
|
+
to_display = [["Filename", "| Size"]]
|
|
22
|
+
backups.each do |backup|
|
|
23
|
+
to_display << [backup.filename, "| #{backup.human_size}"]
|
|
24
|
+
end
|
|
25
|
+
|
|
20
26
|
say "Available backups:", :green
|
|
21
27
|
say_new_line
|
|
22
|
-
print_table(
|
|
23
|
-
[backup['filename'], "| #{backup['size']}"]
|
|
24
|
-
end, :ident => 2)
|
|
28
|
+
print_table(to_display, :ident => 2)
|
|
25
29
|
else
|
|
26
30
|
say "No database backups available"
|
|
27
31
|
end
|
|
@@ -32,6 +36,26 @@ module Shelly
|
|
|
32
36
|
say_error e.message
|
|
33
37
|
end
|
|
34
38
|
end
|
|
39
|
+
|
|
40
|
+
method_option :cloud, :type => :string, :aliases => "-c", :desc => "Specify which cloud list backups for"
|
|
41
|
+
desc "get [FILENAME]", "Downloads specified or last backup to current directory"
|
|
42
|
+
def get(handler = "last")
|
|
43
|
+
multiple_clouds(options[:cloud], "backup get [FILENAME]", "Select cloud for which you want download backup")
|
|
44
|
+
|
|
45
|
+
backup = @app.database_backup(handler)
|
|
46
|
+
bar = Shelly::DownloadProgressBar.new(backup.size)
|
|
47
|
+
backup.download(bar.progress_callback)
|
|
48
|
+
|
|
49
|
+
say_new_line
|
|
50
|
+
say "Backup file saved to #{backup.filename}", :green
|
|
51
|
+
rescue Client::APIError => e
|
|
52
|
+
if e.not_found?
|
|
53
|
+
say_error "Backup not found", :with_exit => false
|
|
54
|
+
say "You can list available backups with 'shelly backup list' command"
|
|
55
|
+
else
|
|
56
|
+
raise e
|
|
57
|
+
end
|
|
58
|
+
end
|
|
35
59
|
end
|
|
36
60
|
end
|
|
37
61
|
end
|
data/lib/shelly/client.rb
CHANGED
|
@@ -4,8 +4,11 @@ require "json"
|
|
|
4
4
|
module Shelly
|
|
5
5
|
class Client
|
|
6
6
|
class APIError < Exception
|
|
7
|
-
|
|
7
|
+
attr_reader :status_code
|
|
8
|
+
|
|
9
|
+
def initialize(response_body, status_code)
|
|
8
10
|
@response = JSON.parse(response_body)
|
|
11
|
+
@status_code = status_code
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
def message
|
|
@@ -23,10 +26,14 @@ module Shelly
|
|
|
23
26
|
def validation?
|
|
24
27
|
message == "Validation Failed"
|
|
25
28
|
end
|
|
29
|
+
|
|
30
|
+
def not_found?
|
|
31
|
+
status_code == 404
|
|
32
|
+
end
|
|
26
33
|
|
|
27
34
|
def unauthorized?
|
|
28
|
-
# FIXME: Return unauthorized if user has no access to cloud
|
|
29
|
-
# Return 404 if
|
|
35
|
+
# FIXME: Return unauthorized if user has no access to cloud, checked by 401 status code
|
|
36
|
+
# Return 404 if child of app doesn't exist, should be fixed in API
|
|
30
37
|
message == "Unauthorized" || message =~ /Cloud .+ not found/
|
|
31
38
|
end
|
|
32
39
|
|
|
@@ -37,6 +44,8 @@ module Shelly
|
|
|
37
44
|
end
|
|
38
45
|
end
|
|
39
46
|
|
|
47
|
+
attr_reader :email, :password
|
|
48
|
+
|
|
40
49
|
def initialize(email = nil, password = nil)
|
|
41
50
|
@email = email
|
|
42
51
|
@password = password
|
|
@@ -121,6 +130,10 @@ module Shelly
|
|
|
121
130
|
def database_backups(code_name)
|
|
122
131
|
get("/apps/#{code_name}/database_backups")
|
|
123
132
|
end
|
|
133
|
+
|
|
134
|
+
def database_backup(code_name, handler)
|
|
135
|
+
get("/apps/#{code_name}/database_backups/#{handler}")
|
|
136
|
+
end
|
|
124
137
|
|
|
125
138
|
def ssh_key_available?(ssh_key)
|
|
126
139
|
get("/users/new", :ssh_key => ssh_key)
|
|
@@ -149,6 +162,23 @@ module Shelly
|
|
|
149
162
|
def delete(path, params = {})
|
|
150
163
|
request(path, :delete, params)
|
|
151
164
|
end
|
|
165
|
+
|
|
166
|
+
def download_backup(cloud, filename, progress_callback = nil)
|
|
167
|
+
File.open(filename, "w") do |out|
|
|
168
|
+
process_response = lambda do |response|
|
|
169
|
+
response.read_body do |chunk|
|
|
170
|
+
out.write(chunk)
|
|
171
|
+
progress_callback.call(chunk.size) if progress_callback
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
options = request_parameters("/apps/#{cloud}/database_backups/#{filename}", :get)
|
|
176
|
+
options = options.merge(:block_response => process_response,
|
|
177
|
+
:headers => {:accept => "application/x-gzip"})
|
|
178
|
+
|
|
179
|
+
RestClient::Request.execute(options)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
152
182
|
|
|
153
183
|
def request(path, method, params = {})
|
|
154
184
|
options = request_parameters(path, method, params)
|
|
@@ -177,7 +207,7 @@ module Shelly
|
|
|
177
207
|
|
|
178
208
|
def process_response(response)
|
|
179
209
|
if [401, 404, 422, 500].include?(response.code)
|
|
180
|
-
raise APIError.new(response.body)
|
|
210
|
+
raise APIError.new(response.body, response.code)
|
|
181
211
|
end
|
|
182
212
|
|
|
183
213
|
response.return!
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "progressbar"
|
|
2
|
+
|
|
3
|
+
module Shelly
|
|
4
|
+
class DownloadProgressBar < ProgressBar
|
|
5
|
+
def initialize(total)
|
|
6
|
+
super("Progress", total)
|
|
7
|
+
self.format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def progress_callback
|
|
11
|
+
lambda { |size| inc(size) }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/shelly/version.rb
CHANGED
data/shelly.gemspec
CHANGED
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
s.add_runtime_dependency "rest-client"
|
|
27
27
|
s.add_runtime_dependency "json"
|
|
28
28
|
s.add_runtime_dependency "wijet-launchy"
|
|
29
|
+
s.add_runtime_dependency "progressbar"
|
|
29
30
|
|
|
30
31
|
s.files = `git ls-files`.split("\n")
|
|
31
32
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/spec/shelly/app_spec.rb
CHANGED
|
@@ -167,6 +167,30 @@ config
|
|
|
167
167
|
end
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
+
describe "#database_backup" do
|
|
171
|
+
before do
|
|
172
|
+
@description = {
|
|
173
|
+
"filename" => "backup.tar.gz",
|
|
174
|
+
"size" => 1234,
|
|
175
|
+
"human_size" => "2KB"
|
|
176
|
+
}
|
|
177
|
+
@client.stub(:database_backup).and_return(@description)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "should fetch backup from API" do
|
|
181
|
+
@client.should_receive(:database_backup).with("foo-staging", "backup.tar.gz")
|
|
182
|
+
@app.database_backup("backup.tar.gz")
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "should initialize backup object" do
|
|
186
|
+
backup = @app.database_backup("backup.tar.gz")
|
|
187
|
+
backup.code_name.should == "foo-staging"
|
|
188
|
+
backup.size.should == 1234
|
|
189
|
+
backup.human_size.should == "2KB"
|
|
190
|
+
backup.filename.should == "backup.tar.gz"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
170
194
|
describe "#create" do
|
|
171
195
|
context "without providing domain" do
|
|
172
196
|
it "should create the app on shelly cloud via API client" do
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "shelly/backup"
|
|
3
|
+
|
|
4
|
+
describe Shelly::Backup do
|
|
5
|
+
before do
|
|
6
|
+
@client = mock
|
|
7
|
+
Shelly::Client.stub(:new).and_return(@client)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should assign attributes" do
|
|
11
|
+
backup = Shelly::Backup.new(attributes)
|
|
12
|
+
|
|
13
|
+
backup.code_name.should == "foo"
|
|
14
|
+
backup.filename.should == "backup.tar.gz"
|
|
15
|
+
backup.human_size.should == "2KB"
|
|
16
|
+
backup.size.should == 2048
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#download" do
|
|
20
|
+
it "should download given backup via API file with filename to which backup will be downloaded" do
|
|
21
|
+
callback = lambda {}
|
|
22
|
+
@client.should_receive(:download_backup).with("foo", "backup.tar.gz", callback)
|
|
23
|
+
backup = Shelly::Backup.new(attributes)
|
|
24
|
+
backup.download(callback)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def attributes
|
|
29
|
+
{"code_name" => "foo",
|
|
30
|
+
"filename" => "backup.tar.gz",
|
|
31
|
+
"human_size" => "2KB",
|
|
32
|
+
"size" => 2048}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
require "shelly/cli/backup"
|
|
3
|
+
require "shelly/download_progress_bar"
|
|
3
4
|
|
|
4
5
|
describe Shelly::CLI::Backup do
|
|
5
6
|
before do
|
|
6
7
|
@backup = Shelly::CLI::Backup.new
|
|
7
8
|
@client = mock
|
|
9
|
+
@client.stub(:token).and_return("abc")
|
|
8
10
|
Shelly::Client.stub(:new).and_return(@client)
|
|
11
|
+
FileUtils.mkdir_p("/projects/foo")
|
|
12
|
+
Dir.chdir("/projects/foo")
|
|
13
|
+
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
|
|
9
14
|
end
|
|
10
15
|
|
|
11
16
|
describe "#list" do
|
|
12
|
-
before do
|
|
13
|
-
FileUtils.mkdir_p("/projects/foo")
|
|
14
|
-
Dir.chdir("/projects/foo")
|
|
15
|
-
File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
|
|
16
|
-
@client.stub(:token).and_return("abc")
|
|
17
|
-
end
|
|
18
|
-
|
|
19
17
|
it "should exit with message if there is no Cloudfile" do
|
|
20
18
|
File.delete("Cloudfile")
|
|
21
19
|
$stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
|
|
@@ -26,7 +24,7 @@ describe Shelly::CLI::Backup do
|
|
|
26
24
|
|
|
27
25
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
|
28
26
|
response = {"message" => "Cloud foo-staging not found"}
|
|
29
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
27
|
+
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
|
30
28
|
@client.stub(:database_backups).and_raise(exception)
|
|
31
29
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
|
32
30
|
lambda { @backup.list }.should raise_error(SystemExit)
|
|
@@ -47,7 +45,7 @@ describe Shelly::CLI::Backup do
|
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
it "should take cloud from command line for which to show backups" do
|
|
50
|
-
@client.should_receive(:database_backups).with("foo-staging").and_return([{"filename" => "backup.postgre.tar.gz", "
|
|
48
|
+
@client.should_receive(:database_backups).with("foo-staging").and_return([{"filename" => "backup.postgre.tar.gz", "human_size" => "10kb", "size" => 12345},{"filename" => "backup.mongo.tar.gz", "human_size" => "22kb", "size" => 333}])
|
|
51
49
|
$stdout.should_receive(:puts).with(green "Available backups:")
|
|
52
50
|
$stdout.should_receive(:puts).with("\n")
|
|
53
51
|
$stdout.should_receive(:puts).with(" Filename | Size")
|
|
@@ -57,5 +55,65 @@ describe Shelly::CLI::Backup do
|
|
|
57
55
|
@backup.list
|
|
58
56
|
end
|
|
59
57
|
end
|
|
58
|
+
|
|
59
|
+
describe "#get" do
|
|
60
|
+
before do
|
|
61
|
+
@client.stub(:download_backup)
|
|
62
|
+
@bar = mock(:progress_callback => @callback)
|
|
63
|
+
Shelly::DownloadProgressBar.stub(:new).and_return(@bar)
|
|
64
|
+
@client.stub(:database_backup).and_return({"filename" => "better.tar.gz", "size" => 12345})
|
|
65
|
+
$stdout.stub(:puts)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should make sure that cloud is choosen" do
|
|
69
|
+
@client.should_receive(:database_backup).with("foo-staging", "last")
|
|
70
|
+
@backup.get
|
|
71
|
+
|
|
72
|
+
@backup.options = {:cloud => "other"}
|
|
73
|
+
@client.should_receive(:database_backup).with("other", "last")
|
|
74
|
+
@backup.get
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should fetch backup size and initialize download progress bar" do
|
|
78
|
+
@client.stub(:database_backup).and_return({"filename" => "backup.postgres.tar.gz", "size" => 333})
|
|
79
|
+
Shelly::DownloadProgressBar.should_receive(:new).with(333).and_return(@bar)
|
|
80
|
+
|
|
81
|
+
@backup.get
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should fetch given backup file itself" do
|
|
85
|
+
@client.should_receive(:download_backup).with("foo-staging", "better.tar.gz", @bar.progress_callback)
|
|
86
|
+
@backup.get("better.tar.gz")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should show info where file has been saved" do
|
|
90
|
+
$stdout.should_receive(:puts)
|
|
91
|
+
$stdout.should_receive(:puts).with(green "Backup file saved to better.tar.gz")
|
|
92
|
+
@client.should_receive(:download_backup).with("foo-staging", "better.tar.gz", @bar.progress_callback)
|
|
93
|
+
@backup.get("last")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "on backup not found" do
|
|
97
|
+
it "it should display error message" do
|
|
98
|
+
exception = Shelly::Client::APIError.new({}.to_json, 404)
|
|
99
|
+
@client.stub(:database_backup).and_raise(exception)
|
|
100
|
+
$stdout.should_receive(:puts).with(red "Backup not found")
|
|
101
|
+
$stdout.should_receive(:puts).with("You can list available backups with 'shelly backup list' command")
|
|
102
|
+
@backup.get("better.tar.gz")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
context "on unsupported exception" do
|
|
107
|
+
it "should re-raise it" do
|
|
108
|
+
exception = Shelly::Client::APIError.new({}.to_json, 500)
|
|
109
|
+
@client.stub(:database_backup).and_raise(exception)
|
|
110
|
+
$stdout.should_not_receive(:puts).with(red "Backup not found")
|
|
111
|
+
$stdout.should_not_receive(:puts).with("You can list available backups with 'shelly backup list' command")
|
|
112
|
+
lambda {
|
|
113
|
+
@backup.get("better.tar.gz")
|
|
114
|
+
}.should raise_error(Shelly::Client::APIError)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
60
118
|
end
|
|
61
119
|
end
|
|
@@ -34,7 +34,7 @@ describe Shelly::CLI::Config do
|
|
|
34
34
|
|
|
35
35
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
|
36
36
|
response = {"message" => "Cloud foo-staging not found"}
|
|
37
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
37
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
38
38
|
@client.stub(:app_configs).and_raise(exception)
|
|
39
39
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
|
40
40
|
lambda { @config.list }.should raise_error(SystemExit)
|
|
@@ -29,7 +29,7 @@ describe Shelly::CLI::Deploys do
|
|
|
29
29
|
|
|
30
30
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
|
31
31
|
response = {"message" => "Cloud foo-staging not found"}
|
|
32
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
32
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
33
33
|
@client.stub(:deploy_logs).and_raise(exception)
|
|
34
34
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
|
35
35
|
lambda { @deploys.list }.should raise_error(SystemExit)
|
|
@@ -87,7 +87,7 @@ describe Shelly::CLI::Deploys do
|
|
|
87
87
|
|
|
88
88
|
it "should exit if user doesn't have access to cloud in Cloudfile" do
|
|
89
89
|
response = {"message" => "Cloud foo-staging not found"}
|
|
90
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
90
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
91
91
|
@client.stub(:deploy_log).and_raise(exception)
|
|
92
92
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
|
93
93
|
lambda { @deploys.show("last") }.should raise_error(SystemExit)
|
|
@@ -172,7 +172,7 @@ OUT
|
|
|
172
172
|
context "on unsuccessful registration" do
|
|
173
173
|
it "should display errors and exit with 1" do
|
|
174
174
|
response = {"message" => "Validation Failed", "errors" => [["email", "has been already taken"]]}
|
|
175
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
175
|
+
exception = Shelly::Client::APIError.new(response.to_json, 422)
|
|
176
176
|
@client.stub(:register_user).and_raise(exception)
|
|
177
177
|
$stdout.should_receive(:puts).with("\e[31mEmail has been already taken\e[0m")
|
|
178
178
|
lambda {
|
|
@@ -259,7 +259,7 @@ OUT
|
|
|
259
259
|
context "on unauthorized user" do
|
|
260
260
|
it "should exit with 1 and display error message" do
|
|
261
261
|
response = {"message" => "Unauthorized", "url" => "https://admin.winniecloud.com/users/password/new"}
|
|
262
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
262
|
+
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
|
263
263
|
@client.stub(:token).and_raise(exception)
|
|
264
264
|
$stdout.should_receive(:puts).with("\e[31mWrong email or password\e[0m")
|
|
265
265
|
$stdout.should_receive(:puts).with("\e[31mYou can reset password by using link:\e[0m")
|
|
@@ -386,7 +386,7 @@ OUT
|
|
|
386
386
|
|
|
387
387
|
it "should display validation errors if they are any" do
|
|
388
388
|
response = {"message" => "Validation Failed", "errors" => [["code_name", "has been already taken"]]}
|
|
389
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
389
|
+
exception = Shelly::Client::APIError.new(response.to_json, 422)
|
|
390
390
|
@app.should_receive(:create).and_raise(exception)
|
|
391
391
|
$stdout.should_receive(:puts).with("\e[31mCode name has been already taken\e[0m")
|
|
392
392
|
$stdout.should_receive(:puts).with("\e[31mFix erros in the below command and type it again to create your cloud\e[0m")
|
|
@@ -475,7 +475,7 @@ OUT
|
|
|
475
475
|
context "on failure" do
|
|
476
476
|
it "should display info that user is not logged in" do
|
|
477
477
|
body = {"message" => "Unauthorized"}
|
|
478
|
-
error = Shelly::Client::APIError.new(body.to_json)
|
|
478
|
+
error = Shelly::Client::APIError.new(body.to_json, 401)
|
|
479
479
|
@client.stub(:token).and_raise(error)
|
|
480
480
|
$stdout.should_receive(:puts).with("\e[31mYou are not logged in, use `shelly login`\e[0m")
|
|
481
481
|
lambda {
|
|
@@ -508,7 +508,7 @@ OUT
|
|
|
508
508
|
|
|
509
509
|
it "should exit if user doesn't have access to clouds in Cloudfile" do
|
|
510
510
|
response = {"message" => "Cloud foo-production not found"}
|
|
511
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
511
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
512
512
|
@client.stub(:start_cloud).and_raise(exception)
|
|
513
513
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
|
514
514
|
lambda { @main.start }.should raise_error(SystemExit)
|
|
@@ -516,7 +516,7 @@ OUT
|
|
|
516
516
|
|
|
517
517
|
it "should exit if user is not logged in" do
|
|
518
518
|
response = {"message" => "Unauthorized"}
|
|
519
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
519
|
+
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
|
520
520
|
@client.stub(:token).and_raise(exception)
|
|
521
521
|
$stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
|
|
522
522
|
$stdout.should_receive(:puts).with(" shelly login")
|
|
@@ -626,7 +626,7 @@ OUT
|
|
|
626
626
|
|
|
627
627
|
it "should exit if user doesn't have access to clouds in Cloudfile" do
|
|
628
628
|
response = {"message" => "Cloud foo-production not found"}
|
|
629
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
629
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
630
630
|
@client.stub(:stop_cloud).and_raise(exception)
|
|
631
631
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
|
|
632
632
|
lambda { @main.stop }.should raise_error(SystemExit)
|
|
@@ -634,7 +634,7 @@ OUT
|
|
|
634
634
|
|
|
635
635
|
it "should exit if user is not logged in" do
|
|
636
636
|
response = {"message" => "Unauthorized"}
|
|
637
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
637
|
+
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
|
638
638
|
@client.stub(:token).and_raise(exception)
|
|
639
639
|
$stdout.should_receive(:puts).with(red "You are not logged in. To log in use:")
|
|
640
640
|
$stdout.should_receive(:puts).with(" shelly login")
|
|
@@ -717,7 +717,7 @@ OUT
|
|
|
717
717
|
|
|
718
718
|
it "should raise an error if user does not have access to cloud" do
|
|
719
719
|
response = {"message" => "Cloud foo-staging not found"}
|
|
720
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
720
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
721
721
|
@client.stub(:app_ips).and_raise(exception)
|
|
722
722
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
|
723
723
|
@main.ip
|
|
@@ -794,7 +794,7 @@ OUT
|
|
|
794
794
|
|
|
795
795
|
it "should raise Client::APIError" do
|
|
796
796
|
response = {:message => "Application not found"}
|
|
797
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
797
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
798
798
|
@app.stub(:delete).and_raise(exception)
|
|
799
799
|
$stdout.should_receive(:puts).with("\e[31mApplication not found\e[0m")
|
|
800
800
|
lambda{
|
|
@@ -854,7 +854,7 @@ OUT
|
|
|
854
854
|
|
|
855
855
|
it "should exit if user doesn't have access to clouds in Cloudfile" do
|
|
856
856
|
response = {"message" => "Cloud foo-production not found"}
|
|
857
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
857
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
858
858
|
@client.stub(:application_logs).and_raise(exception)
|
|
859
859
|
$stdout.should_receive(:puts).
|
|
860
860
|
with(red "You have no access to cloud 'foo-production'")
|
|
@@ -863,7 +863,7 @@ OUT
|
|
|
863
863
|
|
|
864
864
|
it "should exit if user is not logged in" do
|
|
865
865
|
response = {"message" => "Unauthorized"}
|
|
866
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
866
|
+
exception = Shelly::Client::APIError.new(response.to_json, 401)
|
|
867
867
|
@client.stub(:token).and_raise(exception)
|
|
868
868
|
$stdout.should_receive(:puts).
|
|
869
869
|
with(red "You are not logged in. To log in use:")
|
|
@@ -69,7 +69,7 @@ describe Shelly::CLI::User do
|
|
|
69
69
|
context "on failure" do
|
|
70
70
|
it "should raise an error if user does not have access to cloud" do
|
|
71
71
|
response = {"message" => "Cloud foo-staging not found"}
|
|
72
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
72
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
73
73
|
@client.stub(:app_users).and_raise(exception)
|
|
74
74
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
|
75
75
|
@cli_user.list
|
|
@@ -130,7 +130,7 @@ describe Shelly::CLI::User do
|
|
|
130
130
|
context "on failure" do
|
|
131
131
|
it "should raise error if user doesnt have access to cloud" do
|
|
132
132
|
response = {"message" => "Cloud foo-staging not found"}
|
|
133
|
-
exception = Shelly::Client::APIError.new(response.to_json)
|
|
133
|
+
exception = Shelly::Client::APIError.new(response.to_json, 404)
|
|
134
134
|
@client.stub(:send_invitation).and_raise(exception)
|
|
135
135
|
$stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
|
|
136
136
|
@cli_user.add("megan@example.com")
|
data/spec/shelly/client_spec.rb
CHANGED
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
|
3
3
|
describe Shelly::Client::APIError do
|
|
4
4
|
before do
|
|
5
5
|
body = {"message" => "something went wrong", "errors" => [["first", "foo"]], "url" => "https://foo.bar"}
|
|
6
|
-
@error = Shelly::Client::APIError.new(body.to_json)
|
|
6
|
+
@error = Shelly::Client::APIError.new(body.to_json, 404)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
it "should return error message" do
|
|
@@ -21,12 +21,23 @@ describe Shelly::Client::APIError do
|
|
|
21
21
|
it "should return user friendly string" do
|
|
22
22
|
@error.each_error{|error| error.should == "First foo"}
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
describe "#not_found?" do
|
|
26
|
+
it "should return true if response status code is 404" do
|
|
27
|
+
@error.should be_not_found
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should return false if response status code is not 404" do
|
|
31
|
+
error = Shelly::Client::APIError.new({}.to_json, 500)
|
|
32
|
+
error.should_not be_not_found
|
|
33
|
+
end
|
|
34
|
+
end
|
|
24
35
|
|
|
25
36
|
describe "#validation?" do
|
|
26
37
|
context "when error is caused by validation errors" do
|
|
27
38
|
it "should return true" do
|
|
28
39
|
body = {"message" => "Validation Failed"}
|
|
29
|
-
error = Shelly::Client::APIError.new(body.to_json)
|
|
40
|
+
error = Shelly::Client::APIError.new(body.to_json, 422)
|
|
30
41
|
error.should be_validation
|
|
31
42
|
end
|
|
32
43
|
end
|
|
@@ -42,7 +53,7 @@ describe Shelly::Client::APIError do
|
|
|
42
53
|
context "when error is caused by unauthorized error" do
|
|
43
54
|
it "should return true" do
|
|
44
55
|
body = {"message" => "Unauthorized"}
|
|
45
|
-
error = Shelly::Client::APIError.new(body.to_json)
|
|
56
|
+
error = Shelly::Client::APIError.new(body.to_json, 401)
|
|
46
57
|
error.should be_unauthorized
|
|
47
58
|
end
|
|
48
59
|
end
|
|
@@ -59,7 +70,11 @@ describe Shelly::Client do
|
|
|
59
70
|
before do
|
|
60
71
|
ENV['SHELLY_URL'] = nil
|
|
61
72
|
@client = Shelly::Client.new("bob@example.com", "secret")
|
|
62
|
-
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def api_url(resource = "")
|
|
76
|
+
auth = "#{CGI.escape(@client.email)}:#{@client.password}@"
|
|
77
|
+
"https://#{auth}admin.winniecloud.com/apiv2/#{resource}"
|
|
63
78
|
end
|
|
64
79
|
|
|
65
80
|
describe "#api_url" do
|
|
@@ -103,7 +118,7 @@ describe Shelly::Client do
|
|
|
103
118
|
describe "#deploy_logs" do
|
|
104
119
|
it "should send get request" do
|
|
105
120
|
time = Time.now
|
|
106
|
-
FakeWeb.register_uri(:get,
|
|
121
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/deploys"), :body => [{:failed => false, :created_at => time},
|
|
107
122
|
{:failed => true, :created_at => time+1}].to_json)
|
|
108
123
|
response = @client.deploy_logs("staging-foo")
|
|
109
124
|
response.should == [{"failed"=>false, "created_at"=>time.to_s},
|
|
@@ -113,7 +128,7 @@ describe Shelly::Client do
|
|
|
113
128
|
|
|
114
129
|
describe "#deploy_log" do
|
|
115
130
|
it "should send get request with cloud and log" do
|
|
116
|
-
FakeWeb.register_uri(:get,
|
|
131
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/deploys/2011-11-29-11-50-16"), :body => {:content => "Log"}.to_json)
|
|
117
132
|
response = @client.deploy_log("staging-foo", "2011-11-29-11-50-16")
|
|
118
133
|
response.should == {"content" => "Log"}
|
|
119
134
|
end
|
|
@@ -121,7 +136,7 @@ describe Shelly::Client do
|
|
|
121
136
|
|
|
122
137
|
describe "#app_configs" do
|
|
123
138
|
it "should send get request" do
|
|
124
|
-
FakeWeb.register_uri(:get,
|
|
139
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/configs"), :body => [{:created_by_user => true, :path => "config/app.yml"}].to_json)
|
|
125
140
|
response = @client.app_configs("staging-foo")
|
|
126
141
|
response.should == [{"created_by_user" => true, "path" => "config/app.yml"}]
|
|
127
142
|
end
|
|
@@ -130,7 +145,7 @@ describe Shelly::Client do
|
|
|
130
145
|
describe "#application_logs" do
|
|
131
146
|
it "should send get request" do
|
|
132
147
|
time = Time.now
|
|
133
|
-
FakeWeb.register_uri(:get,
|
|
148
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/logs"),
|
|
134
149
|
:body => {:logs => ["application_log_1", "application_log_2"]}.to_json)
|
|
135
150
|
response = @client.application_logs("staging-foo")
|
|
136
151
|
response.should == {"logs" => ["application_log_1", "application_log_2"]}
|
|
@@ -146,7 +161,7 @@ describe Shelly::Client do
|
|
|
146
161
|
|
|
147
162
|
describe "#app_users" do
|
|
148
163
|
it "should send get request with app code_names" do
|
|
149
|
-
FakeWeb.register_uri(:get,
|
|
164
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/users"), :body => [{:email => "test@example.com"},
|
|
150
165
|
{:email => "test2@example.com"}].to_json)
|
|
151
166
|
response = @client.app_users("staging-foo")
|
|
152
167
|
response.should == [{"email" => "test@example.com"}, {"email" => "test2@example.com"}]
|
|
@@ -155,7 +170,7 @@ describe Shelly::Client do
|
|
|
155
170
|
|
|
156
171
|
describe "#app_ips" do
|
|
157
172
|
it "should send get request with app code_name" do
|
|
158
|
-
FakeWeb.register_uri(:get,
|
|
173
|
+
FakeWeb.register_uri(:get, api_url("apps/staging-foo/ips"), :body => {:mail_server_ip => "10.0.1.1", :web_server_ip => "88.198.21.187"}.to_json)
|
|
159
174
|
response = @client.app_ips("staging-foo")
|
|
160
175
|
response.should == {"mail_server_ip" => "10.0.1.1", "web_server_ip" => "88.198.21.187"}
|
|
161
176
|
end
|
|
@@ -163,8 +178,8 @@ describe Shelly::Client do
|
|
|
163
178
|
|
|
164
179
|
describe "#send_invitation" do
|
|
165
180
|
it "should send post with developer's email" do
|
|
166
|
-
FakeWeb.register_uri(:post,
|
|
167
|
-
FakeWeb.register_uri(:post,
|
|
181
|
+
FakeWeb.register_uri(:post, api_url("apps/staging-foo/collaborations"), :body => {}.to_json)
|
|
182
|
+
FakeWeb.register_uri(:post, api_url("apps/production-foo/collaborations"), :body => {}.to_json)
|
|
168
183
|
response = @client.send_invitation("staging-foo", "megan@example.com")
|
|
169
184
|
response.should == {}
|
|
170
185
|
end
|
|
@@ -186,7 +201,7 @@ describe Shelly::Client do
|
|
|
186
201
|
|
|
187
202
|
describe "#start_cloud" do
|
|
188
203
|
it "should sent post request with cloud's code_name" do
|
|
189
|
-
FakeWeb.register_uri(:put,
|
|
204
|
+
FakeWeb.register_uri(:put, api_url("apps/staging-foo/start"), :body => {}.to_json)
|
|
190
205
|
response = @client.start_cloud("staging-foo")
|
|
191
206
|
response.should == {}
|
|
192
207
|
end
|
|
@@ -194,7 +209,7 @@ describe Shelly::Client do
|
|
|
194
209
|
|
|
195
210
|
describe "#stop_cloud" do
|
|
196
211
|
it "should sent delete request with cloud's code_name" do
|
|
197
|
-
FakeWeb.register_uri(:put,
|
|
212
|
+
FakeWeb.register_uri(:put, api_url("apps/staging-foo/stop"), :body => {}.to_json)
|
|
198
213
|
response = @client.stop_cloud("staging-foo")
|
|
199
214
|
response.should == {}
|
|
200
215
|
end
|
|
@@ -206,6 +221,48 @@ describe Shelly::Client do
|
|
|
206
221
|
@client.ssh_key_available?("ssh-key Abb")
|
|
207
222
|
end
|
|
208
223
|
end
|
|
224
|
+
|
|
225
|
+
describe "#database_backup" do
|
|
226
|
+
it "should fetch backup description from API" do
|
|
227
|
+
expected = {
|
|
228
|
+
"filename" => @filename,
|
|
229
|
+
"size" => 1234,
|
|
230
|
+
"human_size" => "2KB"
|
|
231
|
+
}
|
|
232
|
+
filename = "2011.11.26.04.00.10.foo.postgres.tar.gz"
|
|
233
|
+
url = api_url("apps/foo/database_backups/#{filename}")
|
|
234
|
+
FakeWeb.register_uri(:get, url, :body => expected.to_json)
|
|
235
|
+
|
|
236
|
+
@client.database_backup("foo", filename).should == expected
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
describe "#download_backup" do
|
|
241
|
+
before do
|
|
242
|
+
@filename = "2011.11.26.04.00.10.foo.postgres.tar.gz"
|
|
243
|
+
url = api_url("apps/foo/database_backups/#{@filename}")
|
|
244
|
+
response = Net::HTTPResponse.new('', '', '')
|
|
245
|
+
# Streaming
|
|
246
|
+
response.stub(:read_body).and_yield("aaa").and_yield("bbbbb").and_yield("dddf")
|
|
247
|
+
FakeWeb.register_uri(:get, url, :response => response)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
it "should write streamed database backup to file" do
|
|
251
|
+
@client.download_backup("foo", @filename)
|
|
252
|
+
File.read(@filename).should == %w(aaa bbbbb dddf).join
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "should execute progress_callback with size of every chunk" do
|
|
256
|
+
progress = mock(:update => true)
|
|
257
|
+
progress.should_receive(:update).with(3)
|
|
258
|
+
progress.should_receive(:update).with(5)
|
|
259
|
+
progress.should_receive(:update).with(4)
|
|
260
|
+
|
|
261
|
+
callback = lambda { |size| progress.update(size) }
|
|
262
|
+
|
|
263
|
+
@client.download_backup("foo", @filename, callback)
|
|
264
|
+
end
|
|
265
|
+
end
|
|
209
266
|
|
|
210
267
|
describe "#request_parameters" do
|
|
211
268
|
it "should return hash of resquest parameters" do
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "shelly/download_progress_bar"
|
|
3
|
+
|
|
4
|
+
describe Shelly::DownloadProgressBar do
|
|
5
|
+
before do
|
|
6
|
+
$stderr.stub(:print)
|
|
7
|
+
@bar = Shelly::DownloadProgressBar.new(4444)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should inherith from ProgressBar" do
|
|
11
|
+
@bar.should be_kind_of(ProgressBar)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should initialize parent with header and given size" do
|
|
15
|
+
@bar.title.should == "Progress"
|
|
16
|
+
@bar.total.should == 4444
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#progress_callback" do
|
|
20
|
+
it "should return callback for updating progress bar" do
|
|
21
|
+
@bar.should_receive(:inc).with(10)
|
|
22
|
+
@bar.should_receive(:inc).with(20)
|
|
23
|
+
|
|
24
|
+
@bar.progress_callback.call(10)
|
|
25
|
+
@bar.progress_callback.call(20)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
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: 91
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
8
|
- 0
|
|
9
|
-
-
|
|
10
|
-
version: 0.0.
|
|
9
|
+
- 34
|
|
10
|
+
version: 0.0.34
|
|
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-27 00:00:00 Z
|
|
19
19
|
dependencies:
|
|
20
20
|
- !ruby/object:Gem::Dependency
|
|
21
21
|
name: rspec
|
|
@@ -187,6 +187,20 @@ dependencies:
|
|
|
187
187
|
version: "0"
|
|
188
188
|
type: :runtime
|
|
189
189
|
version_requirements: *id012
|
|
190
|
+
- !ruby/object:Gem::Dependency
|
|
191
|
+
name: progressbar
|
|
192
|
+
prerelease: false
|
|
193
|
+
requirement: &id013 !ruby/object:Gem::Requirement
|
|
194
|
+
none: false
|
|
195
|
+
requirements:
|
|
196
|
+
- - ">="
|
|
197
|
+
- !ruby/object:Gem::Version
|
|
198
|
+
hash: 3
|
|
199
|
+
segments:
|
|
200
|
+
- 0
|
|
201
|
+
version: "0"
|
|
202
|
+
type: :runtime
|
|
203
|
+
version_requirements: *id013
|
|
190
204
|
description: Tool for managing applications and clouds at shellycloud.com
|
|
191
205
|
email:
|
|
192
206
|
- support@shellycloud.com
|
|
@@ -208,6 +222,7 @@ files:
|
|
|
208
222
|
- lib/core_ext/object.rb
|
|
209
223
|
- lib/shelly.rb
|
|
210
224
|
- lib/shelly/app.rb
|
|
225
|
+
- lib/shelly/backup.rb
|
|
211
226
|
- lib/shelly/cli/backup.rb
|
|
212
227
|
- lib/shelly/cli/command.rb
|
|
213
228
|
- lib/shelly/cli/config.rb
|
|
@@ -217,6 +232,7 @@ files:
|
|
|
217
232
|
- lib/shelly/cli/user.rb
|
|
218
233
|
- lib/shelly/client.rb
|
|
219
234
|
- lib/shelly/cloudfile.rb
|
|
235
|
+
- lib/shelly/download_progress_bar.rb
|
|
220
236
|
- lib/shelly/helpers.rb
|
|
221
237
|
- lib/shelly/model.rb
|
|
222
238
|
- lib/shelly/templates/Cloudfile.erb
|
|
@@ -229,6 +245,7 @@ files:
|
|
|
229
245
|
- spec/helpers.rb
|
|
230
246
|
- spec/input_faker.rb
|
|
231
247
|
- spec/shelly/app_spec.rb
|
|
248
|
+
- spec/shelly/backup_spec.rb
|
|
232
249
|
- spec/shelly/cli/backup_spec.rb
|
|
233
250
|
- spec/shelly/cli/config_spec.rb
|
|
234
251
|
- spec/shelly/cli/deploys_spec.rb
|
|
@@ -237,6 +254,7 @@ files:
|
|
|
237
254
|
- spec/shelly/cli/user_spec.rb
|
|
238
255
|
- spec/shelly/client_spec.rb
|
|
239
256
|
- spec/shelly/cloudfile_spec.rb
|
|
257
|
+
- spec/shelly/download_progress_bar_spec.rb
|
|
240
258
|
- spec/shelly/model_spec.rb
|
|
241
259
|
- spec/shelly/user_spec.rb
|
|
242
260
|
- spec/spec_helper.rb
|
|
@@ -278,6 +296,7 @@ test_files:
|
|
|
278
296
|
- spec/helpers.rb
|
|
279
297
|
- spec/input_faker.rb
|
|
280
298
|
- spec/shelly/app_spec.rb
|
|
299
|
+
- spec/shelly/backup_spec.rb
|
|
281
300
|
- spec/shelly/cli/backup_spec.rb
|
|
282
301
|
- spec/shelly/cli/config_spec.rb
|
|
283
302
|
- spec/shelly/cli/deploys_spec.rb
|
|
@@ -286,6 +305,7 @@ test_files:
|
|
|
286
305
|
- spec/shelly/cli/user_spec.rb
|
|
287
306
|
- spec/shelly/client_spec.rb
|
|
288
307
|
- spec/shelly/cloudfile_spec.rb
|
|
308
|
+
- spec/shelly/download_progress_bar_spec.rb
|
|
289
309
|
- spec/shelly/model_spec.rb
|
|
290
310
|
- spec/shelly/user_spec.rb
|
|
291
311
|
- spec/spec_helper.rb
|