backup_jenkins 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/config/config-example.yml +3 -2
- data/lib/backup_jenkins/aws.rb +3 -3
- data/lib/backup_jenkins/backup.rb +19 -4
- data/lib/backup_jenkins/cli.rb +47 -22
- data/lib/backup_jenkins/config.rb +15 -0
- data/lib/backup_jenkins/version.rb +1 -1
- data/spec/lib/backup_jenkins/aws_spec.rb +50 -1
- data/spec/lib/backup_jenkins/backup_spec.rb +67 -0
- data/spec/lib/backup_jenkins/cli_spec.rb +256 -2
- data/spec/lib/backup_jenkins/config_spec.rb +62 -1
- data/spec/lib/backup_jenkins/formatter_spec.rb +4 -3
- data/spec/spec_helper.rb +3 -0
- metadata +8 -24
data/Gemfile
CHANGED
data/config/config-example.yml
CHANGED
data/lib/backup_jenkins/aws.rb
CHANGED
@@ -34,10 +34,10 @@ module BackupJenkins
|
|
34
34
|
count = 0
|
35
35
|
remote_file.read do |chunk|
|
36
36
|
file.write(chunk)
|
37
|
-
print "." if count % 512 == 0
|
37
|
+
STDOUT.print "." if count % 512 == 0
|
38
38
|
count += 1
|
39
39
|
end
|
40
|
-
puts "."
|
40
|
+
STDOUT.puts "."
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -54,7 +54,7 @@ module BackupJenkins
|
|
54
54
|
|
55
55
|
# TODO change this to use a time decay algorithm
|
56
56
|
def files_to_remove
|
57
|
-
files - files.last(config.backup["backups_to_keep"])
|
57
|
+
files - files.last(config.backup["backups_to_keep"]["remote"])
|
58
58
|
end
|
59
59
|
|
60
60
|
def files
|
@@ -40,21 +40,32 @@ module BackupJenkins
|
|
40
40
|
raise "Backup directory already exists! (#{backup_directory})" if FileTest.directory?(backup_directory)
|
41
41
|
|
42
42
|
copy_files
|
43
|
-
|
44
43
|
create_tarball
|
45
44
|
remove_temporary_files
|
45
|
+
remove_old_backups
|
46
46
|
rescue Interrupt
|
47
47
|
puts "Cleaning up..."
|
48
48
|
clean_up
|
49
49
|
end
|
50
50
|
|
51
|
+
def remove_old_backups
|
52
|
+
files_to_remove.each do |file|
|
53
|
+
FileUtils.rm(file)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def files_to_remove
|
58
|
+
glob_of_backup_files -
|
59
|
+
glob_of_backup_files.last(config.backup["backups_to_keep"]["local"])
|
60
|
+
end
|
61
|
+
|
51
62
|
def clean_up
|
52
63
|
puts "Removing #{backup_directory}"
|
53
64
|
remove_temporary_files
|
54
65
|
|
55
66
|
puts "Removing #{tarball_filename}"
|
56
67
|
FileUtils.rm_rf(tarball_filename)
|
57
|
-
rescue Errno::ENOENT
|
68
|
+
rescue Errno::ENOENT => e
|
58
69
|
puts e
|
59
70
|
end
|
60
71
|
|
@@ -103,16 +114,20 @@ module BackupJenkins
|
|
103
114
|
attr_reader :config
|
104
115
|
|
105
116
|
def timestamp
|
106
|
-
Time.now.strftime(
|
117
|
+
Time.now.strftime("%Y%m%d_%H%M")
|
107
118
|
end
|
108
119
|
|
109
120
|
def backup_files
|
110
|
-
|
121
|
+
glob_of_backup_files.sort.map do |file|
|
111
122
|
{
|
112
123
|
:key => file.gsub(%r{#{config.backup["dir_base"]}/}, ''),
|
113
124
|
:content_length => File.size(file)
|
114
125
|
}
|
115
126
|
end
|
116
127
|
end
|
128
|
+
|
129
|
+
def glob_of_backup_files
|
130
|
+
Dir["#{config.backup["dir_base"]}/#{config.base_file_name}_*tar.bz2"]
|
131
|
+
end
|
117
132
|
end
|
118
133
|
end
|
data/lib/backup_jenkins/cli.rb
CHANGED
@@ -4,10 +4,18 @@ module BackupJenkins
|
|
4
4
|
def run
|
5
5
|
cli = self.new
|
6
6
|
cli.parse_options
|
7
|
+
cli.check_config
|
7
8
|
cli.run
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
12
|
+
def check_config
|
13
|
+
if !config.valid?
|
14
|
+
STDERR.puts "Config file is incorrect."
|
15
|
+
show_help
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
11
19
|
def parse_options
|
12
20
|
options.each do |opt, arg|
|
13
21
|
case opt
|
@@ -31,7 +39,7 @@ module BackupJenkins
|
|
31
39
|
show_version
|
32
40
|
end
|
33
41
|
end
|
34
|
-
rescue GetoptLong::MissingArgument
|
42
|
+
rescue GetoptLong::MissingArgument, GetoptLong::InvalidOption
|
35
43
|
# GetoptLong Already outputs the error.
|
36
44
|
puts "\n"
|
37
45
|
show_help
|
@@ -58,29 +66,39 @@ module BackupJenkins
|
|
58
66
|
end
|
59
67
|
|
60
68
|
def run
|
69
|
+
do_backup
|
70
|
+
upload_file unless @only_local
|
71
|
+
rescue Interrupt
|
72
|
+
clean_up_backup
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def do_backup
|
61
78
|
backup.do_backup
|
79
|
+
end
|
62
80
|
|
81
|
+
def upload_file
|
63
82
|
full_filename = backup.tarball_filename
|
64
83
|
filename = File.basename(full_filename)
|
65
|
-
|
66
|
-
aws.upload_file(filename, File.open(full_filename)) unless @only_local
|
84
|
+
aws.upload_file(filename, File.open(full_filename))
|
67
85
|
aws.remove_old_files # Clean up!
|
68
|
-
rescue Interrupt
|
69
|
-
backup.clean_up
|
70
86
|
end
|
71
87
|
|
72
|
-
|
88
|
+
def clean_up_backup
|
89
|
+
backup.clean_up
|
90
|
+
end
|
73
91
|
|
74
92
|
def config
|
75
|
-
@config ||=
|
93
|
+
@config ||= Config.new
|
76
94
|
end
|
77
95
|
|
78
96
|
def aws
|
79
|
-
@aws ||=
|
97
|
+
@aws ||= AWS.new(config)
|
80
98
|
end
|
81
99
|
|
82
100
|
def backup
|
83
|
-
@backup ||=
|
101
|
+
@backup ||= Backup.new(config)
|
84
102
|
end
|
85
103
|
|
86
104
|
def options
|
@@ -121,7 +139,7 @@ module BackupJenkins
|
|
121
139
|
|
122
140
|
def override_config_file_with(config_file_name)
|
123
141
|
raise "File not found or not readable" unless File.readable?(config_file_name)
|
124
|
-
@config =
|
142
|
+
@config = Config.new(config_file_name)
|
125
143
|
end
|
126
144
|
|
127
145
|
def override_config_file_with_option(options = {})
|
@@ -135,30 +153,24 @@ module BackupJenkins
|
|
135
153
|
end
|
136
154
|
|
137
155
|
def license_file_path
|
138
|
-
File.expand_path("
|
139
|
-
end
|
140
|
-
|
141
|
-
def version_info
|
142
|
-
<<-EOV
|
143
|
-
backup_jenkins (#{BackupJenkins::VERSION})
|
144
|
-
https://github.com/jcmuller/backup_jenkins
|
145
|
-
(c) 2012 Juan C. Muller
|
146
|
-
Work on this has been proudly backed by ChallengePost, Inc.
|
147
|
-
EOV
|
156
|
+
File.expand_path("../../../LICENSE", __FILE__)
|
148
157
|
end
|
149
158
|
|
150
159
|
def help_info
|
151
160
|
<<-EOH
|
152
161
|
Usage: #{File.basename($0)} [options]
|
153
|
-
|
162
|
+
#{short_hand_options}
|
154
163
|
|
155
164
|
Options:
|
156
165
|
#{option_details}
|
157
|
-
|
158
166
|
#{version_info}
|
159
167
|
EOH
|
160
168
|
end
|
161
169
|
|
170
|
+
def short_hand_options
|
171
|
+
"[#{options_possible.map{ |o| short_hand_option(o)}.join('], [')}]"
|
172
|
+
end
|
173
|
+
|
162
174
|
def short_hand_option(option)
|
163
175
|
if option[2] == GetoptLong::REQUIRED_ARGUMENT
|
164
176
|
[option[0], option[1]].join('|') << " argument"
|
@@ -173,6 +185,19 @@ Usage: #{File.basename($0)} [options]
|
|
173
185
|
EOO
|
174
186
|
end
|
175
187
|
|
188
|
+
def version_info
|
189
|
+
<<-EOV
|
190
|
+
backup_jenkins (#{version_number})
|
191
|
+
https://github.com/jcmuller/backup_jenkins
|
192
|
+
(c) 2012 Juan C. Muller
|
193
|
+
Work on this has been proudly backed by ChallengePost, Inc.
|
194
|
+
EOV
|
195
|
+
end
|
196
|
+
|
197
|
+
def version_number
|
198
|
+
VERSION
|
199
|
+
end
|
200
|
+
|
176
201
|
def longest_width
|
177
202
|
@max_width ||= options_possible.map{ |o| o[0] }.max{ |a, b| a.length <=> b.length }.length
|
178
203
|
end
|
@@ -6,6 +6,21 @@ module BackupJenkins
|
|
6
6
|
@config = config_file(path)
|
7
7
|
end
|
8
8
|
|
9
|
+
def valid?
|
10
|
+
! (
|
11
|
+
aws["access_key"].nil? ||
|
12
|
+
aws["secret"].nil? ||
|
13
|
+
aws["bucket_name"].nil? ||
|
14
|
+
backup["dir_base"].nil? ||
|
15
|
+
backup["file_name_base"].nil? ||
|
16
|
+
backup["backups_to_keep"].nil? ||
|
17
|
+
backup["backups_to_keep"]["remote"].nil? ||
|
18
|
+
backup["backups_to_keep"]["local"].nil? ||
|
19
|
+
jenkins["home"].nil? ||
|
20
|
+
verbose.nil?
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
9
24
|
def method_missing(meth, *args, &block)
|
10
25
|
return config[meth.to_s] if config.has_key?(meth.to_s)
|
11
26
|
super
|
@@ -8,7 +8,7 @@ describe BackupJenkins::AWS do
|
|
8
8
|
BackupJenkins::Config.stub(:new).and_return(config)
|
9
9
|
|
10
10
|
config.stub(:aws).and_return({ "access_key" => "some_key", "secret" => "some_secret" })
|
11
|
-
config.stub(:backup).and_return({ "backups_to_keep" => 2, "file_name_base" => "jenkins" })
|
11
|
+
config.stub(:backup).and_return({ "backups_to_keep" => { "remote" => 2 }, "file_name_base" => "jenkins" })
|
12
12
|
|
13
13
|
::AWS::S3.stub(:new).and_return(s3_mocks)
|
14
14
|
end
|
@@ -51,6 +51,17 @@ describe BackupJenkins::AWS do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
describe "#backup_files_for_all_hosts" do
|
55
|
+
it "should return the right files" do
|
56
|
+
config.should_receive(:backup).and_return("file_name_base" => "base_file_name")
|
57
|
+
objects = mock
|
58
|
+
objects.should_receive(:with_prefix).with("base_file_name").and_return([1, 2, 3])
|
59
|
+
subject.should_receive(:s3_files).and_return(objects)
|
60
|
+
|
61
|
+
subject.send(:backup_files_for_all_hosts).should == [1, 2, 3]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
54
65
|
describe "#list_backup_files" do
|
55
66
|
it "should call the right methods" do
|
56
67
|
subject.should_receive(:s3_object_to_hash).twice.and_return(:blah)
|
@@ -118,8 +129,46 @@ describe BackupJenkins::AWS do
|
|
118
129
|
end
|
119
130
|
end
|
120
131
|
|
132
|
+
describe "#download_file" do
|
133
|
+
it "should locate a file" do
|
134
|
+
chunk = mock
|
135
|
+
io = mock
|
136
|
+
name = mock
|
137
|
+
remote_file = mock
|
138
|
+
remote_files = mock
|
139
|
+
|
140
|
+
subject.stub(:bucket).and_return(remote_files)
|
141
|
+
remote_files.should_receive(:objects).and_return({ name => remote_file })
|
142
|
+
remote_file.should_receive(:read).and_yield(chunk)
|
143
|
+
|
144
|
+
File.should_receive(:open).with(name, 'w').and_yield(io)
|
145
|
+
io.should_receive(:write).with(chunk)
|
146
|
+
|
147
|
+
STDOUT.should_receive(:print).with(".")
|
148
|
+
STDOUT.should_receive(:puts).with(".")
|
149
|
+
|
150
|
+
subject.download_file(name)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
121
154
|
describe "#s3_files" do
|
122
155
|
after { subject.send(:s3_files) }
|
123
156
|
it { subject.should_receive(:bucket).and_return(mock(:objects => mock)) }
|
124
157
|
end
|
158
|
+
|
159
|
+
describe "#s3_object_to_hash" do
|
160
|
+
it "should return a hash from s3 object" do
|
161
|
+
s3_object = mock(
|
162
|
+
:key => "key",
|
163
|
+
:content_length => "length",
|
164
|
+
:metadata => "this is so meta",
|
165
|
+
:another_key => "Which will be ignored"
|
166
|
+
)
|
167
|
+
subject.send(:s3_object_to_hash, s3_object).should == {
|
168
|
+
:content_length => "length",
|
169
|
+
:key => "key",
|
170
|
+
:metadata => "this is so meta"
|
171
|
+
}
|
172
|
+
end
|
173
|
+
end
|
125
174
|
end
|
@@ -13,6 +13,23 @@ describe BackupJenkins::Backup do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
describe "#backup_files" do
|
17
|
+
it "should get a listing for all the files in backup directory" do
|
18
|
+
file = "dir/base_1234"
|
19
|
+
config.stub(:backup).and_return("dir_base" => "dir")
|
20
|
+
config.stub(:base_file_name).and_return("base")
|
21
|
+
|
22
|
+
File.should_receive(:size).with(file).and_return("size")
|
23
|
+
Dir.should_receive(:[]).and_return([file])
|
24
|
+
subject.send(:backup_files).should == [
|
25
|
+
{
|
26
|
+
:key => "base_1234",
|
27
|
+
:content_length => "size"
|
28
|
+
}
|
29
|
+
]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
describe "#backup_directory" do
|
17
34
|
let(:backup) { { "dir_base" => "/path/to/some/dir_base" } }
|
18
35
|
|
@@ -74,6 +91,26 @@ describe BackupJenkins::Backup do
|
|
74
91
|
end
|
75
92
|
end
|
76
93
|
|
94
|
+
describe "#clean_up" do
|
95
|
+
it "should clean up" do
|
96
|
+
subject.stub(:tarball_filename).and_return("tarball")
|
97
|
+
subject.stub(:backup_directory).and_return("directory")
|
98
|
+
|
99
|
+
STDOUT.should_receive(:puts).twice
|
100
|
+
subject.should_receive(:remove_temporary_files)
|
101
|
+
FileUtils.should_receive(:rm_rf).with("tarball")
|
102
|
+
|
103
|
+
subject.clean_up
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should recover from file not found" do
|
107
|
+
subject.stub(:backup_directory).and_return("directory")
|
108
|
+
subject.should_receive(:remove_temporary_files).and_raise(Errno::ENOENT)
|
109
|
+
STDOUT.should_receive(:puts).twice
|
110
|
+
subject.clean_up
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
77
114
|
describe "#create_dir_and_copy_impl" do
|
78
115
|
before do
|
79
116
|
FileTest.stub(:file?).and_return(true)
|
@@ -134,6 +171,7 @@ describe BackupJenkins::Backup do
|
|
134
171
|
subject.stub(:backup_directory).and_return("backup_directory")
|
135
172
|
subject.stub(:copy_files)
|
136
173
|
subject.stub(:create_tarball)
|
174
|
+
subject.stub(:remove_old_backups)
|
137
175
|
subject.stub(:remove_temporary_files)
|
138
176
|
end
|
139
177
|
|
@@ -149,6 +187,13 @@ describe BackupJenkins::Backup do
|
|
149
187
|
it { subject.should_receive(:create_tarball) }
|
150
188
|
it { subject.should_receive(:remove_temporary_files) }
|
151
189
|
end
|
190
|
+
|
191
|
+
it "should clean up if Interrupt" do
|
192
|
+
subject.should_receive(:copy_files).and_raise(Interrupt)
|
193
|
+
subject.should_receive(:clean_up)
|
194
|
+
STDOUT.should_receive(:puts)
|
195
|
+
subject.do_backup
|
196
|
+
end
|
152
197
|
end
|
153
198
|
|
154
199
|
describe "#jobs_files" do
|
@@ -183,6 +228,28 @@ describe BackupJenkins::Backup do
|
|
183
228
|
end
|
184
229
|
end
|
185
230
|
|
231
|
+
describe "#remove_old_backups" do
|
232
|
+
it "should remove the old files" do
|
233
|
+
subject.should_receive(:files_to_remove).and_return(['a_file'])
|
234
|
+
FileUtils.should_receive(:rm).with('a_file')
|
235
|
+
|
236
|
+
subject.remove_old_backups
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe "#files_to_remove" do
|
241
|
+
before do
|
242
|
+
config.stub(:backup).and_return("backups_to_keep" => { "local" => 2 })
|
243
|
+
subject.stub(:glob_of_backup_files).and_return(
|
244
|
+
%w(old_file_1 old_file_2 old_file_3 old_file_4 old_file_5)
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should remove old files" do
|
249
|
+
subject.files_to_remove.should == %w(old_file_1 old_file_2 old_file_3)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
186
253
|
describe "#remove_temporary_files" do
|
187
254
|
before do
|
188
255
|
subject.should_receive(:backup_directory).and_return("backup_directory")
|
@@ -17,24 +17,219 @@ describe BackupJenkins::CLI do
|
|
17
17
|
|
18
18
|
aws.stub(:upload_file)
|
19
19
|
aws.stub(:remove_old_files)
|
20
|
+
|
21
|
+
config.stub(:valid?).and_return(true)
|
20
22
|
end
|
21
23
|
|
22
24
|
describe ".run" do
|
23
25
|
after { BackupJenkins::CLI.run }
|
26
|
+
|
27
|
+
it { BackupJenkins::CLI.any_instance.should_receive(:check_config) }
|
28
|
+
it { BackupJenkins::CLI.any_instance.should_receive(:parse_options) }
|
24
29
|
it { BackupJenkins::CLI.any_instance.should_receive(:run) }
|
25
30
|
end
|
26
31
|
|
32
|
+
describe "#check_config" do
|
33
|
+
it "doesn't show help" do
|
34
|
+
config.should_receive(:valid?).and_return(true)
|
35
|
+
subject.should_not_receive(:show_help)
|
36
|
+
STDERR.should_not_receive(:puts).with("Config file is incorrect.")
|
37
|
+
|
38
|
+
subject.check_config
|
39
|
+
end
|
40
|
+
|
41
|
+
it "shows help if config is invalid" do
|
42
|
+
config.should_receive(:valid?).and_return(false)
|
43
|
+
subject.should_receive(:show_help)
|
44
|
+
STDERR.should_receive(:puts).with("Config file is incorrect.")
|
45
|
+
|
46
|
+
subject.check_config
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#parse_options" do
|
51
|
+
let(:options) { { } }
|
52
|
+
|
53
|
+
before { subject.stub(:options).and_return(options) }
|
54
|
+
after { subject.parse_options }
|
55
|
+
|
56
|
+
it "should call override_config_file_with argument" do
|
57
|
+
options["--config"] = "arg"
|
58
|
+
subject.should_receive(:override_config_file_with).with("arg")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should call download_file with arg" do
|
62
|
+
options["--download"] = "file"
|
63
|
+
subject.should_receive(:download_file).with("file")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should call show_help" do
|
67
|
+
options["--help"] = nil
|
68
|
+
subject.should_receive(:show_help)
|
69
|
+
subject.should_not_receive(:show_license)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should call show_license" do
|
73
|
+
options["--license"] = nil
|
74
|
+
subject.should_receive(:show_license)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should call list_remote_backups" do
|
78
|
+
options["--list"] = nil
|
79
|
+
subject.should_receive(:list_remote_backups)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should call list_local_backups" do
|
83
|
+
options["--list-local"] = nil
|
84
|
+
subject.should_receive(:list_local_backups)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should set only_local" do
|
88
|
+
options["--only-local"] = nil
|
89
|
+
subject.parse_options
|
90
|
+
subject.instance_variable_get(:"@only_local").should be_true
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should call override_config_file_with_option" do
|
94
|
+
options["--verbose"] = nil
|
95
|
+
subject.should_receive(:override_config_file_with_option).with("verbose" => true)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should call show_version" do
|
99
|
+
options["--version"] = nil
|
100
|
+
subject.should_receive(:show_version)
|
101
|
+
subject.should_not_receive(:show_license)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should show help if arguments are missing" do
|
105
|
+
subject.should_receive(:options).and_raise(GetoptLong::MissingArgument)
|
106
|
+
subject.should_receive(:show_help)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should show help if invalid option is passed" do
|
110
|
+
subject.should_receive(:options).and_raise(GetoptLong::InvalidOption)
|
111
|
+
subject.should_receive(:show_help)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
27
115
|
describe "#run" do
|
28
116
|
after { subject.run }
|
29
|
-
|
117
|
+
|
118
|
+
it { subject.should_receive(:do_backup) }
|
119
|
+
it { subject.should_receive(:upload_file) }
|
120
|
+
|
121
|
+
it "should not upload file if only_local is set" do
|
122
|
+
subject.instance_variable_set(:"@only_local", true)
|
123
|
+
|
124
|
+
subject.should_receive(:do_backup)
|
125
|
+
subject.should_not_receive(:upload_file)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should clean up" do
|
129
|
+
subject.should_receive(:do_backup).and_raise(Interrupt)
|
130
|
+
backup.should_receive(:clean_up)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#do_backup" do
|
135
|
+
after { subject.send(:do_backup) }
|
136
|
+
|
30
137
|
it { BackupJenkins::Backup.should_receive(:new).with(config) }
|
31
138
|
it { BackupJenkins::Config.should_receive(:new) }
|
32
139
|
it { backup.should_receive(:do_backup) }
|
33
|
-
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "#upload_file" do
|
143
|
+
after { subject.send(:upload_file) }
|
144
|
+
|
145
|
+
it { backup.should_receive(:tarball_filename) }
|
146
|
+
it { BackupJenkins::AWS.should_receive(:new).with(config) }
|
34
147
|
it { aws.should_receive(:upload_file).with("tarball_filename", :IO) }
|
35
148
|
it { aws.should_receive(:remove_old_files) }
|
36
149
|
end
|
37
150
|
|
151
|
+
|
152
|
+
describe "#show_help" do
|
153
|
+
it "should call help info and exit" do
|
154
|
+
subject.should_receive(:help_info).and_return("help_info")
|
155
|
+
STDOUT.should_receive(:puts).with("help_info")
|
156
|
+
expect{ subject.send(:show_help) }.to raise_error SystemExit
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#show_version" do
|
161
|
+
it "should get version info and exit" do
|
162
|
+
subject.should_receive(:version_info).and_return("version_info")
|
163
|
+
STDOUT.should_receive(:puts).with("version_info")
|
164
|
+
expect{ subject.send(:show_version) }.to raise_error SystemExit
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#show_license" do
|
169
|
+
it "should call license_info and exit" do
|
170
|
+
subject.should_receive(:license_info).and_return("license_info")
|
171
|
+
STDOUT.should_receive(:puts).with("license_info")
|
172
|
+
expect{ subject.send(:show_license) }.to raise_error SystemExit
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#list_remote_backups" do
|
177
|
+
it "should call aws with list_backup_files and exit" do
|
178
|
+
aws.should_receive(:list_backup_files).and_return("list_backup_files")
|
179
|
+
STDOUT.should_receive(:puts).with("list_backup_files")
|
180
|
+
expect{ subject.send(:list_remote_backups) }.to raise_error SystemExit
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#list_local_backups" do
|
185
|
+
it "should call backup with list_local_files and exit" do
|
186
|
+
backup.should_receive(:list_local_files).and_return("list_local_files")
|
187
|
+
STDOUT.should_receive(:puts).with("list_local_files")
|
188
|
+
expect{ subject.send(:list_local_backups) }.to raise_error SystemExit
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "#download_file" do
|
193
|
+
it "should call aws with download_file and pass it the argument and then exit" do
|
194
|
+
aws.should_receive(:download_file).with("filename")
|
195
|
+
expect{ subject.send(:download_file, "filename") }.to raise_error SystemExit
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "#override_config_file_with" do
|
200
|
+
it "should instantiate the config object with the passed in file_name" do
|
201
|
+
File.should_receive(:readable?).and_return(true)
|
202
|
+
config = mock
|
203
|
+
BackupJenkins::Config.should_receive(:new).with("file_name").and_return(config)
|
204
|
+
subject.send(:override_config_file_with, "file_name")
|
205
|
+
subject.instance_variable_get(:"@config").should == config
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should raise exception if file not readable" do
|
209
|
+
expect{ subject.send(:override_config_file_with, "foo") }.to raise_error RuntimeError
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#override_config_file_with_option" do
|
214
|
+
it "should set options on config" do
|
215
|
+
options = mock
|
216
|
+
config.should_receive(:override).with(options)
|
217
|
+
subject.send(:override_config_file_with_option, options)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "#license_info" do
|
222
|
+
it "should get the contents of license path" do
|
223
|
+
subject.should_receive(:license_file_path).and_return("license_file_path")
|
224
|
+
File.should_receive(:read).with("license_file_path").and_return("license_file_content")
|
225
|
+
subject.send(:license_info).should == "license_file_content\n\n"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "#license_file_path" do
|
230
|
+
it { subject.send(:license_file_path).should =~ %r{/LICENSE} }
|
231
|
+
end
|
232
|
+
|
38
233
|
describe "#longest_width" do
|
39
234
|
before { subject.stub(:options_possible).and_return([%w(1234), %w(1234567890), %w(123)]) }
|
40
235
|
it { subject.send(:longest_width).should == 10 }
|
@@ -47,4 +242,63 @@ describe BackupJenkins::CLI do
|
|
47
242
|
)
|
48
243
|
}
|
49
244
|
end
|
245
|
+
|
246
|
+
describe "#help_info" do
|
247
|
+
it "should return helpful information based on options" do
|
248
|
+
subject.stub(:options_possible).and_return(
|
249
|
+
[
|
250
|
+
['--foo', '-f', 1, 'Fooism'],
|
251
|
+
['--bar', '-b', 2, 'Bark']
|
252
|
+
]
|
253
|
+
)
|
254
|
+
File.stub(:basename).and_return("program_name")
|
255
|
+
subject.stub(:version_number).and_return("version")
|
256
|
+
subject.send(:help_info).should == <<-EOH
|
257
|
+
Usage: program_name [options]
|
258
|
+
[--foo|-f argument], [--bar|-b]
|
259
|
+
|
260
|
+
Options:
|
261
|
+
--foo, -f Fooism
|
262
|
+
--bar, -b Bark
|
263
|
+
|
264
|
+
backup_jenkins (version)
|
265
|
+
https://github.com/jcmuller/backup_jenkins
|
266
|
+
(c) 2012 Juan C. Muller
|
267
|
+
Work on this has been proudly backed by ChallengePost, Inc.
|
268
|
+
|
269
|
+
EOH
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "#option_details" do
|
274
|
+
it "should return nice things" do
|
275
|
+
subject.stub(:options_possible).and_return(
|
276
|
+
[
|
277
|
+
['--foo', '-f', 1, 'Fooism'],
|
278
|
+
['--bar', '-b', 2, 'Bark']
|
279
|
+
]
|
280
|
+
)
|
281
|
+
subject.send(:option_details).should ==
|
282
|
+
" --foo, -f Fooism\n --bar, -b Bark\n"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "#short_hand_option" do
|
287
|
+
it "should return '--foo|-f argument'" do
|
288
|
+
option = ["--foo", "-f", GetoptLong::REQUIRED_ARGUMENT]
|
289
|
+
subject.send(:short_hand_option, option).should == "--foo|-f argument"
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should return '--bar|-b'" do
|
293
|
+
option = ["--bar", "-b", nil]
|
294
|
+
subject.send(:short_hand_option, option).should == "--bar|-b"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe "#version_number" do
|
299
|
+
it "returns version" do
|
300
|
+
BackupJenkins::VERSION = "foo"
|
301
|
+
subject.send(:version_number).should == "foo"
|
302
|
+
end
|
303
|
+
end
|
50
304
|
end
|
@@ -5,7 +5,8 @@ describe BackupJenkins::Config do
|
|
5
5
|
before do
|
6
6
|
config = {
|
7
7
|
"aws" => { "access_key" => "some_key", "secret" => "some_secret" },
|
8
|
-
"backup" => { "file_name_base" => "jenkins" }
|
8
|
+
"backup" => { "file_name_base" => "jenkins" },
|
9
|
+
"verbose" => true
|
9
10
|
}
|
10
11
|
|
11
12
|
YAML.stub(:load_file).and_return(config)
|
@@ -55,4 +56,64 @@ describe BackupJenkins::Config do
|
|
55
56
|
regexp = %r{config/config-example.yml$}
|
56
57
|
it { subject.send(:config_file_example_path).should match regexp }
|
57
58
|
end
|
59
|
+
|
60
|
+
describe "#override" do
|
61
|
+
it "should override config file" do
|
62
|
+
subject.verbose.should be_true
|
63
|
+
subject.override("verbose" => false)
|
64
|
+
subject.verbose.should be_false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#valid?" do
|
69
|
+
let(:config) {
|
70
|
+
{
|
71
|
+
"aws" => {
|
72
|
+
"access_key" => "AWS_ACCESS_KEY",
|
73
|
+
"secret" => "AWS_SECRET",
|
74
|
+
"bucket_name" => "BUCKET_NAME"
|
75
|
+
},
|
76
|
+
"backup" => {
|
77
|
+
"dir_base" => "PATH_TO_BACKUP_DIRECTORY",
|
78
|
+
"file_name_base" => "SOME_BASE_NAME",
|
79
|
+
"backups_to_keep" => {
|
80
|
+
"remote" => 2,
|
81
|
+
"local" => 5
|
82
|
+
}
|
83
|
+
},
|
84
|
+
"jenkins" => {
|
85
|
+
"home" => "PATH_TO_JENKINS_HOME"
|
86
|
+
},
|
87
|
+
"verbose" => false
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
before do
|
92
|
+
YAML.stub(:load_file).and_return(config)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should make sure that the config loaded has the necessary options" do
|
96
|
+
should be_valid
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should be valid if verbose is false" do
|
100
|
+
config["verbose"] = false
|
101
|
+
should be_valid
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should not be valid if verbose option is missing" do
|
105
|
+
config.delete("verbose")
|
106
|
+
expect{ should_not be_valid }.to raise_error NameError
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not be valid if aws[access_key] option is missing" do
|
110
|
+
config["aws"].delete("access_key")
|
111
|
+
should_not be_valid
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should not be valid if backup section is missing" do
|
115
|
+
config.delete("backup")
|
116
|
+
expect{ should_not be_valid }.to raise_error NameError
|
117
|
+
end
|
118
|
+
end
|
58
119
|
end
|
@@ -5,13 +5,14 @@ class SpecFormatterIncluder
|
|
5
5
|
|
6
6
|
attr_reader :config
|
7
7
|
|
8
|
-
def initialize
|
9
|
-
@config =
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
describe BackupJenkins::Formatter do
|
14
|
-
|
14
|
+
let(:config) { mock(:backup => { "file_name_base" => "jenkins" }) }
|
15
|
+
subject { SpecFormatterIncluder.new(config) }
|
15
16
|
|
16
17
|
describe "#format_backup_file_data" do
|
17
18
|
let(:files) {
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backup_jenkins
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-11-09 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &30152060 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,15 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
24
|
+
version_requirements: *30152060
|
30
25
|
- !ruby/object:Gem::Dependency
|
31
26
|
name: rake
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirement: &30151640 !ruby/object:Gem::Requirement
|
33
28
|
none: false
|
34
29
|
requirements:
|
35
30
|
- - ! '>='
|
@@ -37,12 +32,7 @@ dependencies:
|
|
37
32
|
version: '0'
|
38
33
|
type: :development
|
39
34
|
prerelease: false
|
40
|
-
version_requirements:
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: '0'
|
35
|
+
version_requirements: *30151640
|
46
36
|
description: Simple Jenkins config and plugin backup to S3
|
47
37
|
email:
|
48
38
|
- jcmuller@gmail.com
|
@@ -87,28 +77,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
77
|
- - ! '>='
|
88
78
|
- !ruby/object:Gem::Version
|
89
79
|
version: '0'
|
90
|
-
segments:
|
91
|
-
- 0
|
92
|
-
hash: -3794041082511016081
|
93
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
81
|
none: false
|
95
82
|
requirements:
|
96
83
|
- - ! '>='
|
97
84
|
- !ruby/object:Gem::Version
|
98
85
|
version: '0'
|
99
|
-
segments:
|
100
|
-
- 0
|
101
|
-
hash: -3794041082511016081
|
102
86
|
requirements: []
|
103
87
|
rubyforge_project:
|
104
|
-
rubygems_version: 1.8.
|
88
|
+
rubygems_version: 1.8.15
|
105
89
|
signing_key:
|
106
90
|
specification_version: 3
|
107
91
|
summary: This gem allows you to get a backup instance of jenkins up and running pretty
|
108
92
|
quickly
|
109
93
|
test_files:
|
110
|
-
- spec/lib/backup_jenkins/
|
94
|
+
- spec/lib/backup_jenkins/formatter_spec.rb
|
111
95
|
- spec/lib/backup_jenkins/backup_spec.rb
|
112
96
|
- spec/lib/backup_jenkins/cli_spec.rb
|
113
97
|
- spec/lib/backup_jenkins/config_spec.rb
|
114
|
-
- spec/lib/backup_jenkins/
|
98
|
+
- spec/lib/backup_jenkins/aws_spec.rb
|