You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@continuum.apache.org by ct...@apache.org on 2008/09/12 09:37:54 UTC

svn commit: r694630 - in /continuum/branches/continuum-transient-state: continuum-api/src/main/java/org/apache/maven/continuum/notification/ continuum-core/src/main/java/org/apache/maven/continuum/ continuum-core/src/main/java/org/apache/maven/continuu...

Author: ctan
Date: Fri Sep 12 00:37:53 2008
New Revision: 694630

URL: http://svn.apache.org/viewvc?rev=694630&view=rev
Log:
added configurable notification when scm failed

Added:
    continuum/branches/continuum-transient-state/continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/PrepareBuildComplete.vm
Modified:
    continuum/branches/continuum-transient-state/continuum-api/src/main/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcher.java
    continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
    continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java
    continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java
    continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java
    continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java
    continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java
    continuum/branches/continuum-transient-state/continuum-model/src/main/mdo/continuum.xml
    continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java
    continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/MessageContext.java
    continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java
    continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java
    continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java
    continuum/branches/continuum-transient-state/continuum-store/src/main/java/org/apache/continuum/dao/AbstractDao.java
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/resources/localization/Continuum.properties
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierIrc.jsp
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierJabber.jsp
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp
    continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMsn.jsp

Modified: continuum/branches/continuum-transient-state/continuum-api/src/main/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcher.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-api/src/main/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcher.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-api/src/main/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcher.java (original)
+++ continuum/branches/continuum-transient-state/continuum-api/src/main/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcher.java Fri Sep 12 00:37:53 2008
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
@@ -47,6 +48,8 @@
     String MESSAGE_ID_GOALS_COMPLETED = "GoalsCompleted";
 
     String MESSAGE_ID_BUILD_COMPLETE = "BuildComplete";
+    
+    String MESSAGE_ID_PREPARE_BUILD_COMPLETE = "PrepareBuildComplete";
 
     String CONTEXT_BUILD = "build";
 
@@ -77,4 +80,6 @@
     void goalsCompleted( Project project, BuildDefinition buildDefinition, BuildResult buildResult );
 
     void buildComplete( Project project, BuildDefinition buildDefinition, BuildResult buildResult );
+    
+    void prepareBuildComplete( ProjectScmRoot projectScmRoot );
 }

Modified: continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java (original)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java Fri Sep 12 00:37:53 2008
@@ -2313,6 +2313,8 @@
 
         notif.setSendOnWarning( notifier.isSendOnWarning() );
 
+        notif.setSendOnScmFailure( notifier.isSendOnScmFailure() );
+
         notif.setConfiguration( notifier.getConfiguration() );
 
         notif.setType( notifier.getType() );
@@ -2341,6 +2343,8 @@
 
         notif.setSendOnWarning( notifier.isSendOnWarning() );
 
+        notif.setSendOnScmFailure( notifier.isSendOnScmFailure() );
+
         notif.setConfiguration( notifier.getConfiguration() );
 
         notif.setType( notifier.getType() );
@@ -3551,11 +3555,6 @@
         for ( Project project : projects )
         {
             int projectId = project.getId();
-
-            if ( projectsAndBuildDefinitionsMap.containsKey( projectId ) )
-            {
-                continue;
-            }
             
             try
             {

Modified: continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java (original)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/DefaultMavenBuilderHelper.java Fri Sep 12 00:37:53 2008
@@ -343,6 +343,8 @@
 
                     userNotifier.setSendOnWarning( notifier.isSendOnWarning() );
 
+                    userNotifier.setSendOnScmFailure( notifier.isSendOnScmFailure() );
+
                     userNotifiers.add( userNotifier );
                 }
             }
@@ -545,6 +547,8 @@
 
                 notifier.setSendOnWarning( projectNotifier.isSendOnWarning() );
 
+                notifier.setSendOnScmFailure( false );
+
                 notifiers.add( notifier );
             }
         }

Modified: continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java (original)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/DefaultContinuumNotificationDispatcher.java Fri Sep 12 00:37:53 2008
@@ -21,6 +21,7 @@
 
 import org.apache.continuum.dao.ProjectDao;
 import org.apache.continuum.dao.ProjectGroupDao;
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
@@ -96,6 +97,11 @@
         sendNotification( MESSAGE_ID_BUILD_COMPLETE, project, buildDefinition, buildResult );
     }
 
+    public void prepareBuildComplete( ProjectScmRoot projectScmRoot )
+    {
+        sendNotification( MESSAGE_ID_PREPARE_BUILD_COMPLETE, projectScmRoot );
+    }
+
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
@@ -117,56 +123,17 @@
             // Here we need to get all the project details
             //  - builds are used to detect if the state has changed (TODO: maybe previousState field is better)
             //  - notifiers are used to send the notification
+            //  - scm results are used to detect if scm failed
             project = projectDao.getProjectWithAllDetails( project.getId() );
 
             ProjectGroup projectGroup =
                 projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( project.getProjectGroup().getId() );
 
             Map<String, List<ProjectNotifier>> notifiersMap = new HashMap<String, List<ProjectNotifier>>();
-            // perform the project level notifications
-            for ( ProjectNotifier notifier : (List<ProjectNotifier>) project.getNotifiers() )
-            {
-                List<ProjectNotifier> notifiers = notifiersMap.get( notifier.getType() );
-                if ( notifiers == null )
-                {
-                    notifiers = new ArrayList<ProjectNotifier>();
-                }
-
-                if ( !notifier.isEnabled() )
-                {
-                    log.info( notifier.getType() + " notifier (id=" + notifier.getId() + ") is disabled." );
-
-                    continue;
-                }
-
-                notifiers.add( notifier );
-                notifiersMap.put( notifier.getType(), notifiers );
-            }
-
-            // perform the project group level notifications
-            if ( projectGroup.getNotifiers() != null )
-            {
-                for ( ProjectNotifier projectNotifier : (List<ProjectNotifier>) projectGroup.getNotifiers() )
-                {
-                    List<ProjectNotifier> projectNotifiers = notifiersMap.get( projectNotifier.getType() );
-                    if ( projectNotifiers == null )
-                    {
-                        projectNotifiers = new ArrayList<ProjectNotifier>();
-                    }
-
-                    if ( !projectNotifier.isEnabled() )
-                    {
-                        log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId() +
-                            ") is disabled." );
-
-                        continue;
-                    }
-
-                    projectNotifiers.add( projectNotifier );
-                    notifiersMap.put( projectNotifier.getType(), projectNotifiers );
-                }
-            }
-
+            
+            getProjectNotifiers( project, notifiersMap );
+            getProjectGroupNotifiers( projectGroup, notifiersMap );
+            
             for ( String notifierType : notifiersMap.keySet() )
             {
                 MessageContext context = new MessageContext();
@@ -190,6 +157,34 @@
         }
     }
 
+    private void sendNotification( String messageId, ProjectScmRoot projectScmRoot )
+    {
+        try
+        {
+            ProjectGroup group =
+                projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( projectScmRoot.getProjectGroup().getId() );
+            
+            Map<String, List<ProjectNotifier>> notifiersMap = new HashMap<String, List<ProjectNotifier>>();
+            getProjectGroupNotifiers( group, notifiersMap );
+            
+            for ( String notifierType : notifiersMap.keySet() )
+            {
+                MessageContext context = new MessageContext();
+                context.setProjectScmRoot( projectScmRoot );
+
+                List<ProjectNotifier> projectNotifiers = notifiersMap.get( notifierType );
+                context.setNotifier( projectNotifiers );
+
+                sendNotification( messageId, context );
+            }
+
+        }
+        catch ( ContinuumStoreException e )
+        {
+            log.error( "Error while population the notification context.", e );
+        }
+    }
+
     private void sendNotification( String messageId, MessageContext context )
     {
         String notifierType = context.getNotifiers().get( 0 ).getType();
@@ -205,4 +200,57 @@
             log.error( "Error while trying to use the " + notifierType + " notifier.", e );
         }
     }
+    
+    private void getProjectNotifiers( Project project, Map<String, List<ProjectNotifier>> notifiersMap )
+    {
+        if ( project.getNotifiers() != null )
+        {
+            // perform the project level notifications
+            for ( ProjectNotifier notifier : (List<ProjectNotifier>) project.getNotifiers() )
+            {
+                List<ProjectNotifier> notifiers = notifiersMap.get( notifier.getType() );
+                if ( notifiers == null )
+                {
+                    notifiers = new ArrayList<ProjectNotifier>();
+                }
+
+                if ( !notifier.isEnabled() )
+                {
+                    log.info( notifier.getType() + " notifier (id=" + notifier.getId() + ") is disabled." );
+
+                    continue;
+                }
+
+                notifiers.add( notifier );
+                notifiersMap.put( notifier.getType(), notifiers );
+            }
+        }
+    }
+    
+    private void getProjectGroupNotifiers( ProjectGroup projectGroup, Map<String, List<ProjectNotifier>>  notifiersMap )
+    {
+        // perform the project group level notifications
+        if ( projectGroup.getNotifiers() != null )
+        {
+            for ( ProjectNotifier projectNotifier : (List<ProjectNotifier>) projectGroup.getNotifiers() )
+            {
+                List<ProjectNotifier> projectNotifiers = notifiersMap.get( projectNotifier.getType() );
+                if ( projectNotifiers == null )
+                {
+                    projectNotifiers = new ArrayList<ProjectNotifier>();
+                }
+
+                if ( !projectNotifier.isEnabled() )
+                {
+                    log.info( projectNotifier.getType() + " projectNotifier (id=" + projectNotifier.getId() +
+                        ") is disabled." );
+
+                    continue;
+                }
+
+                projectNotifiers.add( projectNotifier );
+                notifiersMap.put( projectNotifier.getType(), projectNotifiers );
+            }
+        }
+    }
 }

Modified: continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java (original)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/console/ConsoleNotifier.java Fri Sep 12 00:37:53 2008
@@ -19,12 +19,14 @@
  * under the License.
  */
 
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
 import org.apache.maven.continuum.notification.AbstractContinuumNotifier;
 import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
 import org.apache.maven.continuum.notification.MessageContext;
 import org.apache.maven.continuum.notification.NotificationException;
+import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.codehaus.plexus.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,6 +57,8 @@
         Project project = context.getProject();
 
         BuildResult build = context.getBuildResult();
+        
+        ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
 
         if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_STARTED ) )
         {
@@ -80,6 +84,10 @@
         {
             buildComplete( project, build );
         }
+        else if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE ) )
+        {
+            prepareBuildComplete( projectScmRoot );
+        }
         else
         {
             log.warn( "Unknown messageId: '" + messageId + "'." );
@@ -133,6 +141,23 @@
             out( project, build, "Build complete." );
         }
     }
+    
+    private void prepareBuildStarted( ProjectScmRoot projectScmRoot )
+    {
+        out( projectScmRoot, "Prepare build started." );
+    }
+    
+    private void prepareBuildComplete( ProjectScmRoot projectScmRoot )
+    {
+        if ( StringUtils.isEmpty( projectScmRoot.getError() ) )
+        {
+            out( projectScmRoot, "Prepare build complete. state: " + projectScmRoot.getState() );
+        }
+        else
+        {
+            out( projectScmRoot, "Prepare build complete." );
+        }
+    }
 
     private void out( Project project, BuildResult build, String msg )
     {
@@ -143,4 +168,17 @@
             System.out.println( build.getError() );
         }
     }
+    
+    private void out( ProjectScmRoot projectScmRoot, String msg )
+    {
+        if ( projectScmRoot != null )
+        {
+            System.out.println( "Prepare build event for '" + projectScmRoot.getScmRootAddress() + "':" + msg );
+            
+            if ( !StringUtils.isEmpty( projectScmRoot.getError() ) )
+            {
+                System.out.println( projectScmRoot.getError() );
+            }
+        }
+    }
 }

Modified: continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java (original)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/notification/mail/MailContinuumNotifier.java Fri Sep 12 00:37:53 2008
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.Continuum;
 import org.apache.maven.continuum.configuration.ConfigurationService;
 import org.apache.maven.continuum.execution.ExecutorConfigurator;
@@ -31,6 +32,7 @@
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
 import org.apache.maven.continuum.model.project.ProjectDeveloper;
+import org.apache.maven.continuum.model.project.ProjectGroup;
 import org.apache.maven.continuum.model.project.ProjectNotifier;
 import org.apache.maven.continuum.model.scm.ChangeSet;
 import org.apache.maven.continuum.model.scm.ScmResult;
@@ -241,12 +243,21 @@
         BuildResult build = context.getBuildResult();
         String buildOutput = getBuildOutput( project, build );
         BuildDefinition buildDefinition = context.getBuildDefinition();
-
+        ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
+        
+        boolean isPrepareBuildComplete =
+            messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE );
+        
+        if ( projectScmRoot == null && isPrepareBuildComplete )
+        {
+            return;
+        }
+        
         // ----------------------------------------------------------------------
         // If there wasn't any building done, don't notify
         // ----------------------------------------------------------------------
 
-        if ( build == null )
+        if ( build == null && !isPrepareBuildComplete )
         {
             return;
         }
@@ -259,6 +270,10 @@
         {
             buildComplete( project, notifiers, build, buildOutput, messageId, context, buildDefinition );
         }
+        else if ( isPrepareBuildComplete )
+        {
+            prepareBuildComplete( projectScmRoot, notifiers, messageId, context );
+        }
     }
 
     private void buildComplete( Project project, List<ProjectNotifier> notifiers, BuildResult build, String buildOutput,
@@ -401,6 +416,75 @@
         sendMessage( project, notifiers, subject, content, messageContext );
     }
 
+    private void prepareBuildComplete( ProjectScmRoot projectScmRoot, List<ProjectNotifier> notifiers, 
+                                       String messageId, MessageContext messageContext )
+        throws NotificationException
+    {
+        // ----------------------------------------------------------------------
+        // Generate the mail contents
+        // ----------------------------------------------------------------------
+
+        String packageName = getClass().getPackage().getName().replace( '.', '/' );
+
+        String templateName = packageName + "/templates/"  + messageId + ".vm";
+
+        StringWriter writer = new StringWriter();
+
+        String content;
+
+        try
+        {
+            VelocityContext context = new VelocityContext();
+            
+            // ----------------------------------------------------------------------
+            // Data objects
+            // ----------------------------------------------------------------------
+
+            context.put( "reportUrl", getReportUrl( projectScmRoot.getProjectGroup(), 
+                                                    projectScmRoot, configurationService ) );
+
+            context.put( "projectGroup", projectScmRoot.getProjectGroup() );
+
+            context.put( "projectScmRoot", projectScmRoot );
+            
+            // TODO put other profile env var could be a security if they provide passwords ?
+
+            // ----------------------------------------------------------------------
+            // Generate
+            // ----------------------------------------------------------------------
+
+            velocity.getEngine().mergeTemplate( templateName, context, writer );
+
+            content = writer.getBuffer().toString();
+        }
+        catch ( ResourceNotFoundException e )
+        {
+            log.info( "No such template: '" + templateName + "'." );
+
+            return;
+        }
+        catch ( Exception e )
+        {
+            throw new NotificationException( "Error while generating mail contents.", e );
+        }
+        
+        // ----------------------------------------------------------------------
+        // Send the mail
+        // ----------------------------------------------------------------------
+
+        String subject;
+        try
+        {
+            subject = generateSubject( projectScmRoot );
+        }
+        catch ( Exception e )
+        {
+            throw new NotificationException( "Error while generating mail subject.", e );
+        }
+
+        sendMessage( projectScmRoot, notifiers, subject, content, messageContext );
+    }
+    
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
@@ -482,6 +566,23 @@
 
         return writer.toString();
     }
+    
+    private String generateSubject( ProjectScmRoot projectScmRoot )
+        throws Exception
+    {
+        String state = getState( projectScmRoot );
+        subjectFormat = "[continuum] PREPARE BUILD ${state}: ${projectScmRoot.scmRootAddress}";
+        
+        VelocityContext context = new VelocityContext();
+        context.put( "projectScmRoot", projectScmRoot );
+        context.put( "state", state );
+    
+        StringWriter writer = new StringWriter();
+    
+        boolean velocityResults = velocity.getEngine().evaluate( context, writer, "subjectPattern", subjectFormat );
+    
+        return writer.toString();
+    }
 
     private String getState( Project project, BuildResult build )
     {
@@ -511,7 +612,28 @@
             return "ERROR: Unknown build state " + state;
         }
     }
+    
+    private String getState( ProjectScmRoot projectScmRoot )
+    {
+        int state = projectScmRoot.getState();
+
+        if ( state == ContinuumProjectState.UPDATED )
+        {
+            return "SUCCESSFUL";
+        }
+        else if ( state == ContinuumProjectState.ERROR )
+        {
+            return "ERROR";
+        }
+        else
+        {
+            log.warn( "Unknown prepare build state " + state + " for SCM Root URL " + projectScmRoot.getScmRootAddress() +
+                      " in projectGroup " + projectScmRoot.getProjectGroup().getId() );
 
+            return "ERROR: Unknown build state " + state;
+        }
+    }
+    
     private void sendMessage( Project project, List<ProjectNotifier> notifiers, String subject, String content,
                               MessageContext context )
         throws NotificationException
@@ -588,7 +710,8 @@
                         {
                             if ( Boolean.parseBoolean( committerField ) )
                             {
-                                ScmResult scmResult = context.getBuildResult().getScmResult();
+                                //ScmResult scmResult = context.getBuildResult().getScmResult();
+                                ScmResult scmResult = context.getProject().getScmResult();
                                 if ( scmResult != null && scmResult.getChanges() != null &&
                                     !scmResult.getChanges().isEmpty() )
                                 {
@@ -651,6 +774,99 @@
             throw new NotificationException( "Exception while sending message.", ex );
         }
     }
+    
+    private void sendMessage( ProjectScmRoot projectScmRoot, List<ProjectNotifier> notifiers, 
+                              String subject, String content, MessageContext context )
+        throws NotificationException
+    {
+        ProjectGroup projectGroup = projectScmRoot.getProjectGroup();
+        
+        if ( notifiers.size() == 0 )
+        {
+            // This is a useful message for the users when debugging why they don't
+            // receive any mails
+
+            log.info( "No mail notifier for '" + projectGroup.getName() + "'." );
+
+            return;
+        }
+
+        String fromMailbox = getFromMailbox( notifiers );
+
+        if ( fromMailbox == null )
+        {
+            log
+                .warn( projectGroup.getName() +
+                    ": ProjectGroup is missing nag email and global from mailbox is missing, not sending mail." );
+
+            return;
+        }
+
+        MailMessage message = new MailMessage();
+        
+        try
+        {
+            message.setSubject( subject );
+
+            log.info( "Message Subject: '" + subject + "'." );
+
+            message.setContent( content );
+
+            MailMessage.Address from = new MailMessage.Address( fromMailbox, fromName );
+
+            message.setFrom( from );
+
+            log.info( "Sending message: From '" + from + "'." );
+            
+            if ( StringUtils.isEmpty( toOverride ) )
+            {
+                for ( ProjectNotifier notifier : notifiers )
+                {
+                    if ( !shouldNotify( projectScmRoot, notifier ) )
+                    {
+                        continue;
+                    }
+                    
+                    Map<String, String> conf = notifier.getConfiguration();
+                    if ( conf != null )
+                    {
+                        String addressField = conf.get( ADDRESS_FIELD );
+
+                        if ( StringUtils.isNotEmpty( addressField ) )
+                        {
+                            String[] addresses = StringUtils.split( addressField, "," );
+
+                            for ( String address : addresses )
+                            {
+                                // TODO: set a proper name
+                                MailMessage.Address to = new MailMessage.Address( address.trim() );
+
+                                log.info( "Recipient: To '" + to + "'." );
+
+                                message.addTo( to );
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                // TODO: use configuration file instead of to load it fron component configuration
+                // TODO: set a proper name
+                MailMessage.Address to = new MailMessage.Address( toOverride.trim() );
+
+                log.info( "Recipient: To '" + to + "'." );
+
+                message.addTo( to );
+            }
+
+            mailSender.send( message );
+        }
+        catch ( MailSenderException ex )
+        {
+            throw new NotificationException( "Exception while sending message.", ex );
+        } 
+    }
 
     private Map<String, String> mapDevelopersToRecipients( List<ProjectDeveloper> developers )
     {

Modified: continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java (original)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java Fri Sep 12 00:37:53 2008
@@ -14,6 +14,7 @@
 import org.apache.maven.continuum.model.project.ProjectGroup;
 import org.apache.maven.continuum.model.scm.ChangeSet;
 import org.apache.maven.continuum.model.scm.ScmResult;
+import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
 import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.apache.maven.continuum.store.ContinuumStoreException;
 import org.apache.maven.continuum.utils.ContinuumUtils;
@@ -59,7 +60,12 @@
      * @plexus.requirement
      */
     private WorkingDirectoryService workingDirectoryService;
-    
+
+    /**
+     * @plexus.requirement
+     */
+    private ContinuumNotificationDispatcher notifierDispatcher;
+
     public void executeTask( Task task )
         throws TaskExecutionException
     {
@@ -239,6 +245,7 @@
         if ( projectScmRoot.getState() != ContinuumProjectState.ERROR )
         {
             projectScmRoot.setState( ContinuumProjectState.UPDATED );
+            projectScmRoot.setError( null );
             
             try
             {
@@ -249,6 +256,8 @@
                 throw new TaskExecutionException( "Error persisting projectScmRoot", e );
             }
         }
+
+        notifierDispatcher.prepareBuildComplete( projectScmRoot );
     }
     
     /**

Added: continuum/branches/continuum-transient-state/continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/PrepareBuildComplete.vm
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/PrepareBuildComplete.vm?rev=694630&view=auto
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/PrepareBuildComplete.vm (added)
+++ continuum/branches/continuum-transient-state/continuum-core/src/main/resources/org/apache/maven/continuum/notification/mail/templates/PrepareBuildComplete.vm Fri Sep 12 00:37:53 2008
@@ -0,0 +1,26 @@
+#*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *#
+Online report : $reportUrl
+
+  Project Group: $projectGroup.name
+  SCM Root URL: $projectScmRoot.scmRootAddress
+  
+#if ($projectScmRoot.state == 4)
+****************************************************************************
+Prepare Build Error:
+****************************************************************************
+$projectScmRoot.error
+#end

Modified: continuum/branches/continuum-transient-state/continuum-model/src/main/mdo/continuum.xml
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-model/src/main/mdo/continuum.xml?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-model/src/main/mdo/continuum.xml (original)
+++ continuum/branches/continuum-transient-state/continuum-model/src/main/mdo/continuum.xml Fri Sep 12 00:37:53 2008
@@ -433,6 +433,12 @@
             <multiplicity>*</multiplicity>
           </association>
         </field>
+        <field>
+          <name>sendOnScmFailure</name>
+          <version>1.1.2+</version>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
       </fields>
       <codeSegments>
         <codeSegment>

Modified: continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java (original)
+++ continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/AbstractContinuumNotifier.java Fri Sep 12 00:37:53 2008
@@ -22,6 +22,8 @@
 import org.apache.continuum.configuration.ContinuumConfigurationException;
 import org.apache.continuum.dao.BuildResultDao;
 import org.apache.continuum.dao.ProjectDao;
+import org.apache.continuum.dao.ProjectScmRootDao;
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.ContinuumException;
 import org.apache.maven.continuum.configuration.ConfigurationException;
 import org.apache.maven.continuum.configuration.ConfigurationLoadingException;
@@ -29,6 +31,7 @@
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
+import org.apache.maven.continuum.model.project.ProjectGroup;
 import org.apache.maven.continuum.model.project.ProjectNotifier;
 import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.apache.maven.continuum.store.ContinuumStoreException;
@@ -62,6 +65,11 @@
     private ProjectDao projectDao;
 
     /**
+     * @plexus.requirement
+     */
+    private ProjectScmRootDao projectScmRootDao;
+
+    /**
      * @plexus.configuration
      */
     private boolean alwaysSend = false;
@@ -135,6 +143,42 @@
         }
     }
 
+    public String getReportUrl( ProjectGroup projectGroup, ProjectScmRoot projectScmRoot, 
+                                ConfigurationService configurationService )
+        throws ContinuumException
+    {
+        try
+        {
+            if ( !configurationService.isLoaded() )
+            {
+                configurationService.reload();
+            }
+    
+            StringBuffer buf = new StringBuffer( configurationService.getUrl() );
+    
+            if ( projectGroup != null && projectScmRoot != null )
+            {
+                if ( !buf.toString().endsWith( "/" ) )                
+                {
+                    buf.append( "/" );
+                }
+
+                buf.append( "scmResult.action?projectScmRootId=" ).append( projectScmRoot.getId() )
+                   .append( "&projectGroupId=" ).append( projectGroup.getId() );
+            }
+    
+            return buf.toString();
+        }
+        catch ( ConfigurationLoadingException e )
+        {
+            throw new ContinuumException( "Can't obtain the base url from configuration.", e );
+        }
+        catch ( ContinuumConfigurationException e )
+        {
+            throw new ContinuumException( "Can't obtain the base url from configuration.", e );
+        }
+    }
+    
     /**
      * Determine if message must be sent
      *
@@ -233,6 +277,31 @@
         return false;
     }
 
+    public boolean shouldNotify( ProjectScmRoot projectScmRoot, ProjectNotifier projectNotifier )
+    {
+        if ( projectNotifier == null )
+        {
+            projectNotifier = new ProjectNotifier();
+        }
+
+        if ( projectScmRoot == null )
+        {
+            return false;
+        }
+
+        if ( alwaysSend )
+        {
+            return true;
+        }
+
+        if ( projectScmRoot.getState() == ContinuumProjectState.ERROR && projectNotifier.isSendOnScmFailure() )
+        {
+            return true;
+        }
+
+        return false;
+    }
+    
     protected BuildResult getPreviousBuild( Project project, BuildDefinition buildDef, BuildResult currentBuild )
         throws NotificationException
     {
@@ -291,4 +360,78 @@
             throw new NotificationException( "Unable to obtain project builds", e );
         }
     }
+    
+    protected String generateMessage( Project project, BuildResult build, ConfigurationService configurationService )
+        throws NotificationException
+    {
+        int state = project.getState();
+    
+        if ( build != null )
+        {
+            state = build.getState();
+        }
+    
+        String message;
+    
+        if ( state == ContinuumProjectState.OK )
+        {
+            message = "BUILD SUCCESSFUL: " + project.getName();
+        }
+        else if ( state == ContinuumProjectState.FAILED )
+        {
+            message = "BUILD FAILURE: " + project.getName();
+        }
+        else if ( state == ContinuumProjectState.ERROR )
+        {
+            message = "BUILD ERROR: " + project.getName();
+        }
+        else
+        {
+            log.warn( "Unknown build state " + state + " for project " + project.getId() );
+    
+            message = "ERROR: Unknown build state " + state + " for " + project.getName() + " project";
+        }
+    
+        try
+        {
+            return message + " " + getReportUrl( project, build, configurationService );
+        }
+        catch ( ContinuumException e )
+        {
+            throw new NotificationException( "Cannot generate message", e );
+        }
+    }
+    
+    protected String generateMessage( ProjectScmRoot projectScmRoot, ConfigurationService configurationService )
+        throws NotificationException
+    {
+        int state = projectScmRoot.getState();
+        String scmRootAddress = projectScmRoot.getScmRootAddress();
+    
+        String message;
+    
+        if ( state == ContinuumProjectState.UPDATED )
+        {
+            message = "PREPARE BUILD SUCCESSFUL: " + scmRootAddress;
+        }
+        else if ( state == ContinuumProjectState.ERROR )
+        {
+            message = "PREPARE BUILD ERROR: " + scmRootAddress;
+        }
+        else
+        {
+            log.warn( "Unknown prepare build state " + state + " for SCM root URL " + scmRootAddress );
+    
+            message = "ERROR: Unknown prepare build state " + state + " for SCM root URL" + scmRootAddress;
+        }
+    
+        try
+        {
+            return message + " " + getReportUrl( projectScmRoot.getProjectGroup(), projectScmRoot, configurationService );
+        }
+        catch ( ContinuumException e )
+        {
+            throw new NotificationException( "Cannot generate message", e );
+        }
+    }
 }

Modified: continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/MessageContext.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/MessageContext.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/MessageContext.java (original)
+++ continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-api/src/main/java/org/apache/maven/continuum/notification/MessageContext.java Fri Sep 12 00:37:53 2008
@@ -19,9 +19,11 @@
  * under the License.
  */
 
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
+import org.apache.maven.continuum.model.project.ProjectGroup;
 import org.apache.maven.continuum.model.project.ProjectNotifier;
 
 import java.util.List;
@@ -40,6 +42,8 @@
 
     private BuildResult buildResult;
 
+    private ProjectScmRoot projectScmRoot;
+
     public Project getProject()
     {
         return project;
@@ -79,4 +83,14 @@
     {
         this.buildResult = buildResult;
     }
+
+    public ProjectScmRoot getProjectScmRoot()
+    {
+        return projectScmRoot;
+    }
+
+    public void setProjectScmRoot( ProjectScmRoot projectScmRoot )
+    {
+        this.projectScmRoot = projectScmRoot;
+    }
 }

Modified: continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java (original)
+++ continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-irc/src/main/java/org/apache/maven/continuum/notification/irc/IrcContinuumNotifier.java Fri Sep 12 00:37:53 2008
@@ -19,7 +19,7 @@
  * under the License.
  */
 
-import org.apache.maven.continuum.ContinuumException;
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.configuration.ConfigurationService;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
@@ -29,7 +29,6 @@
 import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
 import org.apache.maven.continuum.notification.MessageContext;
 import org.apache.maven.continuum.notification.NotificationException;
-import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
 import org.codehaus.plexus.util.StringUtils;
 import org.schwering.irc.lib.IRCConnection;
@@ -232,11 +231,21 @@
 
         BuildResult build = context.getBuildResult();
 
+        ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
+
+        boolean isPrepareBuildComplete = 
+            messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE );
+        
+        if ( projectScmRoot == null && isPrepareBuildComplete )
+        {
+            return;
+        }
+        
         // ----------------------------------------------------------------------
         // If there wasn't any building done, don't notify
         // ----------------------------------------------------------------------
 
-        if ( build == null )
+        if ( build == null && !isPrepareBuildComplete )
         {
             return;
         }
@@ -245,38 +254,58 @@
         // Generate and send message
         // ----------------------------------------------------------------------
 
-        try
+        if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_COMPLETE ) )
         {
-            if ( messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_BUILD_COMPLETE ) )
+            for ( ProjectNotifier notifier : notifiers )
             {
-                for ( ProjectNotifier notifier : notifiers )
-                {
-                    buildComplete( project, notifier, build, buildDefinition );
-                }
+                buildComplete( project, notifier, build, buildDefinition );
             }
         }
-        catch ( ContinuumException e )
+        else if ( isPrepareBuildComplete )
         {
-            throw new NotificationException( "Error while notifiying.", e );
+            for ( ProjectNotifier notifier : notifiers )
+            {
+                prepareBuildComplete( projectScmRoot, notifier );
+            }
         }
     }
 
     private void buildComplete( Project project, ProjectNotifier projectNotifier, BuildResult build,
                                 BuildDefinition buildDef )
-        throws ContinuumException, NotificationException
+        throws NotificationException
     {
         // ----------------------------------------------------------------------
         // Check if the message should be sent at all
         // ----------------------------------------------------------------------
 
         BuildResult previousBuild = getPreviousBuild( project, buildDef, build );
-        Map<String, String> configuration = projectNotifier.getConfiguration();
 
         if ( !shouldNotify( build, previousBuild, projectNotifier ) )
         {
             return;
         }
 
+        sendMessage( projectNotifier.getConfiguration(), generateMessage( project, build, configurationService ) );
+    }
+
+    private void prepareBuildComplete( ProjectScmRoot projectScmRoot, ProjectNotifier projectNotifier )
+        throws NotificationException
+    {
+        // ----------------------------------------------------------------------
+        // Check if the message should be sent at all
+        // ----------------------------------------------------------------------
+        
+        if ( !shouldNotify( projectScmRoot, projectNotifier ) )
+        {
+            return;
+        }
+        
+        sendMessage( projectNotifier.getConfiguration(), generateMessage( projectScmRoot, configurationService ) );
+    }    
+
+    private void sendMessage( Map<String, String> configuration, String message )
+        throws NotificationException
+    {
         // ----------------------------------------------------------------------
         // Gather configuration values
         // ----------------------------------------------------------------------
@@ -327,48 +356,14 @@
         {
             IRCConnection ircConnection = getIRConnection( host, port, password, nickName, alternateNickName, userName,
                                                            fullName, channel, isSsl );
-            ircConnection.doPrivmsg( channel, generateMessage( project, build ) );
+            ircConnection.doPrivmsg( channel, message );
         }
         catch ( IOException e )
         {
             throw new NotificationException( "Exception while checkConnection to irc ." + host, e );
         }
     }
-
-    private String generateMessage( Project project, BuildResult build )
-        throws ContinuumException
-    {
-        int state = project.getState();
-
-        if ( build != null )
-        {
-            state = build.getState();
-        }
-
-        String message;
-
-        if ( state == ContinuumProjectState.OK )
-        {
-            message = "BUILD SUCCESSFUL: " + project.getName();
-        }
-        else if ( state == ContinuumProjectState.FAILED )
-        {
-            message = "BUILD FAILURE: " + project.getName();
-        }
-        else if ( state == ContinuumProjectState.ERROR )
-        {
-            message = "BUILD ERROR: " + project.getName();
-        }
-        else
-        {
-            log.warn( "Unknown build state " + state + " for project " + project.getId() );
-
-            message = "ERROR: Unknown build state " + state + " for " + project.getName() + " project";
-        }
-
-        return message + " " + getReportUrl( project, build, configurationService );
-    }
-
+    
     /**
      * Treats IRC events. The most of them are just printed.
      */

Modified: continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java (original)
+++ continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-jabber/src/main/java/org/apache/maven/continuum/notification/jabber/JabberContinuumNotifier.java Fri Sep 12 00:37:53 2008
@@ -19,7 +19,7 @@
  * under the License.
  */
 
-import org.apache.maven.continuum.ContinuumException;
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.configuration.ConfigurationService;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
@@ -29,7 +29,6 @@
 import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
 import org.apache.maven.continuum.notification.MessageContext;
 import org.apache.maven.continuum.notification.NotificationException;
-import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.codehaus.plexus.jabber.JabberClient;
 import org.codehaus.plexus.jabber.JabberClientException;
 import org.codehaus.plexus.util.StringUtils;
@@ -114,11 +113,21 @@
         List<ProjectNotifier> notifiers = context.getNotifiers();
         BuildDefinition buildDefinition = context.getBuildDefinition();
         BuildResult build = context.getBuildResult();
+        ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
+
+        boolean isPrepareBuildComplete = 
+            messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE );
+
+        if ( projectScmRoot == null && isPrepareBuildComplete )
+        {
+            return;
+        }
+        
         // ----------------------------------------------------------------------
         // If there wasn't any building done, don't notify
         // ----------------------------------------------------------------------
 
-        if ( build == null )
+        if ( build == null && !isPrepareBuildComplete )
         {
             return;
         }
@@ -152,7 +161,14 @@
         {
             for ( ProjectNotifier notifier : notifiers )
             {
-                sendMessage( project, notifier, build, buildDefinition );
+                buildComplete( project, notifier, build, buildDefinition );
+            }
+        }
+        else if ( isPrepareBuildComplete )
+        {
+            for ( ProjectNotifier notifier : notifiers )
+            {
+                prepareBuildComplete( projectScmRoot, notifier );
             }
         }
     }
@@ -161,45 +177,9 @@
     //
     // ----------------------------------------------------------------------
 
-    private String generateMessage( Project project, BuildResult build )
-        throws ContinuumException
-    {
-        int state = project.getState();
-
-        if ( build != null )
-        {
-            state = build.getState();
-        }
-
-        String message;
-
-        if ( state == ContinuumProjectState.OK )
-        {
-            message = "BUILD SUCCESSFUL: " + project.getName();
-        }
-        else if ( state == ContinuumProjectState.FAILED )
-        {
-            message = "BUILD FAILURE: " + project.getName();
-        }
-        else if ( state == ContinuumProjectState.ERROR )
-        {
-            message = "BUILD ERROR: " + project.getName();
-        }
-        else
-        {
-            log.warn( "Unknown build state " + state + " for project " + project.getId() );
-
-            message = "ERROR: Unknown build state " + state + " for " + project.getName() + " project";
-        }
-
-        return message + " " + getReportUrl( project, build, configurationService );
-    }
-
-    private void sendMessage( Project project, ProjectNotifier notifier, BuildResult build, BuildDefinition buildDef )
+    private void buildComplete( Project project, ProjectNotifier notifier, BuildResult build, BuildDefinition buildDef )
         throws NotificationException
     {
-        String message;
-
         // ----------------------------------------------------------------------
         // Check if the mail should be sent at all
         // ----------------------------------------------------------------------
@@ -211,26 +191,34 @@
             return;
         }
 
-        try
-        {
-            message = generateMessage( project, build );
-        }
-        catch ( ContinuumException e )
+        sendMessage( notifier.getConfiguration(), generateMessage( project, build, configurationService ) );
+    }
+    
+    private void prepareBuildComplete( ProjectScmRoot projectScmRoot, ProjectNotifier notifier )
+        throws NotificationException
+    {
+        if ( !shouldNotify( projectScmRoot, notifier ) )
         {
-            throw new NotificationException( "Can't generate the message.", e );
+            return;
         }
+        
+        sendMessage( notifier.getConfiguration(), generateMessage( projectScmRoot, configurationService ) );
+    }
+    
+    private void sendMessage( Map<String, String> configuration, String message )
+        throws NotificationException
+    {
+        jabberClient.setHost( getHost( configuration ) );
 
-        jabberClient.setHost( getHost( notifier.getConfiguration() ) );
-
-        jabberClient.setPort( getPort( notifier.getConfiguration() ) );
+        jabberClient.setPort( getPort( configuration ) );
 
-        jabberClient.setUser( getUsername( notifier.getConfiguration() ) );
+        jabberClient.setUser( getUsername( configuration ) );
 
-        jabberClient.setPassword( getPassword( notifier.getConfiguration() ) );
+        jabberClient.setPassword( getPassword( configuration ) );
 
-        jabberClient.setImDomainName( getImDomainName( notifier.getConfiguration() ) );
+        jabberClient.setImDomainName( getImDomainName( configuration ) );
 
-        jabberClient.setSslConnection( isSslConnection( notifier.getConfiguration() ) );
+        jabberClient.setSslConnection( isSslConnection( configuration ) );
 
         try
         {
@@ -238,14 +226,13 @@
 
             jabberClient.logon();
 
-            if ( notifier.getConfiguration() != null &&
-                StringUtils.isNotEmpty( (String) notifier.getConfiguration().get( ADDRESS_FIELD ) ) )
+            if ( configuration != null && StringUtils.isNotEmpty( (String) configuration.get( ADDRESS_FIELD ) ) )
             {
-                String address = (String) notifier.getConfiguration().get( ADDRESS_FIELD );
+                String address = (String) configuration.get( ADDRESS_FIELD );
                 String[] recipients = StringUtils.split( address, "," );
                 for ( String recipient : recipients )
                 {
-                    if ( isGroup( notifier.getConfiguration() ) )
+                    if ( isGroup( configuration ) )
                     {
                         jabberClient.sendMessageToGroup( recipient, message );
                     }

Modified: continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java (original)
+++ continuum/branches/continuum-transient-state/continuum-notifiers/continuum-notifier-msn/src/main/java/org/apache/maven/continuum/notification/msn/MsnContinuumNotifier.java Fri Sep 12 00:37:53 2008
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.ContinuumException;
 import org.apache.maven.continuum.configuration.ConfigurationService;
 import org.apache.maven.continuum.model.project.BuildDefinition;
@@ -103,11 +104,21 @@
 
         BuildResult build = context.getBuildResult();
 
+        ProjectScmRoot projectScmRoot = context.getProjectScmRoot();
+
+        boolean isPrepareBuildComplete = 
+            messageId.equals( ContinuumNotificationDispatcher.MESSAGE_ID_PREPARE_BUILD_COMPLETE );
+        
+        if ( projectScmRoot == null && isPrepareBuildComplete )
+        {
+            return;
+        }
+        
         // ----------------------------------------------------------------------
         // If there wasn't any building done, don't notify
         // ----------------------------------------------------------------------
 
-        if ( build == null )
+        if ( build == null && !isPrepareBuildComplete )
         {
             return;
         }
@@ -143,51 +154,22 @@
                 buildComplete( project, notifier, build, buildDefinition );
             }
         }
+        else if ( isPrepareBuildComplete )
+        {
+            for ( ProjectNotifier notifier : notifiers )
+            {
+                prepareBuildComplete( projectScmRoot, notifier );
+            }
+        }
     }
 
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
 
-    private String generateMessage( Project project, BuildResult build )
-        throws ContinuumException
-    {
-        int state = project.getState();
-
-        if ( build != null )
-        {
-            state = build.getState();
-        }
-
-        String message;
-
-        if ( state == ContinuumProjectState.OK )
-        {
-            message = "BUILD SUCCESSFUL: " + project.getName();
-        }
-        else if ( state == ContinuumProjectState.FAILED )
-        {
-            message = "BUILD FAILURE: " + project.getName();
-        }
-        else if ( state == ContinuumProjectState.ERROR )
-        {
-            message = "BUILD ERROR: " + project.getName();
-        }
-        else
-        {
-            log.warn( "Unknown build state " + state + " for project " + project.getId() );
-
-            message = "ERROR: Unknown build state " + state + " for " + project.getName() + " project";
-        }
-
-        return message + " " + getReportUrl( project, build, configurationService );
-    }
-
     private void buildComplete( Project project, ProjectNotifier notifier, BuildResult build, BuildDefinition buildDef )
         throws NotificationException
     {
-        String message;
-
         // ----------------------------------------------------------------------
         // Check if the message should be sent at all
         // ----------------------------------------------------------------------
@@ -199,27 +181,34 @@
             return;
         }
 
-        try
-        {
-            message = generateMessage( project, build );
-        }
-        catch ( ContinuumException e )
+        sendMessage( notifier.getConfiguration(), generateMessage( project, build, configurationService ) );
+    }
+    
+    private void prepareBuildComplete( ProjectScmRoot projectScmRoot, ProjectNotifier notifier )
+        throws NotificationException
+    {
+        if ( !shouldNotify( projectScmRoot, notifier ) )
         {
-            throw new NotificationException( "Can't generate the message.", e );
+            return;
         }
+        
+        sendMessage( notifier.getConfiguration(), generateMessage( projectScmRoot, configurationService ) );
+    }
+    
+    private void sendMessage( Map<String, String> configuration, String message )
+        throws NotificationException
+    {
+        msnClient.setLogin( getUsername( configuration ) );
 
-        msnClient.setLogin( getUsername( notifier.getConfiguration() ) );
-
-        msnClient.setPassword( getPassword( notifier.getConfiguration() ) );
+        msnClient.setPassword( getPassword( configuration ) );
 
         try
         {
             msnClient.login();
 
-            if ( notifier.getConfiguration() != null &&
-                StringUtils.isNotEmpty( (String) notifier.getConfiguration().get( ADDRESS_FIELD ) ) )
+            if ( configuration != null && StringUtils.isNotEmpty( (String) configuration.get( ADDRESS_FIELD ) ) )
             {
-                String address = (String) notifier.getConfiguration().get( ADDRESS_FIELD );
+                String address = (String) configuration.get( ADDRESS_FIELD );
                 String[] recipients = StringUtils.split( address, "," );
                 for ( String recipient : recipients )
                 {

Modified: continuum/branches/continuum-transient-state/continuum-store/src/main/java/org/apache/continuum/dao/AbstractDao.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-store/src/main/java/org/apache/continuum/dao/AbstractDao.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-store/src/main/java/org/apache/continuum/dao/AbstractDao.java (original)
+++ continuum/branches/continuum-transient-state/continuum-store/src/main/java/org/apache/continuum/dao/AbstractDao.java Fri Sep 12 00:37:53 2008
@@ -58,8 +58,6 @@
     protected static final String BUILD_TEMPLATE_BUILD_DEFINITIONS = "build-template-build-definitions";
     
     protected static final String PROJECT_WITH_SCM_RESULT_FETCH_GROUP = "project-with-scm-result";
-    
-    protected static final String PROJECTGROUP_SCM_FETCH_GROUP = "projectgroup-scm";
 
     /**
      * @plexus.requirement

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/component/NotifierSummaryAction.java Fri Sep 12 00:37:53 2008
@@ -320,6 +320,14 @@
             }
             sb.append( "Warning" );
         }
+        if ( notifier.isSendOnScmFailure() )
+        {
+            if ( sb.length() > 0 )
+            {
+                sb.append( '/' );
+            }
+            sb.append( "SCM Failure" );
+        }
         ns.setEvents( sb.toString() );
 
         ns.setEnabled( notifier.isEnabled() );

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/notifier/AbstractNotifierEditActionSupport.java Fri Sep 12 00:37:53 2008
@@ -75,6 +75,13 @@
     private boolean sendOnWarning;
 
     /**
+     * Detemines if the notifier should fire when prepare build resulted in any error(s).<p>
+     * <code>true</code> implies notifier executes when any error(s) is/are detected
+     * for the build.
+     */
+    private boolean sendOnScmFailure;
+    
+    /**
      * Detemines if the save operation returns to the project group notifier page or not.<p>
      * <code>true</code> implies return to the project group notifier page.
      */
@@ -137,6 +144,8 @@
 
         notifier.setSendOnWarning( isSendOnWarning() );
 
+        notifier.setSendOnScmFailure( isSendOnScmFailure() );
+
         setNotifierConfiguration( notifier );
 
         saveNotifier( notifier );
@@ -186,6 +195,8 @@
 
         setSendOnWarning( notifier.isSendOnWarning() );
 
+        setSendOnScmFailure( notifier.isSendOnScmFailure() );
+
         initConfiguration( notifier.getConfiguration() );
 
         return SUCCESS;
@@ -276,6 +287,16 @@
         this.sendOnWarning = sendOnWarning;
     }
 
+    public boolean isSendOnScmFailure()
+    {
+        return sendOnScmFailure;
+    }
+
+    public void setSendOnScmFailure( boolean sendOnScmFailure )
+    {
+        this.sendOnScmFailure = sendOnScmFailure;
+    }
+    
     /**
      * @param notifierId the notifierId to set
      */

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/resources/localization/Continuum.properties
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/resources/localization/Continuum.properties?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/resources/localization/Continuum.properties (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/resources/localization/Continuum.properties Fri Sep 12 00:37:53 2008
@@ -480,6 +480,7 @@
 notifier.event.sendOnFailure = Send on Failure
 notifier.event.sendOnError = Send on Error
 notifier.event.sendOnWarning = Send on Warning
+notifier.event.sendOnScmFailure = Send On SCM Failure
 
 # ----------------------------------------------------------------------
 # Page: BuildResults

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierIrc.jsp
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierIrc.jsp?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierIrc.jsp (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierIrc.jsp Fri Sep 12 00:37:53 2008
@@ -64,6 +64,7 @@
                 <ww:checkbox label="%{getText('notifier.event.sendOnFailure')}" name="sendOnFailure" value="sendOnFailure" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnError')}" name="sendOnError" value="sendOnError" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnWarning')}" name="sendOnWarning" value="sendOnWarning" fieldValue="true"/>
+                <ww:checkbox label="%{getText('notifier.event.sendOnScmFailure')}" name="sendOnScmFailure" value="sendOnScmFailure" fieldValue="true"/>
               </tbody>
             </table>
             <div class="functnbar3">

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierJabber.jsp
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierJabber.jsp?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierJabber.jsp (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierJabber.jsp Fri Sep 12 00:37:53 2008
@@ -63,6 +63,7 @@
                 <ww:checkbox label="%{getText('notifier.event.sendOnFailure')}" name="sendOnFailure" value="sendOnFailure" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnError')}" name="sendOnError" value="sendOnError" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnWarning')}" name="sendOnWarning" value="sendOnWarning" fieldValue="true"/>
+                <ww:checkbox label="%{getText('notifier.event.sendOnScmFailure')}" name="sendOnScmFailure" value="sendOnScmFailure" fieldValue="true"/>
               </tbody>
             </table>
             <div class="functnbar3">

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMail.jsp Fri Sep 12 00:37:53 2008
@@ -58,6 +58,7 @@
                 <ww:checkbox label="%{getText('notifier.event.sendOnFailure')}" name="sendOnFailure" value="sendOnFailure" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnError')}" name="sendOnError" value="sendOnError" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnWarning')}" name="sendOnWarning" value="sendOnWarning" fieldValue="true"/>
+                <ww:checkbox label="%{getText('notifier.event.sendOnScmFailure')}" name="sendOnScmFailure" value="sendOnScmFailure" fieldValue="true"/>
               </tbody>
             </table>
             <div class="functnbar3">

Modified: continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMsn.jsp
URL: http://svn.apache.org/viewvc/continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMsn.jsp?rev=694630&r1=694629&r2=694630&view=diff
==============================================================================
--- continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMsn.jsp (original)
+++ continuum/branches/continuum-transient-state/continuum-webapp/src/main/webapp/WEB-INF/jsp/notifier/notifierMsn.jsp Fri Sep 12 00:37:53 2008
@@ -58,6 +58,7 @@
                 <ww:checkbox label="%{getText('notifier.event.sendOnFailure')}" name="sendOnFailure" value="sendOnFailure" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnError')}" name="sendOnError" value="sendOnError" fieldValue="true"/>
                 <ww:checkbox label="%{getText('notifier.event.sendOnWarning')}" name="sendOnWarning" value="sendOnWarning" fieldValue="true"/>
+                <ww:checkbox label="%{getText('notifier.event.sendOnScmFailure')}" name="sendOnScmFailure" value="sendOnScmFailure" fieldValue="true"/>
               </tbody>
             </table>
             <div class="functnbar3">