package hudson.plugins.emailext; import hudson.Launcher; import hudson.Util; import hudson.model.Build; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Project; import hudson.model.Result; import hudson.model.User; import hudson.scm.ChangeLogSet; import hudson.scm.ChangeLogSet.Entry; import hudson.tasks.Builder; import hudson.tasks.Mailer; import hudson.tasks.Publisher; import hudson.util.FormFieldValidator; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import javax.mail.Address; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.servlet.ServletException; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; /** * Sample {@link Builder}. * *
* When the user configures the project and enables this builder, * {@link DescriptorImpl#newInstance(StaplerRequest)} is invoked * and a new {@link ExtendedEmailPublisher} is created. The created * instance is persisted to the project configuration XML by using * XStream, so this allows you to use instance fields (like {@link #name}) * to remember the configuration. * *
* When a build is performed, the {@link #perform(Build, Launcher, BuildListener)} method * will be invoked. This Publisher seeks to solve some of the issues people are having with * Hudson's default email publisher. Mainly that you cannot send emails on a successful * build. This plugin should allow you to send any combination of email based on build * status and recipients. * * @author kyle.sweeney@valtech.com * */ public class ExtendedEmailPublisher extends Publisher { private static final Logger LOGGER = Logger.getLogger(Mailer.class.getName()); /** * @see #extractAddressFromId(String) */ public static final String EMAIL_ADDRESS_REGEXP = "^.*<([^>]+)>.*$"; public static final String COMMA_SEPARATED_SPLIT_REGEXP = "[,\\s]+"; private static final String PROJECT_NAME = "\\$PROJECT_NAME"; private static final String BUILD_NUMBER = "\\$BUILD_NUMBER"; private static final String BUILD_STATUS = "\\$BUILD_STATUS"; private static final String BUILD_URL = "\\$BUILD_URL"; private static final String PROJECT_URL = "\\$PROJECT_URL"; private static final String HUDSON_URL = "\\$HUDSON_URL"; private static final String CHANGES = "$CHANGES"; private static final String BUILD_LOG = "$BUILD_LOG"; private static final String DEFAULT_BODY = "\\$DEFAULT_CONTENT"; private static final String DEFAULT_SUBJECT = "\\$DEFAULT_SUBJECT"; private static final String DEFAULT_SUBJECT_TEXT = "$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!"; private static final String DEFAULT_BODY_TEXT = "$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS:\n\n" + "Check console output at $HUDSON_URL/$BUILD_URL to view the results."; /** * Email to send when a build has a fatal error */ public EmailType failureMail; /** * Email to send when the build status changes from stable to unstable */ public EmailType unstableMail; /** * Email to send when the build status is still failing */ public EmailType stillFailingMail; /** * Email to send when the is still unstable */ public EmailType stillUnstableMail; /** * Email to send when the build status changes from unstable or failing to stable/successful */ public EmailType fixedMail; /** * Email to send when the build status is still stable/successful */ public EmailType successfulMail; /** * An array of email recipient lists. These can be configured to be used for each email type. */ public String recipientList; public boolean perform(Build build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { return _perform(build,launcher,listener); } public
,B extends Build
> boolean _perform(B build, Launcher launcher, BuildListener listener) throws InterruptedException { Result buildResult = build.getResult(); boolean succeeded = false; EmailType type= null; if(buildResult == Result.FAILURE){ B prevBuild = build.getPreviousBuild(); if(prevBuild!=null && (prevBuild.getResult() == Result.FAILURE)) type = stillFailingMail; else type = failureMail; } else if(buildResult == Result.UNSTABLE){ B prevBuild = build.getPreviousBuild(); if(prevBuild!=null && (prevBuild.getResult() == Result.UNSTABLE)) type = stillUnstableMail; else type = unstableMail; } else if(buildResult == Result.SUCCESS){ B prevBuild = build.getPreviousBuild(); if(prevBuild!=null && (prevBuild.getResult() == Result.UNSTABLE || prevBuild.getResult() == Result.FAILURE)) type = fixedMail; else type = successfulMail; } if(type != null){ if(type.getHasRecipients()) succeeded = sendMail(type,build,listener); else{ succeeded = true; listener.getLogger().println("There are no recipients configured for this type of email, so no email will be sent."); } } return succeeded; } private
,B extends Build
> boolean sendMail(EmailType mailType,B build, BuildListener listener){ try{ MimeMessage msg = createMail(mailType,build,listener); Address[] allRecipients = msg.getAllRecipients(); if (allRecipients != null) { StringBuffer buf = new StringBuffer("Sending e-mails to:"); for (Address a : allRecipients) buf.append(' ').append(a); listener.getLogger().println(buf); Transport.send(msg); return true; } else { listener.getLogger().println("An attempt to send an e-mail" + " to empty list of recipients, ignored."); } }catch(MessagingException e){ LOGGER.log(Level.WARNING, "Could not send email."); listener.getLogger().println("Could not send email as a part of the post-build publishers."); e.printStackTrace(listener.getLogger()); } return false; } private
,B extends Build
> MimeMessage createMail(EmailType type,B build,BuildListener listener) throws MessagingException {
MimeMessage msg = new MimeMessage(ExtendedEmailPublisher.DESCRIPTOR.createSession());
//Set the contents of the email
msg.setContent("", "text/plain");
msg.setFrom(new InternetAddress(ExtendedEmailPublisher.DESCRIPTOR.getAdminAddress()));
msg.setSentDate(new Date());
String subject = transformText(type,type.getSubject(),build);
msg.setSubject(subject);
String text = transformText(type,type.getBody(),build);
msg.setText(text);
//Get the recipients from the global list of addresses
List > String transformText(EmailType type,String origText,B build){
String status = getEmailTypeAsString(type);
String changes = "";
String log = "Not implemented yet.";
if(origText.indexOf(CHANGES)>=0)
changes = getChangesSinceLastBuild(build);
String newText = origText.replaceAll(DEFAULT_BODY, Matcher.quoteReplacement(DESCRIPTOR.getDefaultBody()))
.replaceAll(DEFAULT_SUBJECT, Matcher.quoteReplacement(DESCRIPTOR.getDefaultSubject()))
.replaceAll(PROJECT_NAME, build.getProject().getName())
.replaceAll(PROJECT_URL, Util.encode(build.getProject().getUrl()))
.replaceAll(BUILD_NUMBER, ""+build.getNumber())
.replaceAll(BUILD_STATUS, status)
.replaceAll(BUILD_LOG, log)
.replaceAll(CHANGES, changes)
.replaceAll(BUILD_URL, Util.encode(build.getUrl()))
.replaceAll(HUDSON_URL, Util.encode(DESCRIPTOR.hudsonUrl));
return newText;
}
private ,B extends Build > String getChangesSinceLastBuild(B build) {
StringBuffer buf= new StringBuffer();
for (ChangeLogSet.Entry entry : build.getChangeSet()) {
buf.append('[');
buf.append(entry.getAuthor().getFullName());
buf.append("] ");
String m = entry.getMsg();
buf.append(m);
if (!m.endsWith("\n")) {
buf.append('\n');
}
buf.append('\n');
}
return buf.toString();
}
private String getEmailTypeAsString(EmailType type) {
String status;
if(type==successfulMail)
status = "Successful";
else if(type==stillUnstableMail)
status = "Still Unstable";
else if(type==failureMail)
status = "Failed";
else if(type==fixedMail)
status = "Fixed";
else if(type==stillFailingMail)
status = "Still Failing";
else if(type==unstableMail)
status = "Unstable";
else
status = "Unknown";
return status;
}
public Descriptor