add back in the changes made for flat multi-module support
(note: some parts needs to be reviewed and updated as necessary before merging to trunk)


git-svn-id: https://svn.apache.org/repos/asf/continuum/branches/continuum-flat-multi-module@943159 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/continuum-api/src/main/java/org/apache/continuum/buildmanager/BuildsManager.java b/continuum-api/src/main/java/org/apache/continuum/buildmanager/BuildsManager.java
index c0150cd..8a34198 100644
--- a/continuum-api/src/main/java/org/apache/continuum/buildmanager/BuildsManager.java
+++ b/continuum-api/src/main/java/org/apache/continuum/buildmanager/BuildsManager.java
@@ -92,13 +92,15 @@
      * @param projectId
      * @param projectName
      * @param workingDirectory
+     * @param scmRootUrl TODO
      * @param scmUsername
      * @param scmPassword
      * @param defaultBuildDefinition
+     * @param subProjects TODO
      * @throws BuildManagerException
      */
-    void checkoutProject( int projectId, String projectName, File workingDirectory, String scmUsername,
-                          String scmPassword, BuildDefinition defaultBuildDefinition )
+	void checkoutProject( int projectId, String projectName, File workingDirectory, String scmRootUrl,
+			                    String scmUsername, String scmPassword, BuildDefinition defaultBuildDefinition, List<Project> subProjects )
         throws BuildManagerException;
 
     /**
diff --git a/continuum-api/src/main/java/org/apache/continuum/taskqueue/CheckOutTask.java b/continuum-api/src/main/java/org/apache/continuum/taskqueue/CheckOutTask.java
index e72f3b3..132649d 100644
--- a/continuum-api/src/main/java/org/apache/continuum/taskqueue/CheckOutTask.java
+++ b/continuum-api/src/main/java/org/apache/continuum/taskqueue/CheckOutTask.java
@@ -20,7 +20,9 @@
  */
 
 import java.io.File;
+import java.util.List;
 
+import org.apache.maven.continuum.model.project.Project;
 import org.codehaus.plexus.taskqueue.Task;
 
 /**
@@ -39,9 +41,13 @@
     private final String scmUserName;
 
     private final String scmPassword;
-
+    
+    private final String scmRootUrl;
+    
+    private final List<Project> projectsWithCommonScmRoot;
+    
     public CheckOutTask( int projectId, File workingDirectory, String projectName, String scmUserName,
-                         String scmPassword )
+    			String scmPassword, String scmRootUrl, List<Project> projectsWithCommonScmRoot )
     {
         this.projectId = projectId;
 
@@ -52,6 +58,10 @@
         this.scmUserName = scmUserName;
 
         this.scmPassword = scmPassword;
+
+        this.scmRootUrl = scmRootUrl;
+        
+        this.projectsWithCommonScmRoot = projectsWithCommonScmRoot;
     }
 
     public int getProjectId()
@@ -85,9 +95,18 @@
         return scmPassword;
     }
 
-
     public int getHashCode()
     {
         return this.hashCode();
     }
+    
+    public String getScmRootUrl()
+    {
+        return scmRootUrl;
+    }
+
+    public List<Project> getProjectsWithCommonScmRoot()
+    {
+        return projectsWithCommonScmRoot;
+    } 
 }
diff --git a/continuum-api/src/main/java/org/apache/maven/continuum/Continuum.java b/continuum-api/src/main/java/org/apache/maven/continuum/Continuum.java
index 828ec0b..e367763 100644
--- a/continuum-api/src/main/java/org/apache/maven/continuum/Continuum.java
+++ b/continuum-api/src/main/java/org/apache/maven/continuum/Continuum.java
@@ -322,13 +322,14 @@
      * @param useCredentialsCache      whether to use cached scm account credentials or not
      * @param loadRecursiveProjects    if multi modules project record all projects (if false only root project added)
      * @param buildDefintionTemplateId buildDefintionTemplateId
+     * @param checkoutInSingleDirectory TODO
      * @return a holder with the projects, project groups and errors occurred during the project adding
      * @throws ContinuumException
      */
     public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId,
                                                               boolean checkProtocol, boolean useCredentialsCache,
                                                               boolean loadRecursiveProjects,
-                                                              int buildDefintionTemplateId )
+                                                              int buildDefintionTemplateId, boolean checkoutInSingleDirectory )
         throws ContinuumException;
 
     /**
diff --git a/continuum-api/src/main/java/org/apache/maven/continuum/execution/ContinuumBuildExecutor.java b/continuum-api/src/main/java/org/apache/maven/continuum/execution/ContinuumBuildExecutor.java
index 368768c..0acc965 100644
--- a/continuum-api/src/main/java/org/apache/maven/continuum/execution/ContinuumBuildExecutor.java
+++ b/continuum-api/src/main/java/org/apache/maven/continuum/execution/ContinuumBuildExecutor.java
@@ -55,7 +55,7 @@
         throws ContinuumBuildExecutorException;
 
     //TODO: Move as a plugin
-    void backupTestFiles( Project project, int buildId );
+    void backupTestFiles( Project project, int buildId, String projectScmRootUrl, List<Project> projectsWithCommonScmRoot );
 
     boolean shouldBuild( List<ChangeSet> changes, Project continuumProject, File workingDirectory,
                          BuildDefinition buildDefinition )
diff --git a/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuilder.java b/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuilder.java
index 1caa092..182b61e 100644
--- a/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuilder.java
+++ b/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuilder.java
@@ -35,12 +35,14 @@
         throws ContinuumProjectBuilderException;
 
     ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
-                                                              boolean recursiveProjects )
+                                                              boolean recursiveProjects,
+                                                              boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException;
 
     ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
                                                               boolean recursiveProjects,
-                                                              BuildDefinitionTemplate buildDefinitionTemplate )
+                                                              BuildDefinitionTemplate buildDefinitionTemplate,
+                                                              boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException;
 
     BuildDefinitionTemplate getDefaultBuildDefinitionTemplate()
diff --git a/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuildingResult.java b/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuildingResult.java
index 362980b..5666619 100644
--- a/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuildingResult.java
+++ b/continuum-api/src/main/java/org/apache/maven/continuum/project/builder/ContinuumProjectBuildingResult.java
@@ -92,6 +92,8 @@
     private final Map<String, String> errors = new HashMap<String, String>();
 
     private static final String LS = System.getProperty( "line.separator" );
+    
+    private Project rootProject;
 
     public void addProject( Project project )
     {
@@ -222,4 +224,14 @@
         }
         return message.toString();
     }
+
+    public Project getRootProject()
+    {
+        return rootProject;
+    }
+
+    public void setRootProject( Project rootProject )
+    {
+        this.rootProject = rootProject;
+    }
 }
diff --git a/continuum-api/src/main/java/org/apache/maven/continuum/utils/WorkingDirectoryService.java b/continuum-api/src/main/java/org/apache/maven/continuum/utils/WorkingDirectoryService.java
index 5caa5ba..d65497d 100644
--- a/continuum-api/src/main/java/org/apache/maven/continuum/utils/WorkingDirectoryService.java
+++ b/continuum-api/src/main/java/org/apache/maven/continuum/utils/WorkingDirectoryService.java
@@ -22,6 +22,7 @@
 import org.apache.maven.continuum.model.project.Project;
 
 import java.io.File;
+import java.util.List;
 
 /**
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
@@ -32,4 +33,10 @@
     String ROLE = WorkingDirectoryService.class.getName();
 
     File getWorkingDirectory( Project project );
+
+    File getWorkingDirectory( Project project, boolean shouldSet );
+    
+    File getWorkingDirectory( Project project, String projectScmRootUrl, List<Project> projects );
+    
+    File getWorkingDirectory( Project project, String projectScmRootUrl, List<Project> projects, boolean shouldSet );
 }
diff --git a/continuum-buildagent/continuum-buildagent-core/src/main/java/org/apache/continuum/buildagent/ContinuumBuildAgentServiceImpl.java b/continuum-buildagent/continuum-buildagent-core/src/main/java/org/apache/continuum/buildagent/ContinuumBuildAgentServiceImpl.java
index f2b191b..d2f4997 100644
--- a/continuum-buildagent/continuum-buildagent-core/src/main/java/org/apache/continuum/buildagent/ContinuumBuildAgentServiceImpl.java
+++ b/continuum-buildagent/continuum-buildagent-core/src/main/java/org/apache/continuum/buildagent/ContinuumBuildAgentServiceImpl.java
@@ -998,7 +998,9 @@
         {
             for ( Iterator modules = model.getModules().iterator(); modules.hasNext(); )
             {
-                processProject( workingDirectory + "/" + modules.next().toString(), "pom.xml", autoVersionSubmodules,
+                String module = StringUtils.replace( modules.next().toString(), '\\', '/' );
+            	
+                processProject( workingDirectory + "/" + module, "pom.xml", autoVersionSubmodules,
                                 projects );
             }
         }
diff --git a/continuum-commons/pom.xml b/continuum-commons/pom.xml
index d65ec58..fedc577 100644
--- a/continuum-commons/pom.xml
+++ b/continuum-commons/pom.xml
@@ -48,6 +48,10 @@
       <scope>runtime</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.maven.release</groupId>
+      <artifactId>maven-release-manager</artifactId>
+    </dependency>
+    <dependency>
       <groupId>javax.annotation</groupId>
       <artifactId>jsr250-api</artifactId>
     </dependency>    
@@ -67,7 +71,35 @@
       <groupId>org.slf4j</groupId>
       <artifactId>jcl-over-slf4j</artifactId>
       <scope>runtime</scope>
-    </dependency>    
+    </dependency>   
+    <dependency>
+      <groupId>org.jmock</groupId>
+      <artifactId>jmock-junit3</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <!-- dependency of jmock3 -->
+    <dependency>
+      <groupId>cglib</groupId>
+      <artifactId>cglib-nodep</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <!-- dependency of jmock3 -->
+    <dependency>
+      <groupId>org.objenesis</groupId>
+      <artifactId>objenesis</artifactId>  
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jmock</groupId>
+      <artifactId>jmock</artifactId>
+      <version>2.4.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock</artifactId>
+      <scope>test</scope>
+    </dependency> 
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
diff --git a/continuum-commons/src/main/java/org/apache/maven/continuum/utils/ChrootJailWorkingDirectoryService.java b/continuum-commons/src/main/java/org/apache/maven/continuum/utils/ChrootJailWorkingDirectoryService.java
index 07c44b5..8d01686 100644
--- a/continuum-commons/src/main/java/org/apache/maven/continuum/utils/ChrootJailWorkingDirectoryService.java
+++ b/continuum-commons/src/main/java/org/apache/maven/continuum/utils/ChrootJailWorkingDirectoryService.java
@@ -20,6 +20,8 @@
  */
 
 import java.io.File;
+import java.util.List;
+
 import javax.annotation.Resource;
 
 import org.apache.maven.continuum.configuration.ConfigurationService;
@@ -65,10 +67,25 @@
 
     public File getWorkingDirectory( Project project )
     {
+    	return getWorkingDirectory( project, true );
+    }
+
+    public File getWorkingDirectory( Project project, boolean shouldSet )
+    {
         ProjectGroup projectGroup = project.getProjectGroup();
 
         File f = new File( getChrootJailDirectory(), projectGroup.getGroupId() );
         f = new File( f, getConfigurationService().getWorkingDirectory().getPath() );
         return new File( f, Integer.toString( project.getId() ) );
     }
+    
+    public File getWorkingDirectory( Project project, String projectScmRoot, List<Project> projects )
+    {
+        return getWorkingDirectory( project, true );
+    }
+
+    public File getWorkingDirectory( Project project, String projectScmRoot, List<Project> projects, boolean shouldSet )
+    {
+        return getWorkingDirectory( project, shouldSet );
+    }
 }
diff --git a/continuum-commons/src/main/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryService.java b/continuum-commons/src/main/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryService.java
index 3952b8a..08b5994 100644
--- a/continuum-commons/src/main/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryService.java
+++ b/continuum-commons/src/main/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryService.java
@@ -21,9 +21,11 @@
 
 import org.apache.maven.continuum.configuration.ConfigurationService;
 import org.apache.maven.continuum.model.project.Project;
+import org.codehaus.plexus.util.StringUtils;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
+import java.util.List;
 
 import javax.annotation.Resource;
 
@@ -54,19 +56,94 @@
 
     public File getWorkingDirectory( Project project )
     {
+    	return getWorkingDirectory( project, null, null );
+    }
+
+    public File getWorkingDirectory( Project project, boolean shouldSet )
+    {
+        return getWorkingDirectory( project, null, null, shouldSet );
+    }
+
+    /**
+     * 
+     * @param project
+     * @param projectScmRoot
+     * @param projects projects under the same projectScmRoot
+     * @return
+     */
+    public File getWorkingDirectory( Project project, String projectScmRoot, List<Project> projects )
+    {
+        return getWorkingDirectory( project, projectScmRoot, projects, true );
+    }
+
+    /**
+     * 
+     * @param project
+     * @param projectScmRoot
+     * @param projects projects under the same projectScmRoot
+     * @param shouldSet
+     * @return
+     */
+    public File getWorkingDirectory( Project project, String projectScmRoot, List<Project> projects, boolean shouldSet )
+    {
 //        TODO: Enable, this is what we really want
 //        ContinuumProjectGroup projectGroup = project.getProjectGroup();
 //
 //        return new File( projectGroup.getWorkingDirectory(),
 //                         project.getPath() );
 
-        if ( project.getWorkingDirectory() == null )
+        String workingDirectory = project.getWorkingDirectory();
+    	
+        if ( project.getWorkingDirectory() == null || "".equals( project.getWorkingDirectory() ) )
+        {   
+            if ( project.isCheckedOutInSingleDirectory() && projectScmRoot != null && !"".equals( projectScmRoot ) )
+            {                
+                Project rootProject = project;
+                if( projects != null )
+                {
+                    // the root project should have the lowest id since it's always added first                    
+                    for( Project projectUnderScmRoot : projects )
+                    {
+                        if( projectUnderScmRoot.getId() < rootProject.getId() )
+                        {
+                            rootProject = projectUnderScmRoot;
+                        }
+                    }
+                }                
+                
+             // determine the path
+                String projectScmUrl = project.getScmUrl();
+                int indexDiff = StringUtils.differenceAt( projectScmUrl, projectScmRoot );
+                                
+                String pathToProject = "";
+                if( indexDiff != -1 )
+                {
+                    pathToProject = projectScmUrl.substring( indexDiff );
+                }
+                
+                if( pathToProject.startsWith( "\\" ) || pathToProject.startsWith( "/" ) )
+                {
+                    workingDirectory = Integer.toString( rootProject.getId() ) + pathToProject;
+                }
+                else
+                {
+                    workingDirectory = Integer.toString( rootProject.getId() ) + File.separatorChar + pathToProject;
+                }                
+            }
+            else
+            {
+                workingDirectory = Integer.toString( project.getId() );
+            }
+        }
+    	
+        if ( shouldSet )
         {
-            project.setWorkingDirectory( Integer.toString( project.getId() ) );
+            project.setWorkingDirectory( workingDirectory );
         }
 
         File workDir;
-        File projectWorkingDirectory = new File( project.getWorkingDirectory() );
+        File projectWorkingDirectory = new File( workingDirectory );
+        
         if ( projectWorkingDirectory.isAbsolute() )
         {
             // clean the project working directory path if it's a subdirectory of the global working directory
@@ -79,15 +156,22 @@
                 {
                     pwd = pwd.substring( 1 );
                 }
-                project.setWorkingDirectory( pwd );
+               
+                if ( shouldSet )
+                {
+                    project.setWorkingDirectory( pwd );
+                }
             }
 
             workDir = projectWorkingDirectory;
         }
         else
         {
-            workDir = new File( getConfigurationService().getWorkingDirectory(), project.getWorkingDirectory() );
+            File baseWorkingDir = getConfigurationService().getWorkingDirectory();            
+        	            
+            workDir = new File( baseWorkingDir, workingDirectory );
         }
+        
         return workDir;
     }
 }
diff --git a/continuum-commons/src/test/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryServiceTest.java b/continuum-commons/src/test/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryServiceTest.java
new file mode 100644
index 0000000..37765b2
--- /dev/null
+++ b/continuum-commons/src/test/java/org/apache/maven/continuum/utils/DefaultWorkingDirectoryServiceTest.java
@@ -0,0 +1,174 @@
+package org.apache.maven.continuum.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.continuum.configuration.ConfigurationService;
+import org.apache.maven.continuum.model.project.Project;
+import org.apache.maven.shared.release.util.ReleaseUtil;
+import org.codehaus.plexus.spring.PlexusInSpringTestCase;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit3.JUnit3Mockery;
+
+/**
+ * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
+ * @version 
+ */
+public class DefaultWorkingDirectoryServiceTest
+    extends PlexusInSpringTestCase
+{
+    private DefaultWorkingDirectoryService workingDirectoryService;
+    
+    private Mockery context;
+    
+    private ConfigurationService configurationService;
+    
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+        
+        context = new JUnit3Mockery();
+        
+        configurationService = context.mock( ConfigurationService.class );
+        
+        workingDirectoryService = ( DefaultWorkingDirectoryService ) lookup( WorkingDirectoryService.class );
+        
+        workingDirectoryService.setConfigurationService( configurationService );
+    }
+    
+    private Project createProject( int id, String groupId, String artifactId, String version, String scmUrl,
+                                   boolean checkedOutInSingleDirectory )
+    {
+        Project project = new Project();        
+        project.setId( id );
+        project.setGroupId( groupId );
+        project.setArtifactId( artifactId );
+        project.setVersion( version );
+        project.setScmUrl( scmUrl );
+        project.setCheckedOutInSingleDirectory( checkedOutInSingleDirectory );
+        
+        return project;
+    }
+    
+    public void testGetWorkingDirectoryOfSingleCheckoutFlatMultiModules()
+        throws Exception
+    {        
+        List<Project> projects = new ArrayList<Project>();
+        
+        Project project = createProject( 7, "org.apache.continuum", "module-a", "1.0-SNAPSHOT",
+                                         "scm:local:src/test-projects:flat-multi-module/module-a", true );
+        
+        projects.add( project );
+        
+        projects.add( createProject( 8, "org.apache.continuum", "module-b", "1.0-SNAPSHOT",
+                                     "scm:local:src/test-projects:flat-multi-module/module-b", true ) );
+                
+        projects.add( createProject( 6, "org.apache.continuum", "parent-project", "1.0-SNAPSHOT",
+                                     "scm:local:src/test-projects:flat-multi-module/parent-project", true ) );
+         
+        final File baseWorkingDirectory = new File( getBasedir(), "target" + File.separatorChar + "working-directory" );
+           
+        context.checking( new Expectations()
+        {
+            {
+                exactly( 2 ).of( configurationService ).getWorkingDirectory();
+                will( returnValue( baseWorkingDirectory ) );                
+            }} );
+        
+        File projectWorkingDirectory =
+            workingDirectoryService.getWorkingDirectory( project, "scm:local:src/test-projects:flat-multi-module",
+                                                         projects );
+        
+        assertEquals( "Incorrect working directory for flat multi-module project", baseWorkingDirectory +
+		              File.separator + "6" + File.separator + "module-a", projectWorkingDirectory.getPath() );
+        
+        // test if separator is appended at the end of the scm root url
+        projectWorkingDirectory =
+            workingDirectoryService.getWorkingDirectory( project, "scm:local:src/test-projects:flat-multi-module/",
+                                                         projects );
+        
+        assertEquals( "Incorrect working directory for flat multi-module project", baseWorkingDirectory +
+                      File.separator + "6" + File.separator + "module-a", projectWorkingDirectory.getPath() );            
+    }
+
+    public void testGetWorkingDirectoryOfSingleCheckoutRegularMultiModules()
+        throws Exception
+    {       
+        List<Project> projects = new ArrayList<Project>();
+        
+        Project project = createProject( 10, "org.apache.continuum", "module-a", "1.0-SNAPSHOT",
+                                         "scm:local:src/test-projects:regular-multi-module/module-a", true );
+        
+        projects.add( project );
+        
+        projects.add( createProject( 11, "org.apache.continuum", "module-b", "1.0-SNAPSHOT",
+                                     "scm:local:src/test-projects:regular-multi-module/module-b", true ) );
+                
+        projects.add( createProject( 9, "org.apache.continuum", "parent-project", "1.0-SNAPSHOT",
+                                     "scm:local:src/test-projects:regular-multi-module/", true ) );
+        
+        final File baseWorkingDirectory = new File( getBasedir(), "target" + File.separator + "working-directory" );
+        
+        context.checking( new Expectations()
+        {
+            {
+                exactly( 2 ).of( configurationService ).getWorkingDirectory();
+                will( returnValue( baseWorkingDirectory ) );                
+            }} );
+        
+        File projectWorkingDirectory =
+            workingDirectoryService.getWorkingDirectory( project, "scm:local:src/test-projects:regular-multi-module",
+                                                         projects );
+        
+        assertEquals( "Incorrect working directory for regular multi-module project", baseWorkingDirectory + File.separator + 
+        			"9" + File.separator + "module-a", projectWorkingDirectory.getPath() );
+        
+        // test if separator is appended at the end of the scm root url
+        projectWorkingDirectory =
+            workingDirectoryService.getWorkingDirectory( project, "scm:local:src/test-projects:regular-multi-module/",
+                                                         projects );
+        
+        assertEquals( "Incorrect working directory for regular multi-module project", baseWorkingDirectory + File.separator + 
+        		    "9" + File.separator + "module-a", projectWorkingDirectory.getPath() );
+        
+     // test generated path of parent project
+        project = createProject( 9, "org.apache.continuum", "parent-project", "1.0-SNAPSHOT",
+                       "scm:local:src/test-projects:regular-multi-module", true );
+        
+        context.checking( new Expectations()
+        {
+            {
+                one( configurationService ).getWorkingDirectory();
+                will( returnValue( baseWorkingDirectory ) );                
+            }} );
+        
+        projectWorkingDirectory =
+            workingDirectoryService.getWorkingDirectory( project, "scm:local:src/test-projects:regular-multi-module",
+                                                         projects );
+        
+        assertEquals( "Incorrect working directory for regular multi-module project", baseWorkingDirectory +
+		            File.separator + "9", projectWorkingDirectory.getPath() );
+    }    
+}
\ No newline at end of file
diff --git a/continuum-core/src/main/java/org/apache/continuum/buildmanager/ParallelBuildsManager.java b/continuum-core/src/main/java/org/apache/continuum/buildmanager/ParallelBuildsManager.java
index 376f3a5..e3efe41 100644
--- a/continuum-core/src/main/java/org/apache/continuum/buildmanager/ParallelBuildsManager.java
+++ b/continuum-core/src/main/java/org/apache/continuum/buildmanager/ParallelBuildsManager.java
@@ -403,10 +403,11 @@
     }
 
     /**
-     * @see BuildsManager#checkoutProject(int, String, File, String, String, BuildDefinition)
+     * @see BuildsManager#checkoutProject(int, String, File, String, String, String, BuildDefinition, List)
      */
-    public void checkoutProject( int projectId, String projectName, File workingDirectory, String scmUsername,
-                                 String scmPassword, BuildDefinition defaultBuildDefinition )
+    public void checkoutProject( int projectId, String projectName, File workingDirectory, String scmRootUrl,
+    		                                 String scmUsername, String scmPassword, BuildDefinition defaultBuildDefinition,
+    		                                 List<Project> subProjects )
         throws BuildManagerException
     {
         try
@@ -426,7 +427,7 @@
         OverallBuildQueue overallBuildQueue =
             getOverallBuildQueue( CHECKOUT_QUEUE, defaultBuildDefinition.getSchedule().getBuildQueues() );
         CheckOutTask checkoutTask =
-            new CheckOutTask( projectId, workingDirectory, projectName, scmUsername, scmPassword );
+        	new CheckOutTask( projectId, workingDirectory, projectName, scmUsername, scmPassword, scmRootUrl, subProjects );
         try
         {
             if ( overallBuildQueue != null )
@@ -914,7 +915,8 @@
             {
                 BuildDefinition buildDefinition = buildDefinitionDao.getDefaultBuildDefinition( task.getProjectId() );
                 checkoutProject( task.getProjectId(), task.getProjectName(), task.getWorkingDirectory(),
-                                 task.getScmUserName(), task.getScmPassword(), buildDefinition );
+                		task.getScmRootUrl(), task.getScmUserName(), task.getScmPassword(), buildDefinition,
+                		task.getProjectsWithCommonScmRoot() );
             }
             catch ( ContinuumStoreException e )
             {
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java b/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
index 6922b60..5a8ebc7 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
@@ -108,6 +108,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Properties;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -940,6 +941,7 @@
         for ( Project project : projectsList )
         {
             List<Integer> buildDefIds = (List<Integer>) projectsMap.get( project.getId() );
+            int projectId = project.getId();
 
             if ( buildDefIds != null && !buildDefIds.isEmpty() )
             {
@@ -956,7 +958,7 @@
                             projectsAndBuildDefinitionsMap = new HashMap<Integer, Integer>();
                         }
 
-                        projectsAndBuildDefinitionsMap.put( project.getId(), buildDefId );
+                        projectsAndBuildDefinitionsMap.put( projectId, buildDefId );
 
                         map.put( scmRoot, projectsAndBuildDefinitionsMap );
 
@@ -1308,7 +1310,7 @@
     {
         return executeAddProjectsFromMetadataActivity( metadataUrl, MavenOneContinuumProjectBuilder.ID, projectGroupId,
                                                        checkProtocol, useCredentialsCache, true,
-                                                       buildDefinitionTemplateId );
+                                                       buildDefinitionTemplateId, false );
     }
 
     // ----------------------------------------------------------------------
@@ -1357,7 +1359,7 @@
         {
             return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID,
                                                            projectGroupId, checkProtocol, useCredentialsCache, true,
-                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId() );
+                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId(), false );
         }
         catch ( BuildDefinitionServiceException e )
         {
@@ -1375,7 +1377,7 @@
             return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID,
                                                            projectGroupId, checkProtocol, useCredentialsCache,
                                                            recursiveProjects,
-                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId() );
+                                                           buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate().getId(), false );
         }
         catch ( BuildDefinitionServiceException e )
         {
@@ -1385,12 +1387,13 @@
 
     public ContinuumProjectBuildingResult addMavenTwoProject( String metadataUrl, int projectGroupId,
                                                               boolean checkProtocol, boolean useCredentialsCache,
-                                                              boolean recursiveProjects, int buildDefinitionTemplateId )
+                                                              boolean recursiveProjects, int buildDefinitionTemplateId,
+                                                              boolean checkoutInSingleDirectory )
         throws ContinuumException
     {
         return executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID, projectGroupId,
                                                        checkProtocol, useCredentialsCache, recursiveProjects,
-                                                       buildDefinitionTemplateId );
+                                                       buildDefinitionTemplateId, checkoutInSingleDirectory );
     }
 
     // ----------------------------------------------------------------------
@@ -1538,7 +1541,7 @@
         throws ContinuumException
     {
         return executeAddProjectsFromMetadataActivity( metadataUrl, projectBuilderId, projectGroupId, checkProtocol,
-                                                       false, false, buildDefinitionTemplateId );
+        						false, false, buildDefinitionTemplateId, false );
     }
 
 
@@ -1549,7 +1552,8 @@
                                                                                      boolean useCredentialsCache,
                                                                                      boolean loadRecursiveProjects,
                                                                                      int buildDefinitionTemplateId,
-                                                                                     boolean addAssignableRoles )
+                                                                                     boolean addAssignableRoles,
+                                                                                     boolean checkoutInSingleDirectory )
         throws ContinuumException
     {
         if ( checkProtocol )
@@ -1564,15 +1568,22 @@
 
         Map<String, Object> context = new HashMap<String, Object>();
 
-        CreateProjectsFromMetadataAction.setProjectBuilderId( context, projectBuilderId );
+        //CreateProjectsFromMetadataAction.setProjectBuilderId( context, projectBuilderId );
+        context.put( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDER_ID, projectBuilderId );
 
-        CreateProjectsFromMetadataAction.setUrl( context, metadataUrl );
+        //CreateProjectsFromMetadataAction.setUrl( context, metadataUrl );
+        context.put( AbstractContinuumAction.KEY_URL, metadataUrl );
 
-        CreateProjectsFromMetadataAction.setLoadRecursiveProject( context, loadRecursiveProjects );
+        //CreateProjectsFromMetadataAction.setLoadRecursiveProject( context, loadRecursiveProjects );
+        context.put( CreateProjectsFromMetadataAction.KEY_LOAD_RECURSIVE_PROJECTS, loadRecursiveProjects );
 
-        StoreProjectAction.setUseScmCredentialsCache( context, useCredentialsCache );
+        //StoreProjectAction.setUseScmCredentialsCache( context, useCredentialsCache );
+        context.put( AbstractContinuumAction.KEY_SCM_USE_CREDENTIALS_CACHE, useCredentialsCache );
 
-        AbstractContinuumAction.setWorkingDirectory( context, getWorkingDirectory() );
+        //AbstractContinuumAction.setWorkingDirectory( context, getWorkingDirectory() );
+        context.put( AbstractContinuumAction.KEY_WORKING_DIRECTORY, getWorkingDirectory() );
+                
+        context.put( CreateProjectsFromMetadataAction.KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY, checkoutInSingleDirectory );
 
         // CreateProjectsFromMetadataAction will check null and use default
         if ( buildDefinitionTemplateId > 0 )
@@ -1594,7 +1605,9 @@
 
         executeAction( "create-projects-from-metadata", context );
 
-        ContinuumProjectBuildingResult result = CreateProjectsFromMetadataAction.getProjectBuildingResult( context );
+        //ContinuumProjectBuildingResult result = CreateProjectsFromMetadataAction.getProjectBuildingResult( context );
+        ContinuumProjectBuildingResult result =
+        	            (ContinuumProjectBuildingResult) context.get( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDING_RESULT );
 
         if ( log.isInfoEnabled() )
         {
@@ -1668,7 +1681,8 @@
 
             projectGroup = projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( projectGroupId );
 
-            String url = CreateProjectsFromMetadataAction.getUrl( context );
+            //String url = CreateProjectsFromMetadataAction.getUrl( context );
+            String url = AbstractContinuumAction.getString( context, AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, null );
 
             List<ProjectScmRoot> scmRoots = getProjectScmRootByProjectGroup( projectGroup.getId() );
 
@@ -1737,77 +1751,36 @@
         {
             projectGroupDao.updateProjectGroup( projectGroup );
 
-            for ( Project project : projects )
+            if( !checkoutInSingleDirectory )
             {
-                context = new HashMap<String, Object>();
-
-                // CONTINUUM-1953 olamy : attached buildDefs from template here
-                // if no group creation
-                if ( !projectGroupCreation && buildDefinitionTemplateId > 0 )
+                for ( Project project : projects )
                 {
-                    buildDefinitionService.addTemplateInProject( buildDefinitionTemplateId,
-                                                                 projectDao.getProject( project.getId() ) );
+                	context = new HashMap<String, Object>();
+            	    addProjectToCheckoutQueue( projectBuilderId, buildDefinitionTemplateId, context,
+            				                                               projectGroupCreation, scmUserName, scmPassword, project );    
                 }
-
-                AbstractContinuumAction.setUnvalidatedProject( context, project );
-                //
-                //            executeAction( "validate-project", context );
-                //
-                //            executeAction( "store-project", context );
-                //
-                AbstractContinuumAction.setProjectId( context, project.getId() );
-
-                if ( !StringUtils.isEmpty( scmUserName ) )
+            }
+            else
+            {   
+                Project project = result.getRootProject();
+                
+                if( project != null )
                 {
-                    project.setScmUsername( scmUserName );
-                    CheckoutProjectContinuumAction.setScmUsername( context, scmUserName );
-                }
-                if ( !StringUtils.isEmpty( scmPassword ) )
-                {
-                    project.setScmPassword( scmPassword );
-                    CheckoutProjectContinuumAction.setScmPassword( context, scmPassword );
-                }
-                // FIXME
-                // olamy  : read again the project to have values because store.updateProjectGroup( projectGroup );
-                // remove object data -> we don't display the project name in the build queue
-                AbstractContinuumAction.setProject( context, projectDao.getProject( project.getId() ) );
+                	String scmRootUrl = AbstractContinuumAction.getString( context, AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, null );
+                	context = new HashMap<String, Object>();
 
-                BuildDefinition defaultBuildDefinition = null;
-                BuildDefinitionTemplate template = null;
-                if ( projectBuilderId.equals( MavenTwoContinuumProjectBuilder.ID ) )
-                {
-                    template = buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate();
-
-                    if( template != null && template.getBuildDefinitions().size() > 0 )
+                	context.put( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, scmRootUrl );
+                	
+                    List<Project> projectsWithSimilarScmRoot = new ArrayList<Project>();
+                    for( Project projectWithSimilarScmRoot : projects )
                     {
-                        defaultBuildDefinition = template.getBuildDefinitions().get( 0 );
+                    	projectsWithSimilarScmRoot.add( projectWithSimilarScmRoot );
                     }
-                }
-                else if ( projectBuilderId.equals( MavenOneContinuumProjectBuilder.ID ) )
-                {
-                    template = buildDefinitionService.getDefaultMavenOneBuildDefinitionTemplate();
 
-                    if ( template != null && template.getBuildDefinitions().size() > 0 )
-                    {
-                        defaultBuildDefinition = template.getBuildDefinitions().get( 0 );
-                    }
-                }
-
-                if ( defaultBuildDefinition == null )
-                {
-                    // do not throw exception
-                    // project already added so might as well continue with the rest
-                    log.warn( "No default build definition found in the template. Project cannot be checked out." );
-                }
-                else
-                {
-                    // used by BuildManager to determine on which build queue will the project be put
-                    AbstractContinuumAction.setBuildDefinition( context, defaultBuildDefinition );
-    
-                    if ( !configurationService.isDistributedBuildEnabled() )
-                    {
-                        executeAction( "add-project-to-checkout-queue", context );
-                    }
+                    context.put( AbstractContinuumAction.KEY_PROJECTS_IN_GROUP_WITH_COMMON_SCM_ROOT, projectsWithSimilarScmRoot );
+                    
+                    addProjectToCheckoutQueue( projectBuilderId, buildDefinitionTemplateId, context, projectGroupCreation,
+                                               scmUserName, scmPassword, project );    
                 }
             }
         }
@@ -1828,6 +1801,82 @@
         }
         return result;
     }
+    
+    private void addProjectToCheckoutQueue( String projectBuilderId, int buildDefinitionTemplateId,
+                                            Map<String, Object> context, boolean projectGroupCreation,
+                                            String scmUserName, String scmPassword, Project project )
+        throws BuildDefinitionServiceException, ContinuumStoreException, ContinuumException
+    {
+        // CONTINUUM-1953 olamy : attached buildDefs from template here
+        // if no group creation
+        if ( !projectGroupCreation && buildDefinitionTemplateId > 0 )
+        {
+            buildDefinitionService.addTemplateInProject( buildDefinitionTemplateId,
+                                                         projectDao.getProject( project.getId() ) );
+        }
+
+        context.put( AbstractContinuumAction.KEY_UNVALIDATED_PROJECT, project );
+        //
+        //            executeAction( "validate-project", context );
+        //
+        //            executeAction( "store-project", context );
+        //
+        context.put( AbstractContinuumAction.KEY_PROJECT_ID, project.getId() );
+
+        // does the scm username & password really have to be set in the project?
+        if ( !StringUtils.isEmpty( scmUserName ) )
+        {
+            project.setScmUsername( scmUserName );
+            context.put( AbstractContinuumAction.KEY_SCM_USERNAME, scmUserName );
+        }
+        if ( !StringUtils.isEmpty( scmPassword ) )
+        {
+            project.setScmPassword( scmPassword );
+            context.put( AbstractContinuumAction.KEY_SCM_PASSWORD, scmPassword );
+        }
+        //FIXME
+        // olamy  : read again the project to have values because store.updateProjectGroup( projectGroup );
+        // remove object data -> we don't display the project name in the build queue
+        context.put( AbstractContinuumAction.KEY_PROJECT, projectDao.getProject( project.getId() ) );
+
+        BuildDefinition defaultBuildDefinition = null;
+        BuildDefinitionTemplate template = null;
+        if ( projectBuilderId.equals( MavenTwoContinuumProjectBuilder.ID ) )
+        {
+            template = buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate();
+
+            if( template != null && template.getBuildDefinitions().size() > 0 )
+            {
+                defaultBuildDefinition = template.getBuildDefinitions().get( 0 );
+            }
+        }
+        else if ( projectBuilderId.equals( MavenOneContinuumProjectBuilder.ID ) )
+        {
+            template = buildDefinitionService.getDefaultMavenOneBuildDefinitionTemplate();
+
+            if ( template != null && template.getBuildDefinitions().size() > 0 )
+            {
+                defaultBuildDefinition = template.getBuildDefinitions().get( 0 );
+            }
+        }
+
+        if ( defaultBuildDefinition == null )
+        {
+            // do not throw exception
+            // project already added so might as well continue with the rest
+            log.warn( "No default build definition found in the template. Project cannot be checked out." );
+        }
+        else
+        {
+            // used by BuildManager to determine on which build queue will the project be put
+            context.put( AbstractContinuumAction.KEY_BUILD_DEFINITION, defaultBuildDefinition );
+
+            if ( !configurationService.isDistributedBuildEnabled() )
+            {
+                executeAction( "add-project-to-checkout-queue", context );
+            }
+        }
+    }
 
     private ContinuumProjectBuildingResult executeAddProjectsFromMetadataActivity( String metadataUrl,
                                                                                    String projectBuilderId,
@@ -1835,12 +1884,13 @@
                                                                                    boolean checkProtocol,
                                                                                    boolean useCredentialsCache,
                                                                                    boolean loadRecursiveProjects,
-                                                                                   int buildDefinitionTemplateId )
+                                                                                   int buildDefinitionTemplateId,
+                                                                                   boolean checkoutInSingleDirectory )
         throws ContinuumException
     {
         return executeAddProjectsFromMetadataActivity( metadataUrl, projectBuilderId, projectGroupId, checkProtocol,
                                                        useCredentialsCache, loadRecursiveProjects,
-                                                       buildDefinitionTemplateId, true );
+                                                       buildDefinitionTemplateId, true, checkoutInSingleDirectory );
     }
 
     // ----------------------------------------------------------------------
@@ -3567,16 +3617,33 @@
 
         projectsList =
             getProjectsInBuildOrder( projectDao.getProjectsWithDependenciesByGroupId( projectGroup.getId() ) );
+        
+        List<ProjectScmRoot> scmRoots = getProjectScmRootByProjectGroup( projectGroup.getId() );
 
         String url = "";
 
         for ( Project project : projectsList )
         {
+        	boolean found = false;
+        	
             if ( StringUtils.isEmpty( url ) || !project.getScmUrl().startsWith( url ) )
             {
-                // this is a root
+            	// this is a root project or the project is part of a flat multi module 
                 url = project.getScmUrl();
-                createProjectScmRoot( projectGroup, url );
+                //createProjectScmRoot( projectGroup, url );
+                
+                for ( ProjectScmRoot scmRoot : scmRoots )
+                {
+                    if ( url.startsWith( scmRoot.getScmRootAddress() ) )
+                    {
+                        found = true;
+                    }
+                }
+
+                if ( !found )
+                {
+                    createProjectScmRoot( projectGroup, url );
+                }
             }
         }
     }
@@ -3584,6 +3651,11 @@
     private ProjectScmRoot createProjectScmRoot( ProjectGroup projectGroup, String url )
         throws ContinuumException
     {
+    	if ( StringUtils.isEmpty( url ) )
+        {
+            return null;
+        }
+    	
         try
         {
             ProjectScmRoot scmRoot =
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java b/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
index e956b32..254f192 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
@@ -27,6 +27,7 @@
 import org.apache.continuum.dao.BuildDefinitionDao;
 import org.apache.continuum.dao.BuildResultDao;
 import org.apache.continuum.dao.ProjectDao;
+import org.apache.continuum.dao.ProjectGroupDao;
 import org.apache.continuum.dao.ProjectScmRootDao;
 import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.continuum.utils.ContinuumUtils;
@@ -40,6 +41,7 @@
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
 import org.apache.maven.continuum.model.project.ProjectDependency;
+import org.apache.maven.continuum.model.project.ProjectGroup;
 import org.apache.maven.continuum.model.scm.ChangeFile;
 import org.apache.maven.continuum.model.scm.ChangeSet;
 import org.apache.maven.continuum.model.scm.ScmResult;
@@ -84,6 +86,11 @@
     /**
      * @plexus.requirement
      */
+    private ProjectGroupDao projectGroupDao;
+
+    /**
+     * @plexus.requirement
+     */
     private ProjectScmRootDao projectScmRootDao;
 
     /**
@@ -330,6 +337,8 @@
         context.setStartTime( System.currentTimeMillis() );
 
         context.setBuildTrigger( buildTrigger );
+        
+        Map actionContext = context.getActionContext();
 
         try
         {
@@ -347,6 +356,37 @@
             context.setOldBuildResult( oldBuildResult );
 
             context.setScmResult( scmResult );
+            
+            // CONTINUUM-2193
+            ProjectGroup projectGroup = project.getProjectGroup();
+            List<ProjectScmRoot> scmRoots = projectScmRootDao.getProjectScmRootByProjectGroup( projectGroup.getId() );
+            String projectScmUrl = project.getScmUrl();
+            String projectScmRootAddress = "";
+
+            for ( ProjectScmRoot projectScmRoot : scmRoots )
+            {
+                projectScmRootAddress = projectScmRoot.getScmRootAddress();
+                if ( projectScmUrl.startsWith( projectScmRoot.getScmRootAddress() ) )
+                {
+                    actionContext.put( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, projectScmRoot.getScmRootAddress() );                    
+                    break;
+                }
+            }
+
+            if( project.isCheckedOutInSingleDirectory() )
+            {
+                List<Project> projectsInGroup =
+                    projectGroupDao.getProjectGroupWithProjects( projectGroup.getId() ).getProjects(); 
+                List<Project> projectsWithCommonScmRoot = new ArrayList<Project>();            
+                for( Project projectInGroup : projectsInGroup )
+                {
+                    if( projectInGroup.getScmUrl().startsWith( projectScmRootAddress ) )
+                    {
+                        projectsWithCommonScmRoot.add( projectInGroup );
+                    }
+                }
+                actionContext.put( AbstractContinuumAction.KEY_PROJECTS_IN_GROUP_WITH_COMMON_SCM_ROOT, projectsWithCommonScmRoot );
+            }
 
             // CONTINUUM-1871 olamy if continuum is killed during building oldBuildResult will have a endTime 0
             // this means all changes since the project has been loaded in continuum will be in memory
@@ -362,7 +402,7 @@
             throw new TaskExecutionException( "Error initializing the build context", e );
         }
 
-        Map<String, Object> actionContext = context.getActionContext();
+       // Map<String, Object> actionContext = context.getActionContext();
 
         AbstractContinuumAction.setProjectId( actionContext, projectId );
 
@@ -518,6 +558,13 @@
             try
             {
                 ContinuumBuildExecutor executor = buildExecutorManager.getBuildExecutor( project.getExecutorId() );
+                
+                Map<String, Object> actionContext = context.getActionContext();
+                List<Project> projectsWithCommonScmRoot =
+                    AbstractContinuumAction.getListOfProjectsInGroupWithCommonScmRoot( actionContext );
+                String projectScmRootUrl =
+                    AbstractContinuumAction.getString( actionContext, AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL,
+                                                       project.getScmUrl() );
 
                 if ( executor == null )
                 {
@@ -526,9 +573,11 @@
                 }
                 else if ( context.getScmResult() != null )
                 {
-                    shouldBuild = executor.shouldBuild( context.getScmResult().getChanges(), project,
-                                                        workingDirectoryService.getWorkingDirectory( project ),
-                                                        context.getBuildDefinition() );
+                    shouldBuild = 
+	                        executor.shouldBuild( context.getScmResult().getChanges(), project,
+	                                              workingDirectoryService.getWorkingDirectory( project, projectScmRootUrl,
+	                                                                                           projectsWithCommonScmRoot ),
+	                                              context.getBuildDefinition() );
                 }
             }
             catch ( Exception e )
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AbstractContinuumAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AbstractContinuumAction.java
index 31dab4b..49ad5ca 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AbstractContinuumAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AbstractContinuumAction.java
@@ -21,6 +21,7 @@
 
 import java.io.File;
 import java.util.List;
+import java.util.ArrayList;
 import java.util.Map;
 
 import org.apache.continuum.model.project.ProjectScmRoot;
@@ -44,43 +45,86 @@
     // Keys for the values that can be in the context
     // ----------------------------------------------------------------------
 
-    private static final String KEY_PROJECT_ID = "project-id";
+    // TODO: Review and fix access of constant variables used for build context!
+    
+    public static final String KEY_PROJECT_ID = "project-id";
 
-    private static final String KEY_PROJECT = "project";
+    public static final String KEY_PROJECT = "project";
 
-    private static final String KEY_PROJECTS = "projects";
+    public static final String KEY_PROJECTS = "projects";
 
-    private static final String KEY_PROJECTS_BUILD_DEFINITIONS_MAP = "projects-build-definitions";
+    public static final String KEY_PROJECTS_BUILD_DEFINITIONS_MAP = "projects-build-definitions";
 
-    private static final String KEY_BUILD_DEFINITION_TEMPLATE = "build-definition-template";
+    public static final String KEY_BUILD_DEFINITION_TEMPLATE = "build-definition-template";
 
-    private static final String KEY_BUILD_DEFINITION = "build-definition";
+    public static final String KEY_BUILD_DEFINITION = "build-definition";
 
-    private static final String KEY_BUILD_DEFINITION_ID = "build-definition-id";
+    public static final String KEY_BUILD_DEFINITION_ID = "build-definition-id";
 
-    private static final String KEY_UNVALIDATED_PROJECT = "unvalidated-project";
+    public static final String KEY_UNVALIDATED_PROJECT = "unvalidated-project";
 
-    private static final String KEY_PROJECT_GROUP_ID = "project-group-id";
+    public static final String KEY_PROJECT_GROUP_ID = "project-group-id";
 
-    private static final String KEY_UNVALIDATED_PROJECT_GROUP = "unvalidated-project-group";
+    public static final String KEY_UNVALIDATED_PROJECT_GROUP = "unvalidated-project-group";
 
-    private static final String KEY_BUILD_ID = "build-id";
+    public static final String KEY_BUILD_ID = "build-id";
 
-    private static final String KEY_WORKING_DIRECTORY = "working-directory";
+    public static final String KEY_WORKING_DIRECTORY = "working-directory";
 
-    private static final String KEY_UPDATE_DEPENDENCIES = "update-dependencies";
+    public static final String KEY_WORKING_DIRECTORY_EXISTS = "working-directory-exists";
+    
+    public static final String KEY_CHECKOUT_SCM_RESULT = "checkout-result";
+    
+    public static final String KEY_UPDATE_SCM_RESULT = "update-result";
+    
+    public static final String KEY_UPDATE_DEPENDENCIES = "update-dependencies";
 
-    private static final String KEY_BUILD_TRIGGER = "buildTrigger";
+    public static final String KEY_BUILD_TRIGGER = "buildTrigger"; 
+    
+    public static final String KEY_FIRST_RUN = "first-run";
 
-    private static final String KEY_SCM_RESULT = "scmResult";
+    //public static final String KEY_OLD_BUILD_ID = "old-buildResult-id";
 
-    private static final String KEY_OLD_SCM_RESULT = "old-scmResult";
+    //public static final String KEY_SCM_RESULT_MAP = "scm-result-map";
+    
+    public static final String KEY_PROJECT_RELATIVE_PATH = "project-relative-path";
+    
+    public static final String KEY_SCM_USE_CREDENTIALS_CACHE = "useCredentialsCache";
+    
+	public static final String KEY_SCM_USERNAME = "scmUserName";
+	
+	public static final String KEY_SCM_PASSWORD = "scmUserPassword";
+	
+	public static final String KEY_SCM_RESULT = "scmResult";
+	
+	public static final String KEY_OLD_SCM_RESULT = "old-scmResult";
+	
+	public static final String KEY_PROJECT_SCM_ROOT = "projectScmRoot";
+	
+    /**
+     * SCM root url. Used in these actions add-project-to-checkout-queue, checkout-project, clean-working-directory,
+     *      create-projects-from-metadata, update-project-from-working-directory, 
+     *      update-working-directory-from-scm
+    */
+    public static final String KEY_PROJECT_SCM_ROOT_URL = "projectScmRootUrl";
 
-    private static final String KEY_PROJECT_SCM_ROOT = "projectScmRoot";
+    /**
+     * List of projects in a project group with a common scm root url.
+    */
+    public static final String KEY_PROJECTS_IN_GROUP_WITH_COMMON_SCM_ROOT = "projects-in-group-with-common-scm-root";
 
-    private static final String KEY_OLD_BUILD_ID = "old-buildResult-id";
+    public static final String KEY_OLD_BUILD_ID = "old-buildResult-id";
 
-    private static final String KEY_SCM_RESULT_MAP = "scm-result-map";
+    public static final String KEY_CANCELLED = "cancelled";
+
+    /**
+     * Metadata url for adding projects.
+    */
+    public static final String KEY_URL = "url";
+
+    public static final String KEY_SCM_RESULT_MAP = "scm-result-map";
+
+    public static final String KEY_ROOT_DIRECTORY = "root-directory";
 
     // ----------------------------------------------------------------------
     //
@@ -282,6 +326,11 @@
     {
         context.put( KEY_PROJECTS, projects );
     }
+    
+    public static List<Project> getListOfProjectsInGroupWithCommonScmRoot( Map<String, Object> context )
+    {
+        return (List<Project>) getObject( context, KEY_PROJECTS_IN_GROUP_WITH_COMMON_SCM_ROOT, new ArrayList<Integer>() );
+    }
 
     public static Map<Integer, BuildDefinition> getProjectsBuildDefinitionsMap( Map<String, Object> context )
     {
@@ -303,17 +352,27 @@
     {
         context.put( KEY_SCM_RESULT_MAP, scmResultMap );
     }
+    
+    public static boolean isRootDirectory( Map<String, Object> context )
+    {
+        return getBoolean( context, KEY_ROOT_DIRECTORY, true );
+    }
+
+    public static void setRootDirectory( Map<String, Object> context, boolean isRootDirectory )
+    {
+        context.put( KEY_ROOT_DIRECTORY, isRootDirectory );
+    }
 
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
 
-    protected static String getString( Map<String, Object> context, String key )
+    public static String getString( Map<String, Object> context, String key )
     {
         return (String) getObject( context, key );
     }
 
-    protected static String getString( Map<String, Object> context, String key, String defaultValue )
+    public static String getString( Map<String, Object> context, String key, String defaultValue )
     {
         return (String) getObject( context, key, defaultValue );
     }
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AddProjectToCheckOutQueueAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AddProjectToCheckOutQueueAction.java
index eaaf428..1691cec 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AddProjectToCheckOutQueueAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/AddProjectToCheckOutQueueAction.java
@@ -75,9 +75,12 @@
             scmPassword = CheckoutProjectContinuumAction.getScmPassword( context, null );
         }
         
+        String scmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, null );
+        
         BuildDefinition defaultBuildDefinition = getBuildDefinition( context );
         parallelBuildsManager.checkoutProject( project.getId(), project.getName(),
                                                workingDirectoryService.getWorkingDirectory( project ),
-                                               scmUsername, scmPassword, defaultBuildDefinition );
+                                               scmRootUrl, scmUsername, scmPassword, defaultBuildDefinition,
+                                               getListOfProjectsInGroupWithCommonScmRoot( context ) );
     }
 }
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckWorkingDirectoryAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckWorkingDirectoryAction.java
index 334a83d..8b6ea2a 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckWorkingDirectoryAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckWorkingDirectoryAction.java
@@ -20,6 +20,7 @@
  */
 
 import java.io.File;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.continuum.dao.ProjectDao;
@@ -52,8 +53,12 @@
         throws Exception
     {
         Project project = projectDao.getProject( getProjectId( context ) );
-
-        File workingDirectory = workingDirectoryService.getWorkingDirectory( project );
+        List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );
+        String projectScmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+       
+        File workingDirectory =
+            workingDirectoryService.getWorkingDirectory( project, projectScmRootUrl,
+                                                         projectsWithCommonScmRoot );
 
         if ( !workingDirectory.exists() )
         {
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckoutProjectContinuumAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckoutProjectContinuumAction.java
index b39adf3..28ee80e 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckoutProjectContinuumAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CheckoutProjectContinuumAction.java
@@ -103,13 +103,17 @@
 
         ScmResult result;
 
+        List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );
+        
         try
         {
             String scmUserName = getScmUsername( context, project.getScmUsername() );
             String scmPassword = getScmPassword( context, project.getScmPassword() );
+            String scmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+            
             ContinuumScmConfiguration config =
-                createScmConfiguration( project, workingDirectory, scmUserName, scmPassword );
-
+            	createScmConfiguration( project, workingDirectory, scmUserName, scmPassword, scmRootUrl, isRootDirectory( context ) );
+                
             String tag = config.getTag();
             getLogger().info(
                 "Checking out project: '" + project.getName() + "', id: '" + project.getId() + "' " + "to '" +
@@ -205,6 +209,19 @@
 
             projectDao.updateProject( project );
 
+            // update state of sub-projects 
+            // if multi-module project was checked out in a single directory, these must not be null            
+            for( Project projectWithCommonScmRoot : projectsWithCommonScmRoot )
+            {
+                projectWithCommonScmRoot = projectDao.getProject( projectWithCommonScmRoot.getId() );
+                if( projectWithCommonScmRoot != null && projectWithCommonScmRoot.getId() != project.getId() &&
+                                projectWithCommonScmRoot.getState() == ContinuumProjectState.NEW )
+                {
+                    projectWithCommonScmRoot.setState( ContinuumProjectState.CHECKEDOUT );
+                   projectDao.updateProject( projectWithCommonScmRoot );                    
+                }
+            }
+            
             notifier.checkoutComplete( project, buildDefinition );
         }
 
@@ -213,10 +230,19 @@
     }
 
     private ContinuumScmConfiguration createScmConfiguration( Project project, File workingDirectory,
-                                                              String scmUserName, String scmPassword )
+    													String scmUserName, String scmPassword, String scmRootUrl,
+    		                                                              boolean isRootDirectory )
     {
         ContinuumScmConfiguration config = new ContinuumScmConfiguration();
-        config.setUrl( project.getScmUrl() );
+        
+        if( project.isCheckedOutInSingleDirectory() && scmRootUrl!= null && !"".equals( scmRootUrl ) && isRootDirectory )
+        {
+            config.setUrl( scmRootUrl );
+        }
+        else
+        {
+            config.setUrl( project.getScmUrl() );
+        }
         config.setUsername( scmUserName );
         config.setPassword( scmPassword );
         config.setUseCredentialsCache( project.isScmUseCache() );
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CleanWorkingDirectoryAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CleanWorkingDirectoryAction.java
index 3419f87..a08f27e 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CleanWorkingDirectoryAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CleanWorkingDirectoryAction.java
@@ -26,6 +26,7 @@
 import org.apache.maven.shared.model.fileset.util.FileSetManager;
 
 import java.io.File;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -51,8 +52,12 @@
         throws Exception
     {
         Project project = projectDao.getProject( getProjectId( context ) );
+        List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );        
+        String projectScmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
 
-        File workingDirectory = workingDirectoryService.getWorkingDirectory( project );
+        File workingDirectory =
+        	            workingDirectoryService.getWorkingDirectory( project, projectScmRootUrl,
+        	                                                         projectsWithCommonScmRoot );
 
         if ( workingDirectory.exists() )
         {
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataAction.java
index e53ec99..d4828df 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataAction.java
@@ -61,13 +61,20 @@
 public class CreateProjectsFromMetadataAction
     extends AbstractContinuumAction
 {
-    private static final String KEY_URL = "url";
+    // TODO: Review and fix access of constant variables used for build context!
+    
+    //private static final String KEY_URL = "url";
+    
+	public static final String KEY_PROJECT_BUILDER_ID = "builderId";
 
-    private static final String KEY_PROJECT_BUILDER_ID = "builderId";
+    //private static final String KEY_PROJECT_BUILDER_ID = "builderId";
+	public static final String KEY_PROJECT_BUILDING_RESULT = "projectBuildingResult";
 
-    private static final String KEY_PROJECT_BUILDING_RESULT = "projectBuildingResult";
+    //private static final String KEY_PROJECT_BUILDING_RESULT = "projectBuildingResult";
+	public static final String KEY_LOAD_RECURSIVE_PROJECTS = "loadRecursiveProjects";
 
-    private static final String KEY_LOAD_RECURSIVE_PROJECTS = "loadRecursiveProjects";
+    //private static final String KEY_LOAD_RECURSIVE_PROJECTS = "loadRecursiveProjects";
+	public static final String KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY = "checkoutProjectsInSingleDirectory";
 
     /**
      * @plexus.requirement
@@ -87,11 +94,16 @@
     public void execute( Map context )
         throws ContinuumException, ContinuumProjectBuilderManagerException, ContinuumProjectBuilderException
     {
-        String projectBuilderId = getProjectBuilderId( context );
+        //String projectBuilderId = getProjectBuilderId( context );
+    	String projectBuilderId = getString( context, KEY_PROJECT_BUILDER_ID );
 
-        boolean loadRecursiveProjects = isLoadRecursiveProject( context );
+        //boolean loadRecursiveProjects = isLoadRecursiveProject( context );
+    	boolean loadRecursiveProjects = getBoolean( context, KEY_LOAD_RECURSIVE_PROJECTS );
+    	        
+        boolean checkoutProjectsInSingleDirectory = getBoolean( context, KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY );
 
-        String curl = getUrl( context );
+        //String curl = getUrl( context );
+        String curl = getString( context, KEY_URL );
 
         URL url;
 
@@ -111,7 +123,7 @@
                 url = new URL( curl );
 
                 result = projectBuilder.buildProjectsFromMetadata( url, null, null, loadRecursiveProjects,
-                                                                   buildDefinitionTemplate );
+                		 						buildDefinitionTemplate, checkoutProjectsInSingleDirectory );
 
             }
             else
@@ -150,7 +162,7 @@
                 {
 
                     result = projectBuilder.buildProjectsFromMetadata( url, username, password, loadRecursiveProjects,
-                                                                       buildDefinitionTemplate );
+                    											buildDefinitionTemplate, checkoutProjectsInSingleDirectory );
 
                 }
                 else
@@ -177,7 +189,8 @@
                     }
                 }
 
-                setUrl( context, scmRootUrl );
+                //setUrl( context, scmRootUrl );
+                context.put( KEY_PROJECT_SCM_ROOT_URL, scmRootUrl );
             }
         }
         catch ( MalformedURLException e )
@@ -193,7 +206,8 @@
             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
         }
 
-        setProjectBuildingResult( context, result );
+        //setProjectBuildingResult( context, result );
+        context.put( KEY_PROJECT_BUILDING_RESULT, result );
     }
 
     private String hidePasswordInUrl( String url )
@@ -299,7 +313,7 @@
         this.urlValidator = urlValidator;
     }
 
-    public static ContinuumProjectBuildingResult getProjectBuildingResult( Map<String, Object> context )
+    /*public static ContinuumProjectBuildingResult getProjectBuildingResult( Map<String, Object> context )
     {
         return (ContinuumProjectBuildingResult) getObject( context, KEY_PROJECT_BUILDING_RESULT );
     }
@@ -337,5 +351,5 @@
     public static void setLoadRecursiveProject( Map<String, Object> context, boolean loadRecursiveProject )
     {
         context.put( KEY_LOAD_RECURSIVE_PROJECTS, loadRecursiveProject );
-    }
+    }*/
 }
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/DeployArtifactContinuumAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/DeployArtifactContinuumAction.java
index 46bfe70..3822d8b 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/DeployArtifactContinuumAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/DeployArtifactContinuumAction.java
@@ -101,10 +101,14 @@
             if ( project.getState() == ContinuumProjectState.OK )
             {
                 BuildDefinition buildDefinition = getBuildDefinition( context );
+                
+                String projectScmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+                
+                List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );
 
                 List<Artifact> artifacts = buildExecutor.getDeployableArtifacts( project,
-                                                                                 workingDirectoryService.getWorkingDirectory(
-                                                                                     project ), buildDefinition );
+                									workingDirectoryService.getWorkingDirectory( 
+                									project, projectScmRootUrl, projectsWithCommonScmRoot ), buildDefinition );
 
                 LocalRepository repository = project.getProjectGroup().getLocalRepository();
 
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java
index 3c3bf92..4b50e5a 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java
@@ -204,12 +204,15 @@
             AbstractContinuumAction.setProject( context, project );
 
             projectDao.updateProject( project );
+            
+            String projectScmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+            List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );
 
             // ----------------------------------------------------------------------
             // Backup test result files
             // ----------------------------------------------------------------------
             //TODO: Move as a plugin
-            buildExecutor.backupTestFiles( project, buildResult.getId() );
+            buildExecutor.backupTestFiles( project, buildResult.getId(), projectScmRootUrl, projectsWithCommonScmRoot );
         }
     }
 
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateProjectFromWorkingDirectoryContinuumAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateProjectFromWorkingDirectoryContinuumAction.java
index ba94ab9..99f31d5 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateProjectFromWorkingDirectoryContinuumAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateProjectFromWorkingDirectoryContinuumAction.java
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import java.util.List;
 import java.util.Map;
 
 import org.apache.continuum.dao.BuildDefinitionDao;
@@ -80,9 +81,11 @@
         ContinuumBuildExecutor builder = buildExecutorManager.getBuildExecutor( project.getExecutorId() );
 
         ScmResult scmResult = (ScmResult) context.get( "scmResult" );
-        builder.updateProjectFromCheckOut( workingDirectoryService.getWorkingDirectory( project ), project,
-                                           buildDefinition, scmResult );
-
+        List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );
+        String projectScmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+        
+        builder.updateProjectFromCheckOut( workingDirectoryService.getWorkingDirectory( project, 
+                        projectScmRootUrl, projectsWithCommonScmRoot ), project, buildDefinition, scmResult );
         // ----------------------------------------------------------------------
         // Store the new descriptor
         // ----------------------------------------------------------------------
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateWorkingDirectoryFromScmContinuumAction.java b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateWorkingDirectoryFromScmContinuumAction.java
index 8e5f3eb..518e9f1 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateWorkingDirectoryFromScmContinuumAction.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/core/action/UpdateWorkingDirectoryFromScmContinuumAction.java
@@ -116,9 +116,15 @@
         {
             notifier.checkoutStarted( project, buildDefinition );
 
-            // TODO: not sure why this is different to the context, but it all needs to change
-            File workingDirectory = workingDirectoryService.getWorkingDirectory( project );
-            ContinuumScmConfiguration config = createScmConfiguration( project, workingDirectory );
+            List<Project> projectsWithCommonScmRoot = getListOfProjectsInGroupWithCommonScmRoot( context );           
+            String projectScmRootUrl = getString( context, KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+            
+         // TODO: not sure why this is different to the context, but it all needs to change            
+            File workingDirectory =
+                workingDirectoryService.getWorkingDirectory( project, projectScmRootUrl,
+                                                             projectsWithCommonScmRoot );    
+            
+            ContinuumScmConfiguration config = createScmConfiguration( project, workingDirectory, projectScmRootUrl );
             config.setLatestUpdateDate( latestUpdateDate );
             String tag = config.getTag();
             String msg =
@@ -198,10 +204,19 @@
         AbstractContinuumAction.setProject( context, project );
     }
 
-    private ContinuumScmConfiguration createScmConfiguration( Project project, File workingDirectory )
+    private ContinuumScmConfiguration createScmConfiguration( Project project, File workingDirectory, String scmRootUrl )
     {
         ContinuumScmConfiguration config = new ContinuumScmConfiguration();
-        config.setUrl( project.getScmUrl() );
+        
+        if( project.isCheckedOutInSingleDirectory() && scmRootUrl!= null && !"".equals( scmRootUrl ) )
+        {
+            config.setUrl( scmRootUrl );
+        }
+        else
+        {
+            config.setUrl( project.getScmUrl() );
+        }
+        
         config.setUsername( project.getScmUsername() );
         config.setPassword( project.getScmPassword() );
         config.setUseCredentialsCache( project.isScmUseCache() );
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/execution/AbstractBuildExecutor.java b/continuum-core/src/main/java/org/apache/maven/continuum/execution/AbstractBuildExecutor.java
index 390178f..e6712a5 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/execution/AbstractBuildExecutor.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/execution/AbstractBuildExecutor.java
@@ -248,7 +248,7 @@
         throws ContinuumBuildExecutorException
     {
 
-        File workingDirectory = getWorkingDirectory( project );
+    	File workingDirectory = getWorkingDirectory( project, null, null );
 
         String actualExecutable = findExecutable( executable, defaultExecutable, resolveExecutable, workingDirectory );
 
@@ -340,7 +340,7 @@
         return jdk.getVarValue();
     }
 
-    public void backupTestFiles( Project project, int buildId )
+    public void backupTestFiles( Project project, int buildId, String projectScmRootUrl, List<Project> projectsWithCommonScmRoot )
     {
         //Nothing to do, by default
     }
@@ -456,7 +456,7 @@
         return Collections.EMPTY_LIST;
     }
 
-    public File getWorkingDirectory( Project project )
+    public File getWorkingDirectory( Project project, String projectScmRootUrl, List<Project> projectsWithCommonScmRoot )
     {
         return getWorkingDirectoryService().getWorkingDirectory( project );
     }
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/MavenTwoBuildExecutor.java b/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/MavenTwoBuildExecutor.java
index 6cc1ddf..e14e8b9 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/MavenTwoBuildExecutor.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/execution/maven/m2/MavenTwoBuildExecutor.java
@@ -338,7 +338,7 @@
     }
 
     @Override
-    public void backupTestFiles( Project project, int buildId )
+    public void backupTestFiles( Project project, int buildId, String projectScmRootUrl, List<Project> projectsWithCommonScmRoot )
     {
         File backupDirectory = null;
         try
@@ -353,7 +353,7 @@
         {
             log.info( "error on surefire backup directory creation skip backup " + e.getMessage(), e );
         }
-        backupTestFiles( getWorkingDirectory( project ), backupDirectory );
+        backupTestFiles( getWorkingDirectory( project, projectScmRootUrl, projectsWithCommonScmRoot ), backupDirectory );
     }
 
     private void backupTestFiles( File workingDir, File backupDirectory )
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilder.java b/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilder.java
index 72340d8..1677044 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilder.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilder.java
@@ -67,17 +67,17 @@
     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password )
         throws ContinuumProjectBuilderException
     {
-        return buildProjectsFromMetadata( url, username, password, true );
+    	return buildProjectsFromMetadata( url, username, password, true, false );
     }
 
     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
-                                                                     boolean recursiveProjects )
+    						boolean recursiveProjects, boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException
     {
         try
         {
             return buildProjectsFromMetadata( url, username, password, recursiveProjects,
-                                              buildDefinitionService.getDefaultMavenOneBuildDefinitionTemplate() );
+            				buildDefinitionService.getDefaultMavenOneBuildDefinitionTemplate(), false );
         }
         catch ( BuildDefinitionServiceException e )
         {
@@ -87,7 +87,7 @@
 
     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
                                                                      boolean recursiveProjects,
-                                                                     BuildDefinitionTemplate buildDefinitionTemplate )
+                                                                     BuildDefinitionTemplate buildDefinitionTemplate, boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException
     {
         ContinuumProjectBuildingResult result = new ContinuumProjectBuildingResult();
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilder.java b/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilder.java
index cbd1c76..a4d8ce9 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilder.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilder.java
@@ -83,6 +83,8 @@
      * @plexus.configuration
      */
     private List<String> excludedPackagingTypes = new ArrayList<String>();
+        
+    private Project rootProject;
 
     // ----------------------------------------------------------------------
     // AbstractContinuumProjectBuilder Implementation
@@ -90,17 +92,18 @@
     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password )
         throws ContinuumProjectBuilderException
     {
-        return buildProjectsFromMetadata( url, username, password, true );
+    	return buildProjectsFromMetadata( url, username, password, true, false );
     }
 
     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
-                                                                     boolean loadRecursiveProjects )
+    				boolean loadRecursiveProjects, boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException
     {
         try
         {
             return buildProjectsFromMetadata( url, username, password, loadRecursiveProjects,
-                                              buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate() );
+            						buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate(),
+                                    checkoutInSingleDirectory );
         }
         catch ( BuildDefinitionServiceException e )
         {
@@ -110,7 +113,7 @@
 
     public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
                                                                      boolean loadRecursiveProjects,
-                                                                     BuildDefinitionTemplate buildDefinitionTemplate )
+                                                                     BuildDefinitionTemplate buildDefinitionTemplate, boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException
     {
         // ----------------------------------------------------------------------
@@ -121,7 +124,7 @@
 
         try
         {
-            readModules( url, result, true, username, password, null, loadRecursiveProjects, buildDefinitionTemplate );
+        	readModules( url, result, true, username, password, null, loadRecursiveProjects, buildDefinitionTemplate, checkoutInSingleDirectory );
         }
         catch ( BuildDefinitionServiceException e )
         {
@@ -136,7 +139,7 @@
 
     private void readModules( URL url, ContinuumProjectBuildingResult result, boolean groupPom, String username,
                               String password, String scmUrl, boolean loadRecursiveProjects,
-                              BuildDefinitionTemplate buildDefinitionTemplate )
+                              BuildDefinitionTemplate buildDefinitionTemplate, boolean checkoutInSingleDirectory )
         throws ContinuumProjectBuilderException, BuildDefinitionServiceException
     {
 
@@ -238,6 +241,9 @@
                     continuumProject.setScmPassword( password );
                 }
             }
+            
+            continuumProject.setCheckedOutInSingleDirectory( checkoutInSingleDirectory );
+            
             // New project
             builderHelper.mapMavenProjectToContinuumProject( result, mavenProject, continuumProject, true);
 
@@ -264,6 +270,13 @@
                 continuumProject.setScmTag( mavenProject.getScm().getTag() );
             }
             result.addProject( continuumProject, MavenTwoBuildExecutor.ID );
+            
+                        
+	        if( checkoutInSingleDirectory && rootProject == null )
+	        {
+	            rootProject = continuumProject;
+	            result.setRootProject( rootProject );
+	        }
         }
 
         List<String> modules = mavenProject.getModules();
@@ -300,6 +313,7 @@
 
                     try
                     {
+                    	urlString = StringUtils.replace( urlString, '\\', '/' );
                         moduleUrl = new URL( urlString );
                     }
                     catch ( MalformedURLException e )
@@ -308,19 +322,34 @@
                         result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL, urlString );
                         continue;
                     }
-
-                    String moduleScmUrl;
-                    if ( scmUrl.endsWith( "/" ) )
-                    {
-                        moduleScmUrl = scmUrl + module;
+                    
+                    String moduleScmUrl = "";                    
+                 
+                    String modulePath = StringUtils.replace( new String( module ), '\\', '/' );
+                    
+                    // check if module is relative
+                    if( modulePath.indexOf( "../" ) != -1 )
+                    {   
+                        int depth =
+                            StringUtils.countMatches( StringUtils.substring( modulePath, 0,
+                                                                             modulePath.lastIndexOf( '/' ) + 1 ), "/" );
+                        
+                        String baseUrl = "";
+                        for( int j = 1; j <= depth; j++ )
+                        {
+                            scmUrl = StringUtils.chompLast( new String( scmUrl ), "/" );
+                            baseUrl = StringUtils.substring( scmUrl, 0, scmUrl.lastIndexOf( '/' ) );                            
+                        }
+                        moduleScmUrl = baseUrl + "/" + StringUtils.substring( modulePath, modulePath.lastIndexOf( "../" ) + 3 );
                     }
                     else
                     {
-                        moduleScmUrl = scmUrl + "/" + module;
+                    	scmUrl = StringUtils.chompLast( scmUrl, "/" );
+                    	moduleScmUrl = scmUrl + "/" + modulePath;
                     }
                     // we are in recursive loading mode
                     readModules( moduleUrl, result, false, username, password, moduleScmUrl, true,
-                                 buildDefinitionTemplate );
+                    		buildDefinitionTemplate, checkoutInSingleDirectory );
                 }
             }
         }
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java b/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java
index b3daaed..d39e1ce 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java
@@ -95,6 +95,11 @@
         CheckoutProjectContinuumAction.setScmUsername( context, task.getScmUserName() );
 
         CheckoutProjectContinuumAction.setScmPassword( context, task.getScmPassword() );
+        
+        context.put( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, task.getScmRootUrl() );
+        
+        context.put( AbstractContinuumAction.KEY_PROJECTS_IN_GROUP_WITH_COMMON_SCM_ROOT,
+                             task.getProjectsWithCommonScmRoot() );
 
         try
         {
diff --git a/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java b/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java
index 3456c3a..6c7538b 100644
--- a/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java
+++ b/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutor.java
@@ -24,10 +24,12 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.io.File;
 
 import org.apache.continuum.dao.BuildDefinitionDao;
 import org.apache.continuum.dao.BuildResultDao;
 import org.apache.continuum.dao.ProjectDao;
+import org.apache.continuum.dao.ProjectGroupDao;
 import org.apache.continuum.dao.ProjectScmRootDao;
 import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
@@ -103,6 +105,11 @@
      */
     private ContinuumNotificationDispatcher notifierDispatcher;
 
+    /**
+     * @plexus.requirement
+     */
+    private ProjectGroupDao projectGroupDao;
+
     public void executeTask( Task task )
         throws TaskExecutionException
     {
@@ -113,58 +120,89 @@
         Set<Integer> projectsId = projectsBuildDefinitionsMap.keySet();
         Map<String, Object> context = new HashMap<String, Object>();
         Map<Integer, ScmResult> scmResultMap = new HashMap<Integer, ScmResult>();
+        List<Project> projectList = new ArrayList<Project>();
+        int projectGroupId = 0;
 
         try
         {
-            for ( Integer projectId : projectsId )
+        	if ( !projectsId.isEmpty() )
             {
-                int buildDefinitionId = projectsBuildDefinitionsMap.get( projectId );
+        	    int projectId = projectsId.iterator().next();
+                Project project = projectDao.getProject( projectId );
+                ProjectGroup projectGroup = project.getProjectGroup();
+                projectGroupId = projectGroup.getId();
 
-                log.info( "Initializing prepare build" );
-                context = initializeContext( projectId, buildDefinitionId, prepareTask.getBuildTrigger() );
+                List<Project> projects = projectDao.getProjectsWithDependenciesByGroupId( projectGroupId );
+                                projectList = ProjectSorter.getSortedProjects( projects, log );
+            }
 
-                log.info(
-                    "Starting prepare build of project: " + AbstractContinuumAction.getProject( context ).getName() );
-                startPrepareBuild( context );
+            Project rootProject = null;
 
-                if ( !checkProjectScmRoot( context ) )
+            for ( Project project : projectList )
+            {
+	            if ( rootProject == null )
                 {
-                    break;
+                    // first project is the root project.
+                    rootProject = project;
                 }
 
-                try
-                {
-                    if ( AbstractContinuumAction.getBuildDefinition( context ).isBuildFresh() )
-                    {
-                        log.info( "Purging existing working copy" );
-                        cleanWorkingDirectory( context );
-                    }
+                int projectId = project.getId();
+                int buildDefinitionId;
 
-                    // ----------------------------------------------------------------------
-                    // TODO: Centralize the error handling from the SCM related actions.
-                    // ContinuumScmResult should return a ContinuumScmResult from all
-                    // methods, even in a case of failure.
-                    // ----------------------------------------------------------------------
-                    log.info( "Updating working dir" );
-                    updateWorkingDirectory( context );
-
-                    log.info( "Merging SCM results" );
-                    //CONTINUUM-1393
-                    if ( !AbstractContinuumAction.getBuildDefinition( context ).isBuildFresh() )
-                    {
-                        mergeScmResults( context );
-                    }
-                }
-                finally
+                if ( projectsBuildDefinitionsMap.get( projectId ) != null )
                 {
+                    buildDefinitionId = projectsBuildDefinitionsMap.get( projectId );
+
+                    log.info( "Initializing prepare build" );
+                    context = initializeContext( project, buildDefinitionId, prepareTask.getBuildTrigger() );
+    
                     log.info(
-                        "Ending prepare build of project: " + AbstractContinuumAction.getProject( context ).getName() );
-                    scmResultMap.put( AbstractContinuumAction.getProjectId( context ),
-                                      AbstractContinuumAction.getScmResult( context, new ScmResult() ) );
-                    endProjectPrepareBuild( context );
+                        "Starting prepare build of project: " + AbstractContinuumAction.getProject( context ).getName() );
+                    startPrepareBuild( context );
+    
+                    if ( !checkProjectScmRoot( context ) )
+                    {
+                    	break;
+                    }
+
+                    try
+                    {
+                        if ( AbstractContinuumAction.getBuildDefinition( context ).isBuildFresh() )
+                        {
+                            log.info( "Purging existing working copy" );
+                            cleanWorkingDirectory( context );
+                        }
+    
+                        // ----------------------------------------------------------------------
+                        // TODO: Centralize the error handling from the SCM related actions.
+                        // ContinuumScmResult should return a ContinuumScmResult from all
+                        // methods, even in a case of failure.
+                        // ----------------------------------------------------------------------
+                        log.info( "Updating working dir" );
+                        updateWorkingDirectory( context, rootProject );
+    
+                        log.info( "Merging SCM results" );
+                        //CONTINUUM-1393
+                        if ( !AbstractContinuumAction.getBuildDefinition( context ).isBuildFresh() )
+                        {
+                            mergeScmResults( context );
+                        }
+                    }
+                    finally
+                    {
+                        log.info(
+                            "Ending prepare build of project: " + AbstractContinuumAction.getProject( context ).getName() );
+                        scmResultMap.put( AbstractContinuumAction.getProjectId( context ),
+                                          AbstractContinuumAction.getScmResult( context, null ) );
+                        endProjectPrepareBuild( context );
+                    }
                 }
             }
         }
+        catch ( ContinuumStoreException e )
+        {
+            throw new TaskExecutionException( "Failed to prepare build project group: " + projectGroupId, e );
+        }
         finally
         {
             log.info( "Ending prepare build" );
@@ -173,35 +211,38 @@
 
         if ( checkProjectScmRoot( context ) )
         {
-            int projectGroupId = AbstractContinuumAction.getProjectGroupId( context );
-            buildProjects( projectGroupId, projectsBuildDefinitionsMap, buildTrigger, scmResultMap );
+            projectGroupId = AbstractContinuumAction.getProjectGroupId( context );
+            buildProjects( projectGroupId, projectList, projectsBuildDefinitionsMap, buildTrigger, scmResultMap );
         }
     }
 
-    private Map<String, Object> initializeContext( int projectId, int buildDefinitionId, BuildTrigger buildTrigger )
+    private Map<String, Object> initializeContext( Project project, int buildDefinitionId, BuildTrigger buildTrigger )
         throws TaskExecutionException
     {
         Map<String, Object> context = new HashMap<String, Object>();
 
         try
         {
-            Project project = projectDao.getProject( projectId );
             ProjectGroup projectGroup = project.getProjectGroup();
 
             List<ProjectScmRoot> scmRoots = projectScmRootDao.getProjectScmRootByProjectGroup( projectGroup.getId() );
             String projectScmUrl = project.getScmUrl();
+            String projectScmRootAddress = "";
 
             for ( ProjectScmRoot projectScmRoot : scmRoots )
             {
+            	projectScmRootAddress = projectScmRoot.getScmRootAddress();
+            	
                 if ( projectScmUrl.startsWith( projectScmRoot.getScmRootAddress() ) )
                 {
                     AbstractContinuumAction.setProjectScmRoot( context, projectScmRoot );
+                    context.put( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, projectScmRootAddress );
                     break;
                 }
             }
 
             AbstractContinuumAction.setProjectGroupId( context, projectGroup.getId() );
-            AbstractContinuumAction.setProjectId( context, projectId );
+            AbstractContinuumAction.setProjectId( context, project.getId() );
             AbstractContinuumAction.setProject( context, project );
             AbstractContinuumAction.setBuildTrigger( context, buildTrigger );
 
@@ -209,13 +250,28 @@
             AbstractContinuumAction.setBuildDefinition( context,
                                                         buildDefinitionDao.getBuildDefinition( buildDefinitionId ) );
 
+             if( project.isCheckedOutInSingleDirectory() )
+             {
+                 List<Project> projectsInGroup =
+                     projectGroupDao.getProjectGroupWithProjects( projectGroup.getId() ).getProjects(); 
+                 List<Project> projectsWithCommonScmRoot = new ArrayList<Project>();            
+                 for( Project projectInGroup : projectsInGroup )
+                 {
+                     if( projectInGroup.getScmUrl().startsWith( projectScmRootAddress ) )
+                     {
+                         projectsWithCommonScmRoot.add( projectInGroup );
+                     }
+                 }            
+                 context.put( AbstractContinuumAction.KEY_PROJECTS_IN_GROUP_WITH_COMMON_SCM_ROOT, projectsWithCommonScmRoot );
+             }
+            
             BuildResult oldBuildResult =
-                buildResultDao.getLatestBuildResultForBuildDefinition( projectId, buildDefinitionId );
+            	buildResultDao.getLatestBuildResultForBuildDefinition( project.getId(), buildDefinitionId );
 
             if ( oldBuildResult != null )
             {
                 AbstractContinuumAction.setOldScmResult( context,
-                                                         getOldScmResults( projectId, oldBuildResult.getBuildNumber(),
+                										getOldScmResults( project.getId(), oldBuildResult.getBuildNumber(),
                                                                            oldBuildResult.getEndTime() ) );
             }
             else
@@ -237,7 +293,7 @@
         performAction( "clean-working-directory", context );
     }
 
-    private void updateWorkingDirectory( Map<String, Object> context )
+    private void updateWorkingDirectory( Map<String, Object> context, Project rootProject )
         throws TaskExecutionException
     {
         performAction( "check-working-directory", context );
@@ -258,6 +314,43 @@
 
             AbstractContinuumAction.setWorkingDirectory( context, workingDirectoryService.getWorkingDirectory(
                 project ).getAbsolutePath() );
+            
+            List<Project> projectsWithCommonScmRoot = AbstractContinuumAction.getListOfProjectsInGroupWithCommonScmRoot( context );           
+            String projectScmRootUrl = AbstractContinuumAction.getString( context, AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL, project.getScmUrl() );
+            String workingDir = null;
+
+            if ( rootProject.getId() == project.getId() )
+            {
+                workingDir = workingDirectoryService.getWorkingDirectory( project, false ).getAbsolutePath();
+
+                if ( project.isCheckedOutInSingleDirectory() )
+                {
+                    File parentDir = new File( workingDir );
+
+                    while ( !isRootDirectory( parentDir.getAbsolutePath(), project ) )
+                    {
+                        parentDir = parentDir.getParentFile();
+                    }
+
+                    if ( !parentDir.exists() )
+                    {
+                        workingDir = parentDir.getAbsolutePath();
+                    }
+                }
+            }
+
+            if ( workingDir == null || new File( workingDir ).exists() )
+            {
+                workingDir = workingDirectoryService.getWorkingDirectory( 
+                    project, projectScmRootUrl, projectsWithCommonScmRoot ).getAbsolutePath();
+            }
+
+            AbstractContinuumAction.setWorkingDirectory( context, workingDir );
+
+            if ( rootProject.getId() != project.getId() || ( rootProject.getId() == project.getId() && !isRootDirectory( workingDir, rootProject ) ) )
+            {
+                AbstractContinuumAction.setRootDirectory(context, false );
+            }
 
             performAction( "checkout-project", context );
 
@@ -509,15 +602,10 @@
         }
     }
 
-    private void buildProjects( int projectGroupId, Map<Integer, Integer> projectsAndBuildDefinitionsMap,
-    		                    BuildTrigger buildTrigger, Map<Integer, ScmResult> scmResultMap )
+    private void buildProjects( int projectGroupId, List<Project> projectList, Map<Integer, Integer> projectsAndBuildDefinitionsMap, BuildTrigger buildTrigger,
+    		Map<Integer, ScmResult> scmResultMap )
         throws TaskExecutionException
-    {
-        List<Project> projects = projectDao.getProjectsWithDependenciesByGroupId( projectGroupId );
-        List<Project> projectList;
-
-        projectList = ProjectSorter.getSortedProjects( projects, log );
-
+    {   
         List<Project> projectsToBeBuilt = new ArrayList<Project>();
         Map<Integer, BuildDefinition> projectsBuildDefinitionsMap = new HashMap<Integer, BuildDefinition>();
 
@@ -566,4 +654,10 @@
             throw new TaskExecutionException( "Error executing action 'build-project'", e );
         }
     }
+    
+    private boolean isRootDirectory( String workingDir, Project rootProject )
+    {
+        return workingDir.endsWith( Integer.toString( rootProject.getId() ) + System.getProperty( "line.separator" ) )
+            || workingDir.endsWith( Integer.toString( rootProject.getId() ) );
+    }
 }
diff --git a/continuum-core/src/test-projects/flat-multi-module/.cvsignore b/continuum-core/src/test-projects/flat-multi-module/.cvsignore
index cce9515..069b8f9 100644
--- a/continuum-core/src/test-projects/flat-multi-module/.cvsignore
+++ b/continuum-core/src/test-projects/flat-multi-module/.cvsignore
@@ -6,3 +6,11 @@
 *.ipr
 *.iws
 *.iml
+target
+*~
+*.log
+.classpath
+.project
+*.ipr
+*.iws
+*.iml
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-a/pom.xml b/continuum-core/src/test-projects/flat-multi-module/module-a/pom.xml
index 5ce5434..d604ab8 100644
--- a/continuum-core/src/test-projects/flat-multi-module/module-a/pom.xml
+++ b/continuum-core/src/test-projects/flat-multi-module/module-a/pom.xml
@@ -1,4 +1,23 @@
-<?xml version="1.0"?><project>
+<?xml version="1.0"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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.
+  -->
+<project>
   <parent>
     <artifactId>parent-project</artifactId>
     <groupId>org.apache.continuum</groupId>
@@ -18,4 +37,4 @@
       <scope>test</scope>
     </dependency>
   </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-a/src/main/java/org/apache/continuum/module/a/App.java b/continuum-core/src/test-projects/flat-multi-module/module-a/src/main/java/org/apache/continuum/module/a/App.java
index af5441b..295b16a 100644
--- a/continuum-core/src/test-projects/flat-multi-module/module-a/src/main/java/org/apache/continuum/module/a/App.java
+++ b/continuum-core/src/test-projects/flat-multi-module/module-a/src/main/java/org/apache/continuum/module/a/App.java
@@ -1,5 +1,37 @@
 package org.apache.continuum.module.a;
 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
+package org.apache.continuum.module.a;
+
 /**
  * Hello world!
  *
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-a/src/test/java/org/apache/continuum/module/a/AppTest.java b/continuum-core/src/test-projects/flat-multi-module/module-a/src/test/java/org/apache/continuum/module/a/AppTest.java
index be48197..9d5cf91 100644
--- a/continuum-core/src/test-projects/flat-multi-module/module-a/src/test/java/org/apache/continuum/module/a/AppTest.java
+++ b/continuum-core/src/test-projects/flat-multi-module/module-a/src/test/java/org/apache/continuum/module/a/AppTest.java
@@ -1,5 +1,62 @@
 package org.apache.continuum.module.a;
 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}
+package org.apache.continuum.module.a;
+
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-b/pom.xml b/continuum-core/src/test-projects/flat-multi-module/module-b/pom.xml
index 6418214..95ff9e5 100644
--- a/continuum-core/src/test-projects/flat-multi-module/module-b/pom.xml
+++ b/continuum-core/src/test-projects/flat-multi-module/module-b/pom.xml
@@ -1,4 +1,23 @@
-<?xml version="1.0"?><project>
+<?xml version="1.0"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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.
+  -->
+<project>
   <parent>
     <artifactId>parent-project</artifactId>
     <groupId>org.apache.continuum</groupId>
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-b/src/main/java/org/apache/continuum/module/b/App.java b/continuum-core/src/test-projects/flat-multi-module/module-b/src/main/java/org/apache/continuum/module/b/App.java
index 03bd5e5..798ec8f 100644
--- a/continuum-core/src/test-projects/flat-multi-module/module-b/src/main/java/org/apache/continuum/module/b/App.java
+++ b/continuum-core/src/test-projects/flat-multi-module/module-b/src/main/java/org/apache/continuum/module/b/App.java
@@ -1,5 +1,37 @@
 package org.apache.continuum.module.b;
 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
+package org.apache.continuum.module.b;
+
 /**
  * Hello world!
  *
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-b/src/test/java/org/apache/continuum/module/b/AppTest.java b/continuum-core/src/test-projects/flat-multi-module/module-b/src/test/java/org/apache/continuum/module/b/AppTest.java
index bd73035..30dab2c 100644
--- a/continuum-core/src/test-projects/flat-multi-module/module-b/src/test/java/org/apache/continuum/module/b/AppTest.java
+++ b/continuum-core/src/test-projects/flat-multi-module/module-b/src/test/java/org/apache/continuum/module/b/AppTest.java
@@ -1,5 +1,62 @@
 package org.apache.continuum.module.b;
 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}
+package org.apache.continuum.module.b;
+
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/pom.xml b/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/pom.xml
new file mode 100644
index 0000000..7129ba2
--- /dev/null
+++ b/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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.
+  -->
+<project>
+  <parent>
+    <artifactId>parent-project</artifactId>
+    <groupId>org.apache.continuum</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.continuum</groupId>
+  <artifactId>module-d</artifactId>
+  <name>module-d</name>
+  <version>1.0-SNAPSHOT</version>
+  <url>http://maven.apache.org</url>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.continuum</groupId>
+      <artifactId>module-a</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/src/main/java/org/apache/continuum/module/d/App.java b/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/src/main/java/org/apache/continuum/module/d/App.java
new file mode 100644
index 0000000..952ee35
--- /dev/null
+++ b/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/src/main/java/org/apache/continuum/module/d/App.java
@@ -0,0 +1,32 @@
+package org.apache.continuum.module.d;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
diff --git a/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/src/test/java/org/apache/continuum/module/d/AppTest.java b/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/src/test/java/org/apache/continuum/module/d/AppTest.java
new file mode 100644
index 0000000..876714b
--- /dev/null
+++ b/continuum-core/src/test-projects/flat-multi-module/module-c/module-d/src/test/java/org/apache/continuum/module/d/AppTest.java
@@ -0,0 +1,57 @@
+package org.apache.continuum.module.a;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}
diff --git a/continuum-core/src/test-projects/flat-multi-module/parent-project/pom.xml b/continuum-core/src/test-projects/flat-multi-module/parent-project/pom.xml
index 8b03350..cbf52d6 100644
--- a/continuum-core/src/test-projects/flat-multi-module/parent-project/pom.xml
+++ b/continuum-core/src/test-projects/flat-multi-module/parent-project/pom.xml
@@ -1,4 +1,22 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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.
+  -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.continuum</groupId>
@@ -22,5 +40,6 @@
   <modules>
     <module>../module-a</module>
     <module>../module-b</module>
+    <module>../module-c/module-d</module>
   </modules>
-</project>
+</project>
\ No newline at end of file
diff --git a/continuum-core/src/test-projects/multi-module/module-C/module-D/pom.xml b/continuum-core/src/test-projects/multi-module/module-C/module-D/pom.xml
new file mode 100644
index 0000000..d9b73e6
--- /dev/null
+++ b/continuum-core/src/test-projects/multi-module/module-C/module-D/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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.
+  -->
+<project>
+  <parent>
+    <artifactId>multi-module-parent</artifactId>
+    <groupId>org.apache.continuum</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.continuum</groupId>
+  <artifactId>module-D</artifactId>
+  <name>module-D</name>
+  <version>1.0-SNAPSHOT</version>
+  <url>http://maven.apache.org</url>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/continuum-core/src/test-projects/multi-module/module-C/module-D/src/main/java/org/apache/continuum/module/c/App.java b/continuum-core/src/test-projects/multi-module/module-C/module-D/src/main/java/org/apache/continuum/module/c/App.java
new file mode 100644
index 0000000..bbf5ad5
--- /dev/null
+++ b/continuum-core/src/test-projects/multi-module/module-C/module-D/src/main/java/org/apache/continuum/module/c/App.java
@@ -0,0 +1,32 @@
+package org.apache.continuum.module.c;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
diff --git a/continuum-core/src/test-projects/multi-module/module-C/module-D/src/test/java/org/apache/continuum/module/b/AppTest.java b/continuum-core/src/test-projects/multi-module/module-C/module-D/src/test/java/org/apache/continuum/module/b/AppTest.java
new file mode 100644
index 0000000..0e8d12f
--- /dev/null
+++ b/continuum-core/src/test-projects/multi-module/module-C/module-D/src/test/java/org/apache/continuum/module/b/AppTest.java
@@ -0,0 +1,57 @@
+package org.apache.continuum.module.b;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}
diff --git a/continuum-core/src/test-projects/multi-module/pom.xml b/continuum-core/src/test-projects/multi-module/pom.xml
index e288ab0..14238d4 100644
--- a/continuum-core/src/test-projects/multi-module/pom.xml
+++ b/continuum-core/src/test-projects/multi-module/pom.xml
@@ -41,5 +41,6 @@
   <modules>
     <module>module-A</module>
     <module>module-B</module>
+    <module>module-C/module-D</module>
   </modules>
 </project>
diff --git a/continuum-core/src/test/java/org/apache/continuum/buildmanager/ParallelBuildsManagerTest.java b/continuum-core/src/test/java/org/apache/continuum/buildmanager/ParallelBuildsManagerTest.java
index 47f260f..0a213c6 100644
--- a/continuum-core/src/test/java/org/apache/continuum/buildmanager/ParallelBuildsManagerTest.java
+++ b/continuum-core/src/test/java/org/apache/continuum/buildmanager/ParallelBuildsManagerTest.java
@@ -435,8 +435,8 @@
         recordCheckoutProjectBuildQueuesAreEmpty();
 
         buildsManager.checkoutProject( 1, "continuum-project-test-1",
-                                       new File( getBasedir(), "/target/test-working-dir/1" ), "dummy", "dummypass",
-                                       buildDef );
+        			new File( getBasedir(), "/target/test-working-dir/1" ), null, "dummy", "dummypass",
+        			buildDef, null );
         context.assertIsSatisfied();
     }
 
@@ -452,8 +452,8 @@
         recordCheckoutProjectBuildQueuesAreEmpty();
 
         buildsManager.checkoutProject( 1, "continuum-project-test-1",
-                                       new File( getBasedir(), "/target/test-working-dir/1" ), "dummy", "dummypass",
-                                       buildDef );
+	        		new File( getBasedir(), "/target/test-working-dir/1" ), null, "dummy", "dummypass",
+	    			buildDef, null );
         context.assertIsSatisfied();
 
         // queue second project - 1st queue has 1 task while 2nd queue is empty; project should be queued in
@@ -465,7 +465,7 @@
         final List<Task> tasksInFirstCheckoutQueue = new ArrayList<Task>();
         tasksInFirstCheckoutQueue.add(
             new CheckOutTask( 1, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-1",
-                              "dummy", "dummypass" ) );
+            			"dummy", "dummypass", null, null ) );
 
         context.checking( new Expectations()
         {
@@ -486,8 +486,8 @@
         recordAddToCheckoutQueue();
 
         buildsManager.checkoutProject( 2, "continuum-project-test-2",
-                                       new File( getBasedir(), "/target/test-working-dir/1" ), "dummy", "dummypass",
-                                       buildDef );
+	        		new File( getBasedir(), "/target/test-working-dir/1" ), null, "dummy", "dummypass",
+	    			buildDef, null );
         context.assertIsSatisfied();
 
         // queue third project - both queues have 1 task queued each; third project should be queued in 1st queue
@@ -509,8 +509,8 @@
         recordAddToCheckoutQueue();
 
         buildsManager.checkoutProject( 3, "continuum-project-test-3",
-                                       new File( getBasedir(), "/target/test-working-dir/1" ), "dummy", "dummypass",
-                                       buildDef );
+	        		new File( getBasedir(), "/target/test-working-dir/1" ), null, "dummy", "dummypass",
+	    			buildDef, null );
         context.assertIsSatisfied();
     }
 
@@ -613,7 +613,7 @@
         final List<CheckOutTask> checkoutTasks = new ArrayList<CheckOutTask>();
         checkoutTasks.add(
             new CheckOutTask( 2, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-2",
-                              "dummy", "dummypass" ) );
+            			"dummy", "dummypass", null, null ) );
 
         final ParallelBuildsThreadedTaskQueueExecutor buildTaskQueueExecutor =
             context.mock( ParallelBuildsThreadedTaskQueueExecutor.class, "parallel-build-task-executor" );
@@ -756,7 +756,7 @@
         final List<CheckOutTask> checkoutTasks = new ArrayList<CheckOutTask>();
         checkoutTasks.add(
             new CheckOutTask( 2, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-2",
-                              "dummy", "dummypass" ) );
+            			"dummy", "dummypass", null, null ) );
 
         try
         {
@@ -863,7 +863,7 @@
         final List<Task> tasks = new ArrayList<Task>();
         tasks.add(
             new CheckOutTask( 2, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-2",
-                              "dummy", "dummypass" ) );
+            			"dummy", "dummypass", null, null ) );
 
         context.checking( new Expectations()
         {
diff --git a/continuum-core/src/test/java/org/apache/continuum/taskqueue/DefaultOverallBuildQueueTest.java b/continuum-core/src/test/java/org/apache/continuum/taskqueue/DefaultOverallBuildQueueTest.java
index dd4e8b1..5961c92 100644
--- a/continuum-core/src/test/java/org/apache/continuum/taskqueue/DefaultOverallBuildQueueTest.java
+++ b/continuum-core/src/test/java/org/apache/continuum/taskqueue/DefaultOverallBuildQueueTest.java
@@ -85,7 +85,7 @@
     {
         final CheckOutTask checkoutTask =
             new CheckOutTask( 1, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-1",
-                              "dummy", "dummypass" );
+            			"dummy", "dummypass", null, null );
         final TaskQueue checkoutQueue = context.mock( TaskQueue.class, "checkout-queue" );
 
         context.checking( new Expectations()
@@ -108,7 +108,7 @@
         final List<Task> tasks = new ArrayList<Task>();
         tasks.add(
             new CheckOutTask( 1, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-1",
-                              "dummy", "dummypass" ) );
+            			"dummy", "dummypass", null, null ) );
 
         context.checking( new Expectations()
         {
@@ -134,7 +134,7 @@
         final List<Task> tasks = new ArrayList<Task>();
         tasks.add(
             new CheckOutTask( 1, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-1",
-                              "dummy", "dummypass" ) );
+            			"dummy", "dummypass", null, null ) );
 
         context.checking( new Expectations()
         {
@@ -155,7 +155,7 @@
     {
         final Task checkoutTask =
             new CheckOutTask( 1, new File( getBasedir(), "/target/test-working-dir/1" ), "continuum-project-test-1",
-                              "dummy", "dummypass" );
+            			"dummy", "dummypass", null, null );
         final TaskQueue checkoutQueue = context.mock( TaskQueue.class, "checkout-queue" );
         final List<Task> tasks = new ArrayList<Task>();
         tasks.add( checkoutTask );
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/AddMaven2ProjectTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/AddMaven2ProjectTest.java
index e031cad..6a9fdbd 100755
--- a/continuum-core/src/test/java/org/apache/maven/continuum/AddMaven2ProjectTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/AddMaven2ProjectTest.java
@@ -91,7 +91,7 @@
         ContinuumProjectBuildingResult result = getContinuum().addMavenTwoProject(
                                                                                    rootPom.toURI().toURL()
                                                                                        .toExternalForm(), pg.getId(),
-                                                                                   true, false, false, bdt.getId() );
+                                                                                       true, false, false, bdt.getId(), false );
         assertNotNull( result );
 
         assertEquals( 1, result.getProjects().size() );
@@ -118,7 +118,7 @@
         ContinuumProjectBuildingResult result = getContinuum().addMavenTwoProject(
                                                                                    rootPom.toURI().toURL()
                                                                                        .toExternalForm(), -1, true,
-                                                                                   false, true, bdt.getId() );
+                                                                                       false, true, bdt.getId(), false );
         assertNotNull( result );
 
         assertEquals( 1, result.getProjects().size() );
@@ -154,7 +154,7 @@
         ContinuumProjectBuildingResult result = getContinuum().addMavenTwoProject(
                                                                                    rootPom.toURI().toURL()
                                                                                        .toExternalForm(), -1, true,
-                                                                                   false, true, -1 );
+                                                                                       false, true, -1, false );
         assertNotNull( result );
 
         assertEquals( 1, result.getProjects().size() );
@@ -202,7 +202,7 @@
         ContinuumProjectBuildingResult result = getContinuum().addMavenTwoProject(
                                                                                    rootPom.toURI().toURL()
                                                                                        .toExternalForm(), pg.getId(),
-                                                                                   true, false, false, -1 );
+                                                                                       true, false, false, -1, false );
         assertNotNull( result );
 
         assertEquals( 1, result.getProjects().size() );
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/AddProjectTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/AddProjectTest.java
index 7a78397..fa26cfd 100755
--- a/continuum-core/src/test/java/org/apache/maven/continuum/AddProjectTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/AddProjectTest.java
@@ -44,7 +44,7 @@
         
         ContinuumProjectBuildingResult result = continuum
             .executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID,
-                                                     getDefaultProjectGroup().getId(), false, true, false, -1, false );
+            						getDefaultProjectGroup().getId(), false, true, false, -1, false, false );
         assertEquals( 1, result.getProjects().size() );
         
         // read the project from store
@@ -62,7 +62,7 @@
 
         ContinuumProjectBuildingResult result = continuum
             .executeAddProjectsFromMetadataActivity( metadataUrl, MavenTwoContinuumProjectBuilder.ID,
-                                                     getDefaultProjectGroup().getId(), false, false, false, -1, false );
+            						getDefaultProjectGroup().getId(), false, false, false, -1, false, false );
         assertEquals( 1, result.getProjects().size() );
 
         // read the project from store
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java
index 0aa86cf..4c4534c 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java
@@ -29,6 +29,7 @@
 import org.apache.continuum.buildmanager.BuildsManager;
 import org.apache.continuum.dao.BuildResultDao;
 import org.apache.continuum.dao.ProjectDao;
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.continuum.model.release.ContinuumReleaseResult;
 import org.apache.continuum.model.repository.LocalRepository;
 import org.apache.continuum.repository.RepositoryService;
@@ -100,7 +101,7 @@
         assertTrue( rootPom.exists() );
 
         ContinuumProjectBuildingResult result =
-            continuum.addMavenTwoProject( rootPom.toURI().toURL().toExternalForm(), -1, true, false, true, -1 );
+        	continuum.addMavenTwoProject( rootPom.toURI().toURL().toExternalForm(), -1, true, false, true, -1, false );
 
         assertNotNull( result );
 
@@ -134,9 +135,95 @@
 
         assertTrue( "no jabber notifier", projects.containsKey( "Continuum Jabber Notifier" ) );
 
-
     }
+    
+    // handle flat multi-module projects
+    public void testAddMavenTwoProjectSetInSingleDirectory()
+        throws Exception
+    {   
+        Continuum continuum = (Continuum) lookup( Continuum.ROLE );
+        
+        String url = getTestFile( "src/test-projects/flat-multi-module/parent-project/pom.xml" ).toURL().toExternalForm();
 
+        ContinuumProjectBuildingResult result = continuum.addMavenTwoProject( url, -1, true, false, true, -1, true );
+ 
+        assertNotNull( result );
+
+        List<Project> projects = result.getProjects();
+
+        assertEquals( 4, projects.size() );     
+        
+        Project rootProject = result.getRootProject();
+        
+        assertNotNull( rootProject );
+        
+        Map<String, Project> projectsMap = new HashMap<String, Project>();
+
+        int projectGroupId = 0;
+
+        for ( Project project : getProjectDao().getAllProjectsByName() )
+        {
+            projectsMap.put( project.getName(), project );
+
+            ProjectGroup projectGroup = getProjectGroupDao().getProjectGroupByProjectId( project.getId() );
+            projectGroupId = projectGroup.getId();
+
+            // validate project in project group
+            assertTrue( "project not in project group", projectGroup != null );
+        }
+
+        // sometimes projects don't get added to checkout queue
+        continuum.buildProjectGroup( projectGroupId, new org.apache.continuum.utils.build.BuildTrigger( 1, "user" ) );
+
+        assertTrue( "no module-a", projectsMap.containsKey( "module-a" ) );
+        
+        assertTrue( "no module-b", projectsMap.containsKey( "module-b" ) );
+
+        assertTrue( "no module-d", projectsMap.containsKey( "module-d" ) );
+
+        // check if the modules were checked out in the same directory as the parent
+        ConfigurationService configurationService = ( ConfigurationService ) lookup( "configurationService" );
+        
+        File workingDir = configurationService.getWorkingDirectory();
+        
+        Project parentProject = getProjectDao().getProjectByName( "parent-project" );
+        
+        File checkoutDir = new File( workingDir, String.valueOf( parentProject.getId() ) );
+
+        for( long delay = 0; delay <= 999999999; delay++ )
+        {
+            // wait while the project has been checked out/build
+        }
+        
+        assertTrue( "checkout directory of project 'parent-project' does not exist." , new File( checkoutDir, "parent-project" ).exists() );
+        
+        assertFalse( "module-a should not have been checked out as a separate project.",
+                    new File( workingDir, String.valueOf( getProjectDao().getProjectByName( "module-a" ).getId() ) ).exists() );
+        
+        assertFalse( "module-b should not have been checked out as a separate project.",
+                    new File( workingDir, String.valueOf( getProjectDao().getProjectByName( "module-b" ).getId() ) ).exists() );
+
+        assertFalse( "module-d should not have been checked out as a separate project.",
+                     new File( workingDir, String.valueOf( getProjectDao().getProjectByName( "module-d" ).getId() ) ).exists() );
+
+        assertTrue( "module-a was not checked out in the same directory as it's parent.", new File( checkoutDir, "module-a" ).exists() );
+        
+        assertTrue( "module-b was not checked out in the same directory as it's parent.", new File( checkoutDir, "module-b" ).exists() );
+
+        assertTrue( "module-d was not checked out in the same directory as it's parent.", new File( checkoutDir, "module-c/module-d" ).exists() );
+
+        // assert project state
+        // commented out this test case as it sometimes fails because the actual checkout hasn't finished yet so
+        //    the state hasn't been updated yet
+        /*assertEquals( "state of 'parent-project' should have been updated.", ContinuumProjectState.CHECKEDOUT, parentProject.getState() );
+        
+        assertEquals( "state of 'module-a' should have been updated.", ContinuumProjectState.CHECKEDOUT,
+                      getProjectDao().getProjectByName( "module-a" ).getState() );
+        
+        assertEquals( "state of 'module-b' should have been updated.", ContinuumProjectState.CHECKEDOUT,
+                      getProjectDao().getProjectByName( "module-b" ).getState() );*/        
+    }
+        
     public void testUpdateMavenTwoProject()
         throws Exception
     {
@@ -432,6 +519,51 @@
         assertFalse( "project still exist on the checkout queue",
                      parallelBuildsManager.isInAnyCheckoutQueue( project.getId() ) );
     }
+    
+    /*public void testCreationOfProjectScmRootDuringInitialization()
+        throws Exception
+    {
+        DefaultContinuum continuum = (DefaultContinuum) getContinuum();
+
+        ProjectGroup defaultProjectGroup =
+            continuum.getProjectGroupByGroupId( ContinuumInitializer.DEFAULT_PROJECT_GROUP_GROUP_ID );
+
+        ProjectScmRoot scmRoot = new ProjectScmRoot();
+        scmRoot.setProjectGroup( defaultProjectGroup );
+        scmRoot.setScmRootAddress( "http://temp.company.com/svn/trunk" );
+        getProjectScmRootDao().addProjectScmRoot( scmRoot );
+        
+        defaultProjectGroup = continuum.getProjectGroupWithProjects( defaultProjectGroup.getId() );
+        assertEquals( 0, defaultProjectGroup.getProjects().size() );
+        
+        Project project = new Project();
+        project.setGroupId( "project1" );
+        project.setArtifactId( "project1" );
+        project.setVersion( "1.0-SNAPSHOT" );
+        project.setScmUrl( "http://temp.company.com/svn/trunk/project1" );
+        defaultProjectGroup.addProject( project );
+
+        project = new Project();
+        project.setGroupId( "project2" );
+        project.setArtifactId( "project2" );
+        project.setVersion( "1.0-SNAPSHOT" );
+        project.setScmUrl( "http://temp.company.com/svn/trunk/project2" );
+        defaultProjectGroup.addProject( project );
+
+        project = new Project();
+        project.setGroupId( "project3" );
+        project.setArtifactId( "project3" );
+        project.setVersion( "1.0-SNAPSHOT" );
+        project.setScmUrl( "http://temp.company.com/svn/trunk/project3" );
+        defaultProjectGroup.addProject( project );
+
+        getProjectGroupDao().updateProjectGroup( defaultProjectGroup );
+
+        continuum.initialize();
+
+        List<ProjectScmRoot> scmRoots = continuum.getProjectScmRootByProjectGroup( defaultProjectGroup.getId() );
+        assertEquals( "#scmRoots in the group", 1, scmRoots.size() );
+    }    */
 
     public void testAddAntProjectWithdefaultBuildDef()
         throws Exception
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/buildcontroller/DefaultBuildControllerTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/buildcontroller/DefaultBuildControllerTest.java
index 2195e4a..8da182c 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/buildcontroller/DefaultBuildControllerTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/buildcontroller/DefaultBuildControllerTest.java
@@ -22,7 +22,9 @@
 import org.apache.continuum.dao.BuildDefinitionDao;
 import org.apache.continuum.dao.BuildResultDao;
 import org.apache.continuum.utils.build.BuildTrigger;
+import org.apache.continuum.model.project.ProjectScmRoot;
 import org.apache.maven.continuum.AbstractContinuumTest;
+import org.apache.maven.continuum.core.action.AbstractContinuumAction;
 import org.apache.maven.continuum.execution.ContinuumBuildExecutorConstants;
 import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
@@ -37,6 +39,7 @@
 import java.io.IOException;
 import java.util.Calendar;
 import java.util.List;
+import java.util.Map;
 
 public class DefaultBuildControllerTest
     extends AbstractContinuumTest
@@ -138,7 +141,14 @@
         BuildResult oldBuildResult = new BuildResult();
         oldBuildResult.setEndTime( Calendar.getInstance().getTimeInMillis() + ( hourOfLastExecution * 3600000 ) );
         context.setOldBuildResult( oldBuildResult );
-        context.setScmResult( new ScmResult() );
+        context.setScmResult( new ScmResult() );     
+                      
+        Map<String, Object> actionContext = context.getActionContext();
+        ProjectScmRoot projectScmRoot = new ProjectScmRoot();
+        projectScmRoot.setId( 1 );
+        projectScmRoot.setScmRootAddress( "scm:local:src/test-projects:flat-multi-module" );
+        actionContext.put( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT, projectScmRoot );
+
         return context;
     }
 
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataTest.java
index 7eec0d9..5cb093a 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/core/action/CreateProjectsFromMetadataTest.java
@@ -36,6 +36,7 @@
 import org.codehaus.plexus.logging.console.ConsoleLogger;
 import org.jmock.Mock;
 import org.jmock.MockObjectTestCase;
+import org.codehaus.plexus.spring.PlexusInSpringTestCase;
 
 public class CreateProjectsFromMetadataTest
     extends MockObjectTestCase
@@ -51,24 +52,35 @@
         result = new ContinuumProjectBuildingResult();
         action = new CreateProjectsFromMetadataAction();
         action.enableLogging( new ConsoleLogger( Logger.LEVEL_DEBUG, "" ) );
-        Mock projectBuilderManagerMock = mock( ContinuumProjectBuilderManager.class );
-        Mock mavenSettingsBuilderMock = mock( MavenSettingsBuilder.class );
-        action.setProjectBuilderManager( (ContinuumProjectBuilderManager) projectBuilderManagerMock.proxy() );
-        action.setMavenSettingsBuilder( (MavenSettingsBuilder) mavenSettingsBuilderMock.proxy() );
-        action.setUrlValidator( new ContinuumUrlValidator() );
-        Mock projectBuilder = mock( ContinuumProjectBuilder.class );
-
-        projectBuilderManagerMock.expects( once() ).method( "getProjectBuilder" ).will(
-            returnValue( projectBuilder.proxy() ) );
-        projectBuilder.expects( once() ).method( "buildProjectsFromMetadata" ).will(
-            returnValue( result ) );
-
-        projectBuilder.expects( once() ).method( "getDefaultBuildDefinitionTemplate" ).will(
-            returnValue( getDefaultBuildDefinitionTemplate() ) );
-
-        mavenSettingsBuilderMock.expects( once() ).method( "buildSettings" ).will( returnValue( new Settings() ) );
-
+        
+        recordBuildProjectFromHttp();
     }
+    
+    private void recordBuildProjectFromHttp()
+            throws Exception
+    {
+        result = new ContinuumProjectBuildingResult();
+        Mock projectBuilderManagerMock = mock( ContinuumProjectBuilderManager.class );
+        
+        action.setProjectBuilderManager( (ContinuumProjectBuilderManager) projectBuilderManagerMock.proxy() );        
+        action.setUrlValidator( new ContinuumUrlValidator() );
+        
+        Mock projectBuilder = mock( ContinuumProjectBuilder.class );
+        
+        projectBuilderManagerMock.expects( once() ).method( "getProjectBuilder" )
+            .will( returnValue( projectBuilder.proxy() ) );
+        projectBuilder.expects( once() ).method( "buildProjectsFromMetadata" )
+            .will( returnValue( result ) );
+        projectBuilder.expects( once() ).method( "getDefaultBuildDefinitionTemplate" )
+            .will( returnValue( getDefaultBuildDefinitionTemplate() ) );        
+    }
+    
+    private void invokeBuildSettings()
+    {
+        Mock mavenSettingsBuilderMock = mock( MavenSettingsBuilder.class );
+        action.setMavenSettingsBuilder( (MavenSettingsBuilder) mavenSettingsBuilderMock.proxy() );
+        mavenSettingsBuilderMock.expects( once() ).method( "buildSettings" ).will( returnValue( new Settings() ) );
+     }
 
     private BuildDefinitionTemplate getDefaultBuildDefinitionTemplate()
         throws Exception
@@ -94,15 +106,19 @@
     public void testExecuteWithNonRecursiveMode()
         throws Exception
     {
+    	invokeBuildSettings();
+    	
         Map<String, Object> context = new HashMap<String, Object>();
-        CreateProjectsFromMetadataAction.setUrl( context,
-                                                 "http://svn.apache.org/repos/asf/maven/continuum/trunk/pom.xml" );
-        CreateProjectsFromMetadataAction.setProjectBuilderId( context, "id" );
-        CreateProjectsFromMetadataAction.setLoadRecursiveProject( context, true );
+        context.put( AbstractContinuumAction.KEY_URL,
+		            "http://svn.apache.org/repos/asf/maven/continuum/trunk/pom.xml" );
+        context.put( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDER_ID, "id" );
+        context.put( CreateProjectsFromMetadataAction.KEY_LOAD_RECURSIVE_PROJECTS, true );
+        context.put( CreateProjectsFromMetadataAction.KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY, false );
 
         action.execute( context );
 
-        ContinuumProjectBuildingResult result = CreateProjectsFromMetadataAction.getProjectBuildingResult( context );
+        ContinuumProjectBuildingResult result =
+	            (ContinuumProjectBuildingResult) context.get( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDING_RESULT );
 
         assertFalse(
             "Should not have errors but had " + result.getErrorsAsString() + " (this test requires internet access)",
@@ -112,24 +128,84 @@
     public void testExecuteWithRecursiveMode()
         throws Exception
     {
+    	invokeBuildSettings();
+    	
         Map<String, Object> context = new HashMap<String, Object>();
-        CreateProjectsFromMetadataAction.setUrl( context,
-                                                 "http://svn.apache.org/repos/asf/maven/archiva/trunk/pom.xml" );
-        CreateProjectsFromMetadataAction.setProjectBuilderId( context, "id" );
-        CreateProjectsFromMetadataAction.setLoadRecursiveProject( context, false );
+        context.put( AbstractContinuumAction.KEY_URL,
+            "http://svn.apache.org/repos/asf/maven/archiva/trunk/pom.xml" );
+        context.put( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDER_ID, "id" );
+        context.put( CreateProjectsFromMetadataAction.KEY_LOAD_RECURSIVE_PROJECTS, false );
+        context.put( CreateProjectsFromMetadataAction.KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY, false );
 
         action.execute( context );
 
-        ContinuumProjectBuildingResult result = CreateProjectsFromMetadataAction.getProjectBuildingResult( context );
+        ContinuumProjectBuildingResult result =
+        	            (ContinuumProjectBuildingResult) context.get( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDING_RESULT );
 
         assertFalse(
             "Should not have errors but had " + result.getErrorsAsString() + " (this test requires internet access)",
             result.hasErrors() );
     }
+    
+            
+    public void testExecuteWithCheckoutProjectsInSingleDirectory()
+        throws Exception
+    {   
+        Project project = new Project();
+        project.setGroupId( "org.apache.continuum" );
+        project.setArtifactId( "parent-project" );
+        project.setVersion( "1.0-SNAPSHOT" );
+        project.setId( 6 );
+        project.setName( "parent-project" );
+        project.setScmUrl( "scm:local:src/test-projects:flat-multi-module/parent-project" );
+        
+        this.result.addProject( project );
+        
+        project = new Project();
+        project.setGroupId( "org.apache.continuum" );
+        project.setArtifactId( "module-a" );
+        project.setVersion( "1.0-SNAPSHOT" );
+        project.setId( 7 );
+        project.setName( "module-a" );
+        project.setScmUrl( "scm:local:src/test-projects:flat-multi-module/module-a" );
+        
+        this.result.addProject( project );
+        
+        project = new Project();
+        project.setGroupId( "org.apache.continuum" );
+        project.setArtifactId( "module-b" );
+        project.setVersion( "1.0-SNAPSHOT" );
+        project.setId( 8 );
+        project.setName( "module-b" );
+        project.setScmUrl( "scm:local:src/test-projects:flat-multi-module/module-b" );
+        
+        this.result.addProject( project );
+                        
+        // assert using scm url set in root!
+        Map<String, Object> context = new HashMap<String, Object>();
+        context.put( AbstractContinuumAction.KEY_URL,
+                     "file://" + PlexusInSpringTestCase.getBasedir() + "/src/test-projects/flat-multi-module/parent-project/pom.xml" );
+        context.put( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDER_ID, "id" );
+        context.put( CreateProjectsFromMetadataAction.KEY_LOAD_RECURSIVE_PROJECTS, true );
+        context.put( CreateProjectsFromMetadataAction.KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY, true );
+
+        action.execute( context );
+
+        ContinuumProjectBuildingResult result =
+            (ContinuumProjectBuildingResult) context.get( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDING_RESULT );
+
+        assertFalse(
+            "Should not have errors but had " + result.getErrorsAsString() + " (this test requires internet access)",
+            result.hasErrors() );
+        assertEquals( "Incorrect SCM Root Url for flat multi-module project.",
+                      "scm:local:src/test-projects:flat-multi-module/", context.get( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL ) );
+    }
 
     public void testExecuteFlatMultiModuleProjectThatStartsWithTheSameLetter()
         throws Exception
     {
+    	invokeBuildSettings();
+    	
         Project project = new Project();
         project.setGroupId( "com.example.flat" );
         project.setArtifactId( "flat-parent" );
@@ -161,14 +237,16 @@
         this.result.addProject( project );
 
         Map<String, Object> context = new HashMap<String, Object>();
-        CreateProjectsFromMetadataAction.setUrl( context,
-                                                 "http://svn.apache.org/repos/asf/continuum/sandbox/flat-example/flat-parent/pom.xml" );
-        CreateProjectsFromMetadataAction.setProjectBuilderId( context, "id" );
-        CreateProjectsFromMetadataAction.setLoadRecursiveProject( context, true );
+        context.put( AbstractContinuumAction.KEY_URL,
+	                 "http://svn.apache.org/repos/asf/continuum/sandbox/flat-example/flat-parent/pom.xml" );
+	    context.put( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDER_ID, "id" );
+	    context.put( CreateProjectsFromMetadataAction.KEY_LOAD_RECURSIVE_PROJECTS, true );
+	    context.put( CreateProjectsFromMetadataAction.KEY_CHECKOUT_PROJECTS_IN_SINGLE_DIRECTORY, false );
 
         action.execute( context );
 
-        ContinuumProjectBuildingResult result = CreateProjectsFromMetadataAction.getProjectBuildingResult( context );
+        ContinuumProjectBuildingResult result =
+        	            (ContinuumProjectBuildingResult) context.get( CreateProjectsFromMetadataAction.KEY_PROJECT_BUILDING_RESULT );
 
         assertFalse(
             "Should not have errors but had " + result.getErrorsAsString() + " (this test requires internet access)",
@@ -176,6 +254,6 @@
 
         assertEquals(
             "Wrong scm root url created", "scm:svn:http://svn.apache.org/repos/asf/continuum/sandbox/flat-example/",
-            CreateProjectsFromMetadataAction.getUrl( context ) );
+            context.get( AbstractContinuumAction.KEY_PROJECT_SCM_ROOT_URL ) );
     }
 }
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/AbstractContinuumProjectBuilderTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/AbstractContinuumProjectBuilderTest.java
index 7b02e79..ef75bf0 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/AbstractContinuumProjectBuilderTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/AbstractContinuumProjectBuilderTest.java
@@ -69,7 +69,7 @@
         }
 
         public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
-                                                                         boolean recursiveProjects )
+        					boolean recursiveProjects, boolean checkoutInSingleDirectory )
             throws ContinuumProjectBuilderException
         {
             return null;
@@ -77,7 +77,7 @@
 
         public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
                                                                          boolean recursiveProjects,
-                                                                         BuildDefinitionTemplate buildDefinitionTemplate )
+                                                                         BuildDefinitionTemplate buildDefinitionTemplate, boolean checkoutInSingleDirectory )
             throws ContinuumProjectBuilderException
         {
             return null;
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilderTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilderTest.java
index 91df7b9..4aa27fd 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilderTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenOneContinuumProjectBuilderTest.java
@@ -63,7 +63,7 @@
         bdt = service.addBuildDefinitionInTemplate( bdt, bd, false );
 
         ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata(
-            getTestFile( "src/test/resources/projects/maven-1.pom.xml" ).toURL(), null, null, false, bdt );
+        		getTestFile( "src/test/resources/projects/maven-1.pom.xml" ).toURL(), null, null, false, bdt, false );
 
         assertOnResult( result );
 
@@ -79,7 +79,7 @@
 
         ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata(
             getTestFile( "src/test/resources/projects/maven-1.pom.xml" ).toURL(), null, null, false,
-            service.getDefaultMavenOneBuildDefinitionTemplate() );
+            service.getDefaultMavenOneBuildDefinitionTemplate(), false );
 
         assertOnResult( result );
 
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilderTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilderTest.java
index abfbbb6..fdea7fa 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilderTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/project/builder/maven/MavenTwoContinuumProjectBuilderTest.java
@@ -39,6 +39,7 @@
 import org.codehaus.plexus.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.codehaus.plexus.spring.PlexusInSpringTestCase;
 
 /**
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
@@ -359,7 +360,7 @@
 
         ContinuumProjectBuildingResult result;
 
-        result = projectBuilder.buildProjectsFromMetadata( url, null, null, false, bdt );
+        result = projectBuilder.buildProjectsFromMetadata( url, null, null, false, bdt, false );
         assertFalse( result.hasErrors() );
 
         assertEquals( 5, service.getAllBuildDefinitionTemplate().size() );
@@ -390,6 +391,49 @@
 
         assertEquals( 0, projectGroup.getProjects().size() );
     }
+    
+	public void testCreateProjectWithFlatStructure()
+	    throws Exception
+	{
+	    ContinuumProjectBuilder projectBuilder =
+	        (ContinuumProjectBuilder) lookup( ContinuumProjectBuilder.ROLE, MavenTwoContinuumProjectBuilder.ID );
+	
+	    URL url = getTestFile( "/src/test-projects/flat-multi-module/parent-project/pom.xml" ).toURL();
+	
+	    ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata( url, null, null, true, true );
+	    
+	    Project rootProject = result.getRootProject();
+	    assertEquals( "Incorrect root project", "parent-project", rootProject.getArtifactId() );
+	    
+	    List<Project> projects = result.getProjects();
+	    for( Project project : projects )
+	    {
+	        if( project.getName().equals( "parent-project" ) )
+	        {
+	            assertEquals( "Incorrect scm url for parent-project",
+	                          "scm:local:src/test-projects:flat-multi-module/parent-project", project.getScmUrl() );
+	        }
+	        else if( project.getName().equals( "module-a" ) )
+	        {
+	            assertEquals( "Incorrect scm url for parent-project",
+	                          "scm:local:src/test-projects:flat-multi-module/module-a", project.getScmUrl() );
+	        }
+	        else if ( project.getName().equals( "module-b" ) )
+	        {
+	            assertEquals( "Incorrect scm url for parent-project",
+	                          "scm:local:src/test-projects:flat-multi-module/module-b", project.getScmUrl() );
+	        }
+	        else if ( project.getName().equals( "module-d" ) )
+	        {
+	            assertEquals( "Incorrect scm url for module-d",
+	                          "scm:local:src/test-projects:flat-multi-module/module-c/module-d", project.getScmUrl() );
+	        }
+	        else
+	        {
+	            fail( "Unknown project: " + project.getName() );
+	        }
+	    }
+	}
 
     private void assertDependency( String dep, String proj, Map<String, Project> projects )
     {
diff --git a/continuum-core/src/test/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutorTest.java b/continuum-core/src/test/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutorTest.java
index efe9e8e..9ce3be0 100644
--- a/continuum-core/src/test/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutorTest.java
+++ b/continuum-core/src/test/java/org/apache/maven/continuum/scm/queue/PrepareBuildProjectsTaskExecutorTest.java
@@ -96,11 +96,12 @@
 
         List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
 
-        assertEquals( "failed to add all projects", 3, projects.size() );
+        assertEquals( "failed to add all projects", 4, projects.size() );
 
         Project rootProject = getProjectDao().getProjectByName( "multi-module-parent" );
         Project moduleA = getProjectDao().getProjectByName( "module-A" );
         Project moduleB = getProjectDao().getProjectByName( "module-B" );
+        Project moduleD = getProjectDao().getProjectByName( "module-D" );
 
         // wait while task finishes prepare build
         while( !prepareBuildQueue.getQueueSnapshot().isEmpty() || 
@@ -120,6 +121,16 @@
 
         assertTrue( "checkout directory of project 'module-B' does not exist.", new File( workingDir, Integer.toString( moduleB.getId() ) ).exists() );
 
+        assertTrue( "checkout directory of project 'module-D' does not exist.", new File( workingDir, Integer.toString( moduleD.getId() ) ).exists() );
+ 
+        assertTrue( "failed to checkout project 'multi-module-parent'", new File( workingDir, Integer.toString( rootProject.getId() ) ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-A'", new File( workingDir, Integer.toString( moduleA.getId() ) ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-B'", new File( workingDir, Integer.toString( moduleB.getId() ) ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-D'", new File( workingDir, Integer.toString( moduleD.getId() ) ).list().length > 0 );
+
         while( !buildsManager.getCurrentBuilds().isEmpty() ||
                         isAnyProjectInBuildQueue() )
         {
@@ -136,11 +147,12 @@
 
         List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
 
-        assertEquals( "failed to add all projects", 3, projects.size() );
+        assertEquals( "failed to add all projects", 4, projects.size() );
 
         Project rootProject = getProjectDao().getProjectByName( "multi-module-parent" );
         Project moduleA = getProjectDao().getProjectByName( "module-A" );
         Project moduleB = getProjectDao().getProjectByName( "module-B" );
+        Project moduleD = getProjectDao().getProjectByName( "module-D" );
 
         // wait while task finishes prepare build
         while( !prepareBuildQueue.getQueueSnapshot().isEmpty() || 
@@ -159,14 +171,24 @@
         assertTrue( "checkout directory of project 'module-A' does not exist.", new File( workingDir, Integer.toString( moduleA.getId() ) ).exists() );
 
         assertTrue( "checkout directory of project 'module-B' does not exist.", new File( workingDir, Integer.toString( moduleB.getId() ) ).exists() );
+        
+        assertTrue( "checkout directory of project 'module-D' does not exist.", new File( workingDir, Integer.toString( moduleD.getId() ) ).exists() );
+ 
+        assertTrue( "failed to checkout project 'multi-module-parent'", new File( workingDir, Integer.toString( rootProject.getId() ) ).list().length > 0 );
 
+        assertTrue( "failed to checkout project 'module-A'", new File( workingDir, Integer.toString( moduleA.getId() ) ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-B'", new File( workingDir, Integer.toString( moduleB.getId() ) ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-D'", new File( workingDir, Integer.toString( moduleD.getId() ) ).list().length > 0 );
+ 
         while( !buildsManager.getCurrentBuilds().isEmpty() ||
                         isAnyProjectInBuildQueue() )
         {
             Thread.sleep( 10 );
         }
     }
-/*
+
     public void testCheckoutPrepareBuildSingleCheckedoutMultiModuleProject()
         throws Exception
     {
@@ -176,7 +198,7 @@
 
         List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
 
-        assertEquals( "failed to add all projects", 3, projects.size() );
+        assertEquals( "failed to add all projects", 4, projects.size() );
 
         Project rootProject = getProjectDao().getProjectByName( "multi-module-parent" );
 
@@ -197,6 +219,22 @@
         assertTrue( "module-A was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-A" ).exists() );
 
         assertTrue( "module-B was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-B" ).exists() );
+       
+        assertTrue( "module-D was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-C/module-D" ).exists() );
+
+        assertTrue( "failed to checkout project 'multi-module-parent'", checkedOutDir.list().length > 0 );
+   
+            assertTrue( "failed to checkout project 'module-A'", new File( checkedOutDir, "module-A" ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-B'", new File( checkedOutDir, "module-B" ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-D'", new File( checkedOutDir, "module-C/module-D" ).list().length > 0 );
+
+        while( !buildsManager.getCurrentBuilds().isEmpty() ||
+                        isAnyProjectInBuildQueue() )
+        {
+            Thread.sleep( 10 );
+        }
     }
 
     public void testCheckoutPrepareBuildSingleCheckedoutMultiModuleProjectFreshBuild()
@@ -208,7 +246,7 @@
 
         List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
 
-        assertEquals( "failed to add all projects", 3, projects.size() );
+        assertEquals( "failed to add all projects", 4, projects.size() );
 
         Project rootProject = getProjectDao().getProjectByName( "multi-module-parent" );
 
@@ -229,6 +267,22 @@
         assertTrue( "module-A was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-A" ).exists() );
 
         assertTrue( "module-B was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-B" ).exists() );
+        
+        assertTrue( "module-D was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-C/module-D" ).exists() );
+
+        assertTrue( "failed to checkout project 'multi-module-parent'", checkedOutDir.list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-A'", new File( checkedOutDir, "module-A" ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-B'", new File( checkedOutDir, "module-B" ).list().length > 0 );
+
+        assertTrue( "failed to checkout project 'module-D'", new File( checkedOutDir, "module-C/module-D" ).list().length > 0 );
+
+        while( !buildsManager.getCurrentBuilds().isEmpty() ||
+                        isAnyProjectInBuildQueue() )
+        {
+            Thread.sleep( 10 );
+        }
     }
 
     public void testCheckoutPrepareBuildSingleCheckoutFlatMultiModuleProject()
@@ -240,8 +294,8 @@
 
         List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
 
-        assertEquals( "failed to add all projects", 3, projects.size() );
-
+        assertEquals( "failed to add all projects", 4, projects.size() );
+        
         Project rootProject = getProjectDao().getProjectByName( "parent-project" );
 
         // wait while task finishes prepare build
@@ -261,6 +315,22 @@
         assertTrue( "module-a was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-a" ).exists() );
 
         assertTrue( "module-b was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-b" ).exists() );
+
+        assertTrue( "module-d was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-c/module-d" ).exists() );
+
+        assertTrue( "failed to checkout parent-project", new File( checkedOutDir, "parent-project" ).list().length > 0 );
+
+        assertTrue( "failed to checkout module-a", new File( checkedOutDir, "module-a" ).list().length > 0 );
+        
+        assertTrue( "failed to checkout module-b", new File( checkedOutDir, "module-b" ).list().length > 0 );
+        
+        assertTrue( "failed to checkout module-d", new File( checkedOutDir, "module-c/module-d" ).list().length > 0 );
+
+        while( !buildsManager.getCurrentBuilds().isEmpty() ||
+                        isAnyProjectInBuildQueue() )
+        {
+            Thread.sleep( 10 );
+        }
     }
 
     public void testCheckoutPrepareBuildSingleCheckoutFlatMultiModuleProjectBuildFresh()
@@ -272,7 +342,7 @@
 
         List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
 
-        assertEquals( "failed to add all projects", 3, projects.size() );
+        assertEquals( "failed to add all projects", 4, projects.size() );
 
         Project rootProject = getProjectDao().getProjectByName( "parent-project" );
 
@@ -296,8 +366,82 @@
         assertTrue( "module-a was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-a" ).exists() );
 
         assertTrue( "module-b was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-b" ).exists() );
+
+        assertTrue( "module-d was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-c/module-d" ).exists() );
+
+        assertTrue( "failed to checkout parent-project", new File( checkedOutDir, "parent-project" ).list().length > 0 );
+
+        assertTrue( "failed to checkout module-a", new File( checkedOutDir, "module-a" ).list().length > 0 );
+        
+        assertTrue( "failed to checkout module-b", new File( checkedOutDir, "module-b" ).list().length > 0 );
+       
+        assertTrue( "failed to checkout module-d", new File( checkedOutDir, "module-c/module-d" ).list().length > 0 );
+
+        while( !buildsManager.getCurrentBuilds().isEmpty() ||
+                        isAnyProjectInBuildQueue() )
+        {
+            Thread.sleep( 10 );
+        }
     }
-*/
+    
+    public void testCheckoutPrepareBuildSingleCheckoutFlatMultiModuleProjectBuildFreshAfterRemovingWorkingCopy()
+        throws Exception
+    {
+        PrepareBuildProjectsTask task = createTask( "src/test-projects/flat-multi-module/parent-project/pom.xml", true, true );
+     
+        List<Project> projects = getProjectDao().getProjectsInGroup( task.getProjectGroupId() );
+     
+        assertEquals( "failed to add all projects", 4, projects.size() );
+    
+        Project rootProject = getProjectDao().getProjectByName( "parent-project" );
+    
+        File rootProjectDir = new File( configurationService.getWorkingDirectory(), Integer.toString( rootProject.getId() ) );
+        rootProjectDir = new File( rootProjectDir, "parent-project" );
+    
+       rootProject.setWorkingDirectory( rootProjectDir.getAbsolutePath() );
+    
+        getProjectDao().updateProject( rootProject );
+   
+        this.prepareBuildQueue.put( task );
+    
+        ProjectScmRoot scmRoot = projectScmRootDao.getProjectScmRoot( task.getProjectScmRootId() );
+        // wait while task finishes prepare build
+        while( !prepareBuildQueue.getQueueSnapshot().isEmpty() || 
+                        prepareBuildTaskQueueExecutor.getCurrentTask() != null || scmRoot.getState() == ContinuumProjectState.UPDATING )
+        {
+            Thread.sleep( 10 );
+
+            scmRoot = projectScmRootDao.getProjectScmRoot( task.getProjectScmRootId() );
+        }
+    
+        scmRoot = projectScmRootDao.getProjectScmRoot( task.getProjectScmRootId() );
+        assertEquals( "Failed to update multi-module project", ContinuumProjectState.UPDATED, scmRoot.getState() );
+    
+        File checkedOutDir = new File( configurationService.getWorkingDirectory(), Integer.toString( rootProject.getId() ) );
+    
+        assertTrue( "checkout directory of project 'parent-project' does not exist.", new File( checkedOutDir, "parent-project" ).exists() );
+    
+        assertTrue( "module-a was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-a" ).exists() );
+    
+        assertTrue( "module-b was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-b" ).exists() );
+
+        assertTrue( "module-d was not checked out in the same directory as it's parent.", new File( checkedOutDir, "module-c/module-d" ).exists() );
+
+        assertTrue( "failed to checkout parent-project", new File( checkedOutDir, "parent-project" ).list().length > 0 );
+
+        assertTrue( "failed to checkout module-a", new File( checkedOutDir, "module-a" ).list().length > 0 );
+        
+        assertTrue( "failed to checkout module-b", new File( checkedOutDir, "module-b" ).list().length > 0 );
+        
+        assertTrue( "failed to checkout module-d", new File( checkedOutDir, "module-c/module-d" ).list().length > 0 );
+
+        while( !buildsManager.getCurrentBuilds().isEmpty() ||
+                        isAnyProjectInBuildQueue() )
+        {
+            Thread.sleep( 10 );
+        }
+    }
+
     private PrepareBuildProjectsTask createTask( String pomResource, boolean singleCheckout, boolean buildFresh )
         throws Exception
     {
@@ -352,10 +496,10 @@
             }
         }
 
-        assertEquals( 3, map.size() );
-        PrepareBuildProjectsTask task = new PrepareBuildProjectsTask( map, new BuildTrigger( 1, "test-user" ), 
-                                                                      projectGroupId, projectGroup.getName(), 
-                                                                      scmRoot.getScmRootAddress(), scmRoot.getId() );
+        assertEquals( 4, map.size() );
+        PrepareBuildProjectsTask task = new PrepareBuildProjectsTask( map, new org.apache.continuum.utils.build.BuildTrigger( 1, "user" ),
+                                                                               projectGroupId, projectGroup.getName(), 
+                                                                               scmRoot.getScmRootAddress(), scmRoot.getId() );
 
         return task;
     }
@@ -367,8 +511,8 @@
     
         assertNotNull( "Can't find project " + pomResource, pom );
 
-        //ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata( pom.toURL(), null, null, true, singleCheckout );
-        ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata( pom.toURL(), null, null, true );
+        //ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata( pom.toURL(), null, null, true );
+        ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata( pom.toURL(), null, null, true, singleCheckout );
 
         // some assertions to make sure our expectations match. This is NOT
         // meant as a unit test for the projectbuilder!
@@ -412,7 +556,7 @@
 
         projectScmRoot.setScmRootAddress( url );
 
-        projectScmRoot.setState( ContinuumProjectState.ERROR );
+        //projectScmRoot.setState( ContinuumProjectState.ERROR );
 
         return projectScmRootDao.addProjectScmRoot( projectScmRoot );
     }
diff --git a/continuum-model/src/main/mdo/continuum.xml b/continuum-model/src/main/mdo/continuum.xml
index 20ad914..a370073 100644
--- a/continuum-model/src/main/mdo/continuum.xml
+++ b/continuum-model/src/main/mdo/continuum.xml
@@ -317,6 +317,12 @@
           <version>1.1.0+</version>
           <type>String</type>
         </field>
+        <field>
+          <name>checkedOutInSingleDirectory</name>
+          <version>1.4.0+</version>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
         <field jpox.mapped-by="project" jpox.fetch-groups="project-with-builds">
           <name>buildResults</name>
           <version>1.0.9+</version>
diff --git a/continuum-model/src/main/resources/package-default.orm b/continuum-model/src/main/resources/package-default.orm
index 6b00547..5e9064b 100644
--- a/continuum-model/src/main/resources/package-default.orm
+++ b/continuum-model/src/main/resources/package-default.orm
@@ -17,4 +17,11 @@
       </field>

     </class>

   </package>

+  <package name="org.apache.maven.continuum.model.project">

+    <class name="Project">

+      <field name="checkedOutInSingleDirectory" null-value="default">

+        <column jdbc-type="CHAR" default-value="N" />

+      </field>

+    </class>

+  </package>

 </orm>

diff --git a/continuum-release/src/main/java/org/apache/continuum/release/phase/AbstractContinuumRunGoalsPhase.java b/continuum-release/src/main/java/org/apache/continuum/release/phase/AbstractContinuumRunGoalsPhase.java
index 908bf7a..25ac333 100644
--- a/continuum-release/src/main/java/org/apache/continuum/release/phase/AbstractContinuumRunGoalsPhase.java
+++ b/continuum-release/src/main/java/org/apache/continuum/release/phase/AbstractContinuumRunGoalsPhase.java
@@ -75,7 +75,7 @@
                     executable = ( (ContinuumReleaseDescriptor) releaseDescriptor).getExecutable();
                 }
                 shellCommandHelper.executeGoals( determineWorkingDirectory( workingDirectory,
-                                                                            releaseDescriptor.getScmRelativePathProjectDirectory() ),
+                								 releaseDescriptor.getScmRelativePathProjectDirectory() ),
                                                  executable, goals, releaseDescriptor.isInteractive(), additionalArguments, result, 
                                                  environments );
             }
diff --git a/continuum-release/src/main/java/org/apache/maven/continuum/release/executors/PerformReleaseTaskExecutor.java b/continuum-release/src/main/java/org/apache/maven/continuum/release/executors/PerformReleaseTaskExecutor.java
index 8166c40..fb9b500 100644
--- a/continuum-release/src/main/java/org/apache/maven/continuum/release/executors/PerformReleaseTaskExecutor.java
+++ b/continuum-release/src/main/java/org/apache/maven/continuum/release/executors/PerformReleaseTaskExecutor.java
@@ -83,10 +83,32 @@
 
         repository = performTask.getLocalRepository();
 
-        List<MavenProject> reactorProjects = getReactorProjects( performTask );
+        List reactorProjects = null;
+        MavenProject mavenProject = null;
+        
+        try
+        {
+        	mavenProject = getMavenProject( performTask );
+            if( mavenProject != null )
+            {
+                reactorProjects = getReactorProjects( descriptor, mavenProject ); 
+            }
+        }
+        catch ( ContinuumReleaseException e )
+        {
+            ReleaseResult result = createReleaseResult();
+
+            result.appendError( e );
+
+            continuumReleaseManager.getReleaseResults().put( performTask.getReleaseId(), result );
+
+            performTask.getListener().error( e.getMessage() );
+
+            throw new TaskExecutionException( "Failed to build reactor projects.", e );
+        }
 
         ReleaseResult result = releaseManager.performWithResult( descriptor, settings, reactorProjects, listener );
-
+        
         //override to show the actual start time
         result.setStartTime( getStartTime() );
 
@@ -98,61 +120,17 @@
         continuumReleaseManager.getReleaseResults().put( performTask.getReleaseId(), result );
     }
 
-    protected List<MavenProject> getReactorProjects( PerformReleaseProjectTask releaseTask )
-        throws TaskExecutionException
-    {
-        List<MavenProject> reactorProjects;
-        ReleaseDescriptor descriptor = releaseTask.getDescriptor();
-
-        if ( StringUtils.isEmpty( descriptor.getWorkingDirectory() ) )
-        {
-            //Perform with provided release parameters (CONTINUUM-1541)
-            descriptor.setCheckoutDirectory( releaseTask.getBuildDirectory().getAbsolutePath() );
-            return null;
-        }
-
-        try
-        {
-            reactorProjects = getReactorProjects( descriptor );
-        }
-        catch ( ContinuumReleaseException e )
-        {
-            ReleaseResult result = createReleaseResult();
-
-            result.appendError( e );
-
-            continuumReleaseManager.getReleaseResults().put( releaseTask.getReleaseId(), result );
-
-            releaseTask.getListener().error( e.getMessage() );
-
-            throw new TaskExecutionException( "Failed to build reactor projects.", e );
-        }
-
-        return reactorProjects;
-    }
-
     /**
      * @todo remove and use generate-reactor-projects phase
      */
-    protected List<MavenProject> getReactorProjects( ReleaseDescriptor descriptor )
+    protected List<MavenProject> getReactorProjects( ReleaseDescriptor descriptor, MavenProject project )
         throws ContinuumReleaseException
     {
         List<MavenProject> reactorProjects = new ArrayList<MavenProject>();
 
-        MavenProject project;
-        try
-        {
-            project = projectBuilder.build( getProjectDescriptorFile( descriptor ), getLocalRepository(),
-                                            getProfileManager( settings ) );
-
-            reactorProjects.add( project );
-
-            addModules( reactorProjects, project );
-        }
-        catch ( ProjectBuildingException e )
-        {
-            throw new ContinuumReleaseException( "Failed to build project.", e );
-        }
+        reactorProjects.add( project );
+       
+        addModules( reactorProjects, project );
 
         try
         {
@@ -238,4 +216,30 @@
     {
         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
     }
+    
+    protected MavenProject getMavenProject( PerformReleaseProjectTask releaseTask )
+	    throws ContinuumReleaseException
+	{
+	    ReleaseDescriptor descriptor = releaseTask.getDescriptor();
+	
+	    if ( StringUtils.isEmpty( descriptor.getWorkingDirectory() ) )
+	    {
+	        //Perform with provided release parameters (CONTINUUM-1541)
+	        descriptor.setCheckoutDirectory( releaseTask.getBuildDirectory().getAbsolutePath() );
+	        return null;
+	    }
+	
+	    MavenProject project;
+	    try
+	    {
+	        project = projectBuilder.build( getProjectDescriptorFile( descriptor ), getLocalRepository(),
+	                                        getProfileManager( settings ) );
+	    }
+	    catch ( ProjectBuildingException e )
+	    {
+	        throw new ContinuumReleaseException( "Failed to build project.", e );
+	    }
+	    
+	    return project;
+	}   
 }
diff --git a/continuum-release/src/main/java/org/apache/maven/continuum/release/phase/GenerateReactorProjectsPhase.java b/continuum-release/src/main/java/org/apache/maven/continuum/release/phase/GenerateReactorProjectsPhase.java
index cf6f77f..d51b0d3 100644
--- a/continuum-release/src/main/java/org/apache/maven/continuum/release/phase/GenerateReactorProjectsPhase.java
+++ b/continuum-release/src/main/java/org/apache/maven/continuum/release/phase/GenerateReactorProjectsPhase.java
@@ -48,6 +48,7 @@
 import org.codehaus.plexus.context.Context;
 import org.codehaus.plexus.context.ContextException;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
+import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
@@ -150,7 +151,7 @@
     {
         for ( Object o : project.getModules() )
         {
-            String moduleDir = o.toString();
+        	String moduleDir = StringUtils.replace( o.toString(), '\\', '/' );
 
             File pomFile = new File( project.getBasedir(), moduleDir + "/pom.xml" );
 
diff --git a/continuum-release/src/main/resources/META-INF/plexus/components.xml b/continuum-release/src/main/resources/META-INF/plexus/components.xml
index 380a771..e8d3121 100644
--- a/continuum-release/src/main/resources/META-INF/plexus/components.xml
+++ b/continuum-release/src/main/resources/META-INF/plexus/components.xml
@@ -279,6 +279,21 @@
           <phase>scm-commit-rollback</phase>
           <phase>remove-scm-tag</phase>
         </rollbackPhases>
+        <!-- Set <branchPhases> even though it is not used in Continuum. Having this empty causes an NPE when cleaning up the release
+             in maven-release 2.0! -->
+        <branchPhases>
+          <phase>create-backup-poms</phase>
+          <phase>check-poms</phase>
+          <phase>scm-check-modifications</phase>
+          <phase>map-branch-versions</phase>
+          <phase>map-development-versions</phase>
+          <phase>rewrite-poms-for-branch</phase>
+          <phase>scm-commit-branch</phase>
+          <phase>scm-branch</phase>
+          <phase>rewrite-poms-for-development</phase>
+          <phase>scm-commit-release</phase>
+          <phase>end-release</phase>
+        </branchPhases>
       </configuration>
     </component>
     <component>
diff --git a/continuum-test/src/main/java/org/apache/maven/continuum/AbstractContinuumTest.java b/continuum-test/src/main/java/org/apache/maven/continuum/AbstractContinuumTest.java
index 4d4eb65..9e88df1 100644
--- a/continuum-test/src/main/java/org/apache/maven/continuum/AbstractContinuumTest.java
+++ b/continuum-test/src/main/java/org/apache/maven/continuum/AbstractContinuumTest.java
@@ -32,6 +32,7 @@
 import org.apache.continuum.dao.DaoUtils;
 import org.apache.continuum.dao.ProjectDao;
 import org.apache.continuum.dao.ProjectGroupDao;
+import org.apache.continuum.dao.ProjectScmRootDao;
 import org.apache.continuum.dao.ScheduleDao;
 import org.apache.maven.continuum.configuration.ConfigurationService;
 import org.apache.maven.continuum.execution.ContinuumBuildExecutor;
@@ -63,6 +64,8 @@
     private ProjectGroupDao projectGroupDao;
 
     private ScheduleDao scheduleDao;
+    
+    private ProjectScmRootDao projectScmRootDao;
 
     // ----------------------------------------------------------------------
     //
@@ -81,6 +84,8 @@
         getProjectGroupDao();
 
         getScheduleDao();
+        
+        getProjectScmRootDao();
 
         setUpConfigurationService( (ConfigurationService) lookup( "configurationService" ) );
 
@@ -246,6 +251,15 @@
         }
         return scheduleDao;
     }
+    
+    protected ProjectScmRootDao getProjectScmRootDao()
+    {
+        if ( projectScmRootDao == null )
+        {
+            projectScmRootDao = (ProjectScmRootDao) lookup( ProjectScmRootDao.class.getName() );
+        }
+        return projectScmRootDao;
+    }
 
     // ----------------------------------------------------------------------
     // Build Executor
diff --git a/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/AddMavenTwoProjectAction.java b/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/AddMavenTwoProjectAction.java
index 35c49a6..d652b77 100644
--- a/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/AddMavenTwoProjectAction.java
+++ b/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/AddMavenTwoProjectAction.java
@@ -53,6 +53,8 @@
     public static final String FILE_SCHEME = "file:/";
 
     private boolean nonRecursiveProject;
+    
+    private boolean checkoutInSingleDirectory;
 
     protected ContinuumProjectBuildingResult doExecute( String pomUrl, int selectedProjectGroup, boolean checkProtocol,
                                                         boolean scmUseCache )
@@ -104,11 +106,18 @@
             }
         }
 
+     // force set checkoutInCingleDirectory to false if adding the project as non-recursive
+        if( this.isNonRecursiveProject() )
+        {
+            this.setCheckoutInSingleDirectory( false );
+        }
+        
         if ( result == null )
         {
             result = getContinuum().addMavenTwoProject( pomUrl, selectedProjectGroup, checkProtocol, scmUseCache,
                                                         !this.isNonRecursiveProject(),
-                                                        this.getBuildDefinitionTemplateId() );
+                                                        this.getBuildDefinitionTemplateId(),
+                                                        this.isCheckoutInSingleDirectory() );
         }
 
         AuditLog event = new AuditLog( hidePasswordInUrl( pomUrl ), AuditLogConstants.ADD_M2_PROJECT );
@@ -165,4 +174,14 @@
     {
         this.nonRecursiveProject = nonRecursiveProject;
     }
+    
+    public boolean isCheckoutInSingleDirectory()
+    {
+        return checkoutInSingleDirectory;
+    }
+
+    public void setCheckoutInSingleDirectory( boolean checkoutInSingleDirectory )
+    {
+        this.checkoutInSingleDirectory = checkoutInSingleDirectory;
+    }
 }
diff --git a/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/ReleasePrepareAction.java b/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/ReleasePrepareAction.java
index cb1d77e..574e97f 100644
--- a/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/ReleasePrepareAction.java
+++ b/continuum-webapp/src/main/java/org/apache/maven/continuum/web/action/ReleasePrepareAction.java
@@ -520,7 +520,9 @@
         {
             for ( Iterator modules = model.getModules().iterator(); modules.hasNext(); )
             {
-                processProject( workingDirectory + "/" + modules.next().toString(), "pom.xml" );
+            	String module = StringUtils.replace( modules.next().toString(), '\\', '/' );
+            	
+                processProject( workingDirectory + "/" + module, "pom.xml" );
             }
         }
     }
diff --git a/continuum-webapp/src/main/resources/localization/Continuum.properties b/continuum-webapp/src/main/resources/localization/Continuum.properties
index b6961e1..03bfd42 100644
--- a/continuum-webapp/src/main/resources/localization/Continuum.properties
+++ b/continuum-webapp/src/main/resources/localization/Continuum.properties
@@ -339,6 +339,7 @@
 add.m2.project.nonRecursiveProject = For multi-module project, load only root as recursive build
 add.m2.project.buildDefinitionTemplate = Build Definition Template
 add.m2.project.defaultBuildDefinition = Default
+add.m2.project.checkoutInSingleDirectory = Checkout multi-module project in single directory
 
 # ----------------------------------------------------------------------
 # Page: AddProject (ant or shell)
diff --git a/continuum-webapp/src/main/webapp/WEB-INF/jsp/addMavenTwoProject.jsp b/continuum-webapp/src/main/webapp/WEB-INF/jsp/addMavenTwoProject.jsp
index e04a64a..7c13137 100644
--- a/continuum-webapp/src/main/webapp/WEB-INF/jsp/addMavenTwoProject.jsp
+++ b/continuum-webapp/src/main/webapp/WEB-INF/jsp/addMavenTwoProject.jsp
@@ -82,6 +82,7 @@
                             </c:otherwise>
                             </c:choose>
                             <s:checkbox label="%{getText('add.m2.project.nonRecursiveProject')}" name="nonRecursiveProject" />
+                            <s:checkbox label="%{getText('add.m2.project.checkoutInSingleDirectory')}" name="checkoutInSingleDirectory" />
                             <s:select label="%{getText('add.m2.project.buildDefinitionTemplate')}" name="buildDefinitionTemplateId"
                                        list="buildDefinitionTemplates" listKey="id" listValue="name" headerKey="-1" 
                                        headerValue="%{getText('add.m2.project.defaultBuildDefinition')}"/> 
diff --git a/pom.xml b/pom.xml
index ec3b238..1147f67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -549,7 +549,7 @@
       <dependency>
         <groupId>org.apache.maven.release</groupId>
         <artifactId>maven-release-manager</artifactId>
-        <version>2.0-beta-9</version>
+        <version>2.0</version>
         <exclusions>
           <exclusion>
             <groupId>commons-logging</groupId>