<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>script/test_email</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,5 @@
 TRUNK
-  - builds can now be serialized - only one build runs at a time on a server
+  - builds can now be serialized - with a config option set, CC.rb will only run one build at a time
   - build requested status now stays on dashboard until a build starts
   - option to auto delete more than N builds
   - moved cruise data into ~/.cruise by default</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -1,9 +1,11 @@
 class LogParser
-  FIND_TEST_ERROR_REGEX = /^\s+\d+\) Error:\n(.*):\n(.*)\n([\s\S]*?)\n\n/
+
+  TEST_ERROR_REGEX = /^\s+\d+\) Error:\n(.*):\n(.*)\n([\s\S]*?)\n\n/
+  TEST_FAILURE_REGEX = /^\s+\d+\) Failure:\n([\S\s]*?)\n\n/
+
   TEST_NAME_REGEX = /\S+/
   MESSAGE_REGEX = /\]\:\n([\s\S]+)/
   STACK_TRACE_REGEX = /\[([\s\S]*?)\]\:/
-  TEST_FAILURE_BLOCK_REGEX = /^\s+\d+\) Failure:\n([\S\s]*?)\n\n/
 
   def initialize(log)
     @log = log
@@ -12,9 +14,9 @@ class LogParser
   def errors
     test_errors = []
     
-    @log.gsub(FIND_TEST_ERROR_REGEX) do |match|
+    @log.scan(TEST_ERROR_REGEX) do |match|
       test_errors &lt;&lt; TestErrorEntry.create_error($1, $2, $3)
-    end    
+    end
   
     return test_errors
   end
@@ -22,7 +24,7 @@ class LogParser
   def failures
     test_failures = []
 
-    @log.gsub(TEST_FAILURE_BLOCK_REGEX) do |text|
+    @log.scan(TEST_FAILURE_REGEX) do |text|
       content = $1
 
       begin
@@ -40,7 +42,7 @@ class LogParser
   end
 
   def failures_and_errors
-      failures + errors
+    failures + errors
   end
 
 end</diff>
      <filename>app/models/log_parser.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,9 +18,6 @@ def find_home
   end
 end
 
-CRUISE_DATA_ROOT = File.join(find_home, &quot;.cruise&quot;) unless defined? CRUISE_DATA_ROOT
-puts &quot;cruise data root = '#{CRUISE_DATA_ROOT}'&quot;
-
 unless defined?(RAILS_ROOT)
   root_path = File.join(File.dirname(__FILE__), '..')
 
@@ -32,6 +29,15 @@ unless defined?(RAILS_ROOT)
   RAILS_ROOT = root_path
 end
 
+unless defined? CRUISE_DATA_ROOT
+  if ENV['CRUISE_DATA_ROOT']
+    CRUISE_DATA_ROOT = ENV['CRUISE_DATA_ROOT']
+  else
+    CRUISE_DATA_ROOT = File.join(find_home, &quot;.cruise&quot;)
+  end
+  puts &quot;cruise data root = '#{CRUISE_DATA_ROOT}'&quot;
+end
+
 unless defined?(Rails::Initializer)
   if File.directory?(&quot;#{RAILS_ROOT}/vendor/rails&quot;)
     require &quot;#{RAILS_ROOT}/vendor/rails/railties/lib/initializer&quot;</diff>
      <filename>config/boot.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,9 @@
 Capistrano::Configuration.instance(:must_exist).load do
+
   namespace :deploy do
 
     desc 'deploy CC.rb'
-    task :ccrb do
+    task :default do
       stop_ccrb
 
       update_code
@@ -12,6 +13,15 @@ Capistrano::Configuration.instance(:must_exist).load do
       start_ccrb
     end
 
+    task :rollback do
+      stop_ccrb
+
+      rollback_code
+      symlink
+
+      start_ccrb
+    end
+
     desc 'stop CC.rb'
     task :stop_ccrb do
       sudo &quot;sv force-stop ccrb_dashboard_1&quot; rescue nil
@@ -28,14 +38,10 @@ Capistrano::Configuration.instance(:must_exist).load do
     task :after_update_code do
       sudo &quot;chmod -R 775 #{release_path}/tmp&quot;
       sudo &quot;chmod -R 775 #{release_path}/log&quot;
-      sudo &quot;rm -rf #{release_path}/projects&quot;
       sudo &quot;mkdir -p #{shared_path}/projects&quot;
       sudo &quot;chmod -R 775 #{shared_path}/projects&quot;
-      sudo &quot;chown deployer #{shared_path}/projects&quot;
-      sudo &quot;chgrp rails #{shared_path}/projects&quot;
+      sudo &quot;chown deployer:rails #{shared_path}/projects&quot;
       sudo &quot;ln -nfs #{shared_path}/projects #{release_path}/projects&quot;
-      sudo &quot;touch #{shared_path}/site_config.rb&quot;
-      sudo &quot;ln -nfs #{shared_path}/site_config.rb #{release_path}/config/site_config.rb&quot;
     end
 
   end</diff>
      <filename>config/recipes/cruisecontrol.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,7 @@ include FileUtils
 DATA_ROOT = ARGV[0]
 RAILS_ROOT = File.expand_path(&quot;.&quot;)
 
-if File.exists? 'projects'
+if File.directory? 'projects'
   mv 'projects', DATA_ROOT + '/projects'
 else
   mkdir_p DATA_ROOT + '/projects'</diff>
      <filename>db/migrate/002_move_custom_files_to_directory_in_user_home.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,9 +2,14 @@ Todo
 ----
 
 externals
-- docs
-- changesets
-- what if external dir doesn't exist yet
+- 1
+  - use revision to see if something has been changed
+- 2
+  - 
+- 3
+  - optimize external handling
+  - only use 1 level 
+  - optimize if in same repos
 
 Questions
 ---------</diff>
      <filename>doc/tasks.txt</filename>
    </modified>
    <modified>
      <diff>@@ -17,7 +17,11 @@ class MinimalConsoleLogger
   end
   
   def new_revisions_detected(new_revisions)
-    puts &quot;New revision #{new_revisions.last.number} detected&quot;
+    if new_revisions.last.nil?
+      puts &quot;Changes detected&quot;
+    else
+      puts &quot;New revision #{new_revisions.last.number} detected&quot;
+    end
   end
 
   def build_loop_failed(error)</diff>
      <filename>lib/builder_plugins/minimal_console_logger.rb</filename>
    </modified>
    <modified>
      <diff>@@ -30,7 +30,11 @@ class ProjectLogger
   end
   
   def new_revisions_detected(new_revisions)
-    CruiseControl::Log.event(&quot;New revision #{new_revisions.last.number} detected&quot;)
+    if new_revisions.last.nil?
+      CruiseControl::Log.event(&quot;Changes detected&quot;)
+    else
+      CruiseControl::Log.event(&quot;New revision #{new_revisions.last.number} detected&quot;)
+    end
   end
 
   def build_loop_failed(error)</diff>
      <filename>lib/builder_plugins/project_logger.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,16 +6,16 @@ Net::SMTP.class_eval do
     raise IOError, 'SMTP session already started' if @started
     check_auth_args user, secret, authtype if user or secret
 
-    socket = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
-    @socket = Net::InternetMessageIO.new(socket)
-    @socket.read_timeout = 60 #@read_timeout
-    @socket.debug_output = STDERR #@debug_output
+    open_conversation(helodomain)
 
-    check_response(critical { recv_response() })
-    do_helo(helodomain)
-
-
-    create_ssl_socket(socket, helodomain) if starttls
+    if starttls
+      create_ssl_socket(helodomain)
+    else
+      # some SMTP servers that don't support TLS drop the socket after rejecting
+      # STARTTLS command, so reopen the conversation
+      @socket.close
+      open_conversation(helodomain)
+    end
 
     authenticate user, secret, authtype if user
     @started = true
@@ -53,9 +53,9 @@ Net::SMTP.class_eval do
     end
   end
 
-  def create_ssl_socket(underlying_socket, helodomain)
+  def create_ssl_socket(helodomain)
     require &quot;openssl&quot;
-    ssl = OpenSSL::SSL::SSLSocket.new(underlying_socket)
+    ssl = OpenSSL::SSL::SSLSocket.new(@tcp_socket)
     ssl.sync_close = true
     ssl.connect
     @socket = Net::InternetMessageIO.new(ssl)
@@ -64,6 +64,16 @@ Net::SMTP.class_eval do
     do_helo(helodomain)
   end
 
+  def open_conversation(helodomain)
+    @tcp_socket = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
+    @socket = Net::InternetMessageIO.new(@tcp_socket)
+    @socket.read_timeout = 60 #@read_timeout
+    @socket.debug_output = STDERR #@debug_output
+
+    check_response(critical { recv_response() })
+    do_helo(helodomain)
+  end
+
   def quit
     begin
       getok('QUIT')
@@ -71,4 +81,4 @@ Net::SMTP.class_eval do
     end
   end
 
-end
\ No newline at end of file
+end</diff>
      <filename>lib/smtp_tls.rb</filename>
    </modified>
    <modified>
      <diff>@@ -55,7 +55,7 @@ class Subversion
 
   def last_locally_known_revision
     return Revision.new(0) unless File.exist?(path)
-    Revision.new(info.last_changed_revision)
+    Revision.new(info.revision)
   end
 
   def latest_revision
@@ -67,7 +67,7 @@ class Subversion
     result = true
     
     latest_revision = self.latest_revision()
-    if latest_revision != Revision.new(revision_number)
+    if latest_revision &gt; Revision.new(revision_number)
       reasons &lt;&lt; &quot;New revision #{latest_revision.number} detected&quot;
       reasons &lt;&lt; revisions_since(revision_number)
       result = false
@@ -76,7 +76,9 @@ class Subversion
     if @check_externals
       externals.each do |ext_path, ext_url|
         ext_logger = ExternalReasons.new(ext_path, reasons)
-        ext_svn = Subversion.new(:path =&gt; File.join(self.path, ext_path), :url =&gt; ext_url)
+        ext_svn = Subversion.new(:path =&gt; File.join(self.path, ext_path), 
+                                 :url =&gt; ext_url, 
+                                 :check_externals =&gt; false)
         result = false unless ext_svn.up_to_date?(ext_logger)
       end
     end
@@ -102,7 +104,8 @@ class Subversion
   def revisions_since(revision_number)
     svn_output = log('HEAD', revision_number)
     log_parser = Subversion::LogParser.new
-    log_parser.parse(svn_output)
+    revisions = log_parser.parse(svn_output)
+    revisions.reject {|revision| revision.number == revision_number} # cut out the revision that was asked for
   end
 
   def log(from, to, arguments = [])
@@ -110,7 +113,7 @@ class Subversion
   end
   
   def info
-    svn_output = svn('info', [&quot;--xml&quot;])
+    svn_output = svn('info', [&quot;--xml&quot;])    
     Subversion::InfoParser.new.parse(svn_output)
   end
 </diff>
      <filename>lib/subversion.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,6 @@ require 'date'
 require 'xml_simple'
 
 class Subversion::LogParser
-
   def parse(lines)
     return [] if lines.empty?
     entries = XmlSimple.xml_in(lines.join, 'ForceArray' =&gt; ['logentry','path'])['logentry'] || []</diff>
      <filename>lib/subversion/log_parser.rb</filename>
    </modified>
    <modified>
      <diff>@@ -37,10 +37,6 @@ Making both revision labels up to date
 Revision 4 committed by averkhov on 2007-01-11 21:02:03
 and one more revision, for good measure
   M /passing_project/revision_label.txt
-
-Revision 3 committed by averkhov on 2007-01-11 21:01:43
-another revision
-  M /passing_project/revision_label.txt
 &quot;
     assert_false @svn.up_to_date?(reasons = [], 3)
     assert_equal expected_reasons, reasons.join(&quot;\n&quot;)</diff>
      <filename>test/integration/subversion_integration_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -210,8 +210,8 @@ class SubversionTest &lt; Test::Unit::TestCase
       svn = new_subversion
       a_svn = Object.new
       b_svn = new_subversion
-      Subversion.expects(:new).with(:path =&gt; &quot;./a&quot;, :url =&gt; &quot;svn+ssh://a&quot;).returns(a_svn)
-      Subversion.expects(:new).with(:path =&gt; &quot;./b&quot;, :url =&gt; &quot;svn+ssh://b&quot;).returns(b_svn)
+      Subversion.expects(:new).with(:path =&gt; &quot;./a&quot;, :url =&gt; &quot;svn+ssh://a&quot;, :check_externals =&gt; false).returns(a_svn)
+      Subversion.expects(:new).with(:path =&gt; &quot;./b&quot;, :url =&gt; &quot;svn+ssh://b&quot;, :check_externals =&gt; false).returns(b_svn)
 
       svn.check_externals = true
       svn.expects(:externals).returns({&quot;a&quot; =&gt; &quot;svn+ssh://a&quot;, &quot;b&quot; =&gt; &quot;svn+ssh://b&quot;})
@@ -235,8 +235,8 @@ class SubversionTest &lt; Test::Unit::TestCase
       svn = new_subversion
       a_svn = Object.new
       b_svn = Object.new
-      Subversion.expects(:new).with(:path =&gt; &quot;./a&quot;, :url =&gt; &quot;svn+ssh://a&quot;).returns(a_svn)
-      Subversion.expects(:new).with(:path =&gt; &quot;./b&quot;, :url =&gt; &quot;svn+ssh://b&quot;).returns(b_svn)
+      Subversion.expects(:new).with(:path =&gt; &quot;./a&quot;, :url =&gt; &quot;svn+ssh://a&quot;, :check_externals =&gt; false).returns(a_svn)
+      Subversion.expects(:new).with(:path =&gt; &quot;./b&quot;, :url =&gt; &quot;svn+ssh://b&quot;, :check_externals =&gt; false).returns(b_svn)
 
       svn.check_externals = true
       svn.expects(:externals).returns({&quot;a&quot; =&gt; &quot;svn+ssh://a&quot;, &quot;b&quot; =&gt; &quot;svn+ssh://b&quot;})</diff>
      <filename>test/unit/subversion_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>2521a44d56609d3c1d8ed02175d774bc145fbc18</id>
    </parent>
    <parent>
      <id>6bda61f1f187b669c430305d36440026d8167ef4</id>
    </parent>
  </parents>
  <author>
    <name>Ben Burkert</name>
    <email>ben@benburkert.com</email>
  </author>
  <url>http://github.com/benburkert/cruisecontrolrb/commit/2b0387d608a57cb050fce432a85788e116a961c6</url>
  <id>2b0387d608a57cb050fce432a85788e116a961c6</id>
  <committed-date>2008-03-25T14:22:54-07:00</committed-date>
  <authored-date>2008-03-25T14:22:54-07:00</authored-date>
  <message>Merge branch 'svn'</message>
  <tree>b294bbd60618d4ebbb2e96b220dd647a7a770a44</tree>
  <committer>
    <name>Ben Burkert</name>
    <email>ben@benburkert.com</email>
  </committer>
</commit>
