backup_jenkins 0.0.7 → 0.0.8
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/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
|