Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.TreeSet;
import edu.umd.cs.findbugs.annotations.Nullable;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

/**
* {@link MatrixExecutionStrategy} that captures historical behavior.
Expand Down Expand Up @@ -54,23 +55,54 @@

private volatile MatrixConfigurationSorter sorter;

/**
* When {@link #isRunSequentially()} is false, sleep this many milliseconds before enqueueing each configuration
* after the first (including between the last touchstone and the first remaining configuration). Zero disables.
*/
private volatile int scheduleDelayMillis;

@DataBoundConstructor
public DefaultMatrixExecutionStrategyImpl(Boolean runSequentially, boolean hasTouchStoneCombinationFilter, String touchStoneCombinationFilter, Result touchStoneResultCondition, MatrixConfigurationSorter sorter) {
this(runSequentially!=null ? runSequentially : false,
hasTouchStoneCombinationFilter ? touchStoneCombinationFilter : null,
hasTouchStoneCombinationFilter ? touchStoneResultCondition : null,
0,
sorter);
}

public DefaultMatrixExecutionStrategyImpl(boolean runSequentially, String touchStoneCombinationFilter, Result touchStoneResultCondition, MatrixConfigurationSorter sorter) {
this(runSequentially, touchStoneCombinationFilter, touchStoneResultCondition, 0, sorter);
}

public DefaultMatrixExecutionStrategyImpl(boolean runSequentially, String touchStoneCombinationFilter, Result touchStoneResultCondition, int scheduleDelayMillis, MatrixConfigurationSorter sorter) {
this.runSequentially = runSequentially;
this.touchStoneCombinationFilter = touchStoneCombinationFilter;
this.touchStoneResultCondition = touchStoneResultCondition;
this.scheduleDelayMillis = Math.max(0, scheduleDelayMillis);
this.sorter = sorter;
}

public DefaultMatrixExecutionStrategyImpl() {
this(false,false,null,null,null);
this(false, false, null, null, null);
}

/**
* Optional delay is not part of {@link DataBoundConstructor} so Stapler/XStream stay compatible
* with the historical 5-argument constructor shape (avoids subtle test/plugin loading issues).
*/
@DataBoundSetter
public void setHasScheduleDelayBetweenChildBuilds(boolean has) {
if (!has) {
scheduleDelayMillis = 0;
}
}

@DataBoundSetter
public void setScheduleDelayMillis(Integer scheduleDelayMillis) {
if (scheduleDelayMillis == null) {

Check warning on line 102 in src/main/java/hudson/matrix/DefaultMatrixExecutionStrategyImpl.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 102 is only partially covered, one branch is missing
return;

Check warning on line 103 in src/main/java/hudson/matrix/DefaultMatrixExecutionStrategyImpl.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 103 is not covered by tests
}
this.scheduleDelayMillis = Math.max(0, scheduleDelayMillis);
}

public boolean getHasTouchStoneCombinationFilter() {
Expand Down Expand Up @@ -114,6 +146,18 @@
this.sorter = sorter;
}

public int getScheduleDelayMillis() {
return scheduleDelayMillis;
}

public void setScheduleDelayMillis(int scheduleDelayMillis) {
this.scheduleDelayMillis = Math.max(0, scheduleDelayMillis);
}

public boolean getHasScheduleDelayBetweenChildBuilds() {
return scheduleDelayMillis > 0;
}

@Override
public Result run(MatrixBuildExecution execution) throws InterruptedException, IOException {

Expand All @@ -133,9 +177,10 @@
delayedConfigurations = createTreeSet(delayedConfigurations, sorter);
}

if(!runSequentially)
for(MatrixConfiguration c : touchStoneConfigurations)
scheduleConfigurationBuild(execution, c);
boolean parallelEnqueueStarted = false;
if (!runSequentially) {
parallelEnqueueStarted = scheduleConfigurationsInParallel(execution, touchStoneConfigurations, parallelEnqueueStarted);
}

PrintStream logger = execution.getListener().getLogger();

Expand All @@ -154,9 +199,9 @@
return r;
}

if(!runSequentially)
for(MatrixConfiguration c : delayedConfigurations)
scheduleConfigurationBuild(execution, c);
if (!runSequentially) {
scheduleConfigurationsInParallel(execution, delayedConfigurations, parallelEnqueueStarted);
}

for (MatrixConfiguration c : delayedConfigurations) {
if(runSequentially)
Expand Down Expand Up @@ -229,6 +274,26 @@
return r;
}

/**
* Enqueue configurations for parallel mode, optionally pausing between each {@link #scheduleConfigurationBuild}.
*
* @param afterPrevious {@code true} if at least one configuration was already enqueued in this matrix build
* @return {@code true} once any configuration from {@code configurations} was enqueued
*/
private boolean scheduleConfigurationsInParallel(
MatrixBuildExecution execution,
Iterable<MatrixConfiguration> configurations,
boolean afterPrevious) throws InterruptedException {
for (MatrixConfiguration c : configurations) {
if (afterPrevious && scheduleDelayMillis > 0) {

Check warning on line 288 in src/main/java/hudson/matrix/DefaultMatrixExecutionStrategyImpl.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 288 is only partially covered, one branch is missing
Thread.sleep(scheduleDelayMillis);

Check warning on line 289 in src/main/java/hudson/matrix/DefaultMatrixExecutionStrategyImpl.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 289 is not covered by tests
}
scheduleConfigurationBuild(execution, c);
afterPrevious = true;
}
return afterPrevious;
}

/** Function to start schedule a single configuration
*
* This function schedule a build of a configuration passing all of the Matrixchild actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ f.optionalBlock (field:"runSequentially", title:_("Run each configuration sequen
}
}

f.optionalBlock(field:"hasScheduleDelayBetweenChildBuilds", title:_("Add delay between scheduling each configuration (parallel mode only)"), inline:true) {
f.entry(title:_("Milliseconds between enqueueing each configuration"), field:"scheduleDelayMillis") {
f.textbox(default:"0")
}
}

f.optionalBlock (field:"hasTouchStoneCombinationFilter", title:_("Execute touchstone builds first"), inline:true) {
// TODO: help="/help/matrix/touchstone.html">
// TODO: move l10n from MatrixProject/configEntries.jelly
Expand Down
7 changes: 7 additions & 0 deletions src/test/java/hudson/matrix/MatrixProjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@ public void testConfigRoundtrip() throws Exception {
p.setExecutionStrategy(before);
j.configRoundtrip(p);
j.assertEqualDataBoundBeans(p.getExecutionStrategy(), before);

before = new DefaultMatrixExecutionStrategyImpl(false, null, null, null);
before.setHasScheduleDelayBetweenChildBuilds(true);
before.setScheduleDelayMillis(150);
p.setExecutionStrategy(before);
j.configRoundtrip(p);
j.assertEqualDataBoundBeans(p.getExecutionStrategy(), before);
}

@Test
Expand Down