Permalink
Browse files

Merge pull request #21 from ikedam/feature/regexpForMatrixChildren

[FIXED JENKINS-26637] Allow regexp applied for matrix children logs
  • Loading branch information...
ikedam committed Oct 26, 2015
2 parents 6b07b08 + 5a92856 commit 82ff6a07f300b0795b83e310b7b51e8f7edeb5ef
@@ -70,12 +70,6 @@
</pluginRepositories>

<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>matrix-project</artifactId>
<version>1.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
@@ -4,14 +4,18 @@
import hudson.Launcher;
import hudson.matrix.MatrixRun;
import hudson.matrix.MatrixBuild;
import hudson.matrix.MatrixProject;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Job;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import net.sf.json.JSONObject;

import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.DataBoundConstructor;

@@ -28,6 +32,7 @@
private final boolean rerunIfUnstable;
private final boolean rerunMatrixPart;
private final boolean checkRegexp;
private final Boolean regexpForMatrixParent;

private ScheduleDelay delay;

@@ -40,18 +45,38 @@ public NaginatorPublisher(String regexpForRerun,
this(regexpForRerun, rerunIfUnstable, false, checkRegexp, 0, new ProgressiveDelay(5*60, 3*60*60));
}

/**
* backward compatible constructor.
*
* Watch that <code>regexpForMatrixParent</code> gets <code>true</code>
* for the backward compatibility.
*/
public NaginatorPublisher(String regexpForRerun,
boolean rerunIfUnstable,
boolean rerunMatrixPart,
boolean checkRegexp,
int maxSchedule,
ScheduleDelay delay) {
this(regexpForRerun, rerunIfUnstable, rerunMatrixPart, checkRegexp, true, maxSchedule, delay);
}

/**
* @since 1.16
*/
@DataBoundConstructor
public NaginatorPublisher(String regexpForRerun,
boolean rerunIfUnstable,
boolean rerunMatrixPart,
boolean checkRegexp,
boolean regexpForMatrixParent,
int maxSchedule,
ScheduleDelay delay) {
this.regexpForRerun = regexpForRerun;
this.rerunIfUnstable = rerunIfUnstable;
this.rerunMatrixPart = rerunMatrixPart;
this.checkRegexp = checkRegexp;
this.maxSchedule = maxSchedule;
this.regexpForMatrixParent = regexpForMatrixParent;
this.delay = delay;
}

@@ -60,6 +85,17 @@ public Object readResolve() {
// Backward compatibility : progressive 5 minutes up to 3 hours
delay = new ProgressiveDelay(5*60, 3*60*60);
}
if (regexpForMatrixParent == null) {
return new NaginatorPublisher(
regexpForRerun,
rerunIfUnstable,
rerunMatrixPart,
checkRegexp,
true, // true for backward compatibility.
maxSchedule,
delay
);
}
return this;
}

@@ -75,6 +111,19 @@ public boolean isCheckRegexp() {
return checkRegexp;
}

/**
* Returns whether apply the regexp to the matrix parent instead of matrix children.
*
* The default is <code>false</code> for naginator-plugin >= 1.16
* though <code>true</code> for configurations upgraded from naginator-plugin < 1.16.
*
* @return Returns whether apply the regexp to the matrix parent instead of matrix children
* @since 1.16
*/
public boolean isRegexpForMatrixParent() {
return regexpForMatrixParent;
}

public String getRegexpForRerun() {
return regexpForRerun;
}
@@ -151,6 +200,19 @@ public boolean isApplicable(Class<? extends AbstractProject> jobType) {
public Notifier newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return req.bindJSON(NaginatorPublisher.class, formData);
}

/**
* @return true if the current request is for a matrix project.
* @since 1.16
*/
public boolean isMatrixProject() {
StaplerRequest req = Stapler.getCurrentRequest();
if (req == null) {
return false;
}
Job<?, ?> job = req.findAncestorObject(Job.class);
return (job instanceof MatrixProject);
}
}

private static final Logger LOGGER = Logger.getLogger(NaginatorPublisher.class.getName());
@@ -1,6 +1,7 @@
package com.chikli.hudson.plugin.naginator;

import hudson.matrix.MatrixRun;
import hudson.matrix.MatrixBuild;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
@@ -19,18 +20,22 @@

/**
* Used from {@link NaginatorPublisher} to mark a build to be reshceduled.
*
* @since 1.16
*/
public class NaginatorPublisherScheduleAction extends NaginatorScheduleAction {
private static final Logger LOGGER = Logger.getLogger(NaginatorPublisherScheduleAction.class.getName());

private final String regexpForRerun;
private final boolean rerunIfUnstable;
private final boolean checkRegexp;
private final boolean regexpForMatrixParent;

public NaginatorPublisherScheduleAction(NaginatorPublisher publisher) {
super(publisher.getMaxSchedule(), publisher.getDelay(), publisher.isRerunMatrixPart());
this.regexpForRerun = publisher.getRegexpForRerun();
this.rerunIfUnstable = publisher.isRerunIfUnstable();
this.regexpForMatrixParent = publisher.isRegexpForMatrixParent();
this.checkRegexp = publisher.isCheckRegexp();
}

@@ -47,6 +52,10 @@ public boolean isCheckRegexp() {
return checkRegexp;
}

public boolean isRegexpForMatrixParent() {
return regexpForMatrixParent;
}

@Override
public boolean shouldSchedule(@Nonnull Run<?, ?> run, @Nonnull TaskListener listener, int retryCount) {
if ((run.getResult() == Result.SUCCESS) || (run.getResult() == Result.ABORTED)) {
@@ -60,24 +69,11 @@ public boolean shouldSchedule(@Nonnull Run<?, ?> run, @Nonnull TaskListener list

// If we're supposed to check for a regular expression in the build output before
// scheduling a new build, do so.
if (isCheckRegexp()) {
if (isCheckRegexp() && (!(run instanceof MatrixBuild) || isRegexpForMatrixParent())) {
LOGGER.log(Level.FINEST, "Got checkRegexp == true");

String regexpForRerun = getRegexpForRerun();
if ((regexpForRerun != null) && (!regexpForRerun.equals(""))) {
LOGGER.log(Level.FINEST, "regexpForRerun - {0}", regexpForRerun);

try {
// If parseLog returns false, we didn't find the regular expression,
// so return true.
if (!parseLog(run.getLogFile(), regexpForRerun)) {
LOGGER.log(Level.FINEST, "regexp not in logfile");
return false;
}
} catch (IOException e) {
e.printStackTrace(listener
.error("error while parsing logs for naginator - forcing rebuild."));
}
if (!testRegexp(run, listener)) {
return false;
}
}

@@ -92,6 +88,33 @@ public boolean shouldScheduleForMatrixRun(@Nonnull MatrixRun run, @Nonnull TaskL
if ((!isRerunIfUnstable()) && (run.getResult() == Result.UNSTABLE)) {
return false;
}
if (isCheckRegexp() && !isRegexpForMatrixParent()) {
LOGGER.log(Level.FINEST, "Got isRerunMatrixPart == true");

if (!testRegexp(run, listener)) {
return false;
}
}
return true;
}

private boolean testRegexp(@Nonnull Run<?, ?> run, TaskListener listener) {
String regexpForRerun = getRegexpForRerun();
if ((regexpForRerun != null) && (!regexpForRerun.equals(""))) {
LOGGER.log(Level.FINEST, "regexpForRerun - {0}", regexpForRerun);

try {
// If parseLog returns false, we didn't find the regular expression,
// so return true.
if (!parseLog(run.getLogFile(), regexpForRerun)) {
LOGGER.log(Level.FINEST, "regexp not in logfile");
return false;
}
} catch (IOException e) {
e.printStackTrace(listener
.error("error while parsing logs for naginator - forcing rebuild."));
}
}
return true;
}

@@ -17,13 +17,17 @@
</f:entry>

<f:advanced>
<f:entry field="checkRegexp"
<f:optionalBlock field="checkRegexp" inline="true"
title="${%Only rerun build if regular expression is found in output}">
<f:checkbox />
</f:entry>
<f:entry title="${%Regular expression to search for}" field="regexpForRerun">
<f:textbox />
</f:entry>
<f:entry title="${%Regular expression to search for}" field="regexpForRerun">
<f:textbox />
</f:entry>
<j:if test="${descriptor.matrixProject}">
<f:entry title="${%Test regular expression for the matrix parent}" field="regexpForMatrixParent">
<f:checkbox />
</f:entry>
</j:if>
</f:optionalBlock>
</f:advanced>

</j:jelly>
@@ -7,8 +7,8 @@
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.chikli.hudson.plugin.naginator.testutils.MyBuilder;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;

@@ -19,7 +19,6 @@
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;
@@ -31,9 +30,7 @@
import hudson.tasks.BuildTrigger;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import net.sf.json.JSONObject;

public class NaginatorListenerTest extends HudsonTestCase {
@Override
@@ -45,46 +42,6 @@ protected void tearDown() throws Exception {
}
}

private final static class MyBuilder extends Builder {
private final String text;
private final Result result;
private final int duration;

public MyBuilder(String text, Result result) {
super();
this.text = text;
this.result = result;
this.duration = 0;
}

private MyBuilder(String text, Result result, int duration) {
this.text = text;
this.result = result;
this.duration = duration;
}

@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws InterruptedException,
IOException {
if (duration > 0) Thread.sleep(duration);

listener.getLogger().println(text);
build.setResult(result);
return true;
}

@Extension
public static final class DescriptorImpl extends Descriptor<Builder> {
public String getDisplayName() {
return "MyBuilder";
}
public MyBuilder newInstance(StaplerRequest req, JSONObject data) {
return new MyBuilder("foo", Result.SUCCESS);
}
}
}

public void testSuccessNoRebuild() throws Exception {
assertEquals(false, isScheduledForRetry("build log", Result.SUCCESS, "foo", false, false));
}
Oops, something went wrong.

0 comments on commit 82ff6a0

Please sign in to comment.