cerberus 0.7 → 0.7.2

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/Changelog.txt CHANGED
@@ -1,5 +1,20 @@
1
1
  = Cerberus Changelog
2
2
 
3
+ == Version 0.7.2
4
+ Bugfixes and updates to RSS publisher
5
+
6
+ * Fix mercurial builder to properly read revision number of merged commits
7
+ * Updated RSS publisher to output a properly formatted RSS feed with the
8
+ ability to keep a certain number of previous builds in the feed. For more
9
+ info on the changes please see the commit message on the following commit:
10
+ http://github.com/cpjolicoeur/cerberus/commit/1f7176a6a611f30a0d70e0f75ec90724f6302043
11
+
12
+ == Version 0.7.1
13
+ New configuration options for publisher
14
+
15
+ * added "extra_subject" publisher option
16
+ * added Mercurial SCM support
17
+
3
18
  == Version 0.7
4
19
  New config options, Bazaar SCM support, removed GMailer bugfixes
5
20
 
@@ -8,8 +23,7 @@ New config options, Bazaar SCM support, removed GMailer bugfixes
8
23
  * removed GMailer library. Use default Mail publisher instead
9
24
  * added 'build_dir' option for setting custom build directory
10
25
  * added 'setup_script' option for a custom script to be run before build command
11
- * Projects using the Git SCM were not getting the full diff output in their
12
- Publishers
26
+ * Projects using the Git SCM were not getting the full diff output in their Publishers
13
27
 
14
28
  == Version 0.6
15
29
  New Ruby builder, bugfixes, and refactoring
data/Copyright.txt CHANGED
@@ -13,4 +13,5 @@ Niklas Koponen
13
13
  Mike Gunderloy
14
14
  Joe Van Dyk
15
15
  Andrew Timberlake
16
- Paul Hinze
16
+ Paul Hinze
17
+ McClain Looney
data/Rakefile CHANGED
@@ -3,6 +3,7 @@ require 'rake'
3
3
  require 'rake/testtask'
4
4
  require 'rake/packagetask'
5
5
  require 'rake/gempackagetask'
6
+ require 'rake/clean'
6
7
 
7
8
  require './lib/cerberus/constants'
8
9
 
@@ -25,6 +26,7 @@ Rake::TestTask.new(:test) do |t|
25
26
  t.verbose = true
26
27
  end
27
28
 
29
+ CLEAN.include %w(**/*~)
28
30
  desc "Clean all generated files"
29
31
  task :clean => :clobber_package do
30
32
  root = File.dirname(__FILE__)
data/Readme.markdown CHANGED
@@ -87,6 +87,7 @@ Cerberus currently supports the following SCM tools:
87
87
  * Perforce
88
88
  * CVS
89
89
  * Bazaar
90
+ * Mercurial
90
91
 
91
92
  Cerberus currently supports the following notification systems:
92
93
 
@@ -126,7 +127,7 @@ is included in the License.txt file.
126
127
 
127
128
 
128
129
  [1]:http://www.martinfowler.com/articles/continuousIntegration.html
129
- [2]:http://wiki.github.com/cpjolicoeur/cerberusci
130
+ [2]:http://wiki.github.com/cpjolicoeur/cerberus
130
131
  [3]:http://groups.google.com/group/cerberusci
131
132
  [4]:http://cpjolicoeur.lighthouseapp.com/projects/22299-cerberus
132
133
  [5]:http://rubyforge.org/frs/?group_id=1794
@@ -6,7 +6,8 @@ module Cerberus
6
6
  :perforce => 'Perforce',
7
7
  :cvs => 'CVS',
8
8
  :bzr => 'Bazaar',
9
- :git => 'Git'
9
+ :git => 'Git',
10
+ :hg => 'Mercurial'
10
11
  }
11
12
 
12
13
  def self.get(type)
@@ -30,6 +31,8 @@ module Cerberus
30
31
  'bzr'
31
32
  when test(?d, path+'/.git')
32
33
  'git'
34
+ when test(?d, path+'/.hg')
35
+ 'hg'
33
36
  end
34
37
  else
35
38
  #guess SCM type by its url
@@ -23,6 +23,9 @@ publisher:
23
23
  # url: http://someemail:password@cerberustool.campfirenow.com/room/51660
24
24
  # rss:
25
25
  # file: /usr/www/rss.xml
26
+ # channel_link: http://example.com/rss.xml
27
+ # keep: 1
28
+ # extra_subject: "#deployment #tags"
26
29
  #builder:
27
30
  # rake:
28
31
  # task: migrate test
@@ -4,5 +4,5 @@ module Cerberus
4
4
 
5
5
  LOCK_WAIT = 30 * 60 # 30 minutes
6
6
 
7
- VERSION = '0.7'
7
+ VERSION = '0.7.2'
8
8
  end
@@ -55,7 +55,7 @@ module Cerberus
55
55
 
56
56
  def initialize(application_name, cli_options = {})
57
57
  unless File.exists?("#{HOME}/config/#{application_name}.yml")
58
- say "Project '#{application_name}' does not present in Cerberus. Type 'cerberus list' to see the list of all active projects."
58
+ say "Project '#{application_name}' does not exist in Cerberus. Type 'cerberus list' to see the list of all active projects."
59
59
  end
60
60
  @app_root = "#{HOME}/work/#{application_name}"
61
61
 
@@ -88,7 +88,7 @@ module Cerberus
88
88
 
89
89
  def initialize(application_name, cli_options = {})
90
90
  unless File.exists?("#{HOME}/config/#{application_name}.yml")
91
- say "Project '#{application_name}' does not present in Cerberus. Type 'cerberus list' to see the list of all active projects."
91
+ say "Project '#{application_name}' does not exist in Cerberus. Type 'cerberus list' to see the list of all active projects."
92
92
  end
93
93
 
94
94
  app_root = "#{HOME}/work/#{application_name}"
@@ -141,7 +141,6 @@ module Cerberus
141
141
  Publisher.get(pub, publisher_config).publish(@status, self, @config) if events.include?(@status.current_state)
142
142
  end
143
143
 
144
-
145
144
  #Process hooks
146
145
  hooks = @config[:hook]
147
146
  hooks.each_pair{|name, hook|
@@ -32,7 +32,7 @@ module Cerberus
32
32
  raise "Unknown build state '#{state.current_state.to_s}'"
33
33
  end
34
34
 
35
- subject = "[#{options[:application_name]}] #{subject}"
35
+ subject = "[#{options[:application_name]}]#{options[:publisher, :extra_subject]} #{subject}"
36
36
  generated_by = "--\nThis email generated by Cerberus tool ver. #{Cerberus::VERSION}, http://cerberus.rubyforge.org/"
37
37
  body = [ manager.scm.last_commit_message ]
38
38
  if options[:changeset_url]
@@ -1,29 +1,41 @@
1
1
  require 'cerberus/publisher/base'
2
2
  require 'time'
3
3
  require 'builder'
4
+ require 'rss'
4
5
 
5
6
  class Cerberus::Publisher::RSS < Cerberus::Publisher::Base
6
7
  def self.publish(state, manager, options)
7
8
  config = options[:publisher, :rss]
8
9
  subject,body = Cerberus::Publisher::Base.formatted_message(state, manager, options)
9
10
 
10
- pub_date = Time.now.iso8601
11
- description = "<pre>#{body}</pre>".to_xs
12
- result = <<-END
13
- <rss version="2.0">
14
- <channel>
15
- <title>Cerberus build feed for #{options[:application_name].to_xs}</title>
16
- <pubDate>#{pub_date}</pubDate>
17
- <generator>http://rubyforge.org/projects/cerberus</generator>
18
- <item>
19
- <title>#{subject.to_xs}</title>
20
- <pubDate>#{pub_date}</pubDate>
21
- <description>#{description}</description>
22
- </item>
23
- </channel>
24
- </rss>
25
- END
11
+ pub_date = Time.now
26
12
 
27
- IO.write(config[:file], result)
13
+ begin
14
+ feed = RSS::Parser.parse(File.read(config[:file]), false)
15
+ raise RSS::Error unless feed
16
+ keep = config[:keep] || 1
17
+ feed.items.slice!(keep -1 ..-1) # one less than keep value, to make room for the new build
18
+ rescue RSS::Error, Errno::ENOENT
19
+ # if there's no existing file or we can't parse it, start a new one from scratch
20
+ feed = RSS::Maker.make("2.0") do |new_rss|
21
+ new_rss.channel.title = "#{options[:application_name].to_xs} build status"
22
+ new_rss.channel.description = "Cerberus build feed for #{options[:application_name].to_xs}"
23
+ new_rss.channel.generator = "http://rubyforge.org/projects/cerberus"
24
+ new_rss.channel.link = config[:channel_link] || "file://#{config[:file]}"
25
+ end
26
+ end
27
+
28
+ # update channel link if we have it explicitly set, otherwise retain existing value
29
+ feed.channel.link = config[:channel_link] unless config[:channel_link].nil?
30
+ feed.channel.pubDate = pub_date
31
+
32
+ new_item = RSS::Rss::Channel::Item.new()
33
+ new_item.title = subject
34
+ new_item.pubDate = pub_date
35
+ new_item.description = "<pre>#{body}</pre>"
36
+
37
+ feed.items.unshift new_item
38
+
39
+ IO.write(config[:file], feed)
28
40
  end
29
41
  end
@@ -54,7 +54,7 @@ class Cerberus::SCM::Bazaar < Cerberus::SCM::Base
54
54
  # message:
55
55
  # sidfugsdiufgsdifusdg
56
56
 
57
- @revision = lastlog.match(/^revno: (\d+)$/)[1].to_i
57
+ @revision = lastlog.match(/^revno: (\d+).*$/)[1].to_i
58
58
  @author = lastlog.match(/^committer: (.+)$/)[1]
59
59
  @date = Time.parse(lastlog.match(/^timestamp: (.+)$/)[1])
60
60
  @message = lastlog.match(/message:\n (.*)/m)[1]
@@ -0,0 +1,87 @@
1
+ require 'cerberus/utils'
2
+ require 'cerberus/scm/base'
3
+
4
+ class Cerberus::SCM::Mercurial < Cerberus::SCM::Base
5
+
6
+ def installed?
7
+ exec_successful? "#{@config[:bin_path]}hg --version"
8
+ end
9
+
10
+ def update!
11
+ @new =false
12
+ if test( ?d, File.join( @path,'.hg' ) )
13
+ r = get_localrev
14
+ get_updates
15
+ r_new = get_localrev
16
+ @has_changes = r_new !=r
17
+ else
18
+ FileUtils.rm_rf(@path) if test(?d, @path)
19
+ encoded_url = (@config[:scm, :url].include?(' ') ? "\"#{@config[:scm, :url]}\"" : @config[:scm, :url])
20
+ @new = true
21
+ @has_changes = true
22
+ @status = execute("clone", "#{encoded_url} #{@path}", false)
23
+ if branch = @config[:scm, :branch]
24
+ execute('update', "-C #{branch}")
25
+ end
26
+ end
27
+ extract_commit_info if @has_changes
28
+ end
29
+
30
+ def has_changes?
31
+ @has_changes
32
+ end
33
+
34
+
35
+ def new?
36
+ @new
37
+ end
38
+
39
+ def current_revision
40
+ @revision
41
+ end
42
+
43
+ def last_commit_message
44
+ @message
45
+ end
46
+
47
+ def last_author
48
+ @author
49
+ end
50
+
51
+ def output
52
+ @status
53
+ end
54
+
55
+ private
56
+ def get_localrev
57
+ execute("id", '-i').strip
58
+ end
59
+
60
+ def get_updates
61
+ execute("pull", '-u')
62
+ end
63
+
64
+ def remote_head
65
+ branch = @config[:scm, :branch] || 'default'
66
+ end
67
+
68
+ def execute(command, parameters = nil, with_path = true)
69
+ if with_path
70
+ cmd = "cd #{@config[:application_root]} && #{@config[:bin_path]}hg #{command} #{parameters}"
71
+ else
72
+ cmd = "#{@config[:bin_path]}hg #{command} #{parameters}"
73
+ end
74
+ `#{cmd}`
75
+ end
76
+
77
+ def extract_commit_info( branch='default' )
78
+ message = execute("log", "-b #{ branch } -r tip --template '{author}|{date|shortdate}|{node}|{desc}'").split("|")
79
+ m= { :author => message.shift, :date => message.shift, :revision => message.shift, :message => message.shift }
80
+ @message = m[:message]
81
+ @author = m[:author]
82
+ @date = m[:date]
83
+ @revision = m[:revision]
84
+ m
85
+ end
86
+
87
+ end
Binary file
@@ -330,6 +330,70 @@ class FunctionalTest < Test::Unit::TestCase
330
330
  build.run
331
331
  assert_equal false, build.scm.has_changes?
332
332
  end
333
+
334
+ def test_mercurial
335
+ add_application('hgapp', HG_URL, :scm => {:type => 'hg'})
336
+
337
+ build = Cerberus::BuildCommand.new('hgapp')
338
+ build.run
339
+ assert build.scm.has_changes?
340
+ assert_equal 1, ActionMailer::Base.deliveries.size #first email that project was setup
341
+ mail = ActionMailer::Base.deliveries[0]
342
+ output = mail.body
343
+
344
+ #Check output that run needed tasks
345
+ assert_match /1 tests, 1 assertions, 0 failures, 0 errors/, output
346
+ assert output !~ /Task 'custom1' has been invoked/
347
+ assert_match /\[hgapp\] Cerberus set up for project/, mail.subject
348
+
349
+ status_file = HOME + '/work/hgapp/status.log'
350
+ assert File.exists?(status_file)
351
+ assert build_successful?(status_file)
352
+ assert 1, Dir[HOME + "/work/hgapp/logs/*.log"].size
353
+
354
+ #There were no changes - no reaction should be
355
+ build = Cerberus::BuildCommand.new('hgapp')
356
+ build.run
357
+ assert_equal false, build.scm.has_changes?
358
+ assert_equal 1, ActionMailer::Base.deliveries.size #first email that project was setup
359
+ assert 1, Dir[HOME + "/work/hgapp/logs/*.log"].size
360
+
361
+ #now we add new broken test
362
+ rand_val = rand(10000)
363
+ test_case_name = "test/#{rand_val}_test.rb"
364
+ File.open(HG_REPO + '/' + test_case_name, 'w') { |f|
365
+ f << %Q( require 'test/unit'
366
+ class A#{rand_val}Test < Test::Unit::TestCase
367
+ def test_ok
368
+ assert false
369
+ end
370
+ end )
371
+ }
372
+
373
+ curr_dir = Dir.pwd
374
+ Dir.chdir HG_REPO
375
+ `hg add #{test_case_name}`
376
+ `hg commit -m 'somepatch'`
377
+ Dir.chdir curr_dir
378
+
379
+ build = Cerberus::BuildCommand.new('hgapp')
380
+ build.run
381
+ assert build.scm.has_changes?
382
+ assert_equal 2, ActionMailer::Base.deliveries.size #first email that project was setup plus new alert email
383
+ assert 2, Dir[HOME + "/work/hgapp/logs/*.log"].size
384
+
385
+ build = Cerberus::BuildCommand.new('hgapp')
386
+ build.run
387
+ assert_equal false, build.scm.has_changes?
388
+ assert_equal 2, ActionMailer::Base.deliveries.size #first email that project was setup
389
+ assert 2, Dir[HOME + "/work/hgapp/logs/*.log"].size
390
+
391
+ #Now we broke remote repository (imitate that network unaccessable)
392
+ FileUtils.rm_rf HG_REPO
393
+ build = Cerberus::BuildCommand.new('hgapp')
394
+ build.run
395
+ assert_equal false, build.scm.has_changes?
396
+ end
333
397
 
334
398
  def test_campfire_publisher
335
399
  # there were not any messages causing login/password is incorrect. We just check that there was no any exceptions
@@ -11,7 +11,7 @@ class IntegrationTest < Test::Unit::TestCase
11
11
  FileUtils.rm_rf HOME
12
12
  end
13
13
 
14
- def test_add_project_as_url
14
+ def test_add_project_as_url_subversion
15
15
  output = run_cerb(" add #{SVN_URL} ")
16
16
  assert_match /has been added to Cerberus successfully/, output
17
17
  assert File.exists?(HOME + '/config/svn_repo.yml')
@@ -31,8 +31,13 @@ class IntegrationTest < Test::Unit::TestCase
31
31
  end
32
32
 
33
33
  def test_status_command
34
- # FIXME: add real tests
35
- assert true
34
+ run_cerb(" add #{SVN_URL} APPLICATION_NAME=mamba ")
35
+ output = run_cerb(" status ")
36
+ assert_match /Project Name/, output
37
+ assert_match /Revision/, output
38
+ assert_match /Status/, output
39
+ assert_match /mamba/, output
40
+ assert_match /(Pass|Fail)/, output
36
41
  end
37
42
 
38
43
  def test_add_project_with_parameters
@@ -80,7 +85,7 @@ class IntegrationTest < Test::Unit::TestCase
80
85
 
81
86
  def test_run_unexist_project
82
87
  output = run_cerb("build some_project")
83
- assert_match /Project 'some_project' does not present in Cerberus/, output
88
+ assert_match /Project 'some_project' does not exist in Cerberus/, output
84
89
  assert !test(?d, HOME + '/work/some_project')
85
90
  end
86
91
 
@@ -104,7 +109,7 @@ class IntegrationTest < Test::Unit::TestCase
104
109
 
105
110
  def test_hook
106
111
  some_number = rand(100000)
107
- tmp_file = File.join(TEMP_DIR, 'some_number')
112
+ tmp_file = File.join(TEMP_DIR, '/some_number')
108
113
  config_file = HOME + '/config/hooks.yml'
109
114
 
110
115
  add_application('hooks', SVN_URL, 'quiet' => true)
@@ -113,7 +118,7 @@ class IntegrationTest < Test::Unit::TestCase
113
118
  cfg['hook'] = {'echo' => {'action' => "echo #{some_number} > #{tmp_file}"}}
114
119
  dump_yml(config_file, cfg)
115
120
 
116
- File.rm_f tmp_file
121
+ # File.rm_f tmp_file
117
122
  run_cerb("build hooks")
118
123
  assert_equal some_number.to_s, IO.read(tmp_file).strip
119
124
  File.rm_f tmp_file
@@ -11,7 +11,8 @@ class MailPublisherTest < Test::Unit::TestCase
11
11
 
12
12
  def test_publisher
13
13
  options = Cerberus::Config.new(nil, :publisher => {
14
- :mail => {:recipients => 'anatol.pomozov@hello.com', :sender => "cerberus@example.com", :delivery_method => 'test'}},
14
+ :mail => {:recipients => 'anatol.pomozov@hello.com', :sender => "cerberus@example.com", :delivery_method => 'test'},
15
+ :extra_subject => "[#deployment]"},
15
16
  :application_name => 'MyApp')
16
17
  build = DummyManager.new('last message', 'this is output', 1232, 'anatol')
17
18
 
@@ -21,6 +22,6 @@ class MailPublisherTest < Test::Unit::TestCase
21
22
  assert_equal 1, mails.size
22
23
  mail = mails[0]
23
24
  assert_equal 'cerberus@example.com', mail.from_addrs[0].address
24
- assert_equal '[MyApp] Cerberus set up for project (1232)', mail.subject
25
+ assert_equal '[MyApp][#deployment] Cerberus set up for project (1232)', mail.subject
25
26
  end
26
27
  end
data/test/test_helper.rb CHANGED
@@ -21,6 +21,9 @@ class Test::Unit::TestCase
21
21
 
22
22
  GIT_REPO = TEMP_DIR + '/git_repo'
23
23
  GIT_URL = 'file:///' + GIT_REPO.gsub(/\\/,'/').gsub(/^\//,'').gsub(' ', '%20')
24
+
25
+ HG_REPO = TEMP_DIR + '/hg_repo'
26
+ HG_URL = 'file:///' + HG_REPO.gsub(/\\/, '/').gsub(/^\//, '').gsub(' ', '%20')
24
27
 
25
28
  def self.refresh_repos
26
29
  # setup base subversion repos
@@ -50,6 +53,16 @@ class Test::Unit::TestCase
50
53
  zf.extract(e, fpath)
51
54
  }
52
55
  }
56
+
57
+ # setup base hg repos
58
+ FileUtils.mkpath HG_REPO
59
+ Zip::ZipFile::open("#{File.dirname(__FILE__)}/data/mercurial.zip") { |zf|
60
+ zf.each { |e|
61
+ fpath = File.join(HG_REPO, e.name)
62
+ FileUtils.mkdir_p(File.dirname(fpath))
63
+ zf.extract(e, fpath)
64
+ }
65
+ }
53
66
  end
54
67
 
55
68
  refresh_repos
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cerberus
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.7"
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Craig P Jolicoeur
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-05 00:00:00 -04:00
12
+ date: 2010-03-20 00:00:00 -04:00
13
13
  default_executable: cerberus
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -81,6 +81,7 @@ files:
81
81
  - lib/cerberus/scm/cvs.rb
82
82
  - lib/cerberus/scm/darcs.rb
83
83
  - lib/cerberus/scm/git.rb
84
+ - lib/cerberus/scm/hg.rb
84
85
  - lib/cerberus/scm/perforce.rb
85
86
  - lib/cerberus/scm/svn.rb
86
87
  - lib/cerberus/utils.rb
@@ -346,6 +347,7 @@ files:
346
347
  - test/cron_string_test.rb
347
348
  - test/data/darcs.zip
348
349
  - test/data/git.zip
350
+ - test/data/mercurial.zip
349
351
  - test/data/subversion.dump
350
352
  - test/functional_test.rb
351
353
  - test/integration_test.rb
@@ -394,7 +396,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
394
396
  requirements: []
395
397
 
396
398
  rubyforge_project: cerberus
397
- rubygems_version: 1.3.4
399
+ rubygems_version: 1.3.5
398
400
  signing_key:
399
401
  specification_version: 3
400
402
  summary: Cerberus is a Continuous Integration tool that could be easily run from Cron.