cerberus 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +26 -0
- data/Rakefile +11 -4
- data/lib/cerberus/builder/bjam.rb +4 -0
- data/lib/cerberus/builder/maven2.rb +3 -1
- data/lib/cerberus/builder/ruby_base.rb +6 -0
- data/lib/cerberus/cli.rb +1 -1
- data/lib/cerberus/component_lazy_loader.rb +63 -0
- data/lib/cerberus/config.example.yml +2 -4
- data/lib/cerberus/constants.rb +1 -1
- data/lib/cerberus/latch.rb +1 -1
- data/lib/cerberus/manager.rb +109 -94
- data/lib/cerberus/publisher/base.rb +19 -5
- data/lib/cerberus/publisher/irc.rb +3 -5
- data/lib/cerberus/publisher/jabber.rb +8 -18
- data/test/functional_test.rb +57 -17
- data/test/integration_test.rb +1 -1
- data/test/irc_publisher_test.rb +2 -1
- data/test/jabber_publisher_test.rb +8 -7
- data/test/mail_publisher_test.rb +1 -1
- data/test/mock/irc.rb +1 -1
- data/test/mock/xmpp4r.rb +19 -0
- data/test/rss_publisher_test.rb +2 -2
- data/test/test_helper.rb +17 -3
- metadata +8 -7
- data/test/mock/jabber4r.rb +0 -24
data/CHANGES
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
= Cerberus Changelog
|
2
2
|
|
3
|
+
== Version 0.3.3
|
4
|
+
Major changes
|
5
|
+
|
6
|
+
* Fix Const load problem with Rails 1.2RC1
|
7
|
+
* Correctly implement Jabber publisher using XMPP4R library
|
8
|
+
* Upgrade Webgen to 0.4.1
|
9
|
+
* Added 'getting better/worse' to build messages' subject
|
10
|
+
* Added possibility to configure events on what you would like to receive messages.
|
11
|
+
By default used 'default' events. It means all except 'successful' state.
|
12
|
+
You could set to this options list of any valid states such as [broken, failed, revival, successful, setup] or predefined sets as
|
13
|
+
[all, default, none].
|
14
|
+
|
15
|
+
You could configure by setting :on_event option to :publisher options branch, or to concrete publisher configuration.
|
16
|
+
In case if this option added both to :publisher and :publisher,<PUBLISHER> then concrete configurations wins.
|
17
|
+
|
18
|
+
Examples of configuration
|
19
|
+
|
20
|
+
publisher:
|
21
|
+
on_event: broken, revival
|
22
|
+
mail:
|
23
|
+
on_event: all
|
24
|
+
jabber:
|
25
|
+
#nothing here
|
26
|
+
|
27
|
+
In given example we would send messages about ALL events by mail and only messages about brokeness and revivalness by Jabber.
|
28
|
+
|
3
29
|
== Version 0.3.2
|
4
30
|
Added Perforce SCM support
|
5
31
|
|
data/Rakefile
CHANGED
@@ -52,8 +52,8 @@ GEM_SPEC = Gem::Specification.new do |s|
|
|
52
52
|
|
53
53
|
s.add_dependency 'actionmailer', '>= 1.2.5'
|
54
54
|
s.add_dependency 'rake', '>= 0.7.1'
|
55
|
-
s.add_dependency '
|
56
|
-
s.add_dependency 'Ruby-IRC', '>= 1.0.
|
55
|
+
s.add_dependency 'xmpp4r', '>= 0.3'
|
56
|
+
s.add_dependency 'Ruby-IRC', '>= 1.0.7'
|
57
57
|
|
58
58
|
s.files = Dir.glob("{bin,lib,test}/**/*").delete_if { |item| item.include?('__workdir') }
|
59
59
|
s.files += %w(LICENSE README CHANGES Rakefile)
|
@@ -143,7 +143,14 @@ task :publish_news do
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
|
147
|
-
|
146
|
+
require 'webgen/rake/webgentask'
|
147
|
+
|
148
|
+
Webgen::Rake::WebgenTask.new do |t|
|
149
|
+
t.directory = File.join(Dir.pwd, "doc/site")
|
150
|
+
end
|
151
|
+
|
152
|
+
task :publish_site => :webgen do
|
148
153
|
sh %{scp -r -q doc/site/output/* #{RUBYFORGE_USER}@rubyforge.org:/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/}
|
149
154
|
end
|
155
|
+
|
156
|
+
task :release => [:release_files, :publish_news, :webgen]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'cerberus/builder/base'
|
2
2
|
|
3
3
|
class Cerberus::Builder::Maven2
|
4
|
-
attr_reader :output
|
4
|
+
attr_reader :output, :brokeness
|
5
5
|
|
6
6
|
def initialize(config)
|
7
7
|
@config = config
|
@@ -23,7 +23,9 @@ class Cerberus::Builder::Maven2
|
|
23
23
|
def add_error_information
|
24
24
|
str = @output
|
25
25
|
@output = ''
|
26
|
+
@brokeness = 0
|
26
27
|
while str =~ / <<< FAILURE!$/
|
28
|
+
@brokeness += 1
|
27
29
|
s = $'
|
28
30
|
|
29
31
|
$` =~ /^(.|\n)*Running (.*)$/
|
@@ -19,6 +19,12 @@ class Cerberus::Builder::RubyBase
|
|
19
19
|
$?.exitstatus == 0 and not @output.include?("#{@cmd} aborted!")
|
20
20
|
end
|
21
21
|
|
22
|
+
def brokeness
|
23
|
+
if @output =~ /\d+ tests, \d+ assertions, (\d+) failures, (\d+) errors/
|
24
|
+
$1.to_i + $2.to_i
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
22
28
|
private
|
23
29
|
def choose_exec
|
24
30
|
ext = ['']
|
data/lib/cerberus/cli.rb
CHANGED
@@ -56,7 +56,7 @@ module Cerberus
|
|
56
56
|
end
|
57
57
|
|
58
58
|
HELP = %{
|
59
|
-
Cerberus is a
|
59
|
+
Cerberus is a lightweight command-line Continuous Integration tool for Ruby.
|
60
60
|
|
61
61
|
Usage:
|
62
62
|
cerberus add <URL> --- add project from svn repository to list watched of applications
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Cerberus
|
2
|
+
module SCM
|
3
|
+
TYPES = {
|
4
|
+
:svn => 'SVN', #Cerberus::SCM
|
5
|
+
:darcs => 'Darcs',
|
6
|
+
:perforce => 'Perforce'
|
7
|
+
}
|
8
|
+
|
9
|
+
def self.get(type)
|
10
|
+
class_name = TYPES[type.to_sym]
|
11
|
+
say "SCM #{type} not supported" unless class_name
|
12
|
+
require "cerberus/scm/#{type}"
|
13
|
+
const_get(class_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def self.guess_type(path)
|
18
|
+
return nil unless test(?d, path)
|
19
|
+
|
20
|
+
case
|
21
|
+
when test(?d, path+'/.svn')
|
22
|
+
'svn'
|
23
|
+
when test(?d, path+'/_darcs')
|
24
|
+
'darcs'
|
25
|
+
when test(?d, path+'/.cvs')
|
26
|
+
'cvs'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Publisher
|
32
|
+
TYPES = {
|
33
|
+
:mail => 'Mail', #Cerberus::Publisher
|
34
|
+
:jabber => 'Jabber',
|
35
|
+
:irc => 'IRC',
|
36
|
+
:rss => 'RSS',
|
37
|
+
:campfire => 'Campfire'
|
38
|
+
}
|
39
|
+
|
40
|
+
def self.get(type)
|
41
|
+
class_name = TYPES[type.to_sym]
|
42
|
+
say "Publisher #{type} not supported" unless class_name
|
43
|
+
require "cerberus/publisher/#{type}"
|
44
|
+
const_get(class_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module Builder
|
49
|
+
TYPES = {
|
50
|
+
:maven2 => 'Maven2', #Cerberus::Builder
|
51
|
+
:rake => 'Rake',
|
52
|
+
:rant => 'Rant',
|
53
|
+
:bjam => 'Bjam'
|
54
|
+
}
|
55
|
+
|
56
|
+
def self.get(type)
|
57
|
+
class_name = TYPES[type.to_sym]
|
58
|
+
say "Builder #{type} not supported" unless class_name
|
59
|
+
require "cerberus/builder/#{type}"
|
60
|
+
const_get(class_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -8,10 +8,8 @@ publisher:
|
|
8
8
|
user_name: someuser
|
9
9
|
password: somepassword
|
10
10
|
# jabber:
|
11
|
-
# jid:
|
12
|
-
#
|
13
|
-
# password: mypass
|
14
|
-
# digest: false
|
11
|
+
# jid: somemailbox@gmail.com/cerberus
|
12
|
+
# password: somepassword
|
15
13
|
# irc:
|
16
14
|
# nick: cerb
|
17
15
|
# server: irc.freenode.net
|
data/lib/cerberus/constants.rb
CHANGED
data/lib/cerberus/latch.rb
CHANGED
data/lib/cerberus/manager.rb
CHANGED
@@ -4,6 +4,7 @@ require 'cerberus/utils'
|
|
4
4
|
require 'cerberus/constants'
|
5
5
|
require 'cerberus/config'
|
6
6
|
require 'cerberus/latch'
|
7
|
+
require 'cerberus/component_lazy_loader'
|
7
8
|
|
8
9
|
module Cerberus
|
9
10
|
class AddCommand
|
@@ -15,7 +16,7 @@ module Cerberus
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def run
|
18
|
-
scm_type = @cli_options[:scm] || 'svn'
|
19
|
+
scm_type = @cli_options[:scm] || Cerberus::SCM.guess_type(@path) || 'svn'
|
19
20
|
scm = Cerberus::SCM.get(scm_type).new(@path, Config.new(nil, @cli_options))
|
20
21
|
say "Can't find any #{scm_type} application under #{@path}" unless scm.url
|
21
22
|
|
@@ -67,7 +68,7 @@ module Cerberus
|
|
67
68
|
@config = Config.new(application_name, cli_options.merge(def_options))
|
68
69
|
@config.merge!(DEFAULT_CONFIG, false)
|
69
70
|
|
70
|
-
@status = Status.
|
71
|
+
@status = Status.read("#{app_root}/status.log")
|
71
72
|
|
72
73
|
scm_type = @config[:scm, :type]
|
73
74
|
@scm = SCM.get(scm_type).new(@config[:application_root], @config)
|
@@ -80,48 +81,47 @@ module Cerberus
|
|
80
81
|
def run
|
81
82
|
begin
|
82
83
|
Latch.lock("#{HOME}/work/#{@config[:application_name]}/.lock", :lock_ttl => 2 * LOCK_WAIT) do
|
83
|
-
previous_status = @status.recall
|
84
84
|
@scm.update!
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@status.keep(:succesful)
|
90
|
-
case previous_status
|
91
|
-
when :failed
|
92
|
-
:revival
|
93
|
-
when :succesful
|
94
|
-
:succesful
|
95
|
-
when false
|
96
|
-
:setup
|
97
|
-
end
|
98
|
-
else
|
99
|
-
@status.keep(:failed)
|
100
|
-
previous_status == :failed ? :broken : :failure
|
101
|
-
end
|
102
|
-
else
|
103
|
-
:unchanged
|
104
|
-
end
|
86
|
+
if @scm.has_changes? or @config[:force] or @status.previous_build_successful.nil?
|
87
|
+
build_successful = @builder.run
|
88
|
+
@status.keep(build_successful, @scm.current_revision, @builder.brokeness)
|
105
89
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
90
|
+
#Save logs to directory
|
91
|
+
if @config[:log, :enable]
|
92
|
+
log_dir = "#{HOME}/work/#{@config[:application_name]}/logs/"
|
93
|
+
FileUtils.mkpath(log_dir)
|
110
94
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
95
|
+
time = Time.now.strftime("%Y%m%d%H%M%S")
|
96
|
+
file_name = "#{log_dir}/#{time}-#{@status.current_state.to_s}.log"
|
97
|
+
body = [ scm.last_commit_message, builder.output ].join("\n\n")
|
98
|
+
IO.write(file_name, body)
|
99
|
+
end
|
116
100
|
|
117
|
-
|
118
|
-
if [:failure, :broken, :revival, :setup].include?(state)
|
101
|
+
#send notifications
|
119
102
|
active_publishers = get_configuration_option(@config[:publisher], :active, 'mail')
|
120
103
|
active_publishers.split(/\W+/).each do |pub|
|
121
|
-
|
122
|
-
|
104
|
+
|
105
|
+
publisher_config = @config[:publisher, pub]
|
106
|
+
raise "Publisher have no configuration: #{pub}" unless publisher_config
|
107
|
+
|
108
|
+
on_event = publisher_config[:on_event] || @config[:publisher, :on_event] || 'default'
|
109
|
+
events =
|
110
|
+
case on_event
|
111
|
+
when 'all'
|
112
|
+
[:setup, :successful, :revival, :broken, :failed]
|
113
|
+
when 'none'
|
114
|
+
[]
|
115
|
+
when 'default'
|
116
|
+
[:setup, :revival, :broken, :failed] #the same as 'all' except successful
|
117
|
+
else
|
118
|
+
on_event.scan(/\w+/).map{|s| s.to_sym}
|
119
|
+
end
|
120
|
+
|
121
|
+
Publisher.get(pub).publish(@status, self, @config) if events.include?(@status.current_state)
|
123
122
|
end
|
124
123
|
end
|
124
|
+
|
125
125
|
end #lock
|
126
126
|
rescue Exception => e
|
127
127
|
if ENV['CERBERUS_ENV'] == 'TEST'
|
@@ -129,7 +129,7 @@ module Cerberus
|
|
129
129
|
else
|
130
130
|
File.open("#{HOME}/error.log", File::WRONLY|File::APPEND|File::CREAT) do |f|
|
131
131
|
f.puts Time.now.strftime("%a, %d %b %Y %H:%M:%S [#{@config[:application_name]}] -- #{e.class}")
|
132
|
-
f.puts e.message unless e.message.
|
132
|
+
f.puts e.message unless e.message.empty?
|
133
133
|
f.puts e.backtrace.collect{|line| ' '*5 + line}
|
134
134
|
f.puts "\n"
|
135
135
|
end
|
@@ -173,7 +173,7 @@ module Cerberus
|
|
173
173
|
end
|
174
174
|
|
175
175
|
class ListCommand
|
176
|
-
def initialize(cli_options = {})
|
176
|
+
def initialize(cli_options = {})
|
177
177
|
end
|
178
178
|
|
179
179
|
def run
|
@@ -194,69 +194,84 @@ module Cerberus
|
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
|
+
#Fields that are contained in status file
|
198
|
+
# successful (true mean previous build was successful, otherwise - false)
|
199
|
+
# timestamp
|
200
|
+
# revision
|
201
|
+
# brokeness
|
202
|
+
# successful_build_timestamp
|
203
|
+
# successful_build_revision
|
197
204
|
class Status
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
205
|
+
attr_reader :previous_build_successful, :previous_brokeness, :current_build_successful, :current_brokeness
|
206
|
+
|
207
|
+
def initialize(param)
|
208
|
+
if param.is_a? Hash
|
209
|
+
@hash = param
|
210
|
+
@current_build_successful = @hash['state']
|
211
|
+
@already_kept = true
|
212
|
+
else
|
213
|
+
@path = param
|
214
|
+
value = File.exists?(@path) ? YAML.load(IO.read(@path)) : nil
|
215
|
+
|
216
|
+
@hash =
|
217
|
+
case value
|
218
|
+
when String
|
219
|
+
value = %w(succesful successful setup).include?(value) #fix typo in status values
|
220
|
+
{'successful' => value}
|
221
|
+
when nil
|
222
|
+
{}
|
223
|
+
else
|
224
|
+
#TODO remove it before 0.3.3 release
|
225
|
+
if state = value['state']
|
226
|
+
value['successful'] = %w(succesful successful setup).include?(state)
|
227
|
+
end
|
228
|
+
|
229
|
+
value
|
230
|
+
end
|
231
|
+
|
232
|
+
@already_kept = false
|
233
|
+
end
|
234
|
+
|
235
|
+
@previous_build_successful = @hash['successful']
|
236
|
+
@previous_brokeness = @hash['brokeness']
|
210
237
|
end
|
211
|
-
end
|
212
|
-
end
|
213
238
|
|
214
|
-
|
215
|
-
|
216
|
-
TYPES = {
|
217
|
-
:svn => 'SVN', #Cerberus::SCM
|
218
|
-
:darcs => 'Darcs',
|
219
|
-
:perforce => 'Perforce'
|
220
|
-
}
|
221
|
-
|
222
|
-
def self.get(type)
|
223
|
-
class_name = TYPES[type.to_sym]
|
224
|
-
say "SCM #{type} not supported" unless class_name
|
225
|
-
require "cerberus/scm/#{type}"
|
226
|
-
const_get(class_name)
|
239
|
+
def self.read(file_name)
|
240
|
+
Status.new(file_name)
|
227
241
|
end
|
228
|
-
end
|
229
242
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
243
|
+
def keep(build_successful, revision, brokeness)
|
244
|
+
raise 'Status could be kept only once. Please try to reread status file.' if @already_kept
|
245
|
+
|
246
|
+
@current_brokeness = brokeness
|
247
|
+
@current_build_successful = build_successful
|
248
|
+
|
249
|
+
hash = {'successful' => @current_build_successful, 'timestamp' => Time.now, 'revision' => revision, 'brokeness' => brokeness}
|
250
|
+
if build_successful
|
251
|
+
hash['successful_build_timestamp'] = Time.now
|
252
|
+
hash['successful_build_revision'] = revision
|
253
|
+
else
|
254
|
+
hash['successful_build_timestamp'] = @hash['successful_build_timestamp']
|
255
|
+
hash['successful_build_revision'] = @hash['successful_build_revision']
|
256
|
+
end
|
257
|
+
|
258
|
+
File.open(@path, "w+", 0777) { |file| file.write(YAML.dump(hash)) }
|
259
|
+
|
260
|
+
@already_kept = true
|
244
261
|
end
|
245
|
-
end
|
246
262
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
const_get(class_name)
|
263
|
+
def current_state
|
264
|
+
raise "Invalid project state. Before calculating status please do keeping of it." unless @already_kept
|
265
|
+
|
266
|
+
if @current_build_successful
|
267
|
+
if @previous_build_successful.nil?
|
268
|
+
:setup
|
269
|
+
else
|
270
|
+
@previous_build_successful ? :successful : :revival
|
271
|
+
end
|
272
|
+
else
|
273
|
+
@previous_build_successful ? :failed : :broken
|
274
|
+
end
|
260
275
|
end
|
261
276
|
end
|
262
|
-
end
|
277
|
+
end
|
@@ -5,17 +5,31 @@ module Cerberus
|
|
5
5
|
class Base
|
6
6
|
def self.formatted_message(state, manager, options)
|
7
7
|
subject =
|
8
|
-
case state
|
8
|
+
case state.current_state
|
9
9
|
when :setup
|
10
10
|
"Cerberus set up for project (##{manager.scm.current_revision})"
|
11
11
|
when :broken
|
12
|
-
|
13
|
-
|
12
|
+
additional_message = nil
|
13
|
+
if state.previous_brokeness and state.current_brokeness
|
14
|
+
additional_message =
|
15
|
+
case
|
16
|
+
when state.previous_brokeness > state.current_brokeness
|
17
|
+
' but getting better'
|
18
|
+
when state.previous_brokeness < state.current_brokeness
|
19
|
+
' and getting worse'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
"Build still broken#{additional_message} (##{manager.scm.current_revision})"
|
23
|
+
|
24
|
+
#FIXME instead of using last author as person that broken build try to guess it. I.e. only if one author since last commit did commit - then he broken it.
|
25
|
+
when :failed
|
14
26
|
"Build broken by #{manager.scm.last_author} (##{manager.scm.current_revision})"
|
15
27
|
when :revival
|
16
28
|
"Build fixed by #{manager.scm.last_author} (##{manager.scm.current_revision})"
|
17
|
-
|
18
|
-
|
29
|
+
when :revival
|
30
|
+
"Build was successfully built (##{manager.scm.current_revision})"
|
31
|
+
else
|
32
|
+
raise "Unknown build state '#{state.current_state.to_s}'"
|
19
33
|
end
|
20
34
|
|
21
35
|
subject = "[#{options[:application_name]}] #{subject}"
|
@@ -3,6 +3,8 @@ require 'IRC'
|
|
3
3
|
require 'cerberus/publisher/base'
|
4
4
|
|
5
5
|
class Cerberus::Publisher::IRC < Cerberus::Publisher::Base
|
6
|
+
class << self; include Cerberus::Utils end
|
7
|
+
|
6
8
|
def self.publish(state, manager, options)
|
7
9
|
irc_options = options[:publisher, :irc]
|
8
10
|
raise "There is no channel provided for IRC publisher" unless irc_options[:channel]
|
@@ -21,11 +23,7 @@ class Cerberus::Publisher::IRC < Cerberus::Publisher::Base
|
|
21
23
|
}
|
22
24
|
bot.send_quit
|
23
25
|
}
|
24
|
-
|
25
|
-
bot.connect #Why it always fails?
|
26
|
-
rescue Exception => e
|
27
|
-
puts e.message
|
28
|
-
end
|
26
|
+
bot.connect
|
29
27
|
}
|
30
28
|
end
|
31
29
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
2
|
+
require 'xmpp4r'
|
3
3
|
require 'cerberus/publisher/base'
|
4
4
|
|
5
5
|
class Cerberus::Publisher::Jabber < Cerberus::Publisher::Base
|
@@ -10,26 +10,16 @@ class Cerberus::Publisher::Jabber < Cerberus::Publisher::Base
|
|
10
10
|
|
11
11
|
subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
12
12
|
|
13
|
-
|
13
|
+
client = Jabber::Client::new(Jabber::JID.new(jabber_options[:jid]))
|
14
|
+
client.connect
|
15
|
+
client.auth(jabber_options[:password])
|
16
|
+
|
14
17
|
jabber_options[:recipients].split(',').each do |address|
|
15
|
-
|
18
|
+
message = Jabber::Message::new(address.strip, body).set_subject(subject)
|
19
|
+
client.send(message)
|
16
20
|
end
|
17
21
|
ensure
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.login(id_resource, password, register_if_login_fails=true)
|
23
|
-
begin
|
24
|
-
session = ::Jabber::Session.bind(id_resource, password)
|
25
|
-
rescue
|
26
|
-
if(register_if_login_fails)
|
27
|
-
if(::Jabber::Session.register(id_resource, password))
|
28
|
-
Cerberus::Publisher::Jabber.login(id_resource, password, false)
|
29
|
-
else
|
30
|
-
raise "Failed to register #{id_resource}"
|
31
|
-
end
|
32
|
-
end
|
22
|
+
client.close if client
|
33
23
|
end
|
34
24
|
end
|
35
25
|
end
|
data/test/functional_test.rb
CHANGED
@@ -62,40 +62,49 @@ class FunctionalTest < Test::Unit::TestCase
|
|
62
62
|
|
63
63
|
status_file = HOME + '/work/myapp/status.log'
|
64
64
|
assert File.exists?(status_file)
|
65
|
-
|
66
|
-
assert 1, Dir[HOME + "/work/rake_cust/logs/*-
|
65
|
+
assert build_successful?(status_file)
|
66
|
+
assert 1, Dir[HOME + "/work/rake_cust/logs/*-setup.log"].size
|
67
67
|
|
68
68
|
FileUtils.rm status_file
|
69
69
|
build = Cerberus::BuildCommand.new('myapp')
|
70
70
|
build.run
|
71
71
|
assert File.exists?(status_file)
|
72
|
+
assert build_successful?(status_file)
|
73
|
+
assert_equal :setup, build.status.current_state
|
72
74
|
assert_equal 2, ActionMailer::Base.deliveries.size #first email that project was setup
|
73
75
|
assert 2, Dir[HOME + "/work/rake_cust/logs/*.log"].size
|
74
76
|
|
75
|
-
build = Cerberus::BuildCommand.new('myapp')
|
77
|
+
build = Cerberus::BuildCommand.new('myapp', :force => true)
|
76
78
|
build.run
|
79
|
+
assert_equal :successful, build.status.current_state
|
77
80
|
assert_equal 2, ActionMailer::Base.deliveries.size #Number of mails not changed
|
78
81
|
assert 2, Dir[HOME + "/work/rake_cust/logs/*.log"].size #even if sources unchanged
|
79
82
|
|
80
83
|
#remove status file to run project again
|
81
84
|
FileUtils.rm status_file
|
82
|
-
add_test_case_to_project('myapp', 'assert false')
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
}
|
85
|
+
add_test_case_to_project('myapp', 'assert false') #if assertion failed
|
86
|
+
build = Cerberus::BuildCommand.new('myapp')
|
87
|
+
build.run
|
88
|
+
assert !build_successful?(status_file)
|
89
|
+
assert_equal :broken, build.status.current_state
|
88
90
|
assert_equal 3, ActionMailer::Base.deliveries.size #We should receive mail if project fails
|
89
91
|
|
90
92
|
|
93
|
+
add_test_case_to_project('myapp', 'raise "Some exception here"') #if we have exception
|
94
|
+
build = Cerberus::BuildCommand.new('myapp', :force => true)
|
95
|
+
build.run
|
96
|
+
assert !build_successful?(status_file)
|
97
|
+
assert_equal :broken, build.status.current_state
|
98
|
+
|
99
|
+
subject = ActionMailer::Base.deliveries.last.subject
|
100
|
+
assert_match /and getting worse/, subject
|
101
|
+
|
91
102
|
#remove status file to run project again
|
92
103
|
FileUtils.rm status_file
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
assert_equal 'failed', IO.read(status_file)
|
98
|
-
}
|
104
|
+
build = Cerberus::BuildCommand.new('myapp')
|
105
|
+
build.run
|
106
|
+
assert !build_successful?(status_file)
|
107
|
+
assert_equal :broken, build.status.current_state
|
99
108
|
end
|
100
109
|
|
101
110
|
def test_have_no_awkward_header
|
@@ -108,6 +117,19 @@ class FunctionalTest < Test::Unit::TestCase
|
|
108
117
|
assert_equal 0, build.scm.last_commit_message.index('-' * 72)
|
109
118
|
end
|
110
119
|
|
120
|
+
def test_send_on_different_events
|
121
|
+
add_application('myapp', SVN_URL, 'publisher' => {'mail' => {'on_event' => 'none'}, 'on_event' => 'all'})
|
122
|
+
build = Cerberus::BuildCommand.new('myapp')
|
123
|
+
build.run
|
124
|
+
assert_equal 0, ActionMailer::Base.deliveries.size
|
125
|
+
|
126
|
+
|
127
|
+
add_application('myapp', SVN_URL, 'publisher' => {'mail' => {'on_event' => 'all'}, 'on_event' => 'none'})
|
128
|
+
build = Cerberus::BuildCommand.new('myapp')
|
129
|
+
build.run
|
130
|
+
assert_equal 1, ActionMailer::Base.deliveries.size
|
131
|
+
end
|
132
|
+
|
111
133
|
def test_multiply_publishers_without_configuration
|
112
134
|
add_application('myapp', SVN_URL, 'publisher' => {'active' => 'mail , jabber , irc, dddd'})
|
113
135
|
|
@@ -148,7 +170,7 @@ class FunctionalTest < Test::Unit::TestCase
|
|
148
170
|
for i in 1..4 do
|
149
171
|
status_file = HOME + "/work/myapp#{i}/status.log"
|
150
172
|
assert File.exists?(status_file)
|
151
|
-
|
173
|
+
assert build_successful?(status_file)
|
152
174
|
end
|
153
175
|
end
|
154
176
|
|
@@ -187,7 +209,7 @@ class FunctionalTest < Test::Unit::TestCase
|
|
187
209
|
|
188
210
|
status_file = HOME + '/work/darcsapp/status.log'
|
189
211
|
assert File.exists?(status_file)
|
190
|
-
|
212
|
+
assert build_successful?(status_file)
|
191
213
|
assert 1, Dir[HOME + "/work/darcsapp/logs/*.log"].size
|
192
214
|
|
193
215
|
#There were no changes - no reaction should be
|
@@ -244,4 +266,22 @@ class FunctionalTest < Test::Unit::TestCase
|
|
244
266
|
|
245
267
|
assert_equal 2, Marshmallow.counter
|
246
268
|
end
|
269
|
+
|
270
|
+
def test_correct_migration_from_previous_status
|
271
|
+
status_fn = TEMP_DIR + '/test_status_file.log'
|
272
|
+
|
273
|
+
status = Cerberus::Status.new(status_fn)
|
274
|
+
assert_equal nil, status.previous_build_successful
|
275
|
+
assert_equal nil, status.current_build_successful
|
276
|
+
|
277
|
+
IO.write(status_fn, 'failed')
|
278
|
+
status = Cerberus::Status.new(status_fn)
|
279
|
+
assert_equal nil, status.current_build_successful
|
280
|
+
assert_equal false, status.previous_build_successful
|
281
|
+
|
282
|
+
status.keep(true, 1232, 0)
|
283
|
+
assert_equal true, status.current_build_successful
|
284
|
+
assert_equal false, status.previous_build_successful
|
285
|
+
assert_equal :revival, status.current_state
|
286
|
+
end
|
247
287
|
end
|
data/test/integration_test.rb
CHANGED
@@ -48,7 +48,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
48
48
|
|
49
49
|
run_cerb("build svn_repo")
|
50
50
|
assert File.exists?(HOME + '/work/svn_repo/status.log')
|
51
|
-
|
51
|
+
assert build_successful?(HOME + '/work/svn_repo/status.log')
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_add_darcs_scm
|
data/test/irc_publisher_test.rb
CHANGED
@@ -10,8 +10,9 @@ class IRCPublisherTest < Test::Unit::TestCase
|
|
10
10
|
options = Cerberus::Config.new(nil, :publisher => {:irc => {:channel => 'hello'}}, :application_name => 'IrcApp')
|
11
11
|
build = DummyManager.new('last message', 'this is output', 1232, 'anatol')
|
12
12
|
|
13
|
-
Cerberus::Publisher::IRC.publish(
|
13
|
+
Cerberus::Publisher::IRC.publish(build_status(true), build, options)
|
14
14
|
|
15
15
|
assert IRCConnection.connected
|
16
|
+
# assert_equal 1, IRCConnection.messages.size
|
16
17
|
end
|
17
18
|
end
|
@@ -1,20 +1,21 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
3
|
require 'cerberus/publisher/jabber'
|
4
|
-
require 'mock/
|
4
|
+
require 'mock/xmpp4r'
|
5
5
|
require 'mock/manager'
|
6
6
|
|
7
7
|
class JabberPublisherTest < Test::Unit::TestCase
|
8
8
|
def test_publisher
|
9
|
-
options = Cerberus::Config.new(nil, :publisher => {:jabber => {:recipients => ' jit1@google.com, another@google.com '}}, :application_name => 'MegaApp')
|
9
|
+
options = Cerberus::Config.new(nil, :publisher => {:jabber => {:jid=>'from.cerberus@gmail.com', :recipients => ' jit1@google.com, another@google.com '}}, :application_name => 'MegaApp')
|
10
10
|
build = DummyManager.new('last message', 'this is output', 1232, 'anatol')
|
11
11
|
|
12
|
-
Cerberus::Publisher::Jabber.publish(
|
12
|
+
Cerberus::Publisher::Jabber.publish(build_status(false), build, options)
|
13
13
|
|
14
|
-
messages = Jabber::
|
15
|
-
|
16
|
-
assert_equal 'google.com', messages[0].to.
|
14
|
+
messages = Jabber::Client.messages
|
15
|
+
assert messages.size > 2
|
16
|
+
assert_equal 'google.com', messages[0].to.domain
|
17
17
|
assert_equal 'jit1', messages[0].to.node
|
18
|
-
assert_equal '[MegaApp]
|
18
|
+
assert_equal '[MegaApp] Build still broken (#1232)', messages[0].subject
|
19
|
+
assert !messages[0].body.nil?
|
19
20
|
end
|
20
21
|
end
|
data/test/mail_publisher_test.rb
CHANGED
@@ -14,7 +14,7 @@ class MailPublisherTest < Test::Unit::TestCase
|
|
14
14
|
:application_name => 'MyApp')
|
15
15
|
build = DummyManager.new('last message', 'this is output', 1232, 'anatol')
|
16
16
|
|
17
|
-
Cerberus::Publisher::Mail.publish(
|
17
|
+
Cerberus::Publisher::Mail.publish(build_status(true), build, options)
|
18
18
|
|
19
19
|
mails = ActionMailer::Base.deliveries
|
20
20
|
assert_equal 1, mails.size
|
data/test/mock/irc.rb
CHANGED
data/test/mock/xmpp4r.rb
ADDED
data/test/rss_publisher_test.rb
CHANGED
@@ -10,11 +10,11 @@ class RSSPublisherTest < Test::Unit::TestCase
|
|
10
10
|
options = Cerberus::Config.new(nil, :publisher => {:rss => {:file => rss_file.path}}, :application_name => 'RSS<App')
|
11
11
|
build = DummyManager.new('last message', 'this is output', 1235, 'anatol')
|
12
12
|
|
13
|
-
Cerberus::Publisher::RSS.publish(
|
13
|
+
Cerberus::Publisher::RSS.publish(build_status(false), build, options)
|
14
14
|
|
15
15
|
xml = REXML::Document.new(IO.read(rss_file.path))
|
16
16
|
|
17
|
-
assert_equal '[RSS<App]
|
17
|
+
assert_equal '[RSS<App] Build still broken (#1235)', xml.elements["rss/channel/item/title/"].get_text.value
|
18
18
|
assert_match %r{<pre>last message\nthis is output\n--\nCerberus 0.\d.\d, http://cerberus.rubyforge.org/</pre>},
|
19
19
|
xml.elements["rss/channel/item/description/"].get_text.value
|
20
20
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
2
3
|
|
3
4
|
require 'test/unit'
|
4
5
|
require 'fileutils'
|
@@ -57,9 +58,10 @@ class A#{rand(10000)}Test < Test::Unit::TestCase
|
|
57
58
|
end"
|
58
59
|
}
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
if block_given?
|
62
|
+
yield
|
63
|
+
FileUtils.rm test_case_name
|
64
|
+
end
|
63
65
|
end
|
64
66
|
|
65
67
|
def add_application(app_name, url, options = {})
|
@@ -71,6 +73,8 @@ end"
|
|
71
73
|
opt.deep_merge!(options)
|
72
74
|
|
73
75
|
dump_yml(HOME + "/config/#{app_name}.yml", opt)
|
76
|
+
|
77
|
+
FileUtils.rm_rf HOME + "/work/#{app_name}"
|
74
78
|
end
|
75
79
|
|
76
80
|
def add_config(options)
|
@@ -88,6 +92,16 @@ end"
|
|
88
92
|
# Create the new method
|
89
93
|
klass.send(:define_method, method_name, block)
|
90
94
|
end
|
95
|
+
|
96
|
+
def build_successful?(file_name)
|
97
|
+
data = YAML.load(IO.read(file_name))
|
98
|
+
assert_kind_of Hash, data
|
99
|
+
data['successful']
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_status(successful)
|
103
|
+
Cerberus::Status.new('state' => successful)
|
104
|
+
end
|
91
105
|
end
|
92
106
|
|
93
107
|
require 'cerberus/config'
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.0.
|
2
|
+
rubygems_version: 0.9.0.8
|
3
3
|
specification_version: 1
|
4
4
|
name: cerberus
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.3.
|
7
|
-
date:
|
6
|
+
version: 0.3.3
|
7
|
+
date: 2007-01-25 00:00:00 +03:00
|
8
8
|
summary: Cerberus is a Continuous Integration tool that could be easily run from Cron.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- lib/cerberus
|
34
34
|
- lib/cerberus/builder
|
35
35
|
- lib/cerberus/cli.rb
|
36
|
+
- lib/cerberus/component_lazy_loader.rb
|
36
37
|
- lib/cerberus/config.example.yml
|
37
38
|
- lib/cerberus/config.rb
|
38
39
|
- lib/cerberus/config_migration.rb
|
@@ -77,9 +78,9 @@ files:
|
|
77
78
|
- test/data/darcs.zip
|
78
79
|
- test/data/subversion.dump
|
79
80
|
- test/mock/irc.rb
|
80
|
-
- test/mock/jabber4r.rb
|
81
81
|
- test/mock/manager.rb
|
82
82
|
- test/mock/marshmallow.rb
|
83
|
+
- test/mock/xmpp4r.rb
|
83
84
|
- LICENSE
|
84
85
|
- README
|
85
86
|
- CHANGES
|
@@ -117,13 +118,13 @@ dependencies:
|
|
117
118
|
version: 0.7.1
|
118
119
|
version:
|
119
120
|
- !ruby/object:Gem::Dependency
|
120
|
-
name:
|
121
|
+
name: xmpp4r
|
121
122
|
version_requirement:
|
122
123
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
123
124
|
requirements:
|
124
125
|
- - ">="
|
125
126
|
- !ruby/object:Gem::Version
|
126
|
-
version: 0.
|
127
|
+
version: "0.3"
|
127
128
|
version:
|
128
129
|
- !ruby/object:Gem::Dependency
|
129
130
|
name: Ruby-IRC
|
@@ -132,5 +133,5 @@ dependencies:
|
|
132
133
|
requirements:
|
133
134
|
- - ">="
|
134
135
|
- !ruby/object:Gem::Version
|
135
|
-
version: 1.0.
|
136
|
+
version: 1.0.7
|
136
137
|
version:
|
data/test/mock/jabber4r.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
class Jabber::Session
|
2
|
-
def self.bind(jid, password)
|
3
|
-
Jabber::Session.new
|
4
|
-
end
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class Jabber::Protocol::Message
|
11
|
-
@@messages = []
|
12
|
-
|
13
|
-
def self.messages
|
14
|
-
@@messages
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.clear
|
18
|
-
@@messages = []
|
19
|
-
end
|
20
|
-
|
21
|
-
def send
|
22
|
-
@@messages << self
|
23
|
-
end
|
24
|
-
end
|