Skip to content

Commit 7dfb26a

Browse files
committed
JENKINS-12092 Block category by other categories
1 parent 9502034 commit 7dfb26a

File tree

5 files changed

+103
-5
lines changed

5 files changed

+103
-5
lines changed

src/main/java/hudson/plugins/throttleconcurrents/ThrottleJobProperty.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,22 @@
1717
import hudson.matrix.MatrixProject;
1818

1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.Collection;
2122
import java.util.Collections;
2223
import java.util.HashMap;
2324
import java.util.List;
2425
import java.util.Map;
2526
import java.util.WeakHashMap;
2627
import java.util.concurrent.CopyOnWriteArrayList;
28+
2729
import javax.annotation.CheckForNull;
2830
import javax.annotation.Nonnull;
29-
import jenkins.model.Jenkins;
3031

32+
import jenkins.model.Jenkins;
3133
import net.sf.json.JSONObject;
3234

35+
import org.apache.commons.lang.StringUtils;
3336
import org.kohsuke.stapler.DataBoundConstructor;
3437
import org.kohsuke.stapler.QueryParameter;
3538
import org.kohsuke.stapler.StaplerRequest;
@@ -322,9 +325,10 @@ public static final class ThrottleCategory extends AbstractDescribableImpl<Throt
322325
private Integer maxConcurrentPerNode;
323326
private Integer maxConcurrentTotal;
324327
private String categoryName;
328+
private String blockingCategories;
329+
private List<String> blockingCategoriesList = new ArrayList<String>();
325330
private List<NodeLabeledPair> nodeLabeledPairs;
326331

327-
@DataBoundConstructor
328332
public ThrottleCategory(String categoryName,
329333
Integer maxConcurrentPerNode,
330334
Integer maxConcurrentTotal,
@@ -335,7 +339,26 @@ public ThrottleCategory(String categoryName,
335339
this.nodeLabeledPairs =
336340
nodeLabeledPairs == null ? new ArrayList<NodeLabeledPair>() : nodeLabeledPairs;
337341
}
342+
343+
@DataBoundConstructor
344+
public ThrottleCategory(String categoryName,
345+
Integer maxConcurrentPerNode,
346+
Integer maxConcurrentTotal,
347+
String blockingCategories,
348+
List<NodeLabeledPair> nodeLabeledPairs) {
349+
this(categoryName, maxConcurrentPerNode, maxConcurrentTotal, nodeLabeledPairs);
350+
this.blockingCategories = blockingCategories;
351+
convertCategoriesToList(blockingCategories);
352+
}
338353

354+
private void convertCategoriesToList(String categoriesString) {
355+
String[] catArray = StringUtils.split(categoriesString, ", ");
356+
catArray = StringUtils.stripAll(catArray);
357+
if (catArray != null) {
358+
Collections.addAll(blockingCategoriesList, catArray);
359+
}
360+
}
361+
339362
public Integer getMaxConcurrentPerNode() {
340363
if (maxConcurrentPerNode == null)
341364
maxConcurrentPerNode = 0;
@@ -354,6 +377,17 @@ public String getCategoryName() {
354377
return categoryName;
355378
}
356379

380+
public String getBlockingCategories() {
381+
return blockingCategories;
382+
}
383+
384+
public List<String> getBlockingCategoriesList() {
385+
if (blockingCategoriesList == null)
386+
blockingCategoriesList = new ArrayList<String>();
387+
388+
return blockingCategoriesList;
389+
}
390+
357391
public List<NodeLabeledPair> getNodeLabeledPairs() {
358392
if (nodeLabeledPairs == null)
359393
nodeLabeledPairs = new ArrayList<NodeLabeledPair>();

src/main/java/hudson/plugins/throttleconcurrents/ThrottleQueueTaskDispatcher.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package hudson.plugins.throttleconcurrents;
22

3+
34
import hudson.Extension;
45
import hudson.matrix.MatrixConfiguration;
56
import hudson.matrix.MatrixProject;
@@ -13,14 +14,18 @@
1314
import hudson.model.labels.LabelAtom;
1415
import hudson.model.queue.CauseOfBlockage;
1516
import hudson.model.queue.QueueTaskDispatcher;
17+
import hudson.plugins.throttleconcurrents.ThrottleJobProperty.ThrottleCategory;
1618

1719
import java.util.List;
1820
import java.util.Set;
1921
import java.util.logging.Level;
2022
import java.util.logging.Logger;
23+
2124
import javax.annotation.CheckForNull;
2225
import javax.annotation.Nonnull;
2326

27+
import org.apache.commons.lang.StringUtils;
28+
2429
@Extension
2530
public class ThrottleQueueTaskDispatcher extends QueueTaskDispatcher {
2631

@@ -153,6 +158,11 @@ else if (tjp.getThrottleOption().equals("category")) {
153158

154159
// Double check category itself isn't null
155160
if (category != null) {
161+
// Check if this job is blocked by category
162+
if (isBlockedByCategories(category.getBlockingCategoriesList())) {
163+
return CauseOfBlockage.fromMessage(Messages._ThrottleQueueTaskDispatcher_BlockedByCategory());
164+
}
165+
156166
if (category.getMaxConcurrentTotal().intValue() > 0) {
157167
int maxConcurrentTotal = category.getMaxConcurrentTotal().intValue();
158168
int totalRunCount = 0;
@@ -178,6 +188,32 @@ else if (tjp.getThrottleOption().equals("category")) {
178188
return null;
179189
}
180190

191+
private boolean isBlockedByCategories(List<String> categoryNames) {
192+
for (String catName : categoryNames) {
193+
if (areProjectsInCategoryBuilding(catName)) {
194+
return true;
195+
}
196+
}
197+
return false;
198+
}
199+
200+
private boolean areProjectsInCategoryBuilding(String categoryName) {
201+
List<AbstractProject<?, ?>> projectsInCategory = ThrottleJobProperty.getCategoryProjects(categoryName);
202+
for (AbstractProject<?, ?> project : projectsInCategory) {
203+
if (isProjectBuilding(project)) {
204+
return true;
205+
}
206+
}
207+
return false;
208+
}
209+
210+
private boolean isProjectBuilding(AbstractProject<?, ?> project) {
211+
if (project.isBuilding() || project.isInQueue()) {
212+
return true;
213+
}
214+
return false;
215+
}
216+
181217
@CheckForNull
182218
private ThrottleJobProperty getThrottleJobProperty(Task task) {
183219
if (task instanceof AbstractProject) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
ThrottleQueueTaskDispatcher.MaxCapacityOnNode=Already running {0} builds on node
22
ThrottleQueueTaskDispatcher.MaxCapacityTotal=Already running {0} builds across all nodes
33
ThrottleQueueTaskDispatcher.BuildPending=A build is pending launch
4+
ThrottleQueueTaskDispatcher.BlockedByCategory=Build is blocked by jobs in another category
45

56
ThrottleMatrixProjectOptions.DisplayName=Additional options for Matrix projects

src/main/resources/hudson/plugins/throttleconcurrents/ThrottleJobProperty/global.jelly

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
<f:entry title="${%Maximum Concurrent Builds Per Node}" field="maxConcurrentPerNode">
1414
<f:textbox />
1515
</f:entry>
16+
<f:entry title="${%Blocking Categories}" field="blockingCategories">
17+
<f:textbox />
18+
</f:entry>
1619
</table>
1720
<f:repeatable field="nodeLabeledPairs" add="${%Add Maximum Per Labeled Node}" minimum="0" header="${%Maximum Per Labeled Node}">
1821
<table width="100%">

src/test/java/hudson/plugins/throttleconcurrents/ThrottleCategoryTest.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ public class ThrottleCategoryTest
3333
private static final String testCategoryName = "aCategory";
3434

3535
@Test
36-
public void shouldGetEmptyNodeLabeledPairsListUponInitialNull()
36+
public void shouldGetEmptyValuesUponInitialNull()
3737
{
3838
ThrottleJobProperty.ThrottleCategory category =
39-
new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, null);
39+
new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, null, null);
4040
assertTrue("nodeLabeledPairs shall be empty", category.getNodeLabeledPairs().isEmpty());
41+
assertTrue("blockingCategories shall be empty", category.getBlockingCategoriesList().isEmpty());
42+
assertNull("blockingCategories shall be empty", category.getBlockingCategories());
4143
}
4244

4345
@Test
@@ -47,7 +49,7 @@ public void shouldGetNonEmptyNodeLabeledPairsListThatWasSet()
4749
Integer expectedMax = new Integer(1);
4850

4951
ThrottleJobProperty.ThrottleCategory category =
50-
new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, null);
52+
new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "", null);
5153
List<ThrottleJobProperty.NodeLabeledPair> nodeLabeledPairs = category.getNodeLabeledPairs();
5254
nodeLabeledPairs.add(new ThrottleJobProperty.NodeLabeledPair(expectedLabel, expectedMax));
5355

@@ -59,4 +61,26 @@ public void shouldGetNonEmptyNodeLabeledPairsListThatWasSet()
5961
assertEquals("maxConcurrentPerNodeLabeled "+actualMax+" does not match expected "+expectedMax,
6062
expectedMax, actualMax);
6163
}
64+
65+
@Test
66+
public void shouldGetNonEmptyBlockCategoriesListThatWasCreated()
67+
{
68+
ThrottleJobProperty.ThrottleCategory categoryOne = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA", null);
69+
assertEquals("blockingCategories should have one entry", 1, categoryOne.getBlockingCategoriesList().size());
70+
assertEquals("blockingCategory name should match", categoryOne.getBlockingCategoriesList().get(0), "catA");
71+
72+
ThrottleJobProperty.ThrottleCategory categoryTwo = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA, ", null);
73+
assertEquals("blockingCategories should have one entry", 1, categoryTwo.getBlockingCategoriesList().size());
74+
assertEquals("blockingCategory name should match", categoryTwo.getBlockingCategoriesList().get(0), "catA");
75+
76+
ThrottleJobProperty.ThrottleCategory categoryThree = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA,catB", null);
77+
assertEquals("blockingCategories should not be empty", 2, categoryThree.getBlockingCategoriesList().size());
78+
assertEquals("blockingCategory name should match", categoryThree.getBlockingCategoriesList().get(0), "catA");
79+
assertEquals("blockingCategory name should match", categoryThree.getBlockingCategoriesList().get(1), "catB");
80+
81+
ThrottleJobProperty.ThrottleCategory categoryFour = new ThrottleJobProperty.ThrottleCategory(testCategoryName, 0, 0, "catA, catB,", null);
82+
assertEquals("blockingCategories should not be empty", 2, categoryFour.getBlockingCategoriesList().size());
83+
assertEquals("blockingCategory name should match", categoryFour.getBlockingCategoriesList().get(0), "catA");
84+
assertEquals("blockingCategory name should match", categoryFour.getBlockingCategoriesList().get(1), "catB");
85+
}
6286
}

0 commit comments

Comments
 (0)