diff --git a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java index f2cba356..089e9790 100644 --- a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java +++ b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java @@ -17,6 +17,7 @@ import hudson.matrix.MatrixProject; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -24,12 +25,14 @@ import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import jenkins.model.Jenkins; +import jenkins.model.Jenkins; import net.sf.json.JSONObject; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; @@ -322,6 +325,8 @@ public static final class ThrottleCategory extends AbstractDescribableImpl blockingCategoriesList = new ArrayList(); private List nodeLabeledPairs; @DataBoundConstructor @@ -335,7 +340,26 @@ public ThrottleCategory(String categoryName, this.nodeLabeledPairs = nodeLabeledPairs == null ? new ArrayList() : nodeLabeledPairs; } + + @DataBoundConstructor + public ThrottleCategory(String categoryName, + Integer maxConcurrentPerNode, + Integer maxConcurrentTotal, + String blockingCategories, + List nodeLabeledPairs) { + this(categoryName, maxConcurrentPerNode, maxConcurrentTotal, nodeLabeledPairs); + this.blockingCategories = blockingCategories; + convertCategoriesToList(blockingCategories); + } + private void convertCategoriesToList(String categoriesString) { + String[] catArray = StringUtils.split(categoriesString, ','); + catArray = StringUtils.stripAll(catArray); + if (catArray != null) { + Collections.addAll(blockingCategoriesList, catArray); + } + } + public Integer getMaxConcurrentPerNode() { if (maxConcurrentPerNode == null) maxConcurrentPerNode = 0; @@ -354,6 +378,14 @@ public String getCategoryName() { return categoryName; } + public String getBlockingCategories() { + return blockingCategories; + } + + public List getBlockingCategoriesList() { + return blockingCategoriesList; + } + public List getNodeLabeledPairs() { if (nodeLabeledPairs == null) nodeLabeledPairs = new ArrayList(); diff --git a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java index eb1abece..8eb79b71 100644 --- a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java +++ b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java @@ -1,5 +1,6 @@ package hudson.plugins.throttleconcurrents; + import hudson.Extension; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; @@ -13,14 +14,18 @@ import hudson.model.labels.LabelAtom; import hudson.model.queue.CauseOfBlockage; import hudson.model.queue.QueueTaskDispatcher; +import hudson.plugins.throttleconcurrents.ThrottleJobProperty.ThrottleCategory; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; +import org.apache.commons.lang.StringUtils; + @Extension public class ThrottleQueueTaskDispatcher extends QueueTaskDispatcher { @@ -153,6 +158,11 @@ else if (tjp.getThrottleOption().equals("category")) { // Double check category itself isn't null if (category != null) { + // Check if this job is blocked by category + if (isBlockedByCategories(category.getBlockingCategoriesList())) { + return CauseOfBlockage.fromMessage(Messages._ThrottleQueueTaskDispatcher_BlockedByCategory()); + } + if (category.getMaxConcurrentTotal().intValue() > 0) { int maxConcurrentTotal = category.getMaxConcurrentTotal().intValue(); int totalRunCount = 0; @@ -178,6 +188,32 @@ else if (tjp.getThrottleOption().equals("category")) { return null; } + private boolean isBlockedByCategories(List categoryNames) { + for (String catName : categoryNames) { + if (areProjectsInCategoryBuilding(catName)) { + return true; + } + } + return false; + } + + private boolean areProjectsInCategoryBuilding(String categoryName) { + List> projectsInCategory = ThrottleJobProperty.getCategoryProjects(categoryName); + for (AbstractProject project : projectsInCategory) { + if (isProjectBuilding(project)) { + return true; + } + } + return false; + } + + private boolean isProjectBuilding(AbstractProject project) { + if (project.isBuilding() || project.isInQueue()) { + return true; + } + return false; + } + @CheckForNull private ThrottleJobProperty getThrottleJobProperty(Task task) { if (task instanceof AbstractProject) { diff --git a/src/main/resources/hudson/plugins/throttleconcurrents/Messages.properties b/src/main/resources/hudson/plugins/throttleconcurrents/Messages.properties index 949b92e3..0bb18f51 100644 --- a/src/main/resources/hudson/plugins/throttleconcurrents/Messages.properties +++ b/src/main/resources/hudson/plugins/throttleconcurrents/Messages.properties @@ -1,5 +1,6 @@ ThrottleQueueTaskDispatcher.MaxCapacityOnNode=Already running {0} builds on node ThrottleQueueTaskDispatcher.MaxCapacityTotal=Already running {0} builds across all nodes ThrottleQueueTaskDispatcher.BuildPending=A build is pending launch +ThrottleQueueTaskDispatcher.BlockedByCategory=Build is blocked by jobs in another category ThrottleMatrixProjectOptions.DisplayName=Additional options for Matrix projects \ No newline at end of file diff --git a/src/main/resources/hudson/plugins/throttleconcurrents/ThrottleJobProperty/global.jelly b/src/main/resources/hudson/plugins/throttleconcurrents/ThrottleJobProperty/global.jelly index 1a6db694..8f2b4efc 100644 --- a/src/main/resources/hudson/plugins/throttleconcurrents/ThrottleJobProperty/global.jelly +++ b/src/main/resources/hudson/plugins/throttleconcurrents/ThrottleJobProperty/global.jelly @@ -13,6 +13,9 @@ + + + diff --git a/src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java b/src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java index d0488566..68c40731 100644 --- a/src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java +++ b/src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java @@ -36,7 +36,7 @@ public class ThrottleCategoryTest public void shouldGetEmptyNodeLabeledPairsListUponInitialNull() { ThrottleJobProperty.ThrottleCategory category = - new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, null); + new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, null, null); assertTrue("nodeLabeledPairs shall be empty", category.getNodeLabeledPairs().isEmpty()); } @@ -47,7 +47,7 @@ public void shouldGetNonEmptyNodeLabeledPairsListThatWasSet() Integer expectedMax = new Integer(1); ThrottleJobProperty.ThrottleCategory category = - new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, null); + new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "", null); List nodeLabeledPairs = category.getNodeLabeledPairs(); nodeLabeledPairs.add(new ThrottleJobProperty.NodeLabeledPair(expectedLabel, expectedMax));