<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>app/models/config_error.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,11 +1,17 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;projectDescription&gt;
-	&lt;name&gt;cruisecontrolrb&lt;/name&gt;
-	&lt;comment&gt;&lt;/comment&gt;
-	&lt;projects&gt;
-	&lt;/projects&gt;
-	&lt;buildSpec&gt;
-	&lt;/buildSpec&gt;
-	&lt;natures&gt;
-	&lt;/natures&gt;
-&lt;/projectDescription&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+&lt;projectDescription&gt;
+	&lt;name&gt;ccrb&lt;/name&gt;
+	&lt;comment&gt;&lt;/comment&gt;
+	&lt;projects&gt;
+	&lt;/projects&gt;
+	&lt;buildSpec&gt;
+		&lt;buildCommand&gt;
+			&lt;name&gt;org.rubypeople.rdt.core.rubybuilder&lt;/name&gt;
+			&lt;arguments&gt;
+			&lt;/arguments&gt;
+		&lt;/buildCommand&gt;
+	&lt;/buildSpec&gt;
+	&lt;natures&gt;
+		&lt;nature&gt;org.rubypeople.rdt.core.rubynature&lt;/nature&gt;
+	&lt;/natures&gt;
+&lt;/projectDescription&gt;</diff>
      <filename>.project</filename>
    </modified>
    <modified>
      <diff>@@ -14,7 +14,7 @@ class Build
     build_log = artifact 'build.log'
     File.open(artifact('cruise_config.rb'), 'w') {|f| f &lt;&lt; @project.config_file_content }
     
-    raise @project.error_message unless @project.config_valid?
+    raise ConfigError.new(@project.error_message) unless @project.config_valid?
     
     # build_command must be set before doing chdir, because there may be some relative paths
     build_command = self.command
@@ -27,9 +27,24 @@ class Build
   rescue =&gt; e
     File.open(build_log, 'a'){|f| f &lt;&lt; e.message }
     CruiseControl::Log.verbose? ? CruiseControl::Log.debug(e) : CruiseControl::Log.info(e.message)
-    @status.fail!((Time.now - (time || Time.now)).ceil)
+    time_escaped = (Time.now - (time || Time.now)).ceil
+    if e.is_a? ConfigError
+      @status.fail!(time_escaped, e.message)
+    else
+      @status.fail!(time_escaped)
+    end
   end
-
+  
+  def brief_error
+    if File.size(@status.status_file) &gt; 0
+      return &quot;config error&quot;
+    end
+    unless plugin_errors.empty?
+      return &quot;plugin error&quot;
+    end
+    nil
+  end
+  
   def abort
     FileUtils.rm_rf artifacts_directory
   end</diff>
      <filename>app/models/build.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 class BuildStatus
-
+  
   def initialize(artifacts_directory)
     @artifacts_directory = artifacts_directory 
   end
@@ -19,7 +19,7 @@ class BuildStatus
   def failed?
     read_latest_status == 'failed'
   end
-
+  
   def start!
     remove_status_file
     touch_status_file(&quot;incomplete&quot;)
@@ -30,11 +30,11 @@ class BuildStatus
     touch_status_file(&quot;success.in#{elapsed_time}s&quot;)
   end
   
-  def fail!(elapsed_time)
+  def fail!(elapsed_time, error_message=nil)
     remove_status_file
-    touch_status_file(&quot;failed.in#{elapsed_time}s&quot;)
+    touch_status_file(&quot;failed.in#{elapsed_time}s&quot;, error_message)
   end
-    
+  
   def created_at
     if file = status_file
       File.mtime(file)
@@ -63,32 +63,36 @@ class BuildStatus
     file = status_file
     match_elapsed_time(File.basename(file))
   end
-
+  
   def match_elapsed_time(file_name)
     match =  /^build_status\.[^\.]+\.in(\d+)s$/.match(file_name)
     raise 'Could not parse elapsed time.' if !match or !$1
     $1.to_i
   end
-        
+ 
+  def status_file
+      Dir[&quot;#{@artifacts_directory}/build_status.*&quot;].first
+  end
+  
   private
   
   def read_latest_status
     file = status_file
     file ? match_status(File.basename(file)).downcase : 'never_built'
   end
-
+  
   def remove_status_file
     FileUtils.rm_f(Dir[&quot;#{@artifacts_directory}/build_status.*&quot;])
   end
   
-  def touch_status_file(status)
-    FileUtils.touch(&quot;#{@artifacts_directory}/build_status.#{status}&quot;)
-  end
-  
-  def status_file
-    Dir[&quot;#{@artifacts_directory}/build_status.*&quot;].first
+  def touch_status_file(status, error_message=nil)
+    filename = &quot;#{@artifacts_directory}/build_status.#{status}&quot;
+    FileUtils.touch(filename)
+    if error_message
+      File.open(filename, &quot;w&quot;){|f|f.write error_message}
+    end
   end
-  
+    
   def match_status(file_name)
      /^build_status\.([^\.]+)(\..+)?/.match(file_name)[1]
   end</diff>
      <filename>app/models/build_status.rb</filename>
    </modified>
    <modified>
      <diff>@@ -153,6 +153,7 @@ class Project
   end
     
   def last_build_status
+    return &quot;failed&quot; if BuilderStatus.new(self).fatal?
     builds.empty? ? 'never_built' : last_build.status
   end
 </diff>
      <filename>app/models/project.rb</filename>
    </modified>
    <modified>
      <diff>@@ -57,7 +57,11 @@
         &lt;/div&gt;
       &lt;% end %&gt;
       &lt;%= show_revisions_in_build(revisions_in_build(latest_build)) %&gt;
-    &lt;% end %&gt;
+      &lt;br&gt;
+      &lt;% if latest_build.brief_error %&gt;
+        &lt;div&gt;&lt;%= link_to latest_build.brief_error, {:action =&gt; 'show', :id =&gt; project.name}, {:class =&gt; &quot;failed&quot;} %&gt;&lt;/div&gt;
+      &lt;% end %&gt;
+    &lt;% end %&gt;   
   &lt;/td&gt;
 
 &lt;/tr&gt;</diff>
      <filename>app/views/projects/_project.rhtml</filename>
    </modified>
    <modified>
      <diff>@@ -22,6 +22,10 @@ class BuilderStatus
     end
   end
 
+  def fatal?
+    status == 'svn_error'
+  end
+  
   def build_initiated
     set_status 'building'
   end</diff>
      <filename>builder_plugins/installed/builder_status.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,7 +22,8 @@ class MinimalConsoleLogger
 
   def build_loop_failed(error)
     puts &quot;Build loop failed&quot;
-    puts &quot;#{error.class}: #{error.message}\n&quot; + error.backtrace.map { |line| &quot;  #{line}&quot; }.join(&quot;\n&quot;)
+    puts &quot;#{error.class}: #{error.message}&quot;
+    puts error.backtrace.map { |line| &quot;  #{line}&quot; }.join(&quot;\n&quot;) rescue nil
   end
   
   def configuration_modified</diff>
      <filename>builder_plugins/installed/minimal_console_logger.rb</filename>
    </modified>
    <modified>
      <diff>@@ -35,7 +35,8 @@ class ProjectLogger
 
   def build_loop_failed(error)
     CruiseControl::Log.event(&quot;Build loop failed&quot;, :debug)
-    CruiseControl::Log.debug(&quot;#{error.class}: #{error.message}\n&quot; + error.backtrace.map { |line| &quot;  #{line}&quot; }.join(&quot;\n&quot;))
+    backtrace = error.backtrace.map { |line| &quot;  #{line}&quot; }.join(&quot;\n&quot;) rescue &quot;&quot;
+    CruiseControl::Log.debug(&quot;#{error.class}: #{error.message}\n#{backtrace}&quot;)
   end
 
 end</diff>
      <filename>builder_plugins/installed/project_logger.rb</filename>
    </modified>
    <modified>
      <diff>@@ -73,7 +73,7 @@ begin
     write_to_log_and_console &quot;Builder for project '#{project.name}' started&quot;
     puts &quot;Logging to: #{File.expand_path(CRUISE_OPTIONS[:log_file_name])}&quot;
 
-	  while (true) do
+	while (true) do
       catch(:reload_project) do
         project.scheduler.run
       end</diff>
      <filename>script/builder</filename>
    </modified>
    <modified>
      <diff>@@ -21,7 +21,7 @@ ActionMailer::Base.delivery_method = :test
 ActionMailer::Base.perform_deliveries = true
 
 class Test::Unit::TestCase
-
+  
   def assert_raises(arg1 = nil, arg2 = nil)
     expected_error = arg1.is_a?(Exception) ? arg1 : nil
     expected_class = arg1.is_a?(Class) ? arg1 : nil
@@ -39,11 +39,11 @@ class Test::Unit::TestCase
       assert_matched(expected_message, e.message, &quot;Unexpected error message&quot;) if expected_message.is_a? Regexp
     end
   end
-
+  
   def assert_false(expression)
     assert_equal false, expression
   end
-
+  
   def in_total_sandbox(&amp;block)
     in_sandbox do |sandbox|
       @dir = File.expand_path(sandbox.root)
@@ -53,14 +53,14 @@ class Test::Unit::TestCase
       yield(sandbox)
     end
   end
-
+  
   def with_sandbox_project(&amp;block)
     in_total_sandbox do |sandbox|
       FileUtils.mkdir_p(&quot;#{sandbox.root}/work&quot;)
-
+      
       project = Project.new('my_project')
       project.path = sandbox.root
-
+      
       yield(sandbox, project)
     end
   end
@@ -80,7 +80,7 @@ class Test::Unit::TestCase
     
     project
   end
-
+  
   def create_build_stub(label, status, time = Time.at(0))
     build = Object.new
     build.stubs(:label).returns(label)
@@ -90,19 +90,21 @@ class Test::Unit::TestCase
     build.stubs(:successful?).returns(status == 'success')
     build.stubs(:incomplete?).returns(status == 'incomplete')
     build.stubs(:changeset).returns(&quot;bobby checked something in&quot;)
+    build.stubs(:brief_error).returns(nil)
+    
     build
   end
-
+  
   class FakeSourceControl
     attr_reader :username
     
     def initialize(username)
       @username = username
     end
-
+    
     def checkout(dir)
       File.open(&quot;#{dir}/README&quot;, &quot;w&quot;) {|f| f &lt;&lt; &quot;some text&quot;}
     end
-
+    
   end  
 end</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -126,7 +126,7 @@ class BuildStatusTest &lt; Test::Unit::TestCase
     Time.expects(:now).returns(time_with_fractional_seconds)
     assert_equal 10, BuildStatus.new(&quot;artifacts_directory&quot;).elapsed_time_in_progress
   end
-
+  
   private
 
   def assert_exception_when_parsing_elapsed_time(file_name)</diff>
      <filename>test/unit/build_status_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -130,7 +130,7 @@ class BuildTest &lt; Test::Unit::TestCase
       Build.new(project, 123).status
     end
   end
-
+  
   def test_build_command_customization
     with_sandbox_project do |sandbox, project|
       build_with_defaults = Build.new(project, '1')
@@ -183,4 +183,25 @@ class BuildTest &lt; Test::Unit::TestCase
     end
   end  
     
+  def test_should_pass_error_to_build_status_if_config_file_is_invalid
+    with_sandbox_project do |sandbox, project|
+      sandbox.new :file =&gt; &quot;build-1/build.log&quot;
+      project.stubs(:error_message).returns(&quot;fail message&quot;)
+      project.stubs(:&quot;config_valid?&quot;).returns(false)
+      
+      build = Build.new(project, 1)
+      build.run
+      assert_equal &quot;fail message&quot;, File.open(&quot;build-1/build_status.failed.in0s&quot;){|f|f.read}
+      assert_equal &quot;config error&quot;, build.brief_error
+    end   
+  end
+    
+  def test_should_pass_error_to_build_status_if_plugin_error_happens
+    with_sandbox_project do |sandbox, project|
+      sandbox.new :file =&gt; &quot;build-1/build_status.success.in0s&quot;
+      build = Build.new(project, 1)
+      build.stubs(:plugin_errors).returns(&quot;plugin error&quot;)
+      assert_equal &quot;plugin error&quot;, build.brief_error
+    end   
+  end    
 end</diff>
      <filename>test/unit/build_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -16,7 +16,7 @@ class BuilderStatusTest &lt; Test::Unit::TestCase
     FileUtils.expects(:touch).with('project_root/builder_status.building')
     @builder_status.build_initiated
   end  
-  
+ 
   def test_sleeping_creates_file__sleeping__
     Dir.stubs(:'[]').returns(['project_root/builder_status.foo'])
     FileUtils.expects(:rm_f).with(['project_root/builder_status.foo'])
@@ -97,4 +97,9 @@ class BuilderStatusTest &lt; Test::Unit::TestCase
     @builder_status.expects(:set_status).with(&quot;error&quot;)
     @builder_status.build_loop_failed(e)
   end
+  
+  def test_should_know_fatal_status
+    @builder_status.expects(:status).returns(&quot;svn_error&quot;)
+    assert @builder_status.fatal?
+  end
 end
\ No newline at end of file</diff>
      <filename>test/unit/builder_status_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -417,6 +417,13 @@ class ProjectTest &lt; Test::Unit::TestCase
       assert @project.error_message.empty?
     end
   end
+  
+  def test_last_build_status_should_be_failed_if_builder_status_is_fatal
+    builder_status = Object.new
+    builder_status.expects(:&quot;fatal?&quot;).returns(true)
+    BuilderStatus.expects(:new).with(@project).returns(builder_status)
+    assert_equal &quot;failed&quot;, @project.last_build_status
+  end
       
   private
   </diff>
      <filename>test/unit/project_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>b78296123295603a50d04f0188dc4b4504ada7b1</id>
    </parent>
  </parents>
  <author>
    <name>Lin Zhang</name>
    <email>geniuslinda@gmail.com</email>
  </author>
  <url>http://github.com/thoughtworks/cruisecontrol.rb/commit/7744d61fc9d14bc3bececd811e6eaa71b877b38c</url>
  <id>7744d61fc9d14bc3bececd811e6eaa71b877b38c</id>
  <committed-date>2007-03-19T00:29:31-07:00</committed-date>
  <authored-date>2007-03-19T00:29:31-07:00</authored-date>
  <message>r375: issue 20 : make outside build error show on dashboard</message>
  <tree>dd38f18a7491b49abf12ba80783547b39cbe7615</tree>
  <committer>
    <name>Lin Zhang</name>
    <email>geniuslinda@gmail.com</email>
  </committer>
</commit>
