Skip to content
Permalink
Browse files

Fix JENKINS-18567, JENKINS-25926 and JENKINS-25719

Added ability for users to watch a job.
Fixup the html content coming from CssInliner
Remove adminAddress field for global config
  • Loading branch information...
Alex Earl
Alex Earl committed Dec 5, 2014
1 parent 6acb6e2 commit bb0053d79fec59f34d3014117883282d6c2239dc
Showing with 839 additions and 303 deletions.
  1. +11 −1 pom.xml
  2. +7 −1 src/main/java/hudson/plugins/emailext/AttachmentUtils.java
  3. +0 −2 src/main/java/hudson/plugins/emailext/EmailExtTemplateAction.java
  4. +52 −25 src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java
  5. +2 −0 src/main/java/hudson/plugins/emailext/ExtendedEmailPublisherDescriptor.java
  6. +30 −14 src/main/java/hudson/plugins/emailext/plugins/CssInliner.java
  7. +11 −0 src/main/java/hudson/plugins/emailext/plugins/EmailTrigger.java
  8. +3 −0 src/main/java/hudson/plugins/emailext/plugins/EmailTriggerDescriptor.java
  9. +0 −12 src/main/java/hudson/plugins/emailext/plugins/trigger/AbstractScriptTrigger.java
  10. +5 −0 src/main/java/hudson/plugins/emailext/plugins/trigger/PreBuildScriptTrigger.java
  11. +5 −0 src/main/java/hudson/plugins/emailext/plugins/trigger/ScriptTrigger.java
  12. +203 −0 src/main/java/hudson/plugins/emailext/watching/EmailExtWatchAction.java
  13. +85 −0 src/main/java/hudson/plugins/emailext/watching/EmailExtWatchJobProperty.java
  14. +9 −0 src/main/resources/hudson/plugins/emailext/EmailExtTemplateAction/action.groovy
  15. +0 −8 src/main/resources/hudson/plugins/emailext/EmailExtTemplateAction/action.jelly
  16. +2 −3 src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.groovy
  17. +3 −0 src/main/resources/hudson/plugins/emailext/Messages.properties
  18. +4 −0 src/main/resources/hudson/plugins/emailext/watching/EmailExtWatchAction/help-triggers.html
  19. +4 −0 src/main/resources/hudson/plugins/emailext/watching/EmailExtWatchAction/help-triggers_ja.html
  20. +4 −0 src/main/resources/hudson/plugins/emailext/watching/EmailExtWatchAction/help-triggers_zh_TW.html
  21. +64 −0 src/main/resources/hudson/plugins/emailext/watching/EmailExtWatchAction/index.groovy
  22. +2 −0 src/main/resources/hudson/plugins/emailext/watching/EmailExtWatchAction/index.properties
  23. +12 −0 src/main/resources/hudson/plugins/emailext/watching/EmailExtWatchAction/jobMain.groovy
  24. +10 −0 src/main/webapp/help/globalConfig/watching.html
  25. +19 −0 src/test/java/hudson/plugins/emailext/EmailTypeTest.java
  26. +109 −83 src/test/java/hudson/plugins/emailext/plugins/CssInlinerTest.java
  27. +2 −55 src/test/java/hudson/plugins/emailext/plugins/content/JellyScriptContentTest.java
  28. +78 −0 src/test/java/hudson/plugins/emailext/plugins/content/ScriptContentChangeLogSet.java
  29. +3 −57 src/test/java/hudson/plugins/emailext/plugins/content/ScriptContentTest.java
  30. +52 −42 src/test/java/hudson/plugins/emailext/plugins/recipients/MockUtilities.java
  31. +48 −0 src/test/resources/recipient-provider-upgrade2.xml
12 pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.554.1</version>
<version>1.580.1</version>
</parent>

<licenses>
@@ -134,6 +134,16 @@
<artifactId>groovy-all</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>matrix-project</artifactId>
<version>1.4</version>
</dependency>
</dependencies>

<scm>
@@ -53,7 +53,13 @@ public FilePathDataSource(FilePath file) {
}

public InputStream getInputStream() throws IOException {
return file.read();
InputStream stream = null;
try {
stream = file.read();
} catch(InterruptedException e) {
stream = null;
}
return stream;
}

public OutputStream getOutputStream() throws IOException {
@@ -5,8 +5,6 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Hudson;
import hudson.model.TaskListener;
import hudson.plugins.emailext.plugins.content.JellyScriptContent;
import hudson.plugins.emailext.plugins.content.ScriptContent;
import hudson.util.FormValidation;
@@ -13,15 +13,14 @@
import hudson.matrix.MatrixAggregator;
import hudson.matrix.MatrixBuild;
import hudson.matrix.MatrixRun;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.model.TaskListener;
import hudson.model.*;
import hudson.plugins.emailext.plugins.ContentBuilder;
import hudson.plugins.emailext.plugins.CssInliner;
import hudson.plugins.emailext.plugins.EmailTrigger;
import hudson.plugins.emailext.plugins.RecipientProvider;
import hudson.plugins.emailext.plugins.content.TriggerNameContent;
import hudson.plugins.emailext.watching.EmailExtWatchAction;
import hudson.plugins.emailext.watching.EmailExtWatchJobProperty;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.MailMessageIdAction;
import hudson.tasks.Mailer;
@@ -33,15 +32,7 @@
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.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
@@ -163,18 +154,10 @@ public ExtendedEmailPublisher(String project_recipient_list, String project_cont
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) {
this.recipientList = project_recipient_list;
this.contentType = project_content_type;
this.defaultSubject = project_default_subject;
this.defaultContent = project_default_content;
this.attachmentsPattern = project_attachments;
this.presendScript = project_presend_script;
this.attachBuildLog = project_attach_buildlog > 0;
this.compressBuildLog = project_attach_buildlog > 1;
this.replyTo = project_replyto;
this.saveOutput = project_save_output;
this.configuredTriggers = project_triggers;
this.matrixTriggerMode = matrixTriggerMode;

this(project_recipient_list, project_content_type, project_default_subject, project_default_content,
project_attachments, project_presend_script, project_attach_buildlog, project_replyto,
project_save_output, project_triggers, matrixTriggerMode, false, Collections.EMPTY_LIST);
}

@DataBoundConstructor
@@ -222,6 +205,11 @@ public void setMatrixTriggerMode(MatrixTriggerMode matrixTriggerMode) {
this.matrixTriggerMode = matrixTriggerMode;
}

@Override
public Collection<? extends Action> getProjectActions(AbstractProject<?,?> project) {
return Collections.singletonList(new EmailExtWatchAction(project));
}

public void debug(PrintStream p, String format, Object... args) {
getDescriptor().debug(p, format, args);
}
@@ -280,6 +268,45 @@ private boolean _perform(AbstractBuild<?, ?> build, Launcher launcher, BuildList
listener.getLogger().println("Trigger " + triggerName + " was overridden by another trigger and will not send an email.");
}

EmailExtWatchJobProperty jprop = build.getParent().getProperty(EmailExtWatchJobProperty.class);

if(jprop != null) {
for(String u : jprop.getWatchers()) {
User user = User.get(u);
if(user != null) {
EmailExtWatchAction.UserProperty prop = user.getProperty(EmailExtWatchAction.UserProperty.class);
if (prop != null) {
final Multimap<String, EmailTrigger> watcherTriggered = ArrayListMultimap.create();
for (EmailTrigger trigger : prop.getTriggers()) {
if (trigger.isPreBuild() == forPreBuild && trigger.trigger(build, listener)) {
String tName = trigger.getDescriptor().getDisplayName();
watcherTriggered.put(tName, trigger);
listener.getLogger().println("Email was triggered for watcher '" + user.getDisplayName() + "' for: " + tName);
emailTriggered = true;
}
}

//Go through and remove triggers that are replaced by others
replacedTriggers = new ArrayList<String>();

for (Object tName : triggered.keySet()) {
String triggerName = (String) tName;
for (EmailTrigger trigger : (Collection<EmailTrigger>) triggered.get(triggerName)) {
replacedTriggers.addAll(trigger.getDescriptor().getTriggerReplaceList());
}
}

for (String triggerName : replacedTriggers) {
watcherTriggered.removeAll(triggerName);
listener.getLogger().println("Trigger " + triggerName + " was overridden by another trigger and will not send an email.");
}

triggered.putAll(watcherTriggered);
}
}
}
}

if (emailTriggered && triggered.isEmpty()) {
listener.getLogger().println("There is a circular trigger replacement with the email triggers. No email is sent.");
return false;
@@ -391,6 +391,8 @@ public boolean configure(StaplerRequest req, JSONObject formData)

requireAdminForTemplateTesting = req.hasParameter("ext_mailer_require_admin_for_template_testing");

enableWatching = req.hasParameter("ext_mailer_watching_enabled");

// specify List-ID information
if (req.hasParameter("ext_mailer_use_list_id")) {
listId = nullify(req.getParameter("ext_mailer_list_id"));
@@ -12,35 +12,41 @@
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.StringTokenizer;
import org.apache.commons.lang.StringEscapeUtils;

/**
* <p>Inlines CSS to avoid the dreaded GMail Grimace.</p>
* <p>
* Inlines CSS to avoid the dreaded GMail Grimace.</p>
*
* <p>The magic keyword is <code><em>data-inline="true"</em></code>.</p>
* <p>
* The magic keyword is <code><em>data-inline="true"</em></code>.</p>
*
* <ul>
* <li>
* When used in conjunction with the <code>style</code> tag, it inlines the stylesheet defined there into all
* html elements matching the rules.
* When used in conjunction with the <code>style</code> tag, it inlines the
* stylesheet defined there into all html elements matching the rules.
* </li>
* <li>
* When used with the <code>img</code> tag, it base64 encodes the image it found to make it visible in the
* email.
* When used with the <code>img</code> tag, it base64 encodes the image it found
* to make it visible in the email.
* </li>
* </ul>
*
* @author <a href="https://github.com/rahulsom">Rahul Somasunderam</a>
*/
public class CssInliner {

public static final String CSS_STYLE = "cssstyle";
public static final String STYLE_ATTR = "style";
public static final String STYLE_TAG = "style";
public static final String IMG_TAG = "img";
public static final String IMG_SRC_ATTR = "src";
public static final String DATA_INLINE_ATTR = "data-inline";

private static String concatenateProperties(String oldProp, String newProp) {
if (!oldProp.endsWith(";"))
if (!oldProp.endsWith(";")) {
oldProp += ";";
}
return oldProp.trim() + " " + newProp.trim() + ";";
}

@@ -63,21 +69,28 @@ private String fetchStyles(Document doc) {
}

/**
* Takes an input string representing an html document and processes it with the Css Inliner.
* Takes an input string representing an html document and processes it with
* the Css Inliner.
*
* @param input the html document
* @return the processed html document
*/
public String process(String input) {

Document doc = Jsoup.parse(input);

// check if the user wants to inline the data
Elements elements = doc.getElementsByAttributeValue(DATA_INLINE_ATTR, "true");
if (elements.isEmpty()) {
return input;
}

extractStyles(doc);
applyStyles(doc);
inlineImages(doc);

doc.outputSettings(doc.outputSettings().prettyPrint(false).escapeMode(Entities.EscapeMode.xhtml));
String output = doc.outerHtml();
return output;
return StringEscapeUtils.unescapeHtml(doc.outerHtml());
}

/**
@@ -88,7 +101,7 @@ public String process(String input) {
private void inlineImages(Document doc) {
Elements allImages = doc.getElementsByTag(IMG_TAG);
for (Element img : allImages) {
if (img.attr("data-inline").equals("true")) {
if (img.attr(DATA_INLINE_ATTR).equals("true")) {
String src = img.attr(IMG_SRC_ATTR);
try {
URL url = new URL(src);
@@ -109,7 +122,8 @@ private void inlineImages(Document doc) {
}

/**
* Transfers styles from the <code>cssstyle</code> attribute to the <code>style</code> attribute.
* Transfers styles from the <code>cssstyle</code> attribute to the
* <code>style</code> attribute.
*
* @param doc the html document
*/
@@ -125,8 +139,10 @@ private void applyStyles(Document doc) {
}

/**
* Extracts styles from the stylesheet and applies them to a <code>cssstyle</code> attribute. This is because the
* styles need to be applied sequentially, but before the <code>style</code> defined for the element inline.
* Extracts styles from the stylesheet and applies them to a
* <code>cssstyle</code> attribute. This is because the styles need to be
* applied sequentially, but before the <code>style</code> defined for the
* element inline.
*
* @param doc the html document
*/
@@ -32,6 +32,17 @@
return Jenkins.getInstance().<EmailTrigger, EmailTriggerDescriptor>getDescriptorList(EmailTrigger.class);
}

public static List<EmailTriggerDescriptor> allWatchable() {
List<EmailTriggerDescriptor> list = new ArrayList<EmailTriggerDescriptor>();
for(EmailTriggerDescriptor d : all()) {
if(d.isWatchable()) {
list.add(d);
}
}

return list;
}

@Deprecated
protected EmailTrigger(boolean sendToList, boolean sendToDevs, boolean sendToRequestor, boolean sendToCulprits, String recipientList, String replyTo, String subject, String body, String attachmentsPattern, int attachBuildLog, String contentType) {
List<RecipientProvider> providers = new ArrayList<RecipientProvider>();
@@ -35,6 +35,8 @@ public void addDefaultRecipientProvider(RecipientProvider provider) {
public List<RecipientProvider> getDefaultRecipientProviders() {
return defaultRecipientProviders;
}

public boolean isWatchable() { return true; }

@Deprecated
public boolean getDefaultSendToCulprits() {
@@ -55,4 +57,5 @@ public boolean getDefaultSendToList() {
public boolean getDefaultSendToRequester() {
return false;
}

}
@@ -24,7 +24,6 @@
public abstract class AbstractScriptTrigger extends EmailTrigger {
protected String triggerScript;

@DataBoundConstructor
public AbstractScriptTrigger(List<RecipientProvider> recipientProviders, String recipientList, String replyTo, String subject, String body, String attachmentsPattern, int attachBuildLog, String contentType, String triggerScript) {
super(recipientProviders, recipientList, replyTo, subject, body, attachmentsPattern, attachBuildLog, contentType);
this.triggerScript = triggerScript;
@@ -100,15 +99,4 @@ private GroovyShell createEngine(AbstractBuild<?, ?> build, TaskListener listene

return shell;
}

public abstract static class DescriptorImpl extends EmailTriggerDescriptor {

public List<RecipientProvider> getDefaultRecipientProviders() {
return new ArrayList<RecipientProvider>() {
{
add(new ListRecipientProvider());
}
};
}
}
}
@@ -33,5 +33,10 @@ public boolean isPreBuild() {
public String getDisplayName() {
return TRIGGER_NAME;
}

@Override
public boolean isWatchable() {
return false;
}
}
}
@@ -37,5 +37,10 @@ public DescriptorImpl() {
public String getDisplayName() {
return TRIGGER_NAME;
}

@Override
public boolean isWatchable() {
return false;
}
}
}

0 comments on commit bb0053d

Please sign in to comment.
You can’t perform that action at this time.