You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@continuum.apache.org by ev...@apache.org on 2006/02/16 22:03:11 UTC

svn commit: r378367 - in /maven/continuum/branches/continuum-1.0.x: continuum-api/src/main/java/org/apache/maven/continuum/store/ continuum-core-it/src/test/java/org/apache/maven/continuum/it/ continuum-core/src/main/java/org/apache/maven/continuum/bui...

Author: evenisse
Date: Thu Feb 16 13:03:10 2006
New Revision: 378367

URL: http://svn.apache.org/viewcvs?rev=378367&view=rev
Log:
[CONTINUUM-567] A build get all changes from last execution of current build definition and not only from last build (with current build definition or an other)

Modified:
    maven/continuum/branches/continuum-1.0.x/continuum-api/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java
    maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/AbstractIntegrationTest.java
    maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/MavenTwoIntegrationTest.java
    maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
    maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java
    maven/continuum/branches/continuum-1.0.x/continuum-model/src/main/mdo/continuum.mdo
    maven/continuum/branches/continuum-1.0.x/continuum-store/src/main/java/org/apache/maven/continuum/store/JdoContinuumStore.java

Modified: maven/continuum/branches/continuum-1.0.x/continuum-api/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-api/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-api/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-api/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java Thu Feb 16 13:03:10 2006
@@ -149,6 +149,8 @@
 
     BuildResult getLatestBuildResultForProject( int projectId );
 
+    List getBuildResultsForProject( int projectId, long fromDate );
+
     Map getLatestBuildResults();
 
     List getBuildResultByBuildNumber( int projectId, int buildNumber );

Modified: maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/AbstractIntegrationTest.java
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/AbstractIntegrationTest.java?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/AbstractIntegrationTest.java (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/AbstractIntegrationTest.java Thu Feb 16 13:03:10 2006
@@ -317,7 +317,7 @@
         }
     }
 
-    private void line()
+    protected void line()
     {
         System.err.println( "-------------------------------------------------------------------------------" );
     }
@@ -403,17 +403,30 @@
         return ( (Project) projects.get( 0 ) ).getId();
     }
 
+    public BuildResult buildProject( int projectId, int trigger )
+        throws Exception
+    {
+        return buildProject( projectId, -1, trigger );
+    }
+
     /**
      * @todo use a notify mechanism rather than polling. That's what queues are for. Really, buildProject should create the build result with a WAITING state, return the ID, and let the queue take it from there
      */
-    public BuildResult buildProject( int projectId, int trigger )
+    public BuildResult buildProject( int projectId, int buildDefinitionId, int trigger )
         throws Exception
     {
         int timeout = 60 * 1000;
 
         BuildResult previousBuild = getContinuum().getLatestBuildResultForProject( projectId );
 
-        getContinuum().buildProject( projectId, trigger );
+        if ( buildDefinitionId <= 0 )
+        {
+            getContinuum().buildProject( projectId, trigger );
+        }
+        else
+        {
+            getContinuum().buildProject( projectId, buildDefinitionId, trigger );
+        }
 
         long start = System.currentTimeMillis();
 

Modified: maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/MavenTwoIntegrationTest.java
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/MavenTwoIntegrationTest.java?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/MavenTwoIntegrationTest.java (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-core-it/src/test/java/org/apache/maven/continuum/it/MavenTwoIntegrationTest.java Thu Feb 16 13:03:10 2006
@@ -16,17 +16,20 @@
  * limitations under the License.
  */
 
-import org.apache.maven.continuum.Continuum;
 import org.apache.maven.continuum.execution.maven.m2.MavenTwoBuildExecutor;
+import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
 import org.apache.maven.continuum.model.project.ProjectNotifier;
+import org.apache.maven.continuum.model.scm.ChangeSet;
 import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.codehaus.plexus.util.FileUtils;
 import org.codehaus.plexus.util.cli.CommandLineException;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -39,8 +42,6 @@
     public void testBasic()
         throws Exception
     {
-        Continuum continuum = getContinuum();
-
         initializeCvsRoot();
 
         progress( "Initializing Maven 2 CVS project" );
@@ -51,11 +52,12 @@
 
         progress( "Adding Maven 2 project" );
 
-        int projectId = getProjectId( continuum.addMavenTwoProject( "file:" + root.getAbsolutePath() + "/pom.xml" ) );
+        int projectId =
+            getProjectId( getContinuum().addMavenTwoProject( "file:" + root.getAbsolutePath() + "/pom.xml" ) );
 
         waitForSuccessfulCheckout( projectId );
 
-        Project project = continuum.getProjectWithAllDetails( projectId );
+        Project project = getContinuum().getProjectWithAllDetails( projectId );
 
         assertProject( projectId, "Maven 2 Project", "2.0-SNAPSHOT", "-N -B", MavenTwoBuildExecutor.ID, project );
 
@@ -74,7 +76,8 @@
 
         progress( "Building Maven 2 project" );
 
-        project = continuum.getProjectWithBuilds( projectId );
+        project = getContinuum().getProjectWithBuilds( projectId );
+
         int originalSize = project.getBuildResults().size();
 
         int buildId = buildProject( projectId, ContinuumProjectState.TRIGGER_SCHEDULED ).getId();
@@ -83,16 +86,18 @@
 
         progress( "Test that a build without any files changed won't execute the executor" );
 
-        project = continuum.getProjectWithBuilds( projectId );
+        project = getContinuum().getProjectWithBuilds( projectId );
+
         int expectedSize = project.getBuildResults().size();
 
         assertEquals( "build list was not updated", originalSize + 1, expectedSize );
 
-        continuum.buildProject( projectId, ContinuumProjectState.TRIGGER_SCHEDULED );
+        getContinuum().buildProject( projectId, ContinuumProjectState.TRIGGER_SCHEDULED );
 
         Thread.sleep( 3000 );
 
-        project = continuum.getProjectWithBuilds( projectId );
+        project = getContinuum().getProjectWithBuilds( projectId );
+
         int actualSize = project.getBuildResults().size();
 
         assertEquals( "A build has unexpectedly been executed.", expectedSize, actualSize );
@@ -107,7 +112,7 @@
 
         progress( "Test that a forced build with a pom deleted executes the executor" );
 
-        File pom = new File(getContinuum().getWorkingDirectory( projectId), "pom.xml");
+        File pom = new File( getContinuum().getWorkingDirectory( projectId ), "pom.xml" );
 
         assertTrue( pom.delete() );
 
@@ -116,6 +121,83 @@
         build = assertSuccessfulMaven2Build( buildId, projectId );
 
         assertEquals( "The 'build forced' flag wasn't true", ContinuumProjectState.TRIGGER_FORCED, build.getTrigger() );
+
+        Thread.sleep( 3000 );
+
+        progress( "Test with two build definition, the second receive scm result from the first." );
+
+        BuildDefinition buildDef = new BuildDefinition();
+
+        buildDef.setBuildFile( "pom.xml" );
+
+        buildDef.setGoals( "clean" );
+
+        getContinuum().addBuildDefinition( projectId, buildDef );
+
+        List buildDefs = getContinuum().getBuildDefinitions( projectId );
+
+        for ( Iterator i = buildDefs.iterator(); i.hasNext(); )
+        {
+            BuildDefinition bd = (BuildDefinition) i.next();
+
+            if ( bd.getGoals().equals( "clean" ) )
+            {
+                buildDef = bd;
+
+                break;
+            }
+        }
+        //FileUtils.deleteDirectory( new File( getContinuum().getWorkingDirectory( projectId ), "src" ) );
+
+        Thread.sleep( 3000 );
+
+        build = buildProject( projectId, buildDef.getId(), ContinuumProjectState.TRIGGER_FORCED );
+
+        build = getContinuum().getBuildResult( build.getId() );
+
+        line();
+        System.out.println( "CHANGESET" );
+        line();
+        for ( Iterator i = build.getScmResult().getChanges().iterator(); i.hasNext(); )
+        {
+            ChangeSet changeSet = (ChangeSet) i.next();
+            System.out.println( changeSet.toString() );
+        }
+        line();
+
+        assertEquals( "Changes list must be empty.", 1, build.getScmResult().getChanges().size() );
+
+        FileUtils.deleteDirectory( new File( getContinuum().getWorkingDirectory( projectId ), "src" ) );
+
+        Thread.sleep( 3000 );
+
+        buildId = buildProject( projectId, ContinuumProjectState.TRIGGER_FORCED ).getId();
+
+        build = assertSuccessfulMaven2Build( buildId, projectId );
+
+        build = getContinuum().getBuildResult( build.getId() );
+
+        line();
+        System.out.println( "CHANGESET" );
+        line();
+        for ( Iterator i = build.getScmResult().getChanges().iterator(); i.hasNext(); )
+        {
+            ChangeSet changeSet = (ChangeSet) i.next();
+            System.out.println( changeSet.toString() );
+        }
+        line();
+
+        assertEquals( "Changes list must be empty.", 2, build.getScmResult().getChanges().size() );
+
+        Thread.sleep( 3000 );
+
+        build = buildProject( projectId, buildDef.getId(), ContinuumProjectState.TRIGGER_FORCED );
+
+        Thread.sleep( 3000 );
+
+        build = getContinuum().getBuildResult( build.getId() );
+
+        assertTrue( build.getScmResult().getChanges().size() >= 1 );
 
         removeProject( projectId );
     }

Modified: maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java Thu Feb 16 13:03:10 2006
@@ -17,6 +17,7 @@
  */
 
 import org.apache.maven.continuum.core.action.AbstractContinuumAction;
+import org.apache.maven.continuum.model.project.BuildDefinition;
 import org.apache.maven.continuum.model.project.BuildResult;
 import org.apache.maven.continuum.model.project.Project;
 import org.apache.maven.continuum.model.scm.ChangeFile;
@@ -86,11 +87,17 @@
 
         Project project;
 
+        BuildDefinition buildDefinition;
+
+        BuildResult oldBuildResult = null;
+
         BuildResult build = null;
 
         try
         {
             project = store.getProject( projectId );
+
+            buildDefinition = store.getBuildDefinition( buildDefinitionId );
         }
         catch ( ContinuumStoreException ex )
         {
@@ -99,6 +106,22 @@
             return;
         }
 
+        try
+        {
+            oldBuildResult = store.getBuildResult( buildDefinition.getLatestBuildId() );
+        }
+        catch ( ContinuumStoreException ex )
+        {
+            // Nothing to do
+        }
+
+        ScmResult oldScmResult = null;
+
+        if ( oldBuildResult != null )
+        {
+            oldScmResult = getOldScmResult( project, oldBuildResult.getEndTime() );
+        }
+
         // ----------------------------------------------------------------------
         // TODO: Centralize the error handling from the SCM related actions.
         // ContinuumScmResult should return a ContinuumScmResult from all
@@ -166,6 +189,9 @@
                     return;
                 }
 
+                // Merge scm results so we'll have all changes since last execution of current build definition
+                scmResult = mergeScmResults( oldScmResult, scmResult );
+
                 actionContext.put( AbstractContinuumAction.KEY_UPDATE_SCM_RESULT, scmResult );
 
                 scmResult = (ScmResult) actionContext.get( AbstractContinuumAction.KEY_UPDATE_SCM_RESULT );
@@ -186,7 +212,6 @@
 
                 while ( iterChanges.hasNext() )
                 {
-
                     changeSet = (ChangeSet) iterChanges.next();
 
                     changeFiles = changeSet.getFiles();
@@ -403,5 +428,66 @@
         store.addBuildResult( project, build );
 
         return store.getBuildResult( build.getId() );
+    }
+
+    private ScmResult getOldScmResult( Project project, long fromDate )
+    {
+        List results = store.getBuildResultsForProject( project.getId(), fromDate );
+
+        ScmResult res = new ScmResult();
+
+        if ( results != null )
+        {
+            for ( Iterator i = results.iterator(); i.hasNext(); )
+            {
+                BuildResult result = (BuildResult) i.next();
+
+                ScmResult scmResult = result.getScmResult();
+
+                if ( scmResult != null )
+                {
+                    List changes = scmResult.getChanges();
+
+                    if ( changes != null )
+                    {
+                        for ( Iterator j = changes.iterator(); j.hasNext(); )
+                        {
+                            ChangeSet changeSet = (ChangeSet) j.next();
+
+                            if ( !res.getChanges().contains( changeSet ) )
+                            {
+                                res.addChange( changeSet );
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return res;
+    }
+
+    private ScmResult mergeScmResults( ScmResult oldScmResult, ScmResult newScmResult )
+    {
+        if ( oldScmResult != null )
+        {
+            List oldChanges = oldScmResult.getChanges();
+
+            List newChanges = newScmResult.getChanges();
+
+            for ( Iterator i = newChanges.iterator(); i.hasNext(); )
+            {
+                ChangeSet change = (ChangeSet) i.next();
+
+                if ( !oldChanges.contains( change ) )
+                {
+                    oldChanges.add( change );
+                }
+            }
+
+            newScmResult.setChanges( oldChanges );
+        }
+
+        return newScmResult;
     }
 }

Modified: maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-core/src/main/java/org/apache/maven/continuum/core/action/ExecuteBuilderContinuumAction.java Thu Feb 16 13:03:10 2006
@@ -79,8 +79,8 @@
         // This is really a precondition for this action to execute
         // ----------------------------------------------------------------------
 
-        if ( project.getOldState() != ContinuumProjectState.NEW && scmResult.getChanges().size() == 0
-            && trigger != ContinuumProjectState.TRIGGER_FORCED && !isNew( project ) )
+        if ( project.getOldState() != ContinuumProjectState.NEW && scmResult.getChanges().size() == 0 &&
+            trigger != ContinuumProjectState.TRIGGER_FORCED && !isNew( project ) )
         {
             getLogger().info( "No files updated, not building. Project id '" + project.getId() + "'." );
 
@@ -146,10 +146,12 @@
 
             project.setLatestBuildId( build.getId() );
 
+            buildDefinition.setLatestBuildId( build.getId() );
+
             build.setBuildNumber( project.getBuildNumber() );
 
-            if ( build.getState() != ContinuumProjectState.OK && build.getState() != ContinuumProjectState.FAILED
-                && build.getState() != ContinuumProjectState.ERROR )
+            if ( build.getState() != ContinuumProjectState.OK && build.getState() != ContinuumProjectState.FAILED &&
+                build.getState() != ContinuumProjectState.ERROR )
             {
                 build.setState( ContinuumProjectState.ERROR );
             }
@@ -161,6 +163,8 @@
             store.updateBuildResult( build );
 
             build = store.getBuildResult( build.getId() );
+
+            store.storeBuildDefinition( buildDefinition );
 
             store.updateProject( project );
 

Modified: maven/continuum/branches/continuum-1.0.x/continuum-model/src/main/mdo/continuum.mdo
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-model/src/main/mdo/continuum.mdo?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-model/src/main/mdo/continuum.mdo (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-model/src/main/mdo/continuum.mdo Thu Feb 16 13:03:10 2006
@@ -516,6 +516,52 @@
           </association>
         </field>
       </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0+</version>
+          <code><![CDATA[
+            /**
+             * @return Returns string representation of the changeset
+             */
+            public String toString()
+            {
+                String result = author + "\n" + date + "\n";
+
+                if ( files != null )
+                {
+                    for ( java.util.Iterator i = files.iterator(); i.hasNext(); )
+                    {
+                        ChangeFile file = (ChangeFile) i.next();
+
+                        result += file + "\n";
+                    }
+                }
+
+                result += comment;
+
+                return result;
+            }
+
+            /**
+             * @see java.lang.Object#equals(java.lang.Object)
+             */
+            public boolean equals( Object obj )
+            {
+                if ( obj instanceof ChangeSet )
+                {
+                    ChangeSet changeSet = (ChangeSet) obj;
+
+                    if ( toString().equals( changeSet.toString() ) )
+                    {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+          ]]></code>
+        </codeSegment>
+      </codeSegments>
     </class>
 
     <class>
@@ -539,6 +585,29 @@
           <type>String</type>
         </field>
       </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0+</version>
+          <code><![CDATA[
+            /**
+             * Provide a version of the object as a string for debugging purposes
+             *
+             * @return a {@link String}made up of the properties of the object
+             */
+            public String toString()
+            {
+                StringBuffer buffer = new StringBuffer( getName() );
+
+                if ( getRevision() != null )
+                {
+                    buffer.append( ", " ).append( getRevision() );
+                }
+
+                return buffer.toString();
+            }
+          ]]></code>
+        </codeSegment>
+      </codeSegments>
     </class>
 
     <class>
@@ -586,6 +655,11 @@
           <association stash.part="true" jpox.dependent="false">
             <type>Profile</type>
           </association>
+        </field>
+        <field>
+          <name>latestBuildId</name>
+          <version>1.0.0</version>
+          <type>int</type>
         </field>
       </fields>
     </class>

Modified: maven/continuum/branches/continuum-1.0.x/continuum-store/src/main/java/org/apache/maven/continuum/store/JdoContinuumStore.java
URL: http://svn.apache.org/viewcvs/maven/continuum/branches/continuum-1.0.x/continuum-store/src/main/java/org/apache/maven/continuum/store/JdoContinuumStore.java?rev=378367&r1=378366&r2=378367&view=diff
==============================================================================
--- maven/continuum/branches/continuum-1.0.x/continuum-store/src/main/java/org/apache/maven/continuum/store/JdoContinuumStore.java (original)
+++ maven/continuum/branches/continuum-1.0.x/continuum-store/src/main/java/org/apache/maven/continuum/store/JdoContinuumStore.java Thu Feb 16 13:03:10 2006
@@ -32,12 +32,6 @@
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 import javax.jdo.Extent;
 import javax.jdo.JDOException;
 import javax.jdo.JDOHelper;
@@ -47,6 +41,11 @@
 import javax.jdo.PersistenceManagerFactory;
 import javax.jdo.Query;
 import javax.jdo.Transaction;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
@@ -159,7 +158,7 @@
 
             query.declareImports( "import org.apache.maven.continuum.model.project.BuildDefinition" );
 
-            query.declareVariables ("BuildDefinition buildDef");
+            query.declareVariables( "BuildDefinition buildDef" );
 
             query.setFilter( "buildDefinitions.contains(buildDef) && buildDef.schedule.id == scheduleId" );
 
@@ -377,9 +376,10 @@
 
             query.declareParameters( "int projectId" );
 
-            query.declareVariables ("BuildDefinition buildDef");
+            query.declareVariables( "BuildDefinition buildDef" );
 
-            query.setFilter( "this.buildDefinitions.contains(buildDef) && buildDef.defaultForProject == true && this.id == projectId" );
+            query.setFilter(
+                "this.buildDefinitions.contains(buildDef) && buildDef.defaultForProject == true && this.id == projectId" );
 
             query.setResult( "buildDef" );
 
@@ -392,7 +392,8 @@
             if ( result != null && !result.isEmpty() )
             {
                 BuildDefinition bd = (BuildDefinition) result.get( 0 );
-                getLogger().info( "nb bd for project " + projectId + " : " + result.size() + " - bd id : " + bd.getId() );
+                getLogger().info(
+                    "nb bd for project " + projectId + " : " + result.size() + " - bd id : " + bd.getId() );
                 return bd;
             }
         }
@@ -423,7 +424,7 @@
 
             query.setFilter( "this.buildDefinitions.contains(buildDef) && buildDef.defaultForProject == true" );
 
-            query.declareVariables ("BuildDefinition buildDef");
+            query.declareVariables( "BuildDefinition buildDef" );
 
             query.setResult( "this.id, buildDef.id" );
 
@@ -912,6 +913,40 @@
         }
     }
 
+    public List getBuildResultsForProject( int projectId, long fromDate )
+    {
+        PersistenceManager pm = pmf.getPersistenceManager();
+
+        Transaction tx = pm.currentTransaction();
+
+        pm.getFetchPlan().addGroup( BUILD_RESULT_WITH_DETAILS_FETCH_GROUP );
+
+        try
+        {
+            tx.begin();
+
+            Extent extent = pm.getExtent( BuildResult.class, true );
+
+            Query query = pm.newQuery( extent );
+
+            query.declareParameters( "int projectId, long fromDate" );
+
+            query.setFilter( "this.project.id == projectId && this.startTime > fromDate" );
+
+            List result = (List) query.execute( new Integer( projectId ), new Long( fromDate ) );
+
+            result = (List) pm.detachCopyAll( result );
+
+            tx.commit();
+
+            return result;
+        }
+        finally
+        {
+            rollback( tx );
+        }
+    }
+
     public Map getBuildResultsInSuccess()
     {
         PersistenceManager pm = pmf.getPersistenceManager();
@@ -1157,7 +1192,8 @@
         }
         else if ( systemConfs.size() > 1 )
         {
-            throw new ContinuumStoreException( "Database is corrupted. There are more than one systemConfiguration object." );
+            throw new ContinuumStoreException(
+                "Database is corrupted. There are more than one systemConfiguration object." );
         }
         else
         {
@@ -1326,7 +1362,7 @@
         return (Permission) addObject( perm );
     }
 
-    public UserGroup addUserGroup( UserGroup group)
+    public UserGroup addUserGroup( UserGroup group )
     {
         return (UserGroup) addObject( group );
     }