Skip to content

Commit

Permalink
[FIXED JENKINS-32821] Introduced a new option "How to apply the regul…
Browse files Browse the repository at this point in the history
…ar expression to matrix" which replaces "Test regular expression for the matrix parent"
  • Loading branch information
ikedam committed Feb 27, 2016
1 parent 9ce342c commit 7b9f2f2
Show file tree
Hide file tree
Showing 7 changed files with 497 additions and 67 deletions.
Expand Up @@ -13,9 +13,12 @@
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import net.sf.json.JSONObject;

import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.DataBoundConstructor;
Expand All @@ -37,7 +40,9 @@ public class NaginatorPublisher extends Notifier {
private final boolean rerunIfUnstable;
private final boolean rerunMatrixPart;
private final boolean checkRegexp;
private final Boolean regexpForMatrixParent;
@Deprecated
private transient Boolean regexpForMatrixParent;
private RegexpForMatrixStrategy regexpForMatrixStrategy; /* almost final */
private NoChildStrategy noChildStrategy; /* almost final */

private ScheduleDelay delay;
Expand All @@ -52,55 +57,54 @@ public NaginatorPublisher(String regexpForRerun,
}

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

/**
* @since 1.16
* @deprecated use {@link #NaginatorPublisher(String, boolean, boolean, boolean, int, ScheduleDelay)} and other setters
*/
@DataBoundConstructor
@Deprecated
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;
this(regexpForRerun, rerunIfUnstable, rerunMatrixPart, checkRegexp, maxSchedule, delay);
setRegexpForMatrixParent(regexpForMatrixParent);
}

public Object readResolve() {
if (this.delay == null) {
// 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
);
if (regexpForMatrixStrategy == null) {
if (regexpForMatrixParent != null) {
// >= 1.16
setRegexpForMatrixParent(regexpForMatrixParent.booleanValue());
regexpForMatrixParent = null;
} else {
// < 1.16
setRegexpForMatrixStrategy(RegexpForMatrixStrategy.TestParent);
}
}
return this;
}
Expand Down Expand Up @@ -147,15 +151,43 @@ public boolean isCheckRegexp() {
*
* @return Returns whether apply the regexp to the matrix parent instead of matrix children
* @since 1.16
* @deprecated use {@link #getRegexpForMatrixStrategy()}
*/
@Deprecated
public boolean isRegexpForMatrixParent() {
return regexpForMatrixParent;
return (getRegexpForMatrixStrategy() == RegexpForMatrixStrategy.TestParent);
}

private void setRegexpForMatrixParent(boolean regexpForMatrixParent) {
setRegexpForMatrixStrategy(
regexpForMatrixParent
? RegexpForMatrixStrategy.TestParent
: RegexpForMatrixStrategy.TestChildrenRetriggerMatched // compatible with 1.16.
);
}

public String getRegexpForRerun() {
return regexpForRerun;
}

/**
* @param regexpForMatrixStrategy
* @since 1.17
*/
@DataBoundSetter
public void setRegexpForMatrixStrategy(@Nonnull RegexpForMatrixStrategy regexpForMatrixStrategy) {
this.regexpForMatrixStrategy = regexpForMatrixStrategy;
}

/**
* @return how to apply regexp for matrix builds.
* @since 1.17
*/
@Nonnull
public RegexpForMatrixStrategy getRegexpForMatrixStrategy() {
return regexpForMatrixStrategy;
}

public ScheduleDelay getDelay() {
return delay;
}
Expand All @@ -167,6 +199,13 @@ public int getMaxSchedule() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
if (build instanceof MatrixRun) {
if (
getRegexpForMatrixStrategy() == RegexpForMatrixStrategy.TestChildrenRetriggerMatched
&& !isRerunMatrixPart()
) {
listener.getLogger().println("[Naginator] Warning: TestChildrenRetriggerMatched doesn't work without rerunMatrixPart");
}

MatrixBuild parent = ((MatrixRun)build).getParentBuild();
if (parent.getAction(NaginatorPublisherScheduleAction.class) == null) {
// No strict exclusion is required
Expand Down Expand Up @@ -265,6 +304,26 @@ public Notifier newInstance(StaplerRequest req, JSONObject formData) throws Form
public boolean isMatrixProject(Object it) {
return (it instanceof MatrixProject);
}

public FormValidation doCheckRegexpForMatrixStrategy(
@QueryParameter RegexpForMatrixStrategy value,
@QueryParameter boolean rerunMatrixPart
) {
// called only when regexpForMatrixStrategy is displayed,
// and we can assume that this is a matrix project.
if (value == RegexpForMatrixStrategy.TestChildrenRetriggerMatched && !rerunMatrixPart) {
return FormValidation.warning(Messages.NaginatorPublisher_RegexpForMatrixStrategy_RerunMatrixPartShouldBeEnabled());
}
return FormValidation.ok();
}

public ListBoxModel doFillRegexpForMatrixStrategyItems() {
ListBoxModel ret = new ListBoxModel();
for (RegexpForMatrixStrategy strategy: RegexpForMatrixStrategy.values()) {
ret.add(strategy.getDisplayName(), strategy.name());
}
return ret;
}
}

private static final Logger LOGGER = Logger.getLogger(NaginatorPublisher.class.getName());
Expand Down
Expand Up @@ -36,18 +36,36 @@ public class NaginatorPublisherScheduleAction extends NaginatorScheduleAction {
private final String regexpForRerun;
private final boolean rerunIfUnstable;
private final boolean checkRegexp;
private final boolean regexpForMatrixParent;
private transient Boolean regexpForMatrixParent; // for backward compatibility
private /* almost final */ RegexpForMatrixStrategy regexpForMatrixStrategy;
private final NoChildStrategy noChildStrategy;

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();
this.regexpForMatrixStrategy = publisher.getRegexpForMatrixStrategy();
this.noChildStrategy = publisher.getNoChildStrategy();
}

public Object readResolve() {
if (regexpForMatrixStrategy == null) {
// < 1.17
if (regexpForMatrixParent != null) {
regexpForMatrixStrategy =
regexpForMatrixParent.booleanValue()
? RegexpForMatrixStrategy.TestParent
: RegexpForMatrixStrategy.TestChildrenRetriggerMatched;
regexpForMatrixParent = null;
} else {
// something strange.
regexpForMatrixStrategy = RegexpForMatrixStrategy.getDefault();
}
}
return this;
}

@CheckForNull
public String getRegexpForRerun() {
return regexpForRerun;
Expand All @@ -61,43 +79,69 @@ public boolean isCheckRegexp() {
return checkRegexp;
}

/**
* @deprecated use {@link #getRegexpForMatrixStrategy()}
*/
@Deprecated
public boolean isRegexpForMatrixParent() {
return regexpForMatrixParent;
return getRegexpForMatrixStrategy() == RegexpForMatrixStrategy.TestParent;
}

/**
* @since 1.17
*/
@Nonnull
public RegexpForMatrixStrategy getRegexpForMatrixStrategy() {
return regexpForMatrixStrategy;
}

@Override
public boolean shouldSchedule(@Nonnull Run<?, ?> run, @Nonnull TaskListener listener, int retryCount) {
if ((run.getResult() == Result.SUCCESS) || (run.getResult() == Result.ABORTED)) {
return false;
}

// If we're not set to rerun if unstable, and the build's unstable, return true.
if ((!isRerunIfUnstable()) && (run.getResult() == Result.UNSTABLE)) {
if (!checkCommonScheduleThreshold(run)) {
return false;
}

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

if (!testRegexp(run, listener)) {
return false;
}
} else if (
isCheckRegexp()
&& (run instanceof MatrixBuild)
&& getRegexpForMatrixStrategy() == RegexpForMatrixStrategy.TestChildrenRetriggerAll
) {
// check should be performed for child builds here.
if (!testRegexpForFailedChildren((MatrixBuild)run, listener)) {
return false;
}
}

return super.shouldSchedule(run, listener, retryCount);
}

private boolean testRegexpForFailedChildren(@Nonnull MatrixBuild run, @Nonnull TaskListener listener) {
for (MatrixRun r : ((MatrixBuild)run).getExactRuns()) {
if (!checkCommonScheduleThreshold(r)) {
continue;
}
if (testRegexp(r, listener)) {
return true;
}
}
// no children matched.
return false;
}

@Override
public boolean shouldScheduleForMatrixRun(@Nonnull MatrixRun run, @Nonnull TaskListener listener) {
if ((run.getResult() == Result.SUCCESS) || (run.getResult() == Result.ABORTED)) {
if (!checkCommonScheduleThreshold(run)) {
return false;
}
if ((!isRerunIfUnstable()) && (run.getResult() == Result.UNSTABLE)) {
return false;
}
if (isCheckRegexp() && !isRegexpForMatrixParent()) {
if (isCheckRegexp() && getRegexpForMatrixStrategy() == RegexpForMatrixStrategy.TestChildrenRetriggerMatched) {
LOGGER.log(Level.FINEST, "Got isRerunMatrixPart == true");

if (!testRegexp(run, listener)) {
Expand All @@ -107,6 +151,18 @@ public boolean shouldScheduleForMatrixRun(@Nonnull MatrixRun run, @Nonnull TaskL
return true;
}

private boolean checkCommonScheduleThreshold(@Nonnull Run<?, ?> run) {
if ((run.getResult() == Result.SUCCESS) || (run.getResult() == Result.ABORTED)) {
return false;
}

// If we're not set to rerun if unstable, and the build's unstable, return true.
if ((!isRerunIfUnstable()) && (run.getResult() == Result.UNSTABLE)) {
return false;
}
return true;
}

private boolean testRegexp(@Nonnull Run<?, ?> run, TaskListener listener) {
String regexpForRerun = getRegexpForRerun();
if ((regexpForRerun != null) && (!regexpForRerun.equals(""))) {
Expand Down
@@ -0,0 +1,53 @@
/*
* The MIT License
*
* Copyright (c) 2016 IKEDA Yasuyuki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.chikli.hudson.plugin.naginator;

import javax.annotation.Nonnull;

import org.jvnet.localizer.Localizable;

/**
* How to apply regexp to matrix builds.
*/
public enum RegexpForMatrixStrategy {
TestChildrenRetriggerAll(Messages._RegexpForMatrixStrategy_TestChildrenRetriggerAll()),
TestChildrenRetriggerMatched(Messages._RegexpForMatrixStrategy_TestChildrenRetriggerMatched()),
TestParent(Messages._RegexpForMatrixStrategy_TestParent()),
;
private final Localizable displayName;

private RegexpForMatrixStrategy(Localizable displayName) {
this.displayName = displayName;
}

public String getDisplayName() {
return displayName.toString();
}

@Nonnull
public static RegexpForMatrixStrategy getDefault() {
return TestChildrenRetriggerAll;
}
}
@@ -1,4 +1,9 @@
NaginatorCause.Description=Started by Naginator after build {0} failure
RegexpForMatrixStrategy.TestChildrenRetriggerAll=Test failed matrix parts, and retrigger all
RegexpForMatrixStrategy.TestChildrenRetriggerMatched=Test failed matrix parts, and retrigger only matched parts
RegexpForMatrixStrategy.TestParent=Test the parent build
NoChildStrategy.RerunWhole.DisplayName=Rerun the matrix with all combinations
NoChildStrategy.RerunEmpty.DisplayName=Rerun the matrix with no combinations
NoChildStrategy.DontRerun.DisplayName=Don''t rerun
NaginatorPublisher.RegexpForMatrixStrategy.RerunMatrixPartShouldBeEnabled=You need to enable "Rerun build only for failed parts on the matrix" to use this strategy.

0 comments on commit 7b9f2f2

Please sign in to comment.