package hudson.plugins.promoted_builds.conditions;
import groovy.lang.Binding;
import hudson.EnvVars;
import hudson.PluginManager;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.plugins.promoted_builds.PromotionBadge;
import hudson.plugins.promoted_builds.PromotionCondition;
import hudson.plugins.promoted_builds.PromotionProcess;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
import org.jenkinsci.plugins.scriptsecurity.scripts.UnapprovedClasspathException;
import org.jenkinsci.plugins.scriptsecurity.scripts.UnapprovedUsageException;
import org.kohsuke.stapler.DataBoundConstructor;
import javax.annotation.CheckForNull;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Allow specification of Groovy scripts to qualify builds. Script evaluation is done using the
* <a href="https://wiki.jenkins-ci.org/display/JENKINS/Script+Security+Plugin">Script Security plugin</a>
*/
public class GroovyCondition extends PromotionCondition {
private static final Logger LOGGER = Logger.getLogger(GroovyCondition.class.getName());
@CheckForNull
private final String unmetQualificationLabel;
@CheckForNull
private final String metQualificationLabel;
private final SecureGroovyScript script;
@DataBoundConstructor
public GroovyCondition(final SecureGroovyScript script, final String unmetQualificationLabel, final String metQualificationLabel) {
this.unmetQualificationLabel = Util.fixEmptyAndTrim(unmetQualificationLabel);
this.metQualificationLabel = Util.fixEmptyAndTrim(metQualificationLabel);
this.script = script.configuringWithNonKeyItem();
}
// exposed for config.jelly
public SecureGroovyScript getScript() {
return script;
}
// exposed for config.jelly
public String getUnmetQualificationLabel() {
return unmetQualificationLabel;
}
// exposed for config.jelly
public String getMetQualificationLabel() {
return metQualificationLabel;
}
// exposed for promotion status page
public String getDisplayLabel() {
return unmetQualificationLabel == null ? Messages.GroovyCondition_UnmetQualificationLabel() : unmetQualificationLabel;
}
@Override
public PromotionBadge isMet(final PromotionProcess promotionProcess, final AbstractBuild<?, ?> build) {
// TODO switch to Jenkins.getActiveInstance() once bumped to 1.590
final Jenkins jenkins = Jenkins.getInstance();
if (jenkins == null) {
// Jenkins not started or shut down
LOGGER.log(Level.WARNING, "Missing Jenkins instance");
return null;
}
final PluginManager pluginManager = jenkins.getPluginManager();
if (pluginManager == null) {
LOGGER.log(Level.WARNING, "Unable to retrieve PluginManager");
return null;
}
final ClassLoader classLoader = pluginManager.uberClassLoader;
final Binding binding = new Binding();
binding.setVariable("promotionProcess", promotionProcess);
binding.setVariable("build", build);
binding.setVariable("jenkins", jenkins);
Object result = null;
try {
result = script.evaluate(classLoader, binding);
} catch (final RejectedAccessException e) {
LOGGER.log(Level.WARNING, "Sandbox exception", e);
return null;
} catch (final UnapprovedUsageException e) {
LOGGER.log(Level.WARNING, "Unapproved script", e);
return null;
} catch (final UnapprovedClasspathException e) {
LOGGER.log(Level.WARNING, "Unapproved classpath", e);
return null;
} catch (final Exception e) {
LOGGER.log(Level.WARNING, "Evaluation error", e);
return null;
}
final String displayLabel = metQualificationLabel == null ? Messages.GroovyCondition_MetQualificationLabel() : metQualificationLabel;
if (Boolean.TRUE.equals(result)) {
return new Badge(displayLabel, Collections.<String,String>emptyMap());
} else if (result instanceof Map && !((Map) result).isEmpty()) {
final Map<String, String> variables = new HashMap<String, String>(((Map) result).size());
for (final Map.Entry entry : ((Map<Object, Object>) result).entrySet()) {
final Object key = entry.getKey();
final Object value = entry.getValue();
if (key == null) {
continue;
}
variables.put(key.toString(), value == null ? "" : value.toString());
}
return new Badge(displayLabel, variables);
}
return null;
}
public static final class Badge extends PromotionBadge {
private final String displayLabel;
private final Map<String, String> variables;
public Badge(final String displayLabel, final Map<String, String> variables) {
this.displayLabel = displayLabel;
this.variables = variables;
}
// exposed for Jelly
public String getDisplayLabel() {
return displayLabel;
}
@Override
public void buildEnvVars(final AbstractBuild<?, ?> build, final EnvVars env) {
super.buildEnvVars(build, env);
for (final Map.Entry<String, String> entry :
variables.entrySet()) {
env.put(entry.getKey(), entry.getValue());
}
}
}
}