Skip to content
Permalink
Browse files

Merge pull request #19 from ikedam/feature/JENKINS-17626_FixRetryCount

[JENKINS-17626] Count the number a build rescheduled precisely
  • Loading branch information...
ndeloof committed Sep 7, 2015
2 parents a8f193d + eb87736 commit 6b07b088edcd576082d734cede6f52f21dd1f270
@@ -7,6 +7,23 @@
* @author: <a hef="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public class NaginatorAction implements BuildBadgeAction {
private final int retryCount;

/**
* @deprecated use {@link NaginatorAction#NaginatorAction(int)}
*/
@Deprecated
public NaginatorAction() {
this(0);
}

/**
* @param retryCount the number of retry this build is rescheduled for.
* @since 1.16
*/
public NaginatorAction(int retryCount) {
this.retryCount = retryCount;
}

public String getIconFileName() {
return null;
@@ -19,4 +36,16 @@ public String getDisplayName() {
public String getUrlName() {
return null;
}

/**
* Returns the number of retry this build is rescheduled for.
* This may be <code>0</code> for builds rescheduled with
* older versions of naginator-plugin.
*
* @return the number of retry this build is rescheduled for.
* @since 1.16
*/
public int getRetryCount() {
return retryCount;
}
}
@@ -59,9 +59,9 @@ public void onCompleted(AbstractBuild<?, ?> build, @Nonnull TaskListener listene

if (!combsToRerun.isEmpty()) {
LOGGER.log(Level.FINE, "schedule matrix rebuild");
scheduleMatrixBuild(build, combsToRerun, n);
scheduleMatrixBuild(build, combsToRerun, n, retryCount + 1);
} else {
scheduleBuild(build, n);
scheduleBuild(build, n, retryCount + 1);
}
}
}
@@ -87,7 +87,16 @@ public boolean canSchedule(Run build, NaginatorPublisher naginator) {
return n < max;
}

private int calculateRetryCount(@Nonnull Run<?, ?> r) {
public static int calculateRetryCount(@Nonnull Run<?, ?> r) {
NaginatorAction naginatorAction = r.getAction(NaginatorAction.class);
if (naginatorAction == null) {
return 0;
}
if (naginatorAction.getRetryCount() > 0) {
return naginatorAction.getRetryCount();
}

// fallback for build made by older versions.
int n = 0;

while (r != null && r.getAction(NaginatorAction.class) != null) {
@@ -97,8 +106,16 @@ private int calculateRetryCount(@Nonnull Run<?, ?> r) {
return n;
}

/**
* @deprecated use {@link NaginatorScheduleAction} to make a build rescheduled.
*/
@Deprecated
public boolean scheduleMatrixBuild(AbstractBuild<?, ?> build, List<Combination> combinations, int n) {
NaginatorMatrixAction nma = new NaginatorMatrixAction();
return scheduleMatrixBuild(build, combinations, n, NaginatorListener.calculateRetryCount(build));
}

private boolean scheduleMatrixBuild(AbstractBuild<?, ?> build, List<Combination> combinations, int n, int retryCount) {
NaginatorMatrixAction nma = new NaginatorMatrixAction(retryCount);
for (Combination c : combinations) {
nma.addCombinationToRerun(c);
}
@@ -107,9 +124,16 @@ public boolean scheduleMatrixBuild(AbstractBuild<?, ?> build, List<Combination>

/**
* Wrapper method for mocking purposes.
*
* @deprecated use {@link NaginatorScheduleAction} to make a build rescheduled.
*/
@Deprecated
public boolean scheduleBuild(AbstractBuild<?, ?> build, int n) {
return NaginatorRetryAction.scheduleBuild(build, n);
return scheduleBuild(build, n, NaginatorListener.calculateRetryCount(build));
}

private boolean scheduleBuild(AbstractBuild<?, ?> build, int n, int retryCount) {
return NaginatorRetryAction.scheduleBuild(build, n, retryCount);
}

private static final Logger LOGGER = Logger.getLogger(NaginatorListener.class.getName());
@@ -12,7 +12,20 @@
public class NaginatorMatrixAction extends NaginatorAction {
private List<Combination> combsToRerun;

/**
* @deprecated use {@link NaginatorMatrixAction#NaginatorMatrixAction(int)}.
*/
@Deprecated
public NaginatorMatrixAction() {
this(0);
}

/**
* @param retryCount the number of retry this build is rescheduled for.
* @since 1.16
*/
public NaginatorMatrixAction(int retryCount) {
super(retryCount);
this.combsToRerun = new ArrayList<Combination>();
}

@@ -37,12 +37,12 @@ public String getUrlName() {

public void doIndex(StaplerResponse res, @AncestorInPath AbstractBuild build) throws IOException {
Jenkins.getInstance().checkPermission(Item.BUILD);
NaginatorRetryAction.scheduleBuild(build, 0);
NaginatorRetryAction.scheduleBuild(build, 0, NaginatorListener.calculateRetryCount(build));
res.sendRedirect2(build.getUpUrl());
}

static boolean scheduleBuild(final AbstractBuild<?, ?> build, final int delay) {
return scheduleBuild(build, delay, new NaginatorAction());
static boolean scheduleBuild(final AbstractBuild<?, ?> build, final int delay, int retryCount) {
return scheduleBuild(build, delay, new NaginatorAction(retryCount));
}

static boolean scheduleBuild(final AbstractBuild<?, ?> build, final int delay, final NaginatorAction action) {
@@ -3,19 +3,31 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;

import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.FailureBuilder;
import org.jvnet.hudson.test.SleepBuilder;
import org.kohsuke.stapler.StaplerRequest;

import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Cause;
import hudson.model.CauseAction;
import hudson.model.Descriptor;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.ParametersAction;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.StringParameterDefinition;
import hudson.model.StringParameterValue;
import hudson.model.Result;
import hudson.model.TaskListener;
import hudson.tasks.BuildTrigger;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
@@ -197,4 +209,73 @@ public String getDisplayName() {
}
}
}

@Bug(17626)
public void testCountScheduleIndependently() throws Exception {
// Running a two sequence of builds
// with parameter PARAM=A and PARAM=B.
// Each of them should be rescheduled
// 2 times.

FreeStyleProject p = createFreeStyleProject();
p.addProperty(new ParametersDefinitionProperty(
new StringParameterDefinition("PARAM", "")
));
p.getBuildersList().add(new SleepBuilder(100));
p.getBuildersList().add(new FailureBuilder());
p.getPublishersList().add(new NaginatorPublisher(
"", // regexpForRerun
false, // rerunIfUnstable
false, // rerunMatrixPart
false, // checkRegexp
2, // maxSchedule
new FixedDelay(0) // delay
));

p.scheduleBuild2(
0,
new Cause.UserIdCause(),
new ParametersAction(
new StringParameterValue("PARAM", "A")
)
);
p.scheduleBuild2(
0,
new Cause.UserIdCause(),
new ParametersAction(
new StringParameterValue("PARAM", "B")
)
);

waitUntilNoActivity();

assertEquals(3, Collections2.filter(
p.getBuilds(),
new Predicate<FreeStyleBuild>() {
public boolean apply(FreeStyleBuild b) {
try {
return "A".equals(b.getEnvironment(TaskListener.NULL).get("PARAM"));
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
}
).size());
assertEquals(3, Collections2.filter(
p.getBuilds(),
new Predicate<FreeStyleBuild>() {
public boolean apply(FreeStyleBuild b) {
try {
return "B".equals(b.getEnvironment(TaskListener.NULL).get("PARAM"));
} catch (IOException e) {
return false;
} catch (InterruptedException e) {
return false;
}
}
}
).size());
}
}
@@ -55,7 +55,7 @@ public void testComputeScheduleDelayNoMax() {
private static AbstractBuild createBuild(final boolean hasNaginatorAction, final AbstractBuild previousBuild) {
final AbstractBuild build = mock(AbstractBuild.class);
when(build.getPreviousBuild()).thenReturn(previousBuild);
when(build.getAction(NaginatorAction.class)).thenReturn(hasNaginatorAction ? new NaginatorAction() : null);
when(build.getAction(NaginatorAction.class)).thenReturn(hasNaginatorAction ? new NaginatorAction(0) : null);
return build;
}
}

0 comments on commit 6b07b08

Please sign in to comment.
You can’t perform that action at this time.