cerberus 0.3.5 → 0.3.6
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/CHANGES +159 -129
- data/LICENSE +21 -21
- data/README +75 -75
- data/Rakefile +161 -159
- data/bin/cerberus +2 -2
- data/lib/cerberus/builder/maven2.rb +38 -38
- data/lib/cerberus/builder/rake.rb +7 -7
- data/lib/cerberus/builder/rant.rb +7 -7
- data/lib/cerberus/builder/rspec.rb +13 -0
- data/lib/cerberus/builder/ruby_base.rb +48 -47
- data/lib/cerberus/cli.rb +73 -70
- data/lib/cerberus/component_lazy_loader.rb +2 -0
- data/lib/cerberus/config.example.yml +28 -28
- data/lib/cerberus/config.rb +47 -46
- data/lib/cerberus/constants.rb +8 -8
- data/lib/cerberus/latch.rb +26 -26
- data/lib/cerberus/manager.rb +296 -267
- data/lib/cerberus/publisher/base.rb +47 -47
- data/lib/cerberus/publisher/gmailer.rb +17 -0
- data/lib/cerberus/publisher/irc.rb +27 -27
- data/lib/cerberus/publisher/jabber.rb +25 -25
- data/lib/cerberus/publisher/mail.rb +36 -36
- data/lib/cerberus/publisher/netsmtp_tls_fix.rb +66 -66
- data/lib/cerberus/publisher/rss.rb +27 -28
- data/lib/cerberus/scm/cvs.rb +48 -48
- data/lib/cerberus/scm/darcs.rb +70 -70
- data/lib/cerberus/scm/svn.rb +83 -83
- data/lib/cerberus/utils.rb +156 -156
- data/test/config_test.rb +45 -45
- data/test/functional_test.rb +288 -287
- data/test/integration_test.rb +104 -104
- data/test/irc_publisher_test.rb +18 -18
- data/test/jabber_publisher_test.rb +21 -21
- data/test/mail_publisher_test.rb +25 -25
- data/test/maven2_builer_test.rb +81 -81
- data/test/mock/irc.rb +20 -20
- data/test/mock/manager.rb +10 -10
- data/test/mock/xmpp4r.rb +19 -19
- data/test/rss_publisher_test.rb +21 -21
- data/test/test_helper.rb +105 -105
- metadata +58 -40
- data/lib/cerberus/helper/xchar.rb +0 -61
@@ -1,47 +1,47 @@
|
|
1
|
-
require 'cerberus/constants'
|
2
|
-
|
3
|
-
module Cerberus
|
4
|
-
module Publisher
|
5
|
-
class Base
|
6
|
-
def self.formatted_message(state, manager, options)
|
7
|
-
subject =
|
8
|
-
case state.current_state
|
9
|
-
when :setup
|
10
|
-
"Cerberus set up for project (##{manager.scm.current_revision})"
|
11
|
-
when :broken
|
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
|
26
|
-
"Build broken by #{manager.scm.last_author} (##{manager.scm.current_revision})"
|
27
|
-
when :revival
|
28
|
-
"Build fixed by #{manager.scm.last_author} (##{manager.scm.current_revision})"
|
29
|
-
when :
|
30
|
-
"Build
|
31
|
-
else
|
32
|
-
raise "Unknown build state '#{state.current_state.to_s}'"
|
33
|
-
end
|
34
|
-
|
35
|
-
subject = "[#{options[:application_name]}] #{subject}"
|
36
|
-
generated_by = "--\
|
37
|
-
body = [ manager.scm.last_commit_message ]
|
38
|
-
if options[:changeset_url]
|
39
|
-
body << options[:changeset_url] + manager.scm.current_revision.to_s + "\n"
|
40
|
-
end
|
41
|
-
body += [ manager.builder.output, generated_by ]
|
42
|
-
|
43
|
-
return subject, body.join("\n")
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
1
|
+
require 'cerberus/constants'
|
2
|
+
|
3
|
+
module Cerberus
|
4
|
+
module Publisher
|
5
|
+
class Base
|
6
|
+
def self.formatted_message(state, manager, options)
|
7
|
+
subject =
|
8
|
+
case state.current_state
|
9
|
+
when :setup
|
10
|
+
"Cerberus set up for project (##{manager.scm.current_revision})"
|
11
|
+
when :broken
|
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
|
26
|
+
"Build broken by #{manager.scm.last_author} (##{manager.scm.current_revision})"
|
27
|
+
when :revival
|
28
|
+
"Build fixed by #{manager.scm.last_author} (##{manager.scm.current_revision})"
|
29
|
+
when :successful
|
30
|
+
"Build successful (##{manager.scm.current_revision})"
|
31
|
+
else
|
32
|
+
raise "Unknown build state '#{state.current_state.to_s}'"
|
33
|
+
end
|
34
|
+
|
35
|
+
subject = "[#{options[:application_name]}] #{subject}"
|
36
|
+
generated_by = "--\nThis email generated by Cerberus tool ver. #{Cerberus::VERSION}, http://cerberus.rubyforge.org/"
|
37
|
+
body = [ manager.scm.last_commit_message ]
|
38
|
+
if options[:changeset_url]
|
39
|
+
body << options[:changeset_url] + manager.scm.current_revision.to_s + "\n"
|
40
|
+
end
|
41
|
+
body += [ manager.builder.output, generated_by ]
|
42
|
+
|
43
|
+
return subject, body.join("\n")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'cerberus/publisher/base'
|
2
|
+
|
3
|
+
class Cerberus::Publisher::Gmailer < Cerberus::Publisher::Base
|
4
|
+
def self.publish(state, manager, options)
|
5
|
+
require 'gmailer'
|
6
|
+
|
7
|
+
subject, body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
8
|
+
|
9
|
+
gopts = options[:publisher, :gmailer]
|
10
|
+
recipients = options[:publisher, :gmailer, :recipients]
|
11
|
+
GMailer.connect(gopts) do |g|
|
12
|
+
success = g.send(:to => recipients, :subject => subject, :body => body)
|
13
|
+
|
14
|
+
raise 'Unable to send mail using Gmailer' unless success
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'IRC'
|
3
|
-
require 'cerberus/publisher/base'
|
4
|
-
|
5
|
-
class Cerberus::Publisher::IRC < Cerberus::Publisher::Base
|
6
|
-
def self.publish(state, manager, options)
|
7
|
-
irc_options = options[:publisher, :irc]
|
8
|
-
raise "There is no channel provided for IRC publisher" unless irc_options[:channel]
|
9
|
-
subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
10
|
-
message = subject + "\n" + '*' * subject.length + "\n" + body
|
11
|
-
|
12
|
-
|
13
|
-
channel = '#' + irc_options[:channel]
|
14
|
-
bot = IRC.new(irc_options[:nick] || 'cerberus', irc_options[:server], irc_options[:port] || 6667)
|
15
|
-
|
16
|
-
silence_stream(STDOUT) {
|
17
|
-
IRCEvent.add_callback('endofmotd') { |event|
|
18
|
-
bot.add_channel(channel)
|
19
|
-
message.split("\n").each{|line|
|
20
|
-
bot.send_message(channel, line)
|
21
|
-
}
|
22
|
-
bot.send_quit
|
23
|
-
}
|
24
|
-
bot.connect
|
25
|
-
}
|
26
|
-
end
|
27
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'IRC'
|
3
|
+
require 'cerberus/publisher/base'
|
4
|
+
|
5
|
+
class Cerberus::Publisher::IRC < Cerberus::Publisher::Base
|
6
|
+
def self.publish(state, manager, options)
|
7
|
+
irc_options = options[:publisher, :irc]
|
8
|
+
raise "There is no channel provided for IRC publisher" unless irc_options[:channel]
|
9
|
+
subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
10
|
+
message = subject + "\n" + '*' * subject.length + "\n" + body
|
11
|
+
|
12
|
+
|
13
|
+
channel = '#' + irc_options[:channel]
|
14
|
+
bot = IRC.new(irc_options[:nick] || 'cerberus', irc_options[:server], irc_options[:port] || 6667)
|
15
|
+
|
16
|
+
silence_stream(STDOUT) {
|
17
|
+
IRCEvent.add_callback('endofmotd') { |event|
|
18
|
+
bot.add_channel(channel)
|
19
|
+
message.split("\n").each{|line|
|
20
|
+
bot.send_message(channel, line)
|
21
|
+
}
|
22
|
+
bot.send_quit
|
23
|
+
}
|
24
|
+
bot.connect
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
@@ -1,25 +1,25 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'xmpp4r'
|
3
|
-
require 'cerberus/publisher/base'
|
4
|
-
|
5
|
-
class Cerberus::Publisher::Jabber < Cerberus::Publisher::Base
|
6
|
-
def self.publish(state, manager, options)
|
7
|
-
begin
|
8
|
-
jabber_options = options[:publisher, :jabber]
|
9
|
-
raise "There is no recipients provided for Jabber publisher" unless jabber_options[:recipients]
|
10
|
-
|
11
|
-
subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
12
|
-
|
13
|
-
client = Jabber::Client::new(Jabber::JID.new(jabber_options[:jid]))
|
14
|
-
client.connect
|
15
|
-
client.auth(jabber_options[:password])
|
16
|
-
|
17
|
-
jabber_options[:recipients].split(',').each do |address|
|
18
|
-
message = Jabber::Message::new(address.strip, body).set_subject(subject)
|
19
|
-
client.send(message)
|
20
|
-
end
|
21
|
-
ensure
|
22
|
-
client.close if client
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'xmpp4r'
|
3
|
+
require 'cerberus/publisher/base'
|
4
|
+
|
5
|
+
class Cerberus::Publisher::Jabber < Cerberus::Publisher::Base
|
6
|
+
def self.publish(state, manager, options)
|
7
|
+
begin
|
8
|
+
jabber_options = options[:publisher, :jabber]
|
9
|
+
raise "There is no recipients provided for Jabber publisher" unless jabber_options[:recipients]
|
10
|
+
|
11
|
+
subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
12
|
+
|
13
|
+
client = Jabber::Client::new(Jabber::JID.new(jabber_options[:jid]))
|
14
|
+
client.connect
|
15
|
+
client.auth(jabber_options[:password])
|
16
|
+
|
17
|
+
jabber_options[:recipients].split(',').each do |address|
|
18
|
+
message = Jabber::Message::new(address.strip, body).set_subject(subject)
|
19
|
+
client.send(message)
|
20
|
+
end
|
21
|
+
ensure
|
22
|
+
client.close if client
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,37 +1,37 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'action_mailer'
|
3
|
-
require 'cerberus/publisher/base'
|
4
|
-
|
5
|
-
if RUBY_VERSION > '1.8.2'
|
6
|
-
#This hack works only on 1.8.4
|
7
|
-
require 'cerberus/publisher/netsmtp_tls_fix'
|
8
|
-
end
|
9
|
-
|
10
|
-
class Cerberus::Publisher::Mail < Cerberus::Publisher::Base
|
11
|
-
def self.publish(state, manager, options)
|
12
|
-
mail_opts = options[:publisher, :mail].dup
|
13
|
-
raise "There is no recipients provided for mail publisher" unless mail_opts[:recipients]
|
14
|
-
|
15
|
-
configure(mail_opts)
|
16
|
-
ActionMailerPublisher.deliver_message(state, manager, options)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
def self.configure(config)
|
21
|
-
[:authentication, :delivery_method].each do |k|
|
22
|
-
config[k] = config[k].to_sym if config[k]
|
23
|
-
end
|
24
|
-
|
25
|
-
ActionMailer::Base.delivery_method = config[:delivery_method] if config[:delivery_method]
|
26
|
-
ActionMailer::Base.smtp_settings = config
|
27
|
-
end
|
28
|
-
|
29
|
-
class ActionMailerPublisher < ActionMailer::Base
|
30
|
-
def message(state, manager, options)
|
31
|
-
@subject, @body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
32
|
-
@recipients, @sent_on = options[:publisher, :mail, :recipients], Time.now
|
33
|
-
@from = options[:publisher, :mail, :sender] || "'Cerberus' <cerberus@example.com>"
|
34
|
-
raise "Please specify recipient addresses for application '#{options[:application_name]}'" unless @recipients
|
35
|
-
end
|
36
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'action_mailer'
|
3
|
+
require 'cerberus/publisher/base'
|
4
|
+
|
5
|
+
if RUBY_VERSION > '1.8.2'
|
6
|
+
#This hack works only on 1.8.4
|
7
|
+
require 'cerberus/publisher/netsmtp_tls_fix'
|
8
|
+
end
|
9
|
+
|
10
|
+
class Cerberus::Publisher::Mail < Cerberus::Publisher::Base
|
11
|
+
def self.publish(state, manager, options)
|
12
|
+
mail_opts = options[:publisher, :mail].dup
|
13
|
+
raise "There is no recipients provided for mail publisher" unless mail_opts[:recipients]
|
14
|
+
|
15
|
+
configure(mail_opts)
|
16
|
+
ActionMailerPublisher.deliver_message(state, manager, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def self.configure(config)
|
21
|
+
[:authentication, :delivery_method].each do |k|
|
22
|
+
config[k] = config[k].to_sym if config[k]
|
23
|
+
end
|
24
|
+
|
25
|
+
ActionMailer::Base.delivery_method = config[:delivery_method] if config[:delivery_method]
|
26
|
+
ActionMailer::Base.smtp_settings = config
|
27
|
+
end
|
28
|
+
|
29
|
+
class ActionMailerPublisher < ActionMailer::Base
|
30
|
+
def message(state, manager, options)
|
31
|
+
@subject, @body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
32
|
+
@recipients, @sent_on = options[:publisher, :mail, :recipients], Time.now
|
33
|
+
@from = options[:publisher, :mail, :sender] || "'Cerberus' <cerberus@example.com>"
|
34
|
+
raise "Please specify recipient addresses for application '#{options[:application_name]}'" unless @recipients
|
35
|
+
end
|
36
|
+
end
|
37
37
|
end
|
@@ -1,67 +1,67 @@
|
|
1
|
-
require "openssl"
|
2
|
-
require "net/smtp"
|
3
|
-
|
4
|
-
Net::SMTP.class_eval do
|
5
|
-
private
|
6
|
-
def do_start(helodomain, user, secret, authtype)
|
7
|
-
raise IOError, 'SMTP session already started' if @started
|
8
|
-
check_auth_args user, secret, authtype if user or secret
|
9
|
-
|
10
|
-
sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
|
11
|
-
@socket = Net::InternetMessageIO.new(sock)
|
12
|
-
@socket.read_timeout = 60 #@read_timeout
|
13
|
-
#@socket.debug_output = STDERR #@debug_output
|
14
|
-
|
15
|
-
check_response(critical { recv_response() })
|
16
|
-
do_helo(helodomain)
|
17
|
-
|
18
|
-
if starttls
|
19
|
-
raise 'openssl library not installed' unless defined?(OpenSSL)
|
20
|
-
ssl = OpenSSL::SSL::SSLSocket.new(sock)
|
21
|
-
ssl.sync_close = true
|
22
|
-
ssl.connect
|
23
|
-
@socket = Net::InternetMessageIO.new(ssl)
|
24
|
-
@socket.read_timeout = 60 #@read_timeout
|
25
|
-
#@socket.debug_output = STDERR #@debug_output
|
26
|
-
do_helo(helodomain)
|
27
|
-
end
|
28
|
-
|
29
|
-
authenticate user, secret, authtype if user
|
30
|
-
@started = true
|
31
|
-
ensure
|
32
|
-
unless @started
|
33
|
-
# authentication failed, cancel connection.
|
34
|
-
@socket.close if not @started and @socket and not @socket.closed?
|
35
|
-
@socket = nil
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def do_helo(helodomain)
|
40
|
-
begin
|
41
|
-
if @esmtp
|
42
|
-
ehlo helodomain
|
43
|
-
else
|
44
|
-
helo helodomain
|
45
|
-
end
|
46
|
-
rescue Net::ProtocolError
|
47
|
-
if @esmtp
|
48
|
-
@esmtp = false
|
49
|
-
@error_occured = false
|
50
|
-
retry
|
51
|
-
end
|
52
|
-
raise
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def starttls
|
57
|
-
getok('STARTTLS') rescue return false
|
58
|
-
return true
|
59
|
-
end
|
60
|
-
|
61
|
-
def quit
|
62
|
-
begin
|
63
|
-
getok('QUIT')
|
64
|
-
rescue EOFError
|
65
|
-
end
|
66
|
-
end
|
1
|
+
require "openssl"
|
2
|
+
require "net/smtp"
|
3
|
+
|
4
|
+
Net::SMTP.class_eval do
|
5
|
+
private
|
6
|
+
def do_start(helodomain, user, secret, authtype)
|
7
|
+
raise IOError, 'SMTP session already started' if @started
|
8
|
+
check_auth_args user, secret, authtype if user or secret
|
9
|
+
|
10
|
+
sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
|
11
|
+
@socket = Net::InternetMessageIO.new(sock)
|
12
|
+
@socket.read_timeout = 60 #@read_timeout
|
13
|
+
#@socket.debug_output = STDERR #@debug_output
|
14
|
+
|
15
|
+
check_response(critical { recv_response() })
|
16
|
+
do_helo(helodomain)
|
17
|
+
|
18
|
+
if starttls
|
19
|
+
raise 'openssl library not installed' unless defined?(OpenSSL)
|
20
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock)
|
21
|
+
ssl.sync_close = true
|
22
|
+
ssl.connect
|
23
|
+
@socket = Net::InternetMessageIO.new(ssl)
|
24
|
+
@socket.read_timeout = 60 #@read_timeout
|
25
|
+
#@socket.debug_output = STDERR #@debug_output
|
26
|
+
do_helo(helodomain)
|
27
|
+
end
|
28
|
+
|
29
|
+
authenticate user, secret, authtype if user
|
30
|
+
@started = true
|
31
|
+
ensure
|
32
|
+
unless @started
|
33
|
+
# authentication failed, cancel connection.
|
34
|
+
@socket.close if not @started and @socket and not @socket.closed?
|
35
|
+
@socket = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def do_helo(helodomain)
|
40
|
+
begin
|
41
|
+
if @esmtp
|
42
|
+
ehlo helodomain
|
43
|
+
else
|
44
|
+
helo helodomain
|
45
|
+
end
|
46
|
+
rescue Net::ProtocolError
|
47
|
+
if @esmtp
|
48
|
+
@esmtp = false
|
49
|
+
@error_occured = false
|
50
|
+
retry
|
51
|
+
end
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def starttls
|
57
|
+
getok('STARTTLS') rescue return false
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
|
61
|
+
def quit
|
62
|
+
begin
|
63
|
+
getok('QUIT')
|
64
|
+
rescue EOFError
|
65
|
+
end
|
66
|
+
end
|
67
67
|
end
|
@@ -1,28 +1,27 @@
|
|
1
|
-
require 'cerberus/publisher/base'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
<
|
13
|
-
|
14
|
-
<
|
15
|
-
<
|
16
|
-
<
|
17
|
-
|
18
|
-
<
|
19
|
-
<
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
1
|
+
require 'cerberus/publisher/base'
|
2
|
+
|
3
|
+
class Cerberus::Publisher::RSS < Cerberus::Publisher::Base
|
4
|
+
def self.publish(state, manager, options)
|
5
|
+
config = options[:publisher, :rss]
|
6
|
+
subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
7
|
+
|
8
|
+
pub_date = Time.now.iso8601
|
9
|
+
description = "<pre>#{body}</pre>".to_xs
|
10
|
+
result = <<-END
|
11
|
+
<rss version="2.0">
|
12
|
+
<channel>
|
13
|
+
<title>Cerberus build feed for #{options[:application_name].to_xs}</title>
|
14
|
+
<pubDate>#{pub_date}</pubDate>
|
15
|
+
<generator>http://rubyforge.org/projects/cerberus</generator>
|
16
|
+
<item>
|
17
|
+
<title>#{subject.to_xs}</title>
|
18
|
+
<pubDate>#{pub_date}</pubDate>
|
19
|
+
<description>#{description}</description>
|
20
|
+
</item>
|
21
|
+
</channel>
|
22
|
+
</rss>
|
23
|
+
END
|
24
|
+
|
25
|
+
IO.write(config[:file], result)
|
26
|
+
end
|
27
|
+
end
|