cerberus 0.2.2 → 0.2.3
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 +11 -0
- data/Rakefile +5 -5
- data/lib/cerberus/builder/maven2.rb +13 -9
- data/lib/cerberus/cli.rb +6 -2
- data/lib/cerberus/config.example.yml +9 -8
- data/lib/cerberus/config.rb +8 -2
- data/lib/cerberus/constants.rb +4 -0
- data/lib/cerberus/latch.rb +15 -10
- data/lib/cerberus/manager.rb +60 -31
- data/lib/cerberus/publisher/base.rb +1 -1
- data/lib/cerberus/publisher/irc.rb +13 -10
- data/lib/cerberus/publisher/mail.rb +2 -1
- data/lib/cerberus/publisher/netsmtp_tls_fix.rb +65 -0
- data/lib/cerberus/scm/cvs.rb +46 -0
- data/lib/cerberus/scm/darcs.rb +46 -0
- data/lib/cerberus/scm/svn.rb +14 -4
- data/lib/cerberus/utils.rb +2 -2
- data/lib/cerberus/version.rb +1 -1
- data/test/config_test.rb +11 -3
- data/test/functional_test.rb +14 -3
- data/test/maven2_builer_test.rb +26 -11
- data/test/test_helper.rb +1 -1
- metadata +4 -5
- data/doc/FAQ +0 -33
- data/doc/OPTIONS +0 -47
data/CHANGES
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
= Cerberus Changelog
|
2
2
|
|
3
|
+
== Version 0.2.3
|
4
|
+
Features release
|
5
|
+
|
6
|
+
* Added Lock files that prevent from mutiply build of the same project by several different processes
|
7
|
+
* Added multythread build for 'buildall' command. Now if one of threads froses (for example because of SVN repo is broken) then other threads would continue execution.
|
8
|
+
* Added possibility to send to gmail host using GMailer library
|
9
|
+
* Added --force oprion that would be helpful if you want to rebuild project even if there are no changes in VSC.
|
10
|
+
Use 'cerberus build --force my_project'
|
11
|
+
* Added site for Cerberus project. http://cerberus.rubyforge.org/
|
12
|
+
* From now all builds logs their build data. It would be switched off by :log/:enable => false in configuration file
|
13
|
+
|
3
14
|
== Version 0.2.2
|
4
15
|
Minor fix release
|
5
16
|
|
data/Rakefile
CHANGED
@@ -3,7 +3,6 @@ require 'rake'
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'rake/packagetask'
|
5
5
|
require 'rake/gempackagetask'
|
6
|
-
require 'rake/contrib/rubyforgepublisher'
|
7
6
|
|
8
7
|
require "./lib/cerberus/version"
|
9
8
|
|
@@ -100,10 +99,6 @@ end
|
|
100
99
|
|
101
100
|
task :reinstall => [:uninstall, :install]
|
102
101
|
|
103
|
-
task :site_webgen do
|
104
|
-
sh %{pushd doc/site; webgen; scp -r output/* #{RUBYFORGE_USER}@rubyforge.org:/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/; popd }
|
105
|
-
end
|
106
|
-
|
107
102
|
begin
|
108
103
|
require 'rcov/rcovtask'
|
109
104
|
Rcov::RcovTask.new do |t|
|
@@ -149,3 +144,8 @@ task :publish_news do
|
|
149
144
|
publisher.details = IO.read(File.dirname(__FILE__) + '/README')
|
150
145
|
end
|
151
146
|
end
|
147
|
+
|
148
|
+
task :publish_site do
|
149
|
+
system('cd doc/site && webgen')
|
150
|
+
sh %{scp -r -q doc/site/output/* #{RUBYFORGE_USER}@rubyforge.org:/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/}
|
151
|
+
end
|
@@ -9,8 +9,8 @@ class Cerberus::Builder::Maven2
|
|
9
9
|
Dir.chdir @config[:application_root]
|
10
10
|
cmd = @config[:builder, :maven2, :cmd] || 'mvn'
|
11
11
|
task = @config[:builder, :maven2, :task] || 'test'
|
12
|
-
output = `#{@config[:bin_path]}#{cmd} #{task} 2>&1`
|
13
|
-
|
12
|
+
@output = `#{@config[:bin_path]}#{cmd} #{task} 2>&1`
|
13
|
+
add_error_information
|
14
14
|
successful?
|
15
15
|
end
|
16
16
|
|
@@ -18,14 +18,18 @@ class Cerberus::Builder::Maven2
|
|
18
18
|
$?.exitstatus == 0 and not @output.include?('[ERROR] BUILD FAILURE')
|
19
19
|
end
|
20
20
|
|
21
|
-
def add_error_information
|
22
|
-
|
23
|
-
|
21
|
+
def add_error_information
|
22
|
+
str = @output
|
23
|
+
@output = ''
|
24
|
+
while str =~ / <<< FAILURE!$/
|
25
|
+
s = $'
|
26
|
+
|
27
|
+
$` =~ /^(.|\n)*Running (.*)$/
|
24
28
|
failed_class = $2
|
25
|
-
output << $` << $&
|
26
|
-
output << "\n" << IO.readlines("#{@config[:application_root]}/target/surefire-reports/#{failed_class}.txt")[4..-1].join
|
27
|
-
str =
|
29
|
+
@output << $` << $& << ' <<< FAILURE!'
|
30
|
+
@output << "\n" << IO.readlines("#{@config[:application_root]}/target/surefire-reports/#{failed_class}.txt")[4..-1].join.lstrip #map{|str| ' ' + str}..gsub(' <<< FAILURE!','')
|
31
|
+
str = s
|
28
32
|
end
|
29
|
-
output << str
|
33
|
+
@output << str
|
30
34
|
end
|
31
35
|
end
|
data/lib/cerberus/cli.rb
CHANGED
@@ -39,9 +39,13 @@ module Cerberus
|
|
39
39
|
result = {}
|
40
40
|
args_copy = args.dup
|
41
41
|
args_copy.each do |arg|
|
42
|
-
|
42
|
+
case arg
|
43
|
+
when /^(\w+)=(.*)$/
|
43
44
|
result[$1.downcase.to_sym] = $2
|
44
45
|
args.delete(arg)
|
46
|
+
when '--force'
|
47
|
+
result[:force] = true
|
48
|
+
args.delete(arg)
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
@@ -50,7 +54,7 @@ module Cerberus
|
|
50
54
|
end
|
51
55
|
|
52
56
|
HELP = %{
|
53
|
-
Cerberus is a Continuous Integration tool
|
57
|
+
Cerberus is a simple Continuous Integration tool for Ruby projects that run from command-line interface.
|
54
58
|
|
55
59
|
Usage:
|
56
60
|
cerberus add <URL> --- add project from svn repository to list watched of applications
|
@@ -2,14 +2,12 @@
|
|
2
2
|
publisher:
|
3
3
|
active: mail jabber rss
|
4
4
|
mail:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
domain: mymail.com
|
9
|
-
user_name: cerberus
|
10
|
-
password: somepass
|
5
|
+
address: smtp.gmail.com
|
6
|
+
port: 587
|
7
|
+
domain: gmail.com
|
11
8
|
authentication: plain
|
12
|
-
|
9
|
+
user_name: someuser
|
10
|
+
password: somemail
|
13
11
|
jabber:
|
14
12
|
jid: cerberus@gtalk.google.com
|
15
13
|
port: 5222
|
@@ -20,4 +18,7 @@ publisher:
|
|
20
18
|
server: irc.freenode.net
|
21
19
|
channel: cerberus
|
22
20
|
rss:
|
23
|
-
file: /usr/www/rss.xml
|
21
|
+
file: /usr/www/rss.xml
|
22
|
+
builder:
|
23
|
+
rake:
|
24
|
+
task: migrate test
|
data/lib/cerberus/config.rb
CHANGED
@@ -24,8 +24,14 @@ module Cerberus
|
|
24
24
|
c
|
25
25
|
end
|
26
26
|
|
27
|
-
def merge!(hash)
|
28
|
-
|
27
|
+
def merge!(hash, overwrite = true)
|
28
|
+
if overwrite
|
29
|
+
@config.deep_merge!(hash)
|
30
|
+
else
|
31
|
+
d = HashWithIndifferentAccess.new(hash)
|
32
|
+
d.deep_merge!(@config)
|
33
|
+
@config = d
|
34
|
+
end
|
29
35
|
end
|
30
36
|
|
31
37
|
def inspect
|
data/lib/cerberus/constants.rb
CHANGED
data/lib/cerberus/latch.rb
CHANGED
@@ -1,21 +1,26 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
1
3
|
module Cerberus
|
2
|
-
|
4
|
+
class Latch
|
3
5
|
#Emulate File.flock
|
4
|
-
def self.lock(lock_file,
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def self.lock(lock_file, options = {})
|
7
|
+
if File.exists?(lock_file)
|
8
|
+
modif_time = File::Stat.new(lock_file).mtime
|
9
|
+
ttl = options[:lock_ttl]
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
if ttl and modif_time < ttl.ago
|
12
|
+
File.delete(lock_file)
|
13
|
+
else
|
14
|
+
return
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
begin
|
15
|
-
File.
|
19
|
+
FileUtils.mkpath(File.dirname(lock_file))
|
20
|
+
File.new(lock_file, 'w').close
|
16
21
|
yield
|
17
22
|
ensure
|
18
|
-
File.
|
23
|
+
File.delete(lock_file)
|
19
24
|
end
|
20
25
|
end
|
21
26
|
end
|
data/lib/cerberus/manager.rb
CHANGED
@@ -4,6 +4,7 @@ require 'fileutils'
|
|
4
4
|
require 'cerberus/utils'
|
5
5
|
require 'cerberus/constants'
|
6
6
|
require 'cerberus/config'
|
7
|
+
require 'cerberus/latch'
|
7
8
|
|
8
9
|
require 'cerberus/publisher/mail'
|
9
10
|
require 'cerberus/publisher/jabber'
|
@@ -75,6 +76,12 @@ module Cerberus
|
|
75
76
|
include Cerberus::Utils
|
76
77
|
attr_reader :builder, :success, :scm, :status
|
77
78
|
|
79
|
+
DEFAULT_CONFIG = {:scm => {:type => 'svn'},
|
80
|
+
:builder => {:type => 'rake'},
|
81
|
+
:publisher => {:active => 'mail'},
|
82
|
+
:log => {:enable => true}
|
83
|
+
}
|
84
|
+
|
78
85
|
def initialize(application_name, cli_options = {})
|
79
86
|
unless File.exists?("#{HOME}/config/#{application_name}.yml")
|
80
87
|
say "Project #{application_name} does not present in Cerberus"
|
@@ -84,52 +91,65 @@ module Cerberus
|
|
84
91
|
|
85
92
|
def_options = {:application_root => app_root + '/sources', :application_name => application_name} #pseudo options that stored in config. Could not be set in any config file not through CLI
|
86
93
|
@config = Config.new(application_name, cli_options.merge(def_options))
|
94
|
+
@config.merge!(DEFAULT_CONFIG, false)
|
87
95
|
|
88
96
|
@status = Status.new("#{app_root}/status.log")
|
89
97
|
|
90
|
-
scm_type = @config[:scm, :type]
|
98
|
+
scm_type = @config[:scm, :type]
|
91
99
|
@scm = SCM_TYPES[scm_type.to_sym].new(@config[:application_root], @config)
|
92
100
|
|
93
|
-
builder_type = @config[:builder, :type]
|
101
|
+
builder_type = @config[:builder, :type]
|
94
102
|
@builder = BUILDER_TYPES[builder_type.to_sym].new(@config)
|
95
103
|
end
|
96
104
|
|
97
105
|
def run
|
98
106
|
begin
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
if
|
105
|
-
@
|
106
|
-
|
107
|
-
|
108
|
-
:
|
109
|
-
|
110
|
-
:succesful
|
111
|
-
|
112
|
-
|
107
|
+
Latch.lock("#{HOME}/work/#{@config[:application_name]}/.lock", :lock_ttl => 2 * LOCK_WAIT) do
|
108
|
+
previous_status = @status.recall
|
109
|
+
@scm.update!
|
110
|
+
|
111
|
+
state =
|
112
|
+
if @scm.has_changes? or @config[:force] or not previous_status
|
113
|
+
if status = @builder.run
|
114
|
+
@status.keep(:succesful)
|
115
|
+
case previous_status
|
116
|
+
when :failed
|
117
|
+
:revival
|
118
|
+
when :succesful
|
119
|
+
:succesful
|
120
|
+
when false
|
121
|
+
:setup
|
122
|
+
end
|
123
|
+
else
|
124
|
+
@status.keep(:failed)
|
125
|
+
previous_status == :failed ? :broken : :failure
|
113
126
|
end
|
114
127
|
else
|
115
|
-
|
116
|
-
|
128
|
+
:unchanged
|
129
|
+
end
|
130
|
+
|
131
|
+
#Save logs to directory
|
132
|
+
if @config[:log, :enable] and state != :unchanged
|
133
|
+
log_dir = "#{HOME}/work/#{@config[:application_name]}/logs/"
|
134
|
+
FileUtils.mkpath(log_dir)
|
135
|
+
|
136
|
+
time = Time.now.strftime("%Y%m%d%H%M%S")
|
137
|
+
file_name = "#{log_dir}/#{time}-#{state.to_s}.log"
|
138
|
+
body = [ scm.last_commit_message, builder.output ].join("\n\n")
|
139
|
+
IO.write(file_name, body)
|
117
140
|
end
|
118
|
-
else
|
119
|
-
:unchanged
|
120
|
-
end
|
121
141
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
142
|
+
#send notifications
|
143
|
+
if [:failure, :broken, :revival, :setup].include?(state)
|
144
|
+
active_publishers = @config[:publisher, :active]
|
145
|
+
active_publishers.split(/\W+/).each do |pub|
|
146
|
+
raise "Publisher have no configuration: #{pub}" unless @config[:publisher, pub]
|
147
|
+
clazz = PUBLISHER_TYPES[pub.to_sym]
|
148
|
+
raise "There is no such publisher: #{pub}" unless clazz
|
129
149
|
clazz.publish(state, self, @config)
|
130
|
-
|
150
|
+
end
|
131
151
|
end
|
132
|
-
end
|
152
|
+
end #lock
|
133
153
|
rescue Exception => e
|
134
154
|
if ENV['CERBERUS_ENV'] == 'TEST'
|
135
155
|
raise e
|
@@ -151,12 +171,21 @@ module Cerberus
|
|
151
171
|
end
|
152
172
|
|
153
173
|
def run
|
174
|
+
threads = []
|
154
175
|
Dir["#{HOME}/config/*.yml"].each do |fn|
|
155
176
|
fn =~ %r{#{HOME}/config/(.*).yml}
|
156
177
|
application_name = $1
|
157
178
|
|
158
179
|
command = Cerberus::BuildCommand.new(application_name, @cli_options)
|
159
|
-
command.run
|
180
|
+
threads << Thread.new { command.run }
|
181
|
+
end
|
182
|
+
|
183
|
+
@already_waited = false
|
184
|
+
threads.each do |t|
|
185
|
+
if @already_waited or not t.join(LOCK_WAIT)
|
186
|
+
t.kill
|
187
|
+
@already_waited = true
|
188
|
+
end
|
160
189
|
end
|
161
190
|
end
|
162
191
|
end
|
@@ -19,7 +19,7 @@ module Cerberus
|
|
19
19
|
end
|
20
20
|
|
21
21
|
subject = "[#{options[:application_name]}] #{subject}"
|
22
|
-
generated_by = "--\nCerberus #{Cerberus::VERSION::STRING}, http://rubyforge.
|
22
|
+
generated_by = "--\nCerberus #{Cerberus::VERSION::STRING}, http://cerberus.rubyforge.com/"
|
23
23
|
body = [ manager.scm.last_commit_message, manager.builder.output, generated_by ].join("\n\n")
|
24
24
|
|
25
25
|
return subject, body
|
@@ -11,17 +11,20 @@ class Cerberus::Publisher::IRC < Cerberus::Publisher::Base
|
|
11
11
|
|
12
12
|
channel = '#' + irc_options[:channel]
|
13
13
|
bot = IRC.new(irc_options[:nick] || 'cerberus', irc_options[:server], irc_options[:port] || 6667)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
bot.
|
14
|
+
|
15
|
+
silence_stream(STDOUT) {
|
16
|
+
IRCEvent.add_callback('endofmotd') { |event|
|
17
|
+
bot.add_channel(channel)
|
18
|
+
message.split("\n").each{|line|
|
19
|
+
bot.send_message(channel, line)
|
20
|
+
}
|
21
|
+
bot.send_quit
|
18
22
|
}
|
19
|
-
|
23
|
+
begin
|
24
|
+
bot.connect #Why it always fails?
|
25
|
+
rescue Exception => e
|
26
|
+
puts e.message
|
27
|
+
end
|
20
28
|
}
|
21
|
-
begin
|
22
|
-
bot.connect #Why it always fails?
|
23
|
-
rescue Exception => e
|
24
|
-
puts e.message
|
25
|
-
end
|
26
29
|
end
|
27
30
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'action_mailer'
|
2
2
|
require 'cerberus/publisher/base'
|
3
|
+
require 'cerberus/publisher/netsmtp_tls_fix'
|
3
4
|
|
4
5
|
class Cerberus::Publisher::Mail < Cerberus::Publisher::Base
|
5
6
|
def self.publish(state, manager, options)
|
@@ -25,7 +26,7 @@ class Cerberus::Publisher::Mail < Cerberus::Publisher::Base
|
|
25
26
|
@subject, @body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
|
26
27
|
@recipients, @sent_on = options[:publisher, :mail, :recipients], Time.now
|
27
28
|
@from = options[:publisher, :mail, :sender] || "'Cerberus' <cerberus@example.com>"
|
28
|
-
|
29
|
+
raise "Please specify recipient addresses for application '#{options[:application_name]}'" unless @recipients
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -0,0 +1,65 @@
|
|
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
|
+
raise 'openssl library not installed' unless defined?(OpenSSL)
|
19
|
+
starttls
|
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
|
+
|
28
|
+
authenticate user, secret, authtype if user
|
29
|
+
@started = true
|
30
|
+
ensure
|
31
|
+
unless @started
|
32
|
+
# authentication failed, cancel connection.
|
33
|
+
@socket.close if not @started and @socket and not @socket.closed?
|
34
|
+
@socket = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def do_helo(helodomain)
|
39
|
+
begin
|
40
|
+
if @esmtp
|
41
|
+
ehlo helodomain
|
42
|
+
else
|
43
|
+
helo helodomain
|
44
|
+
end
|
45
|
+
rescue Net::ProtocolError
|
46
|
+
if @esmtp
|
47
|
+
@esmtp = false
|
48
|
+
@error_occured = false
|
49
|
+
retry
|
50
|
+
end
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def starttls
|
56
|
+
getok('STARTTLS')
|
57
|
+
end
|
58
|
+
|
59
|
+
def quit
|
60
|
+
begin
|
61
|
+
getok('QUIT')
|
62
|
+
rescue EOFError
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/cerberus/scm/cvs.rb
CHANGED
@@ -1,2 +1,48 @@
|
|
1
1
|
class Cerberus::SCM::CVS
|
2
|
+
def initialize(path, config = {})
|
3
|
+
raise "Path can't be nil" unless path
|
4
|
+
|
5
|
+
@path, @config = path.strip, config
|
6
|
+
@encoded_path = (@path.include?(' ') ? "\"#{@path}\"" : @path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def update!
|
10
|
+
if test(?d, @path + '/CVS')
|
11
|
+
@status = execute("update")
|
12
|
+
else
|
13
|
+
FileUtils.mkpath(@path) unless test(?d,@path)
|
14
|
+
@status = execute("checkout", nil, @config[:scm, :url])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_changes?
|
19
|
+
@status =~ /[A-Z]\s+[\w\/]+/
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_revision
|
23
|
+
info['Revision'].to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
def url
|
27
|
+
info['URL']
|
28
|
+
end
|
29
|
+
|
30
|
+
def last_commit_message
|
31
|
+
message = execute("log", "--limit 1 -v")
|
32
|
+
#strip first line that contains command line itself (svn log --limit ...)
|
33
|
+
if ((idx = message.index('-'*72)) != 0 )
|
34
|
+
message[idx..-1]
|
35
|
+
else
|
36
|
+
message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def last_author
|
41
|
+
info['Last Changed Author']
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def execute(command, parameters = nil, pre_parameters = nil)
|
46
|
+
`#{@config[:bin_path]}cvs #{command} #{pre_parameters} #{@encoded_path} #{parameters}`
|
47
|
+
end
|
2
48
|
end
|
data/lib/cerberus/scm/darcs.rb
CHANGED
@@ -1,2 +1,48 @@
|
|
1
1
|
class Cerberus::SCM::Darcs
|
2
|
+
def initialize(path, config = {})
|
3
|
+
raise "Path can't be nil" unless path
|
4
|
+
|
5
|
+
@path, @config = path.strip, config
|
6
|
+
@encoded_path = (@path.include?(' ') ? "\"#{@path}\"" : @path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def update!
|
10
|
+
if test(?d, @path + '/_darcs')
|
11
|
+
@status = execute("pull")
|
12
|
+
else
|
13
|
+
FileUtils.mkpath(@path) unless test(?d,@path)
|
14
|
+
@status = execute("get", nil, @config[:scm, :url])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_changes?
|
19
|
+
@status =~ /[A-Z]\s+[\w\/]+/
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_revision
|
23
|
+
info['Revision'].to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
def url
|
27
|
+
info['URL']
|
28
|
+
end
|
29
|
+
|
30
|
+
def last_commit_message
|
31
|
+
message = execute("log", "--limit 1 -v")
|
32
|
+
#strip first line that contains command line itself (svn log --limit ...)
|
33
|
+
if ((idx = message.index('-'*72)) != 0 )
|
34
|
+
message[idx..-1]
|
35
|
+
else
|
36
|
+
message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def last_author
|
41
|
+
info['Last Changed Author']
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def execute(command, parameters = nil, pre_parameters = nil)
|
46
|
+
`#{@config[:bin_path]}darcs #{command} #{pre_parameters} #{@encoded_path} #{parameters}`
|
47
|
+
end
|
2
48
|
end
|
data/lib/cerberus/scm/svn.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
+
require 'cerberus/utils'
|
2
|
+
|
1
3
|
class Cerberus::SCM::SVN
|
4
|
+
include Cerberus::Utils
|
5
|
+
|
2
6
|
def initialize(path, config = {})
|
3
7
|
raise "Path can't be nil" unless path
|
4
8
|
|
5
9
|
@path, @config = path.strip, config
|
6
10
|
@encoded_path = (@path.include?(' ') ? "\"#{@path}\"" : @path)
|
11
|
+
end
|
7
12
|
|
13
|
+
def update!
|
8
14
|
if test(?d, @path + '/.svn') #check first that it was not locked
|
9
15
|
execute("cleanup") if locked?
|
10
|
-
|
16
|
+
say "Could not unlock svn directory #{@encoded_path}. Please do it manually." if locked? #In case if we could not unlock from command line - ask user to do it
|
11
17
|
end
|
12
|
-
end
|
13
18
|
|
14
|
-
def update!
|
15
19
|
if test(?d, @path + '/.svn')
|
16
20
|
@status = execute("update")
|
17
21
|
else
|
@@ -52,7 +56,13 @@ class Cerberus::SCM::SVN
|
|
52
56
|
end
|
53
57
|
|
54
58
|
def info
|
55
|
-
|
59
|
+
output = execute("info")
|
60
|
+
@info ||= YAML.load(output)
|
61
|
+
|
62
|
+
unless @info === Hash or @info['Repository Root'] #.size > 8
|
63
|
+
say "Could not parse svn output. Seems source directory #{@encoded_path} is corrupted.\n#{output}"
|
64
|
+
end
|
65
|
+
@info
|
56
66
|
end
|
57
67
|
|
58
68
|
def execute(command, parameters = nil, pre_parameters = nil)
|
data/lib/cerberus/utils.rb
CHANGED
data/lib/cerberus/version.rb
CHANGED
data/test/config_test.rb
CHANGED
@@ -28,11 +28,19 @@ class ConfigTest < Test::Unit::TestCase
|
|
28
28
|
cfg = Cerberus::Config.new
|
29
29
|
cfg.merge!(:hello => {'msg' => {:a202 => 'bye'}})
|
30
30
|
cfg.merge!(:hello => {:msg => {:a203 => 'hello'}})
|
31
|
-
cfg.merge!(:hello => {:msg => {:
|
31
|
+
cfg.merge!(:hello => {:msg => {:a203 => 'another'}})
|
32
32
|
cfg.merge!(:hello => {:bread => {:a204 => 'bread'}})
|
33
33
|
|
34
34
|
assert_equal 'bye', cfg[:hello, :msg, :a202]
|
35
|
-
assert_equal '
|
35
|
+
assert_equal 'another', cfg[:hello, :msg, :a203]
|
36
36
|
assert_equal 'bread', cfg[:hello, :bread, :a204]
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
|
+
def test_deep_merge_not_overwrite
|
40
|
+
cfg = Cerberus::Config.new
|
41
|
+
cfg.merge!({:hello => {'msg' => {:a202 => 'bye'}}}, false)
|
42
|
+
cfg.merge!({:hello => {:msg => {:a202 => 'hello'}}}, false)
|
43
|
+
|
44
|
+
assert_equal 'bye', cfg[:hello, :msg, :a202]
|
45
|
+
end
|
46
|
+
end
|
data/test/functional_test.rb
CHANGED
@@ -49,27 +49,30 @@ class FunctionalTest < Test::Unit::TestCase
|
|
49
49
|
build = Cerberus::BuildCommand.new('myapp')
|
50
50
|
build.run
|
51
51
|
assert_equal 1, ActionMailer::Base.deliveries.size #first email that project was setup
|
52
|
-
|
52
|
+
mail = ActionMailer::Base.deliveries[0]
|
53
|
+
output = mail.body
|
53
54
|
|
54
55
|
#Check outpus that run needed tasks
|
55
56
|
assert_match /1 tests, 1 assertions, 0 failures, 0 errors/, output
|
56
57
|
assert output !~ /Task 'custom1' has been invoked/
|
58
|
+
assert_equal '[myapp] Cerberus set up for project (#2)', mail.subject
|
57
59
|
|
58
60
|
status_file = HOME + '/work/myapp/status.log'
|
59
61
|
assert File.exists?(status_file)
|
60
62
|
assert_equal 'succesful', IO.read(status_file)
|
63
|
+
assert 1, Dir[HOME + "/work/rake_cust/logs/*-succesful.log"].size
|
61
64
|
|
62
65
|
FileUtils.rm status_file
|
63
66
|
build = Cerberus::BuildCommand.new('myapp')
|
64
67
|
build.run
|
65
68
|
assert File.exists?(status_file)
|
66
|
-
|
67
69
|
assert_equal 2, ActionMailer::Base.deliveries.size #first email that project was setup
|
70
|
+
assert 2, Dir[HOME + "/work/rake_cust/logs/*.log"].size
|
68
71
|
|
69
72
|
build = Cerberus::BuildCommand.new('myapp')
|
70
73
|
build.run
|
71
74
|
assert_equal 2, ActionMailer::Base.deliveries.size #Number of mails not changed
|
72
|
-
|
75
|
+
assert 2, Dir[HOME + "/work/rake_cust/logs/*.log"].size #even if sources unchanged
|
73
76
|
|
74
77
|
#remove status file to run project again
|
75
78
|
FileUtils.rm status_file
|
@@ -155,4 +158,12 @@ class FunctionalTest < Test::Unit::TestCase
|
|
155
158
|
assert_match /Task 'custom1' has been invoked/, output
|
156
159
|
assert_match /Task 'custom2' has been invoked/, output
|
157
160
|
end
|
161
|
+
|
162
|
+
def test_logs_disabled
|
163
|
+
add_application('rake_cust', SVN_URL, 'log' => {'enable' => false})
|
164
|
+
build = Cerberus::BuildAllCommand.new
|
165
|
+
build.run
|
166
|
+
|
167
|
+
assert !File.exists?(HOME + "/work/rake_cust/logs")
|
168
|
+
end
|
158
169
|
end
|
data/test/maven2_builer_test.rb
CHANGED
@@ -15,12 +15,15 @@ class Maven2BuilderTest < Test::Unit::TestCase
|
|
15
15
|
builder.output = MVN_OUTPUT
|
16
16
|
assert !builder.successful?
|
17
17
|
|
18
|
-
|
19
|
-
FileUtils.mkpath
|
20
|
-
IO.write(
|
18
|
+
reports_dir = tmp + '/target/surefire-reports/'
|
19
|
+
FileUtils.mkpath reports_dir
|
20
|
+
IO.write(reports_dir + 'wicket.util.resource.ResourceTest.txt', SUREFIRE1_OUTPUT)
|
21
|
+
IO.write(reports_dir + 'wicket.markup.html.form.persistence.CookieValuePersisterTest.txt', SUREFIRE2_OUTPUT)
|
21
22
|
|
22
|
-
output =
|
23
|
-
|
23
|
+
builder.output = MVN_OUTPUT
|
24
|
+
builder.add_error_information
|
25
|
+
assert builder.output.include?('at wicket.markup.html.basic.SimplePageTest.testRenderHomePage_3(SimplePageTest.java:285)')
|
26
|
+
assert builder.output.include?('This is for wicket.util.resource.ResourceTest :=')
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
@@ -29,6 +32,8 @@ MVN_OUTPUT =<<-END
|
|
29
32
|
-------------------------------------------------------
|
30
33
|
T E S T S
|
31
34
|
-------------------------------------------------------
|
35
|
+
Running wicket.util.resource.ResourceTest
|
36
|
+
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.047 sec <<< FAILURE!
|
32
37
|
Running wicket.markup.html.list.PagedTableNavigatorWithMarginTest
|
33
38
|
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.313 sec
|
34
39
|
Running wicket.markup.html.list.IncrementalTableNavigationTest
|
@@ -52,17 +57,27 @@ Tests run: 449, Failures: 4, Errors: 9, Skipped: 0
|
|
52
57
|
[INFO] There are test failures.
|
53
58
|
END
|
54
59
|
|
55
|
-
|
60
|
+
SUREFIRE1_OUTPUT =<<-END
|
61
|
+
-------------------------------------------------------------------------------
|
62
|
+
Test set: wicket.markup.html.basic.SimplePageTest
|
63
|
+
-------------------------------------------------------------------------------
|
64
|
+
Tests run: 13, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.521 sec <<< FAILURE!
|
65
|
+
testRenderHomePage_3(wicket.markup.html.basic.SimplePageTest) Time elapsed: 0.06 sec <<< FAILURE!
|
66
|
+
This is for wicket.util.resource.ResourceTest :=
|
67
|
+
|
68
|
+
END
|
69
|
+
|
70
|
+
SUREFIRE2_OUTPUT =<<-END
|
56
71
|
-------------------------------------------------------------------------------
|
57
72
|
Test set: wicket.markup.html.basic.SimplePageTest
|
58
73
|
-------------------------------------------------------------------------------
|
59
74
|
Tests run: 13, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.521 sec <<< FAILURE!
|
60
75
|
testRenderHomePage_3(wicket.markup.html.basic.SimplePageTest) Time elapsed: 0.06 sec <<< FAILURE!
|
61
76
|
junit.framework.AssertionFailedError
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
77
|
+
at junit.framework.Assert.fail(Assert.java:47)
|
78
|
+
at junit.framework.Assert.assertTrue(Assert.java:20)
|
79
|
+
at junit.framework.Assert.assertTrue(Assert.java:27)
|
80
|
+
at wicket.WicketTestCase.executeTest(WicketTestCase.java:78)
|
81
|
+
at wicket.markup.html.basic.SimplePageTest.testRenderHomePage_3(SimplePageTest.java:285)
|
67
82
|
|
68
83
|
END
|
data/test/test_helper.rb
CHANGED
@@ -29,7 +29,7 @@ class Test::Unit::TestCase
|
|
29
29
|
|
30
30
|
CERBERUS_PATH = File.expand_path(File.dirname(__FILE__) + '/../')
|
31
31
|
def run_cerb(args)
|
32
|
-
`ruby -I"#{CERBERUS_PATH}/lib" "#{CERBERUS_PATH}/bin/cerberus" #{args}`
|
32
|
+
`ruby -I"#{CERBERUS_PATH}/lib" "#{CERBERUS_PATH}/bin/cerberus" #{args} 2>&1`
|
33
33
|
end
|
34
34
|
|
35
35
|
def add_test_case_to_project(project_name, content)
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.0
|
2
|
+
rubygems_version: 0.9.0.1
|
3
3
|
specification_version: 1
|
4
4
|
name: cerberus
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2006-
|
6
|
+
version: 0.2.3
|
7
|
+
date: 2006-09-18 00:00:00 +04:00
|
8
8
|
summary: Cerberus is a Continuous Integration tool that could be easily run from Cron.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/cerberus/publisher/irc.rb
|
50
50
|
- lib/cerberus/publisher/jabber.rb
|
51
51
|
- lib/cerberus/publisher/mail.rb
|
52
|
+
- lib/cerberus/publisher/netsmtp_tls_fix.rb
|
52
53
|
- lib/cerberus/publisher/rss.rb
|
53
54
|
- lib/cerberus/scm/cvs.rb
|
54
55
|
- lib/cerberus/scm/darcs.rb
|
@@ -72,8 +73,6 @@ files:
|
|
72
73
|
- README
|
73
74
|
- CHANGES
|
74
75
|
- Rakefile
|
75
|
-
- doc/FAQ
|
76
|
-
- doc/OPTIONS
|
77
76
|
- doc/site
|
78
77
|
test_files:
|
79
78
|
- test/integration_test.rb
|
data/doc/FAQ
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
* How to schedule Cerberus build on nnCron
|
2
|
-
|
3
|
-
nnCron has simple user interface and it is easy to add new task - just run task with AsLoggedUser option.
|
4
|
-
There is only issue - nnCron do not pass HOME environment variable to process so you need to add it to nncron.tab file.
|
5
|
-
|
6
|
-
You could add CERBERUS_HOME envronment variable or HOME (in last case CERBERUS_HOME would be calculated as
|
7
|
-
HOME/.cerberus)
|
8
|
-
|
9
|
-
Mine nncron.tab file looks like this
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
SET CERBERUS_HOME="C:\Documents and Settings\anatol\.cerberus"
|
14
|
-
|
15
|
-
#( [cerberus]watsjit
|
16
|
-
AsLoggedUser
|
17
|
-
Time: */15 * * * * *
|
18
|
-
Action:
|
19
|
-
SWHide NormalPriority
|
20
|
-
START-APPW: c:\progra~1\ruby\bin\cerberus.CMD build cerberus
|
21
|
-
)#
|
22
|
-
|
23
|
-
|
24
|
-
* How to change task for Rake
|
25
|
-
In my project we need to run Rails migrations before tests. But by default Cerberus runs :default task.
|
26
|
-
How could I run migations?
|
27
|
-
|
28
|
-
it is easy - just set Rake tasks option in config
|
29
|
-
builder:
|
30
|
-
rake:
|
31
|
-
task: migrate test
|
32
|
-
|
33
|
-
And it would run migrations
|
data/doc/OPTIONS
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
bin_path:
|
2
|
-
publisher:
|
3
|
-
active:
|
4
|
-
mail:
|
5
|
-
delivery_method: smtp C
|
6
|
-
address: mail.tut.by C
|
7
|
-
port: 2525 C
|
8
|
-
domain: C
|
9
|
-
user_name: anatol C
|
10
|
-
password: somepass C
|
11
|
-
authentication: login C
|
12
|
-
sender: "'Cerberus' <anatol2003@tut.by>" C
|
13
|
-
recipients: anatol.pomozov@gmail.com A
|
14
|
-
jabber:
|
15
|
-
jid: C
|
16
|
-
port: C
|
17
|
-
password: C
|
18
|
-
digest: C
|
19
|
-
recipients: A
|
20
|
-
irc:
|
21
|
-
nick: A
|
22
|
-
server: A
|
23
|
-
port: A
|
24
|
-
channel: A
|
25
|
-
rss:
|
26
|
-
file:
|
27
|
-
scm:
|
28
|
-
type: svn A
|
29
|
-
url: A
|
30
|
-
builder:
|
31
|
-
type: rake #supported: maven2 A
|
32
|
-
rake: C
|
33
|
-
task: test CA
|
34
|
-
maven2:
|
35
|
-
|
36
|
-
|
37
|
-
L - Only for command line interface
|
38
|
-
C - Cerberus config
|
39
|
-
A - application level config
|
40
|
-
|
41
|
-
|
42
|
-
L
|
43
|
-
recipients (add)
|
44
|
-
verbose or quite ??(add, build)
|
45
|
-
application_name (add)
|
46
|
-
scm (add, default svn)
|
47
|
-
builder
|