<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/fixtures/svn-repo/db/revprops/21</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revprops/22</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revprops/23</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revprops/24</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revprops/25</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revs/21</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revs/22</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revs/23</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revs/24</filename>
    </added>
    <added>
      <filename>test/fixtures/svn-repo/db/revs/25</filename>
    </added>
    <added>
      <filename>test/unit/revision_test.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -39,7 +39,7 @@ class Project
     @settings = ''
     @config_file_content = ''
     @error_message = ''
-    @trigger = ChangeInSourceControlTrigger.new
+    @triggers = [ChangeInSourceControlTrigger.new(self)]
     instantiate_plugins
   end
   
@@ -199,8 +199,7 @@ class Project
 
   def build_if_necessary
     begin
-      revisions = @trigger.get_revisions_to_build(self)
-      
+      revisions = revisions_to_build
       if revisions.empty?
         notify :no_new_revisions_detected
         return nil
@@ -220,6 +219,10 @@ class Project
     end
   end
 
+  def revisions_to_build
+    @triggers.collect(&amp;:revisions_to_build).flatten.sort.uniq  
+  end
+
   def new_revisions
     if builds.empty?
       [@source_control.latest_revision(self)].compact
@@ -395,7 +398,25 @@ class Project
   def load_timestamp(file)
     Time.parse(File.read(file))
   end
-  
+
+  def triggered_by(*new_triggers)
+    @triggers += new_triggers
+
+    @triggers.map! do |trigger|
+      if trigger.is_a?(String) || trigger.is_a?(Symbol)
+        SuccessfulBuildTrigger.new(self, trigger)
+      else
+        trigger
+      end
+    end
+    @triggers
+  end
+
+  def triggered_by=(triggers)
+    @triggers = [triggers].flatten
+  end
+
+
   private
   
   # sorts a array of builds in order of revision number and rebuild number </diff>
      <filename>app/models/project.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,8 @@
 Revision = Struct.new :number, :committed_by, :time, :message, :changeset
 
-class Revision  
+class Revision
+  include Comparable
+  
   def to_s
     &lt;&lt;-EOL
 Revision #{number} committed by #{committed_by} on #{time.strftime('%Y-%m-%d %H:%M:%S') if time}
@@ -9,10 +11,11 @@ Revision #{number} committed by #{committed_by} on #{time.strftime('%Y-%m-%d %H:
     EOL
   end
 
-  def ==(other)
-    number == other.number
+  def &lt;=&gt;(other)
+    raise(&quot;Comparing a revision to #{other.class} is not supported&quot;) unless other.is_a? Revision
+    self.number &lt;=&gt; other.number
   end
-  
+
   def to_i
     number
   end</diff>
      <filename>app/models/revision.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,22 +1,27 @@
 class ChangeInSourceControlTrigger
-  def get_revisions_to_build(project)
-    project.notify :polling_source_control      
-    project.new_revisions
+  def initialize(triggered_project)
+    @triggered_project = triggered_project 
+  end
+
+  def revisions_to_build
+    @triggered_project.notify :polling_source_control
+    @triggered_project.new_revisions
   end
 end
 
 class SuccessfulBuildTrigger
-  attr_accessor :triggering_project_name
+  attr_accessor :triggering_project_name, :triggered_project
   
-  def initialize(triggering_project_name)
+  def initialize(triggered_project, triggering_project_name)
+    @triggered_project = triggered_project
     @triggering_project_name = triggering_project_name.to_s
   end
   
-  def get_revisions_to_build(project)
+  def revisions_to_build
     triggering_project = Project.new(@triggering_project_name)
     last_successful_build = last_successful(triggering_project.builds)
     
-    if !last_successful_build || project.find_build(last_successful_build.label)
+    if last_successful_build.nil? || @triggered_project.find_build(last_successful_build.label)
       []
     else
       [Revision.new(last_successful_build.label)]
@@ -24,7 +29,9 @@ class SuccessfulBuildTrigger
   end
   
   def ==(other)
-    other.is_a?(SuccessfulBuildTrigger) &amp;&amp; triggering_project_name == other.triggering_project_name
+    other.is_a?(SuccessfulBuildTrigger) &amp;&amp;
+      triggered_project == other.triggered_project &amp;&amp;
+      triggering_project_name == other.triggering_project_name
   end
   
   private
@@ -34,18 +41,3 @@ class SuccessfulBuildTrigger
   end
 end
 
-class SvnExternalTrigger &lt; ChangeInSourceControlTrigger
-  def get_revisions_to_build
-    if svn_external_changed
-      super
-    end
-  end
-end
-
-class Project
-  def triggered_by(trigger)
-    trigger = SuccessfulBuildTrigger.new(trigger) if trigger.is_a?(String) || trigger.is_a?(Symbol)
-    @trigger = trigger
-  end
-end
-</diff>
      <filename>app/models/triggers.rb</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ module CruiseControl
   # This hack is needed because db:test:purge implementation for MySQL drops the test database, invalidating
   # the existing connection. A solution is to reconnect again.
   def self.reconnect
-    require 'active_record'
+    require 'active_record' unless defined? ActiveRecord
     configurations = ActiveRecord::Base.configurations
     if configurations and configurations.has_key?(&quot;test&quot;) and configurations[&quot;test&quot;][&quot;adapter&quot;] == 'mysql'
       ActiveRecord::Base.establish_connection(:test)</diff>
      <filename>tasks/cc_build.rake</filename>
    </modified>
    <modified>
      <diff>@@ -1 +1 @@
-20 3f 3
+25 3f 3</diff>
      <filename>test/fixtures/svn-repo/db/current</filename>
    </modified>
    <modified>
      <diff>@@ -137,7 +137,7 @@ class BuilderIntegrationTest &lt; Test::Unit::TestCase
       build = project.build
       build_log = File.read(&quot;#{build.artifacts_directory}/build.log&quot;)
 
-      expected_output = &quot;RAILS_ENV=test\ndb:migrate invoked\n[CruiseControl] Invoking Rake task \&quot;default\&quot;\ndefault invoked\n&quot;
+      expected_output = &quot;[CruiseControl] Invoking Rake task \&quot;db:migrate\&quot;\nRAILS_ENV=test\n[CruiseControl] Invoking Rake task \&quot;default\&quot;\n&quot;
       assert build_log.include?(expected_output), &quot;#{expected_output.inspect} not found in build log:\n#{build_log}&quot;
     end
     </diff>
      <filename>test/integration/builder_integration_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -568,7 +568,48 @@ class ProjectTest &lt; Test::Unit::TestCase
       assert @project.do_clean_checkout?
     end
   end
-  
+
+
+  def test_new_project_should_have_source_control_triggers
+    project = Project.new('foo')
+    trigger_classes = project.triggered_by.map(&amp;:class)
+    assert_equal [ChangeInSourceControlTrigger], trigger_classes
+  end
+
+
+  def test_project_triggered_by
+    project = Project.new('foo')
+
+    project.triggered_by = []
+    assert_equal [], project.triggered_by
+
+    project.triggered_by 1
+    assert_equal [1], project.triggered_by
+
+    project.triggered_by 2, 3
+    assert_equal [1, 2, 3], project.triggered_by
+  end
+
+  def test_project_triggered_by_should_convert_strings_and_symbols_to_successful_build_triggers
+    project = Project.new('foo')
+
+    project.triggered_by = ['foo', 123]
+    project.triggered_by :bar
+    project.triggered_by &lt;&lt; :baz
+    assert_equal [SuccessfulBuildTrigger.new(project, 'foo'), 123, SuccessfulBuildTrigger.new(project, 'bar'),
+                  SuccessfulBuildTrigger.new(project, 'baz')],
+                  project.triggered_by
+  end
+
+  def test_revisions_to_build_should_merge_revisions_from_triggers
+    project = Project.new('foo')
+    stub_trigger_1 = Object.new
+    stub_trigger_2 = Object.new
+    project.triggered_by = [stub_trigger_1, stub_trigger_2]
+    stub_trigger_1.stubs(:revisions_to_build).returns([Revision.new(2)])
+    stub_trigger_2.stubs(:revisions_to_build).returns([Revision.new(1), Revision.new(3)])
+    assert_equal [Revision.new(1), Revision.new(2), Revision.new(3)], project.revisions_to_build
+  end
   private
   
   def stub_build(label)</diff>
      <filename>test/unit/project_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -19,58 +19,41 @@ class TriggerTest &lt; Test::Unit::TestCase
     in_total_sandbox do |sandbox|
       Configuration.stubs(:projects_directory).returns(sandbox.root)
       one, two = sandbox.new_project('one'), sandbox.new_project('two')
-      trigger = SuccessfulBuildTrigger.new(:two)
+      trigger = SuccessfulBuildTrigger.new(one, :two)
 
       create_build one, 1
       create_build two, 1
-      assert_equal [], trigger.get_revisions_to_build(one)
+      assert_equal [], trigger.revisions_to_build
 
       create_build two, 2, :fail!
-      assert_equal [], trigger.get_revisions_to_build(one)
+      assert_equal [], trigger.revisions_to_build
       create_build two, 3
-      assert_equal [Revision.new('3')], trigger.get_revisions_to_build(one)
+      assert_equal [Revision.new('3')], trigger.revisions_to_build
       
       create_build one, 3, :fail!
-      assert_equal [], trigger.get_revisions_to_build(one)
+      assert_equal [], trigger.revisions_to_build
 
       create_build two, 4
       create_build two, 5
       create_build two, 6, :fail!
-      assert_equal [Revision.new('5')], trigger.get_revisions_to_build(one)      
+      assert_equal [Revision.new('5')], trigger.revisions_to_build
     end
   end
   
   def test_triggered_by__change_in_source_control
     with_sandbox_project do |sandbox, project|
-      project.expects(:new_revisions).returns(5)
+      project.expects(:new_revisions).returns([Revision.new('5')])
 
-      trigger = ChangeInSourceControlTrigger.new
+      trigger = ChangeInSourceControlTrigger.new(project)
 
-      assert_equal 5, trigger.get_revisions_to_build(project)
+      assert_equal [Revision.new('5')], trigger.revisions_to_build
     end
   end
-  
-  def test_triggered_by__change_in_svn_external
-  end
-  
-  def test_project_triggered_by
-    p = Project.new('foo')
-    def p.trigger
-      @trigger
-    end
-    
-    assert_equal ChangeInSourceControlTrigger, p.trigger.class
-    
-    p.triggered_by 'CruiseControl-Fast'
-    assert_equal SuccessfulBuildTrigger.new('CruiseControl-Fast'), p.trigger
-    
-    p.triggered_by :ccrb
-    assert_equal SuccessfulBuildTrigger.new(:ccrb), p.trigger
-  end
-   
+
   private
-  
+
   def create_build(project, label, state = :succeed!)
     project.create_build(label).build_status.send(state, 0)
   end
+
 end</diff>
      <filename>test/unit/trigger_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>432a1a3dede64ee3d8cdd8df8b58e978c2381251</id>
    </parent>
  </parents>
  <author>
    <name>Alexey Verkhovsky</name>
    <email>alexey.verkhovsky@gmail.com</email>
  </author>
  <url>http://github.com/willbryant/cruisecontrolrb/commit/48612c18d5db54c7bb9e00971ce5681032603fde</url>
  <id>48612c18d5db54c7bb9e00971ce5681032603fde</id>
  <committed-date>2007-08-15T18:06:21-07:00</committed-date>
  <authored-date>2007-08-15T18:06:21-07:00</authored-date>
  <message>r525: Multiple triggers per project</message>
  <tree>915a150f950e3ad568271d6449fa1e1d070f2ca8</tree>
  <committer>
    <name>Alexey Verkhovsky</name>
    <email>alexey.verkhovsky@gmail.com</email>
  </committer>
</commit>
