Index: email-ext/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly =================================================================== --- email-ext/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly (revision 19390) +++ email-ext/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly Wed Dec 02 10:04:49 HST 2009 @@ -42,6 +42,25 @@ + + + + + + + + + + + + @@ -57,6 +76,19 @@ + + + + + + + + + + + @@ -90,7 +122,16 @@ - + + + + + + + Index: email-ext/src/main/webapp/help/projectConfig/mailType/script.html =================================================================== --- email-ext/src/main/webapp/help/projectConfig/mailType/script.html Tue Nov 24 17:23:05 HST 2009 +++ email-ext/src/main/webapp/help/projectConfig/mailType/script.html Tue Nov 24 17:23:05 HST 2009 @@ -0,0 +1,6 @@ +
+ Specifies whether the mail's content should be interpreted as a Groovy + SimpleTemplate script. + If so, the script can access the AbstractBuild object using the + build bind variable. +
Index: email-ext/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java =================================================================== --- email-ext/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java (revision 22062) +++ email-ext/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java Fri Dec 18 14:06:15 HST 2009 @@ -2,11 +2,7 @@ import hudson.Extension; import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; -import hudson.model.BuildListener; -import hudson.model.Hudson; -import hudson.model.User; +import hudson.model.*; import hudson.plugins.emailext.plugins.ContentBuilder; import hudson.plugins.emailext.plugins.EmailTrigger; import hudson.plugins.emailext.plugins.EmailTriggerDescriptor; @@ -30,6 +26,7 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import java.nio.charset.Charset; import javax.mail.Address; import javax.mail.Authenticator; @@ -46,6 +43,7 @@ import net.sf.json.JSONObject; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; /** * {@link Publisher} that sends notification e-mail. @@ -67,8 +65,10 @@ public static final String PROJECT_DEFAULT_SUBJECT_TEXT = "$PROJECT_DEFAULT_SUBJECT"; public static final String PROJECT_DEFAULT_BODY_TEXT = "$PROJECT_DEFAULT_CONTENT"; - + + private static final String DEFAULT_CHARSET_SENTINAL = "default"; + - public static void addEmailTriggerType(EmailTriggerDescriptor triggerType) throws EmailExtException { + public static void addEmailTriggerType(EmailTriggerDescriptor triggerType) throws EmailExtException { if(EMAIL_TRIGGER_TYPE_MAP.containsKey(triggerType.getMailerId())) throw new EmailExtException("An email trigger type with name " + triggerType.getTriggerName() + " was already added."); @@ -113,7 +113,12 @@ */ public String contentType; - /** + /** + * The charset of the emails for this project. + */ + public String charset; + + /** * The default subject of the emails for this project. ($PROJECT_DEFAULT_SUBJECT) */ public String defaultSubject; @@ -123,6 +128,10 @@ */ public String defaultContent; + public boolean defaultContentIsScript; + + public String buildForTesting; + /** * Get the list of configured email triggers for this project. */ @@ -260,9 +269,16 @@ //Set the contents of the email msg.setSentDate(new Date()); String subject = new ContentBuilder().transformText(type.getSubject(), this, type, build); + String specificCharset = charset; + if (specificCharset == null || DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(specificCharset)) { + specificCharset = DESCRIPTOR.getDefaultCharset(); + } + if (specificCharset == null || DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(specificCharset)) { - msg.setSubject(subject); + msg.setSubject(subject); + } else { + msg.setSubject(subject, specificCharset); + } String text = new ContentBuilder().transformText(type.getBody(), this, type, build); - msg.setContent(text, contentType); String messageContentType = contentType; // contentType is null if the project was not reconfigured after upgrading. if (messageContentType == null || "default".equals(messageContentType)) { @@ -273,6 +289,9 @@ messageContentType = "text/plain"; } } + if (specificCharset != null && !DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(specificCharset)) { + messageContentType += "; charset=" + specificCharset; + } msg.setContent(text, messageContentType); // Get the recipients from the global list of addresses @@ -388,8 +407,13 @@ * This is a global default content type (mime type) for emails. */ private String defaultContentType; - - /** + + /** + * This is a global default charset (mime type) for emails. + */ + private String defaultCharset; + + /** * This is a global default subject line for sending emails. */ private String defaultSubject; @@ -399,9 +423,19 @@ */ private String defaultBody; + /** + * This indicates that the global default body or subject line should be evaluated as a script. + */ + private boolean defaultIsScript; + + /** + * This just remembers the last build for testing that was saved, for the user's convenience. + */ + public String defaultBuildForTesting; + private boolean overrideGlobalSettings; - - @Override + + @Override public String getDisplayName() { return "Editable Email Notification"; } @@ -495,11 +529,15 @@ public String getSmtpPort() { return smtpPort; } - - public String getDefaultContentType() { - return defaultContentType; - } - + + public String getDefaultContentType() { + return defaultContentType; + } + + public String getDefaultCharset() { + return defaultCharset; + } + public String getDefaultSubject() { return defaultSubject; } @@ -507,7 +545,15 @@ public String getDefaultBody() { return defaultBody; } - + + public boolean getDefaultIsScript() { + return defaultIsScript; + } + + public String getDefaultBuildForTesting() { + return defaultBuildForTesting; + } + public boolean getOverrideGlobalSettings() { return overrideGlobalSettings; } @@ -525,10 +571,13 @@ ExtendedEmailPublisher m = new ExtendedEmailPublisher(); m.recipientList = listRecipients; m.contentType = req.getParameter("project_content_type"); + m.charset = req.getParameter("project_charset"); m.defaultSubject = req.getParameter("project_default_subject"); m.defaultContent = req.getParameter("project_default_content"); + m.defaultContentIsScript = req.getParameter("project_default_content_is_script")!=null; m.configuredTriggers = new ArrayList(); + m.buildForTesting = req.getParameter("project_build_for_testing"); - + // Create a new email trigger for each one that is configured for (String mailerId : EMAIL_TRIGGER_TYPE_MAP.keySet()) { EmailType type = createMailType(req, mailerId); @@ -556,6 +605,7 @@ m.setSendToRecipientList(req.getParameter(prefix + "sendToRecipientList")!=null); m.setSendToDevelopers(req.getParameter(prefix + "sendToDevelopers")!=null); m.setIncludeCulprits(req.getParameter(prefix + "includeCulprits")!=null); + m.setScript(req.getParameter(prefix + "script")!=null); return m; } @@ -602,11 +652,14 @@ smtpPort = nullify(req.getParameter("ext_mailer_smtp_port")); defaultContentType = nullify(req.getParameter("ext_mailer_default_content_type")); + defaultCharset = nullify(req.getParameter("ext_mailer_default_charset")); // Allow global defaults to be set for the subject and body of the email defaultSubject = nullify(req.getParameter("ext_mailer_default_subject")); defaultBody = nullify(req.getParameter("ext_mailer_default_body")); + defaultIsScript = req.getParameter("ext_mailer_default_is_script") != null; + defaultBuildForTesting = req.getParameter("ext_mailer_default_build_for_testing"); - + overrideGlobalSettings = req.getParameter("ext_mailer_use_global_settings") != null; save(); @@ -651,9 +704,130 @@ } return FormValidation.ok(); } - + + public FormValidation doCharsetCheck(StaplerRequest req, StaplerResponse rsp, @QueryParameter final String value) throws IOException, ServletException { + String charset = nullify(value); + if (charset == null || DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(charset) || Charset.isSupported(charset)) { + return FormValidation.ok(); + } else { + return FormValidation.error("unsupported charset"); - } + } + } + public FormValidation doBuildForTestingCheck(StaplerRequest req, StaplerResponse rsp, @QueryParameter final String value) throws IOException, ServletException { + String buildForTesting = nullify(value); + if (buildForTesting == null) { + return FormValidation.ok(); + } + try { + getBuildForTesting(buildForTesting); + return FormValidation.ok(); + } + catch (FormValidation e) { + return e; + } + } + private interface TransformStrategy { + String transformText(String origText, ExtendedEmailPublisher publisher, EmailType type, AbstractBuild build); + } + public FormValidation doTestAgainstBuild(StaplerRequest req, @QueryParameter("project_build_for_testing") String buildForTesting) throws IOException { + TransformStrategy strategy = new TransformStrategy() { + public String transformText(String origText, ExtendedEmailPublisher publisher, EmailType type, AbstractBuild build) { + return new ContentBuilder().transformText(origText, publisher, type, build); -} + } + }; + return doTestAgainstBuild(strategy, PROJECT_DEFAULT_SUBJECT_TEXT, PROJECT_DEFAULT_BODY_TEXT, req, buildForTesting); + } + + public FormValidation doGlobalTestAgainstBuild(StaplerRequest req, + @QueryParameter("ext_mailer_default_build_for_testing") String buildForTesting, + @QueryParameter("ext_mailer_default_is_script") final boolean globalIsScript, + @QueryParameter("ext_mailer_default_subject") String globalSubject, + @QueryParameter("ext_mailer_default_body") String globalBody + ) throws IOException { + TransformStrategy strategy = new TransformStrategy() { + public String transformText(String origText, ExtendedEmailPublisher publisher, EmailType type, AbstractBuild build) { + // This works around ContentBuilder.transformText()'s static access of the global subject and body, + // which has not been updated before testing. + return new ContentBuilder().transformResolvedText(globalIsScript, origText, publisher, type, build); + } + }; + return doTestAgainstBuild(strategy, globalSubject, globalBody, req, buildForTesting); + } + + private String testedEmailText; + + private FormValidation doTestAgainstBuild(TransformStrategy strategy, + String originalSubject, + String originalBody, + StaplerRequest req, + String buildForTesting + ) throws IOException { + buildForTesting = nullify(buildForTesting); + if (buildForTesting == null) { + return FormValidation.error("need to configure a build for testing"); + } + try { + AbstractBuild build = getBuildForTesting(buildForTesting); + ExtendedEmailPublisher publisher = (ExtendedEmailPublisher) newInstance(req, null); + EmailType type = new EmailType(); + type.setBody(ExtendedEmailPublisher.PROJECT_DEFAULT_BODY_TEXT); + type.setSubject(ExtendedEmailPublisher.PROJECT_DEFAULT_SUBJECT_TEXT); + String subject = strategy.transformText(originalSubject, publisher, type, build); + testedEmailText = strategy.transformText(originalBody, publisher, type, build); + String resultUrl = req.getRequestURI().replace("testAgainstBuild", "testedEmailText") + .replace("globalTestAgainstBuild", "testedEmailText"); // todo: some better hack + return FormValidation.okWithMarkup("resulting subject: " + subject + + "
resulting body: