From 7dfb26a15aad24f794dc5e18c01f964e03b6244e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=C3=A1n=20Dunne?= Date: Sat, 24 Jan 2015 10:16:06 +0000 Subject: [PATCH] JENKINS-12092 Block category by other categories --- .../ThrottleJobProperty.java | 38 ++++++++++++++++++- .../ThrottleQueueTaskDispatcher.java | 36 ++++++++++++++++++ .../throttleconcurrents/Messages.properties | 1 + .../ThrottleJobProperty/global.jelly | 3 ++ .../ThrottleCategoryTest.java | 30 +++++++++++++-- 5 files changed, 103 insertions(+), 5 deletions(-) diff --git a/src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java b/src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java index f2cba356..f38401e4 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,9 +325,10 @@ public static final class ThrottleCategory extends AbstractDescribableImpl blockingCategoriesList = new ArrayList(); private List nodeLabeledPairs; - @DataBoundConstructor public ThrottleCategory(String categoryName, Integer maxConcurrentPerNode, Integer maxConcurrentTotal, @@ -335,7 +339,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 +377,17 @@ public String getCategoryName() { return categoryName; } + public String getBlockingCategories() { + return blockingCategories; + } + + public List getBlockingCategoriesList() { + if (blockingCategoriesList == null) + blockingCategoriesList = new ArrayList(); + + 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..49e25625 100644 --- a/src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java +++ b/src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java @@ -33,11 +33,13 @@ public class ThrottleCategoryTest private static final String testCategoryName = "aCategory"; @Test - public void shouldGetEmptyNodeLabeledPairsListUponInitialNull() + public void shouldGetEmptyValuesUponInitialNull() { 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()); + assertTrue("blockingCategories shall be empty", category.getBlockingCategoriesList().isEmpty()); + assertNull("blockingCategories shall be empty", category.getBlockingCategories()); } @Test @@ -47,7 +49,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)); @@ -59,4 +61,26 @@ public void shouldGetNonEmptyNodeLabeledPairsListThatWasSet() assertEquals("maxConcurrentPerNodeLabeled "+actualMax+" does not match expected "+expectedMax, expectedMax, actualMax); } + + @Test + public void shouldGetNonEmptyBlockCategoriesListThatWasCreated() + { + ThrottleJobProperty.ThrottleCategory categoryOne = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA", null); + assertEquals("blockingCategories should have one entry", 1, categoryOne.getBlockingCategoriesList().size()); + assertEquals("blockingCategory name should match", categoryOne.getBlockingCategoriesList().get(0), "catA"); + + ThrottleJobProperty.ThrottleCategory categoryTwo = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA, ", null); + assertEquals("blockingCategories should have one entry", 1, categoryTwo.getBlockingCategoriesList().size()); + assertEquals("blockingCategory name should match", categoryTwo.getBlockingCategoriesList().get(0), "catA"); + + ThrottleJobProperty.ThrottleCategory categoryThree = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA,catB", null); + assertEquals("blockingCategories should not be empty", 2, categoryThree.getBlockingCategoriesList().size()); + assertEquals("blockingCategory name should match", categoryThree.getBlockingCategoriesList().get(0), "catA"); + assertEquals("blockingCategory name should match", categoryThree.getBlockingCategoriesList().get(1), "catB"); + + ThrottleJobProperty.ThrottleCategory categoryFour = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA, catB,", null); + assertEquals("blockingCategories should not be empty", 2, categoryFour.getBlockingCategoriesList().size()); + assertEquals("blockingCategory name should match", categoryFour.getBlockingCategoriesList().get(0), "catA"); + assertEquals("blockingCategory name should match", categoryFour.getBlockingCategoriesList().get(1), "catB"); + } }