jenkins-peace 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,71 @@
1
+ require 'ruby-progressbar'
2
+ require 'net/http'
3
+ require 'uri'
4
+
5
+ module Jenkins
6
+ module Peace
7
+ class ContentDownloader
8
+
9
+ attr_reader :target_file
10
+ attr_reader :logger
11
+
12
+
13
+ def initialize(target_file, logger)
14
+ @target_file = target_file
15
+ @logger = logger
16
+ end
17
+
18
+
19
+ def download(url, limit = 10)
20
+ raise ArgumentError, 'too many HTTP redirects' if limit == 0
21
+
22
+ start_http_session(url) do |http, uri|
23
+ response = http.request_head(uri.path)
24
+ case response
25
+ when Net::HTTPSuccess
26
+ download_content(url)
27
+ when Net::HTTPRedirection
28
+ redirect = response['location']
29
+ logger.info "Redirected to : '#{redirect}'"
30
+ download(redirect, limit - 1)
31
+ else
32
+ logger.error response.value
33
+ end
34
+ end
35
+ rescue => e
36
+ logger.error "Error while downloading '#{url}' : #{e.message}"
37
+ end
38
+
39
+
40
+ def download_content(url)
41
+ logger.info "Downloading : '#{url}'"
42
+ start_http_session(url) do |http, uri|
43
+ response = http.request_head(uri.path)
44
+ progressbar = build_progress_bar(response['content-length'].to_i)
45
+ File.open(target_file, 'wb') do |file|
46
+ http.get(uri.path) do |chunk|
47
+ file.write chunk
48
+ progressbar.progress += chunk.length
49
+ end
50
+ end
51
+ end
52
+ rescue => e
53
+ logger.error "Error while downloading '#{url}' : #{e.message}"
54
+ end
55
+
56
+
57
+ def build_progress_bar(total)
58
+ ProgressBar.create(title: 'Downloading', starting_at: 0, total: total, format: '%a |%b>%i| %p%% %t')
59
+ end
60
+
61
+
62
+ def start_http_session(url)
63
+ uri = URI(url)
64
+ Net::HTTP.start(uri.host, uri.port) do |http|
65
+ yield http, uri
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,86 @@
1
+ module Jenkins
2
+ module Peace
3
+ module ThorExtensions
4
+
5
+ def warn(message)
6
+ say message, :yellow
7
+ end
8
+
9
+
10
+ def info(message)
11
+ say message, :green
12
+ end
13
+
14
+
15
+ def green(string)
16
+ set_color string, :green
17
+ end
18
+
19
+
20
+ def red(string)
21
+ set_color string, :red
22
+ end
23
+
24
+
25
+ def bold(string)
26
+ set_color string, :bold
27
+ end
28
+
29
+
30
+ def success_message
31
+ info 'Done !'
32
+ end
33
+
34
+
35
+ def yes_no_question(question, &block)
36
+ answer = yes? question, :bold
37
+ if answer
38
+ yield if block_given?
39
+ success_message
40
+ else
41
+ warn 'Canceled !'
42
+ end
43
+ end
44
+
45
+
46
+ def download_it_first!
47
+ warn "War file doesn't exist, you should install it first with : jenkins.peace install <version>"
48
+ warn 'Exiting !'
49
+ end
50
+
51
+
52
+ def check_conflicts_and_call_method(method, version, check_method = :exists?, &block)
53
+ war_file = Jenkins::Peace.build_war_file(version)
54
+ yield war_file if block_given?
55
+ message = "#{method.capitalize}ing Jenkins war file version : '#{version}'"
56
+ if war_file.send(check_method)
57
+ yes_no_question('Overwrite existing file?') do
58
+ info message
59
+ Jenkins::Peace.send(method, version, true)
60
+ end
61
+ else
62
+ info message
63
+ Jenkins::Peace.send(method, version)
64
+ success_message
65
+ end
66
+ end
67
+
68
+
69
+ def formated_war_files_list
70
+ list = []
71
+ Jenkins::Peace.list.each do |war_file|
72
+ installed = war_file.installed? ? green(war_file.installed?) : red(war_file.installed?)
73
+ version = war_file.latest_version? ? "latest (#{war_file.real_version})" : war_file.version
74
+ list << [green(version), war_file.location, war_file.classpath, installed]
75
+ end
76
+ list
77
+ end
78
+
79
+
80
+ def formated_headers
81
+ [bold('Version'), bold('Location'), bold('Classpath'), bold('Installed')]
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ module Jenkins
2
+ module Peace
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,151 @@
1
+ require 'socket'
2
+
3
+ module Jenkins
4
+ module Peace
5
+ class WarFile
6
+
7
+ JENKINS_VERSION_REGEX = /jenkins-core-(1\.\d{3}).jar/
8
+
9
+ attr_reader :version
10
+ attr_reader :lib_path
11
+ attr_reader :base_path
12
+ attr_reader :base_url
13
+ attr_reader :server_path
14
+ attr_reader :logger
15
+
16
+ attr_reader :file_name
17
+ attr_reader :base_dir
18
+ attr_reader :lib_dir
19
+ attr_reader :klass_path
20
+ attr_reader :plugins_path
21
+ attr_reader :location
22
+ attr_reader :url
23
+
24
+
25
+ def initialize(version, opts = {})
26
+ @version = version
27
+ @lib_path = opts.fetch(:lib_path, '')
28
+ @base_path = opts.fetch(:base_path, '')
29
+ @base_url = opts.fetch(:base_url, '')
30
+ @server_path = opts.fetch(:server_path, '')
31
+ @logger = opts.fetch(:logger, $stdout)
32
+
33
+ @file_name = 'jenkins.war'
34
+ @base_dir = File.join(base_path, version)
35
+ @lib_dir = File.join(lib_path, version)
36
+ @klass_path = File.join(lib_dir, '**/*.jar')
37
+ @plugins_path = File.join(lib_dir, 'WEB-INF', 'plugins')
38
+ @location = File.join(base_dir, file_name)
39
+ @url = File.join(base_url, version, file_name)
40
+ end
41
+
42
+
43
+ def latest_version?
44
+ version == 'latest'
45
+ end
46
+
47
+
48
+ def real_version
49
+ return version unless latest_version?
50
+ klass = find_core_librairy
51
+ klass.nil? ? nil : klass.match(JENKINS_VERSION_REGEX)[1]
52
+ end
53
+
54
+
55
+ def classpath
56
+ File.join(lib_dir, 'WEB-INF', 'lib', "jenkins-core-#{real_version}.jar")
57
+ end
58
+
59
+
60
+ def exists?
61
+ File.exists?(location)
62
+ end
63
+
64
+
65
+ def unpacked?
66
+ File.exists?(lib_dir) && File.exists?(classpath)
67
+ end
68
+
69
+
70
+ def installed?
71
+ exists? && unpacked?
72
+ end
73
+
74
+
75
+ def download!
76
+ FileUtils.mkdir_p base_dir
77
+ fetch_content(url, location)
78
+ end
79
+
80
+
81
+ def install!
82
+ download!
83
+ unpack!
84
+ end
85
+
86
+
87
+ def remove!
88
+ FileUtils.rm_rf base_dir
89
+ FileUtils.rm_rf lib_dir
90
+ end
91
+
92
+
93
+ def unpack!
94
+ FileUtils.mkdir_p(lib_dir)
95
+ execute_command("cd #{lib_dir} && jar xvf #{location}")
96
+ end
97
+
98
+
99
+ def start!(options = {})
100
+ control = options.fetch(:control, 3002).to_i
101
+ kill = options.fetch(:kill, false)
102
+
103
+ if kill
104
+ TCPSocket.open('localhost', control) { |sock| sock.write('0') }
105
+ else
106
+ command = build_command_line(options)
107
+ exec(*command)
108
+ end
109
+ end
110
+
111
+
112
+ def build_command_line(options = {})
113
+ home = options.fetch(:home, server_path)
114
+ port = options.fetch(:port, 3001).to_i
115
+ control = options.fetch(:control, 3002).to_i
116
+ daemon = options.fetch(:daemon, false)
117
+ logfile = options.fetch(logfile, nil)
118
+
119
+ java_tmp = File.join(home, 'javatmp')
120
+ FileUtils.mkdir_p java_tmp
121
+
122
+ ENV['HUDSON_HOME'] = home
123
+ cmd = ['java', "-Djava.io.tmpdir=#{java_tmp}", '-jar', location]
124
+ cmd << '--daemon' if daemon
125
+ cmd << "--httpPort=#{port}"
126
+ cmd << "--controlPort=#{control}"
127
+ cmd << "--logfile=#{File.expand_path(logfile)}" if logfile
128
+ cmd
129
+ end
130
+
131
+
132
+ private
133
+
134
+
135
+ def execute_command(command)
136
+ `#{command}`
137
+ end
138
+
139
+
140
+ def fetch_content(url, target_file, limit = 10)
141
+ ContentDownloader.new(target_file, logger).download(url)
142
+ end
143
+
144
+
145
+ def find_core_librairy
146
+ Dir[File.join(lib_dir, 'WEB-INF', 'lib', '*.jar')].select { |f| f =~ JENKINS_VERSION_REGEX }.first
147
+ end
148
+
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,7 @@
1
+ require 'yaml'
2
+ require 'jenkins/peace'
3
+ require 'jenkins/peace/thor_extensions'
4
+ require 'jenkins/peace/cli'
5
+ require 'jenkins/peace/console_logger'
6
+ require 'jenkins/peace/content_downloader'
7
+ require 'jenkins/peace/war_file'
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jenkins::Peace::ConsoleLogger do
4
+
5
+ def helper
6
+ Jenkins::Peace::ConsoleLogger.new([])
7
+ end
8
+
9
+
10
+ describe '.info' do
11
+ it 'should render colored message' do
12
+ # allow_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:logger).and_return([])
13
+ expect(helper.info('foo')).to eq ["\e[32mfoo\e[0m\n"]
14
+ end
15
+ end
16
+
17
+
18
+ describe '.warn' do
19
+ it 'should render colored message' do
20
+ # allow_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:logger).and_return([])
21
+ expect(helper.warn('bar')).to eq ["\e[33mbar\e[0m\n"]
22
+ end
23
+ end
24
+
25
+
26
+ describe '.error' do
27
+ it 'should render colored message' do
28
+ # allow_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:logger).and_return([])
29
+ expect(helper.error('boo')).to eq ["\e[31mboo\e[0m\n"]
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jenkins::Peace::ContentDownloader do
4
+
5
+ VALID_URL = 'http://jenkins.mirror.isppower.de/war/1.629/jenkins.war'
6
+ REDIRECT_URL = 'http://mirrors.jenkins-ci.org/war/latest/jenkins.war'
7
+ INVALID_URL = 'http://mirrors.jenkins-ci.org/war/120000/jenkins.war'
8
+
9
+
10
+ def logger
11
+ Jenkins::Peace::ConsoleLogger.new([])
12
+ end
13
+
14
+
15
+ def build_content_downloader
16
+ Jenkins::Peace::ContentDownloader.new('/tmp/jenkins-test.war', logger)
17
+ end
18
+
19
+ let(:content_downloader) { build_content_downloader }
20
+
21
+
22
+ describe '#start_http_session' do
23
+ it 'should start a http session' do
24
+ uri = URI(VALID_URL)
25
+ expect(Net::HTTP).to receive(:start).with(uri.host, uri.port)
26
+ content_downloader.start_http_session(VALID_URL)
27
+ end
28
+ end
29
+
30
+
31
+ describe '#build_progress_bar' do
32
+ it 'should return a progress bar object' do
33
+ allow_any_instance_of(ProgressBar).to receive(:create)
34
+ content_downloader.build_progress_bar(100)
35
+ end
36
+ end
37
+
38
+
39
+ describe '#download' do
40
+ context 'when url is valid' do
41
+ it 'should download file' do
42
+ expect(content_downloader).to receive(:download_content).with(VALID_URL)
43
+ content_downloader.download(VALID_URL)
44
+ end
45
+ end
46
+
47
+ context 'when url is valid and redirecting' do
48
+ it 'should redirect' do
49
+ expect(content_downloader).to receive(:download_content)
50
+ expect_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:info)
51
+ content_downloader.download(REDIRECT_URL)
52
+ end
53
+ end
54
+
55
+ context 'when url is invalid' do
56
+ it 'should not download file' do
57
+ expect_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:error)
58
+ content_downloader.download(INVALID_URL)
59
+ end
60
+ end
61
+ end
62
+
63
+
64
+ describe '#download_content' do
65
+ context 'when url is valid' do
66
+ it 'should download file' do
67
+ expect_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:info).with("Downloading : '#{VALID_URL}'")
68
+ expect(content_downloader).to receive(:start_http_session).with(VALID_URL)
69
+ content_downloader.download_content(VALID_URL)
70
+ end
71
+ end
72
+
73
+ context 'when url is invalid' do
74
+ it 'should not download file' do
75
+ expect_any_instance_of(Jenkins::Peace::ConsoleLogger).to receive(:error)
76
+ content_downloader.download_content(INVALID_URL)
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,194 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jenkins::Peace do
4
+
5
+ def helper
6
+ Jenkins::Peace
7
+ end
8
+
9
+
10
+ def infos
11
+ {
12
+ base_path: BASE_PATH,
13
+ war_files_cache: WAR_FILES_CACHE,
14
+ war_unpacked_cache: WAR_UNPACKED_CACHE,
15
+ server_path: SERVER_PATH,
16
+ jenkins_war_url: JENKINS_WAR_URL
17
+ }
18
+ end
19
+
20
+
21
+ describe '.jenkins_war_url' do
22
+ it { expect(helper.jenkins_war_url).to eq JENKINS_WAR_URL }
23
+ end
24
+
25
+
26
+ describe '.base_path' do
27
+ it { expect(helper.base_path).to eq BASE_PATH }
28
+ end
29
+
30
+
31
+ describe '.war_files_cache' do
32
+ it { expect(helper.war_files_cache).to eq WAR_FILES_CACHE }
33
+ end
34
+
35
+
36
+ describe '.war_unpacked_cache' do
37
+ it { expect(helper.war_unpacked_cache).to eq WAR_UNPACKED_CACHE }
38
+ end
39
+
40
+
41
+ describe '.server_path' do
42
+ it { expect(helper.server_path).to eq SERVER_PATH }
43
+ end
44
+
45
+
46
+ describe '.infos' do
47
+ it { expect(helper.infos).to eq infos }
48
+ end
49
+
50
+
51
+ def stub_all_war_files_with_return(value)
52
+ expect_any_instance_of(Jenkins::Peace).to receive(:all_war_files).at_least(:once).and_return(value)
53
+ end
54
+
55
+
56
+ describe '.list' do
57
+ context 'when no war file is installed' do
58
+ it 'should return empty array' do
59
+ stub_all_war_files_with_return([])
60
+ expect(helper.list).to eq []
61
+ end
62
+ end
63
+
64
+ context 'when war files are installed' do
65
+ it 'should return a list of war files' do
66
+ stub_all_war_files_with_return(['1.629', '1.628', '1.630'])
67
+ allow_any_instance_of(Jenkins::Peace::WarFile).to receive(:installed?).and_return(true)
68
+ expect(helper.list.first).to be_instance_of(Jenkins::Peace::WarFile)
69
+ expect(helper.list.first.version).to eq '1.630'
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ describe '.latest_war_file' do
76
+ context 'when no war file is installed' do
77
+ it 'should return nil' do
78
+ stub_all_war_files_with_return([])
79
+ expect(helper.latest_war_file).to be nil
80
+ end
81
+ end
82
+
83
+ context 'when war files are installed' do
84
+ it 'should return the last war file installed' do
85
+ stub_all_war_files_with_return(['1.629', '1.628'])
86
+ allow_any_instance_of(Jenkins::Peace::WarFile).to receive(:installed?).and_return(true)
87
+ expect(helper.latest_war_file).to be_instance_of(Jenkins::Peace::WarFile)
88
+ expect(helper.latest_war_file.version).to eq '1.629'
89
+ end
90
+ end
91
+ end
92
+
93
+
94
+ describe '.latest_version' do
95
+ context 'when no war file is installed' do
96
+ it 'should return nil' do
97
+ stub_all_war_files_with_return([])
98
+ expect(helper.latest_version).to be nil
99
+ end
100
+ end
101
+
102
+ context 'when war files are installed' do
103
+ it 'should return the classpath of the last war file installed' do
104
+ stub_all_war_files_with_return(['1.629', '1.628'])
105
+ allow_any_instance_of(Jenkins::Peace::WarFile).to receive(:installed?).and_return(true)
106
+ expect(helper.latest_version).to eq File.join(ENV['HOME'], '.jenkins/wars/1.629/WEB-INF/lib/jenkins-core-1.629.jar')
107
+ end
108
+ end
109
+ end
110
+
111
+
112
+ describe '.clean!' do
113
+ it 'should remove all war files' do
114
+ stub_all_war_files_with_return(['1.629', '1.628'])
115
+ allow_any_instance_of(Jenkins::Peace::WarFile).to receive(:remove!)
116
+ helper.clean!
117
+ end
118
+ end
119
+
120
+
121
+ describe '.download' do
122
+ it 'should download a war file' do
123
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:download!)
124
+ expect(helper.download('1.628')).to be_instance_of(Jenkins::Peace::WarFile)
125
+ end
126
+ end
127
+
128
+
129
+ describe '.install' do
130
+ it 'should install a war file' do
131
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:install!)
132
+ expect(helper.install('1.628')).to be_instance_of(Jenkins::Peace::WarFile)
133
+ end
134
+ end
135
+
136
+
137
+ describe '.unpack' do
138
+ it 'should unpack a war file' do
139
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:unpack!)
140
+ expect(helper.unpack('1.628')).to be_instance_of(Jenkins::Peace::WarFile)
141
+ end
142
+ end
143
+
144
+
145
+ describe '.remove' do
146
+ it 'should remove a war file' do
147
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:exists?).and_return(true)
148
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:remove!)
149
+ expect(helper.remove('1.628')).to be_instance_of(Jenkins::Peace::WarFile)
150
+ end
151
+ end
152
+
153
+
154
+ describe '.all_war_files' do
155
+ it 'should return a list of war files' do
156
+ expect(FileUtils).to receive(:mkdir_p).with(WAR_FILES_CACHE)
157
+ expect(Pathname).to receive(:new).with(WAR_FILES_CACHE).and_return(OpenStruct.new(children: []))
158
+ helper.all_war_files
159
+ end
160
+ end
161
+
162
+
163
+ describe 'check_for_presence_and_execute' do
164
+ context 'when file doesnt exist' do
165
+ it 'should check for file existence before executing method' do
166
+ war_file = helper.build_war_file('1.628')
167
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:exists?).and_return(false)
168
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:download!)
169
+ helper.check_for_presence_and_execute(war_file, :download!)
170
+ end
171
+ end
172
+
173
+ context 'when file exists' do
174
+ context 'and overwrite is false' do
175
+ it 'should do nothing' do
176
+ war_file = helper.build_war_file('1.628')
177
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:exists?).at_least(:twice).and_return(true)
178
+ expect_any_instance_of(Jenkins::Peace::WarFile).to_not receive(:download!)
179
+ helper.check_for_presence_and_execute(war_file, :download!, false)
180
+ end
181
+ end
182
+
183
+ context 'and overwrite is true' do
184
+ it 'should execute method' do
185
+ war_file = helper.build_war_file('1.628')
186
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:exists?).at_least(:twice).and_return(true)
187
+ expect_any_instance_of(Jenkins::Peace::WarFile).to receive(:download!)
188
+ helper.check_for_presence_and_execute(war_file, :download!, true)
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ end