Index: src/main/java/hudson/maven/AbstractMavenBuild.java
===================================================================
--- src/main/java/hudson/maven/AbstractMavenBuild.java (revision 0)
+++ src/main/java/hudson/maven/AbstractMavenBuild.java (revision 0)
@@ -0,0 +1,146 @@
+package hudson.maven;
+
+import hudson.Util;
+import hudson.model.AbstractBuild;
+import hudson.model.AbstractProject;
+import hudson.model.BuildListener;
+import hudson.model.DependencyGraph;
+import hudson.model.Hudson;
+import hudson.model.Result;
+import hudson.model.Run;
+import hudson.model.Cause.UpstreamCause;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Set;
+
+public abstract class AbstractMavenBuild
,R extends AbstractMavenBuild
> extends AbstractBuild
{
+
+ /**
+ * Extra versbose debug switch.
+ */
+ public static boolean debug = false;
+
+ protected AbstractMavenBuild(P job) throws IOException {
+ super(job);
+ }
+
+ public AbstractMavenBuild(P job, Calendar timestamp) {
+ super(job, timestamp);
+ }
+
+ public AbstractMavenBuild(P project, File buildDir) throws IOException {
+ super(project, buildDir);
+ }
+
+ /**
+ * Schedules all the downstream builds.
+ *
+ * @param downstreams
+ * List of downstream jobs that are already scheduled.
+ * The method will add jobs that it triggered here,
+ * and won't try to trigger jobs that are already in this list.
+ * @param listener
+ * Where the progress reports go.
+ */
+ protected final void scheduleDownstreamBuilds(BuildListener listener) {
+ // trigger dependency builds
+ DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
+ for( AbstractProject,?> down : getParent().getDownstreamProjects()) {
+// if(downstreams.contains(down))
+// continue; // already triggered
+
+ if(debug)
+ listener.getLogger().println("Considering whether to trigger "+down+" or not");
+
+ if(graph.hasIndirectDependencies(getProject(),down)) {
+ // if there's a longer dependency path to this project,
+ // then scheduling the build now is going to be a waste,
+ // so don't do that.
+ // let the longer path eventually trigger this build
+ if(debug)
+ listener.getLogger().println(" -> No, because there's a longer dependency path");
+ continue;
+ }
+
+ // if the downstream module depends on multiple modules,
+ // only trigger them when all the upstream dependencies are updated.
+ boolean trigger = true;
+
+ if (down.isInQueue()) {
+ if(debug)
+ listener.getLogger().println(" -> No, because dependency is already in queue");
+ trigger = false;
+ } else {
+ AbstractBuild,?> dlb = down.getLastBuild(); // can be null.
+ for (AbstractMavenProject up : Util.filter(down.getUpstreamProjects(),AbstractMavenProject.class)) {
+ Run ulb;
+ if(up==getParent()) {
+ // the current build itself is not registered as lastSuccessfulBuild
+ // at this point, so we have to take that into account. ugly.
+ if(getResult()==null || !getResult().isWorseThan(Result.UNSTABLE))
+ ulb = this;
+ else
+ ulb = up.getLastSuccessfulBuild();
+ } else
+ ulb = up.getLastSuccessfulBuild();
+ if(ulb==null) {
+ // if no usable build is available from the upstream,
+ // then we have to wait at least until this build is ready
+ if(debug)
+ listener.getLogger().println(" -> No, because another upstream "+up+" for "+down+" has no successful build");
+ trigger = false;
+ break;
+ }
+
+ // if no record of the relationship in the last build
+ // is available, we'll just have to assume that the condition
+ // for the new build is met, or else no build will be fired forever.
+ if(dlb==null) continue;
+ int n = dlb.getUpstreamRelationship(up);
+ if(n==-1) continue;
+
+ assert ulb.getNumber()>=n;
+
+ if(ulb.getNumber()==n) {
+ // there's no new build of this upstream since the last build
+ // of the downstream, and the upstream build is in progress.
+ // The new downstream build should wait until this build is started
+ AbstractProject bup = getBuildingUpstream(graph, up);
+ if(bup!=null) {
+ if(debug)
+ listener.getLogger().println(" -> No, because another upstream "+bup+" for "+down+" is building");
+ trigger = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if(trigger) {
+ listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
+ down.scheduleBuild(new UpstreamCause(this));
+ }
+ }
+ }
+
+ /**
+ * Returns the project if any of the upstream project (or itself) is either
+ * building or is in the queue.
+ *
+ * This means eventually there will be an automatic triggering of
+ * the given project (provided that all builds went smoothly.)
+ */
+ private AbstractProject getBuildingUpstream(DependencyGraph graph, AbstractProject project) {
+ Set tups = graph.getTransitiveUpstream(project);
+ tups.add(project);
+ for (AbstractProject tup : tups) {
+ if(tup!=getProject() && (tup.isBuilding() || tup.isInQueue()))
+ return tup;
+ }
+ return null;
+ }
+
+
+}
Index: src/main/java/hudson/maven/AbstractMavenProject.java
===================================================================
--- src/main/java/hudson/maven/AbstractMavenProject.java (revision 15307)
+++ src/main/java/hudson/maven/AbstractMavenProject.java (working copy)
@@ -26,9 +26,11 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
+import hudson.model.DependencyGraph;
+import hudson.model.Hudson;
import hudson.model.ItemGroup;
-import hudson.triggers.Trigger;
import hudson.tasks.Maven.ProjectWithMaven;
+import hudson.triggers.Trigger;
import java.util.HashSet;
import java.util.Set;
@@ -65,4 +67,48 @@
}
protected abstract void addTransientActionsFromBuild(R lastBuild, Set added);
+
+ @Override
+ public boolean isBuildBlocked() {
+ boolean blocked = super.isBuildBlocked();
+ if (!blocked) {
+ DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
+ AbstractProject bup = getBuildingUpstream();
+ if(bup!=null) {
+ return true;
+ }
+ }
+ return blocked;
+ }
+
+ public String getWhyBlocked() {
+ if (super.isBuildBlocked()) {
+ return super.getWhyBlocked();
+ } else {
+ AbstractProject bup = getBuildingUpstream();
+ String projectName = "";
+ if(bup!=null) {
+ projectName = bup.getName();
+ }
+ return "Upstream project is building: " + projectName;
+ }
+ }
+
+ /**
+ * Returns the project if any of the upstream project (or itself) is either
+ * building or is in the queue.
+ *
+ * This means eventually there will be an automatic triggering of
+ * the given project (provided that all builds went smoothly.)
+ */
+ private AbstractProject getBuildingUpstream() {
+ DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
+ Set tups = graph.getTransitiveUpstream(this);
+ tups.add(this);
+ for (AbstractProject tup : tups) {
+ if(tup!=this && (tup.isBuilding() || tup.isInQueue()))
+ return tup;
+ }
+ return null;
+ }
}
Index: src/main/java/hudson/maven/MavenBuild.java
===================================================================
--- src/main/java/hudson/maven/MavenBuild.java (revision 15307)
+++ src/main/java/hudson/maven/MavenBuild.java (working copy)
@@ -68,7 +68,7 @@
*
* @author Kohsuke Kawaguchi
*/
-public class MavenBuild extends AbstractBuild {
+public class MavenBuild extends AbstractMavenBuild {
/**
* {@link MavenReporter}s that will contribute project actions.
* Can be null if there's none.
@@ -493,111 +493,8 @@
public void cleanUp(BuildListener listener) throws Exception {
if(getResult().isBetterOrEqualTo(Result.SUCCESS))
- scheduleDownstreamBuilds(listener,new HashSet());
- }
- }
-
- /**
- * Schedules all the downstream builds.
- *
- * @param downstreams
- * List of downstream jobs that are already scheduled.
- * The method will add jobs that it triggered here,
- * and won't try to trigger jobs that are already in this list.
- * @param listener
- * Where the progress reports go.
- */
- /*package*/ final void scheduleDownstreamBuilds(BuildListener listener, Set downstreams) {
- // trigger dependency builds
- DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
- for( AbstractProject,?> down : getParent().getDownstreamProjects()) {
- if(downstreams.contains(down))
- continue; // already triggered
-
- if(debug)
- listener.getLogger().println("Considering whether to trigger "+down+" or not");
-
- if(graph.hasIndirectDependencies(getProject(),down)) {
- // if there's a longer dependency path to this project,
- // then scheduling the build now is going to be a waste,
- // so don't do that.
- // let the longer path eventually trigger this build
- if(debug)
- listener.getLogger().println(" -> No, because there's a longer dependency path");
- continue;
- }
-
- // if the downstream module depends on multiple modules,
- // only trigger them when all the upstream dependencies are updated.
- boolean trigger = true;
-
- AbstractBuild,?> dlb = down.getLastBuild(); // can be null.
- for (MavenModule up : Util.filter(down.getUpstreamProjects(),MavenModule.class)) {
- MavenBuild ulb;
- if(up==getProject()) {
- // the current build itself is not registered as lastSuccessfulBuild
- // at this point, so we have to take that into account. ugly.
- if(getResult()==null || !getResult().isWorseThan(Result.UNSTABLE))
- ulb = MavenBuild.this;
- else
- ulb = up.getLastSuccessfulBuild();
- } else
- ulb = up.getLastSuccessfulBuild();
- if(ulb==null) {
- // if no usable build is available from the upstream,
- // then we have to wait at least until this build is ready
- if(debug)
- listener.getLogger().println(" -> No, because another upstream "+up+" for "+down+" has no successful build");
- trigger = false;
- break;
- }
-
- // if no record of the relationship in the last build
- // is available, we'll just have to assume that the condition
- // for the new build is met, or else no build will be fired forever.
- if(dlb==null) continue;
- int n = dlb.getUpstreamRelationship(up);
- if(n==-1) continue;
-
- assert ulb.getNumber()>=n;
-
- if(ulb.getNumber()==n) {
- // there's no new build of this upstream since the last build
- // of the downstream, and the upstream build is in progress.
- // The new downstream build should wait until this build is started
- AbstractProject bup = getBuildingUpstream(graph, up);
- if(bup!=null) {
- if(debug)
- listener.getLogger().println(" -> No, because another upstream "+bup+" for "+down+" is building");
- trigger = false;
- break;
- }
- }
- }
-
- if(trigger) {
- listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
- downstreams.add(down);
- down.scheduleBuild(new UpstreamCause(this));
- }
- }
- }
-
- /**
- * Returns the project if any of the upstream project (or itself) is either
- * building or is in the queue.
- *
- * This means eventually there will be an automatic triggering of
- * the given project (provided that all builds went smoothly.)
- */
- private AbstractProject getBuildingUpstream(DependencyGraph graph, AbstractProject project) {
- Set tups = graph.getTransitiveUpstream(project);
- tups.add(project);
- for (AbstractProject tup : tups) {
- if(tup!=getProject() && (tup.isBuilding() || tup.isInQueue()))
- return tup;
+ scheduleDownstreamBuilds(listener);
}
- return null;
}
private static final int MAX_PROCESS_CACHE = 5;
Index: src/main/java/hudson/maven/MavenModuleSet.java
===================================================================
--- src/main/java/hudson/maven/MavenModuleSet.java (revision 15307)
+++ src/main/java/hudson/maven/MavenModuleSet.java (working copy)
@@ -438,6 +438,10 @@
}
protected void buildDependencyGraph(DependencyGraph graph) {
+ Collection modules = getModules();
+ for (MavenModule m : modules) {
+ m.buildDependencyGraph(graph);
+ }
publishers.buildDependencyGraph(this,graph);
buildWrappers.buildDependencyGraph(this,graph);
}
Index: src/main/java/hudson/maven/MavenModuleSetBuild.java
===================================================================
--- src/main/java/hudson/maven/MavenModuleSetBuild.java (revision 15307)
+++ src/main/java/hudson/maven/MavenModuleSetBuild.java (working copy)
@@ -25,11 +25,9 @@
import hudson.AbortException;
import hudson.FilePath;
-import hudson.FilePath.FileCallable;
import hudson.Launcher;
import hudson.Util;
-import hudson.tasks.BuildWrapper;
-import hudson.tasks.Maven.MavenInstallation;
+import hudson.FilePath.FileCallable;
import hudson.maven.MavenBuild.ProxyImpl2;
import hudson.maven.reporters.MavenFingerprinter;
import hudson.model.AbstractBuild;
@@ -39,23 +37,15 @@
import hudson.model.BuildListener;
import hudson.model.Fingerprint;
import hudson.model.Hudson;
-import hudson.model.Result;
import hudson.model.ParametersAction;
+import hudson.model.Result;
import hudson.model.Cause.UpstreamCause;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
+import hudson.tasks.BuildWrapper;
+import hudson.tasks.Maven.MavenInstallation;
import hudson.util.ArgumentListBuilder;
import hudson.util.StreamTaskListener;
-import org.apache.maven.BuildFailureException;
-import org.apache.maven.embedder.MavenEmbedderException;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.execution.ReactorManager;
-import org.apache.maven.lifecycle.LifecycleExecutionException;
-import org.apache.maven.monitor.event.EventDispatcher;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.ProjectBuildingException;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
import java.io.File;
import java.io.IOException;
@@ -68,12 +58,23 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
import java.util.Properties;
+import java.util.Set;
+import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.apache.maven.BuildFailureException;
+import org.apache.maven.embedder.MavenEmbedderException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.ReactorManager;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.monitor.event.EventDispatcher;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuildingException;
+import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerResponse;
+
/**
* {@link Build} for {@link MavenModuleSet}.
*
@@ -91,7 +92,7 @@
*
* @author Kohsuke Kawaguchi
*/
-public final class MavenModuleSetBuild extends AbstractBuild {
+public final class MavenModuleSetBuild extends AbstractMavenBuild {
/**
* {@link MavenReporter}s that will contribute project actions.
* Can be null if there's none.
@@ -492,10 +493,7 @@
// schedule downstream builds. for non aggregator style builds,
// this is done by each module
if(getResult().isBetterOrEqualTo(Result.SUCCESS)) {
- for(AbstractProject down : getProject().getDownstreamProjects()) {
- listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
- down.scheduleBuild(new UpstreamCause(MavenModuleSetBuild.this));
- }
+ scheduleDownstreamBuilds(listener);
}
}
@@ -503,7 +501,7 @@
performAllBuildStep(listener, project.getProperties(),false);
}
}
-
+
/**
* Runs Maven and builds the project.
*
@@ -752,8 +750,4 @@
private static final Logger LOGGER = Logger.getLogger(MavenModuleSetBuild.class.getName());
- /**
- * Extra versbose debug switch.
- */
- public static boolean debug = false;
}