package hudson.plugins.parameterizedtrigger;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import hudson.EnvVars;
import hudson.Extension;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.TaskListener;
import hudson.util.FormValidation;
import hudson.util.VariableResolver;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A BuildParameterFactory generating Predefined Parameters for a counter
*
* @author Chris Johnson
*/
public class CounterBuildParameterFactory extends AbstractBuildParameterFactory {
private final String from;
private final String to;
private final String step;
private final String paramExpr;
private final SteppingValidationEnum validationFail;
public enum SteppingValidationEnum {
FAIL("Fail the build step"), // previous behaviour (default)
SKIP("Don't trigger these projects"){
@Override
public void failCheck(TaskListener listener) throws AbstractBuildParameters.DontTriggerException {
listener.getLogger().println(Messages.CounterBuildParameterFactory_CountingWillNotTerminateSkipping());
throw new AbstractBuildParameters.DontTriggerException();
}},
NOPARMS("Skip these parameters"){
@Override
public void failCheck(TaskListener listener) throws AbstractBuildParameters.DontTriggerException {
listener.getLogger().println(Messages.CounterBuildParameterFactory_CountingWillNotTerminateIgnore());
}};
private String description;
public String getDescription() {
return description;
}
SteppingValidationEnum(String description) {
this.description = description;
}
public void failCheck(TaskListener listener) throws AbstractBuildParameters.DontTriggerException {
throw new RuntimeException(Messages.CounterBuildParameterFactory_CountingWillNotTerminate());
}
}
public CounterBuildParameterFactory(long from, long to, long step, String paramExpr) {
this(Long.toString(from), Long.toString(to), Long.toString(step), paramExpr);
}
public CounterBuildParameterFactory(long from, long to, long step, String paramExpr, SteppingValidationEnum validationFail) {
this(Long.toString(from), Long.toString(to), Long.toString(step), paramExpr, validationFail);
}
public CounterBuildParameterFactory(String from, String to, String step, String paramExpr) {
// mimic old behaviour which failed job
this(from, to, step, paramExpr, SteppingValidationEnum.FAIL);
}
@DataBoundConstructor
public CounterBuildParameterFactory(String from, String to, String step, String paramExpr, SteppingValidationEnum validationFail) {
this.from = from;
this.to = to;
this.step = step;
this.paramExpr = paramExpr;
this.validationFail = validationFail;
}
@Override
public List<AbstractBuildParameters> getParameters(AbstractBuild<?, ?> build, TaskListener listener) throws IOException, InterruptedException, AbstractBuildParameters.DontTriggerException {
EnvVars envVars = build.getEnvironment(listener);
long fromNum = Long.valueOf(envVars.expand(from));
long toNum = Long.valueOf(envVars.expand(to));
long stepNum = Long.valueOf(envVars.expand(step));
ArrayList<AbstractBuildParameters> params = Lists.newArrayList();
int upDown = Long.signum(toNum - fromNum);
if (upDown == 0) {
params.add(getParameterForCount(fromNum));
} else {
if (stepNum == 0) {
validationFail.failCheck(listener);
} else if (upDown * stepNum < 0) {
validationFail.failCheck(listener);
} else {
for (Long i = fromNum; upDown * i <= upDown * toNum; i += stepNum) {
params.add(getParameterForCount(i));
}
}
}
return params;
}
private PredefinedBuildParameters getParameterForCount(Long i) {
String stringWithCount = Util.replaceMacro(paramExpr, ImmutableMap.of("COUNT", i.toString()));
return new PredefinedBuildParameters(stringWithCount);
}
@Extension
public static class DescriptorImpl extends AbstractBuildParameterFactoryDescriptor {
@Override
public String getDisplayName() {
return Messages.CounterBuildParameterFactory_CounterBuildParameterFactory();
}
public FormValidation doCheckFrom(@QueryParameter String value) { return validateNumberField(value);
}
public FormValidation doCheckTo(@QueryParameter String value) {
return validateNumberField(value);
}
public FormValidation doCheckStep(@QueryParameter String value) {
return validateNumberField(value);
}
private FormValidation validateNumberField(String value) {
// The field can contain Parameters - eliminate them first. The remaining String should
// be empty or a number.
String valueWithoutVariables = Util.replaceMacro(value, EMPTY_STRING_VARIABLE_RESOLVER);
if (StringUtils.isNotEmpty(valueWithoutVariables) && !isNumber(valueWithoutVariables)) {
return FormValidation.warning(hudson.model.Messages.Hudson_NotANumber());
} else {
return FormValidation.validateRequired(value);
}
}
private boolean isNumber(String value) {
try {
Long.valueOf(value);
} catch (NumberFormatException e) {
return false;
}
return true;
}
}
public String getFrom() {
return from;
}
public String getTo() {
return to;
}
public String getStep() {
return step;
}
public String getParamExpr() {
return paramExpr;
}
public SteppingValidationEnum getvalidationFail() {
return validationFail;
}
private static final VariableResolver<String> EMPTY_STRING_VARIABLE_RESOLVER = new VariableResolver<String>() {
@Override
public String resolve(String name) {
return "";
}
};
}