Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix JENKINS-21672 - Add classpath for presend script
  • Loading branch information
Jeff MAURY committed Aug 6, 2014
1 parent 58f0a1e commit 9c57b9d
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 6 deletions.
48 changes: 45 additions & 3 deletions src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java
Expand Up @@ -3,7 +3,9 @@
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import hudson.EnvVars;
import hudson.FilePath;
Expand All @@ -29,12 +31,15 @@
import hudson.tasks.Mailer;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -45,6 +50,7 @@
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.mail.Address;
Expand All @@ -58,8 +64,10 @@
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import jenkins.model.Jenkins;
import jenkins.model.JenkinsLocationConfiguration;

import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
Expand Down Expand Up @@ -126,6 +134,8 @@ public class ExtendedEmailPublisher extends Notifier implements MatrixAggregatab
* The project's pre-send script.
*/
public String presendScript;

public List<GroovyScriptPath> classpath;

/**
* True to attach the log from the build to the email.
Expand Down Expand Up @@ -174,13 +184,15 @@ public ExtendedEmailPublisher(String project_recipient_list, String project_cont
this.saveOutput = project_save_output;
this.configuredTriggers = project_triggers;
this.matrixTriggerMode = matrixTriggerMode;
System.out.println("Deprecated const called");

This comment has been minimized.

Copy link
@slide

slide Aug 6, 2014

Member

Debug code?

This comment has been minimized.

Copy link
@jeffmaury

jeffmaury Aug 6, 2014

Member

My fault: owe you a beer

}

@DataBoundConstructor
public ExtendedEmailPublisher(String project_recipient_list, String project_content_type, String project_default_subject,
String project_default_content, String project_attachments, String project_presend_script,
int project_attach_buildlog, String project_replyto, boolean project_save_output,
List<EmailTrigger> project_triggers, MatrixTriggerMode matrixTriggerMode, boolean project_disabled) {
List<EmailTrigger> project_triggers, MatrixTriggerMode matrixTriggerMode, boolean project_disabled,
List<GroovyScriptPath> classpath) {
this.recipientList = project_recipient_list;
this.contentType = project_content_type;
this.defaultSubject = project_default_subject;
Expand All @@ -194,10 +206,12 @@ public ExtendedEmailPublisher(String project_recipient_list, String project_cont
this.configuredTriggers = project_triggers;
this.matrixTriggerMode = matrixTriggerMode;
this.disabled = project_disabled;
this.classpath = classpath;
System.out.println("Const called");

This comment has been minimized.

Copy link
@slide

slide Aug 6, 2014

Member

Debug code?

This comment has been minimized.

Copy link
@jeffmaury

jeffmaury Aug 6, 2014

Member

My fault: owe you a beer

}

public ExtendedEmailPublisher() {

System.out.println("Empty const called");

This comment has been minimized.

Copy link
@slide

slide Aug 6, 2014

Member

Debug code?

This comment has been minimized.

Copy link
@jeffmaury

jeffmaury Aug 6, 2014

Member

My fault: owe you a beer

}

/**
Expand Down Expand Up @@ -423,6 +437,7 @@ private boolean executePresendScript(ExtendedEmailPublisherContext context, Mime
"hudson",
"hudson.model"));

cl = expandClassLoader(cl, cc);
if (getDescriptor().isSecurityEnabled()) {
debug(context.getListener().getLogger(), "Setting up sandbox for pre-send script");
cc.addCompilationCustomizers(new SandboxTransformer());
Expand Down Expand Up @@ -464,7 +479,34 @@ private boolean executePresendScript(ExtendedEmailPublisherContext context, Mime
return !cancel;
}

private MimeMessage createMail(ExtendedEmailPublisherContext context) throws MessagingException, IOException, InterruptedException {
/**
* Expand the plugin class loader with URL taken from the project descriptor
* and the global configuration.
*
* @param cl the original plugin classloader
* @param cc
* @return the new expanded classloader
*/
private ClassLoader expandClassLoader(ClassLoader cl, CompilerConfiguration cc) {
if ((classpath != null) && classpath.size() > 0) {
cl = new GroovyClassLoader(cl, cc);
for(GroovyScriptPath path : classpath) {
((GroovyClassLoader)cl).addURL(path.asURL());
}
}
List<GroovyScriptPath> globalClasspath = getDescriptor().getDefaultClasspath();
if ((globalClasspath != null) && (globalClasspath.size() > 0)) {
if (!(cl instanceof GroovyClassLoader)) {
cl = new GroovyClassLoader(cl, cc);
}
for(GroovyScriptPath path : globalClasspath) {
((GroovyClassLoader)cl).addURL(path.asURL());
}
}
return cl;
}

private MimeMessage createMail(ExtendedEmailPublisherContext context) throws MessagingException, IOException, InterruptedException {
ExtendedEmailPublisherDescriptor descriptor = getDescriptor();
boolean overrideGlobalSettings = descriptor.getOverrideGlobalSettings();

Expand Down
@@ -1,15 +1,18 @@
package hudson.plugins.emailext;

import hudson.Extension;
import hudson.ExtensionList;
import hudson.matrix.MatrixProject;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Item;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Publisher;
import hudson.util.FormValidation;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

Expand All @@ -19,8 +22,12 @@
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.servlet.ServletException;

import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


Expand Down Expand Up @@ -93,6 +100,8 @@ public final class ExtendedEmailPublisherDescriptor extends BuildStepDescriptor<
*/
private String defaultPresendScript = "";

private List<GroovyScriptPath> defaultClasspath = new ArrayList<GroovyScriptPath>();

/**
* This is the global emergency email address
*/
Expand Down Expand Up @@ -298,6 +307,10 @@ public String getDefaultPresendScript() {
return defaultPresendScript;
}

public List<GroovyScriptPath> getDefaultClasspath() {
return defaultClasspath;
}

public ExtendedEmailPublisherDescriptor() {
super(ExtendedEmailPublisher.class);
load();
Expand Down Expand Up @@ -348,7 +361,12 @@ public boolean configure(StaplerRequest req, JSONObject formData)
req.getParameter("ext_mailer_default_replyto") : "";
defaultPresendScript = nullify(req.getParameter("ext_mailer_default_presend_script")) != null ?
req.getParameter("ext_mailer_default_presend_script") : "";

if (req.hasParameter("ext_mailer_default_classpath")) {
defaultClasspath.clear();
for(String s : req.getParameterValues("ext_mailer_default_classpath")) {
defaultClasspath.add(new GroovyScriptPath(s));
}
}
debugMode = req.hasParameter("ext_mailer_debug_mode");

//enableWatching = req.getParameter("ext_mailer_enable_watching") != null;
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/hudson/plugins/emailext/GroovyScriptPath.java
@@ -0,0 +1,58 @@
package hudson.plugins.emailext;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import org.kohsuke.stapler.DataBoundConstructor;

import hudson.Extension;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;

/**
* Model a classpath entry for Groovy pre script execution.
* The syntax can be an URL, and if the syntax is invalid, defaults to a
* file path.
* This has been inspired by the Jenkins Postbuild plugin.
*
* @see <a href="https://github.com/jenkinsci/groovy-postbuild-plugin">https://github.com/jenkinsci/groovy-postbuild-plugin</a>
* @see <a href="https://github.com/jenkinsci/groovy-postbuild-plugin/blob/master/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.java">https://github.com/jenkinsci/groovy-postbuild-plugin/blob/master/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.java</a>
*
*/
public class GroovyScriptPath extends AbstractDescribableImpl<GroovyScriptPath> {

private String path;

@DataBoundConstructor
public GroovyScriptPath(String path) {
this.path = path;
}

public String getPath() {
return path;
}

public URL asURL() {
URL url = null;

try {
url = new URL(path);
}
catch (MalformedURLException e) {
try {
url = new File(path).toURI().toURL();
} catch (MalformedURLException e1) {
}
}
return url;
}

@Extension
public static class GroovyScriptPathDescriptor extends Descriptor<GroovyScriptPath> {

This comment has been minimized.

Copy link
@slide

slide Aug 6, 2014

Member

Formatting seems a little off here.

This comment has been minimized.

Copy link
@jeffmaury

jeffmaury Aug 6, 2014

Member

Tab character problem but seems at lot of code using it as well: will remove them in a separate commit

@Override
public String getDisplayName() {
return "";
}
}
}
Expand Up @@ -58,6 +58,14 @@ f.advanced(title: _("Advanced Settings")) {
f.entry(title: _("Pre-send Script"), help: "/plugin/email-ext/help/projectConfig/presendScript.html") {
f.textarea(id: "project_presend_script", name: "project_presend_script", value: configured ? instance.presendScript : "\$DEFAULT_PRESEND_SCRIPT", class: "setting-input")
}
f.entry(title: _("Additional groovy classpath"), help: "/plugin/help/projectConfig/defaultClasspath.html") {
f.repeatable(field: "classpath") {
f.textbox(field: "path")
div(align: "right") {
f.repeatableDeleteButton()
}
}
}

f.entry(title: _("Save to Workspace"), help: "/plugin/email-ext/help/projectConfig/saveOutput.html") {
f.checkbox(name: "project_save_output", checked: instance?.saveOutput)
Expand Down
Expand Up @@ -77,6 +77,14 @@ f.section(title: _("Extended E-mail Notification")) {
f.entry(help: "/plugin/email-ext/help/globalConfig/defaultPresendScript.html", title: _("Default Pre-send Script")) {
f.textarea(class: "setting-input", value: descriptor.defaultPresendScript, name: "ext_mailer_default_presend_script")
}
f.entry(title: _("Additional groovy classpath"), help: "/plugin/email-ext/help/globalConfig/defaultClasspath.html") {
f.repeatable(field: "defaultClasspath") {
f.textbox(field: "path", name: "ext_mailer_default_classpath")
div(align: "right") {
f.repeatableDeleteButton()
}
}
}
f.optionalBlock(help: "/plugin/email-ext/help/globalConfig/debugMode.html", checked: descriptor.isDebugMode(), name: "ext_mailer_debug_mode", title: _("Enable Debug Mode"))
f.optionalBlock(help: "/plugin/email-ext/help/globalConfig/security.html", checked: descriptor.isSecurityEnabled(), name: "ext_mailer_security_enabled", title: _("Enable Security"))

Expand Down
7 changes: 7 additions & 0 deletions src/main/webapp/help/globalConfig/defaultClasspath.html
@@ -0,0 +1,7 @@
<div>
These pathes allow to extend the Groovy classpath when the
presend script is run. The syntax of the path is either a
full url or a simple file path (may be relative).
These pathes are common to all projects when configured at
the global scope.
</div>
7 changes: 7 additions & 0 deletions src/main/webapp/help/projectConfig/defaultClasspath.html
@@ -0,0 +1,7 @@
<div>
These pathes allow to extend the Groovy classpath when the
presend script is run. The syntax of the path is either a
full url or a simple file path (may be relative).
These pathes are specific to this project and will be added
to those of the global scope.
</div>
@@ -1,15 +1,19 @@
package hudson.plugins.emailext;

import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlDivision;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSelect;
import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;

import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import static org.junit.Assert.*;

import org.jvnet.hudson.test.Bug;

public class ExtendedEmailPublisherDescriptorTest {
Expand Down Expand Up @@ -88,6 +92,11 @@ public void testGlobalConfigDefaultState() throws Exception {
HtmlCheckBoxInput securityMode = page.getElementByName("ext_mailer_security_enabled");
assertNotNull("Security mode should be present", securityMode);
assertFalse("Security mode should not be checked by default", securityMode.isChecked());

try {
page.getElementByName("defaultClasspath");
fail("defaultClasspath section should not be present");
} catch (ElementNotFoundException e) {}
}

@Test
Expand Down

0 comments on commit 9c57b9d

Please sign in to comment.