cerberus 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|