diff --git a/src/main/java/hudson/plugins/emailext/AttachmentUtils.java b/src/main/java/hudson/plugins/emailext/AttachmentUtils.java index 33f06b0e6..7e4f49660 100644 --- a/src/main/java/hudson/plugins/emailext/AttachmentUtils.java +++ b/src/main/java/hudson/plugins/emailext/AttachmentUtils.java @@ -2,8 +2,11 @@ import hudson.FilePath; import hudson.Launcher; +import hudson.matrix.MatrixBuild; +import hudson.matrix.MatrixRun; import hudson.model.AbstractBuild; import hudson.model.BuildListener; +import hudson.model.Run; import hudson.plugins.emailext.plugins.ContentBuilder; import hudson.plugins.emailext.plugins.ZipDataSource; import java.io.ByteArrayInputStream; @@ -80,22 +83,22 @@ private static class LogFileDataSource implements DataSource { private static final String DATA_SOURCE_NAME = "build.log"; - private final AbstractBuild build; + private final Run run; private final boolean compress; - public LogFileDataSource(AbstractBuild build, boolean compress) { - this.build = build; + public LogFileDataSource(Run run, boolean compress) { + this.run = run; this.compress = compress; } public InputStream getInputStream() throws IOException { InputStream res; - long logFileLength = build.getLogText().length(); + long logFileLength = run.getLogText().length(); long pos = 0; ByteArrayOutputStream bao = new ByteArrayOutputStream(); while(pos < logFileLength) { - pos = build.getLogText().writeLogTo(pos, bao); + pos = run.getLogText().writeLogTo(pos, bao); } res = new ByteArrayInputStream(bao.toByteArray()); @@ -112,7 +115,7 @@ public OutputStream getOutputStream() throws IOException { public String getContentType() { return MimetypesFileTypeMap.getDefaultFileTypeMap() - .getContentType(build.getLogFile()); + .getContentType(run.getLogFile()); } public String getName() { @@ -190,9 +193,9 @@ public void attach(Multipart multipart, ExtendedEmailPublisherContext context) { } } - public static void attachBuildLog(ExtendedEmailPublisherContext context, Multipart multipart, boolean compress) { + private static void attachSingleLog(ExtendedEmailPublisherContext context, Run run, Multipart multipart, boolean compress) { try { - File logFile = context.getBuild().getLogFile(); + File logFile = run.getLogFile(); long maxAttachmentSize = context.getPublisher().getDescriptor().getMaxAttachmentSize(); if (maxAttachmentSize > 0 && logFile.length() >= maxAttachmentSize) { @@ -207,14 +210,28 @@ public static void attachBuildLog(ExtendedEmailPublisherContext context, Multipa context.getListener().getLogger().println("Request made to compress build log"); } - fileSource = new LogFileDataSource(context.getBuild(), compress); - attachment.setFileName("build." + (compress ? "zip" : "log")); + fileSource = new LogFileDataSource(run, compress); + if(run instanceof MatrixRun) + attachment.setFileName("build" + "-" + ((MatrixRun)run).getParent().getCombination().toString('-', '-') + "." + (compress ? "zip" : "log")); + else + attachment.setFileName("build." + (compress ? "zip" : "log")); attachment.setDataHandler(new DataHandler(fileSource)); multipart.addBodyPart(attachment); - } catch (MessagingException e) { + } catch(MessagingException e) { context.getListener().error("Error attaching build log to message: " + e.getMessage()); } } + + public static void attachBuildLog(ExtendedEmailPublisherContext context, Multipart multipart, boolean compress) { + if(context.getBuild() instanceof MatrixBuild) { + MatrixBuild build = (MatrixBuild)context.getBuild(); + for(MatrixRun run : build.getExactRuns()) { + attachSingleLog(context, run, multipart, compress); + } + } else { + attachSingleLog(context, context.getBuild(), multipart, compress); + } + } @Deprecated public static void attachBuildLog(ExtendedEmailPublisher publisher, Multipart multipart, AbstractBuild build, BuildListener listener, boolean compress) { diff --git a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherMatrixTest.java b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherMatrixTest.java index 31d5e3ce4..3684ed282 100644 --- a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherMatrixTest.java +++ b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherMatrixTest.java @@ -4,17 +4,22 @@ import hudson.matrix.AxisList; import hudson.matrix.MatrixBuild; import hudson.matrix.MatrixProject; +import hudson.matrix.MatrixRun; import hudson.model.labels.LabelAtom; import hudson.plugins.emailext.plugins.EmailTrigger; import hudson.plugins.emailext.plugins.RecipientProvider; +import hudson.plugins.emailext.plugins.trigger.AlwaysTrigger; import hudson.plugins.emailext.plugins.trigger.PreBuildTrigger; -import hudson.plugins.emailext.plugins.recipients.ListRecipientProvider; import hudson.slaves.DumbSlave; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import javax.mail.BodyPart; +import javax.mail.Message; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; @@ -37,6 +42,7 @@ public void before() throws Throwable { publisher = new ExtendedEmailPublisher(); publisher.defaultSubject = "%DEFAULT_SUBJECT"; publisher.defaultContent = "%DEFAULT_CONTENT"; + publisher.attachBuildLog = false; project = createMatrixProject(); project.getPublishersList().add( publisher ); @@ -63,8 +69,7 @@ public void testPreBuildMatrixBuildSendParentOnly() throws Exception { addEmailType( trigger ); publisher.getConfiguredTriggers().add( trigger ); MatrixBuild build = project.scheduleBuild2(0).get(); - j.assertBuildStatusSuccess(build); - + j.assertBuildStatusSuccess(build); assertThat( "Email should have been triggered, so we should see it in the logs.", build.getLog( 100 ), hasItems( "Email was triggered for: " + PreBuildTrigger.TRIGGER_NAME ) ); @@ -88,7 +93,7 @@ public void testPreBuildMatrixBuildSendSlavesOnly() throws Exception{ } @Test - public void testPreBuildMatrixBuildSendSlavesAndParent() throws Exception{ + public void testPreBuildMatrixBuildSendSlavesAndParent() throws Exception { addSlaveToProject(0,1); List recProviders = Collections.emptyList(); publisher.setMatrixTriggerMode(MatrixTriggerMode.BOTH); @@ -102,6 +107,42 @@ public void testPreBuildMatrixBuildSendSlavesAndParent() throws Exception{ j.assertBuildStatusSuccess(build); assertEquals( 3, Mailbox.get( "solganik@gmail.com" ).size() ); } + + @Test + public void testAttachBuildLogForAllAxes() throws Exception { + publisher.setMatrixTriggerMode(MatrixTriggerMode.ONLY_PARENT); + publisher.attachBuildLog = true; + addSlaveToProject(0,1,2); + List recProviders = Collections.emptyList(); + AlwaysTrigger trigger = new AlwaysTrigger(recProviders, "$DEFAULT_RECIPIENTS", + "$DEFAULT_REPLYTO", "$DEFAULT_SUBJECT", "$DEFAULT_CONTENT", "", 0, "project"); + addEmailType( trigger ); + publisher.getConfiguredTriggers().add( trigger ); + MatrixBuild build = project.scheduleBuild2(0).get(); + j.assertBuildStatusSuccess(build); + + assertThat( "Email should have been triggered, so we should see it in the logs.", build.getLog( 100 ), + hasItems( "Email was triggered for: " + AlwaysTrigger.TRIGGER_NAME ) ); + + assertEquals( 1, Mailbox.get( "solganik@gmail.com" ).size() ); + + Message msg = Mailbox.get("solganik@gmail.com").get(0); + + assertTrue("Message should be multipart", msg instanceof MimeMessage); + assertTrue("Content should be a MimeMultipart", msg.getContent() instanceof MimeMultipart); + + MimeMultipart part = (MimeMultipart)msg.getContent(); + + assertEquals("Should have four body items (message + attachment)", 4, part.getCount()); + + int i = 1; + for(MatrixRun r : build.getExactRuns()) { + String fileName = "build" + "-" + r.getParent().getCombination().toString('-', '-') + ".log"; + BodyPart attach = part.getBodyPart(i); + assertTrue("There should be a log named \"" + fileName + "\" attached", fileName.equalsIgnoreCase(attach.getFileName())); + i++; + } + } private void addEmailType( EmailTrigger trigger ) { trigger.setEmail( new EmailType() diff --git a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java index 55fd98879..4cf43c607 100644 --- a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java +++ b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java @@ -3,19 +3,18 @@ import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.BuildListener; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.matchers.JUnitMatchers.containsString; -import static org.junit.matchers.JUnitMatchers.hasItems; -import static org.junit.matchers.JUnitMatchers.hasItem; -import hudson.model.FreeStyleBuild; -import hudson.model.Result; import hudson.model.Cause.UserCause; import hudson.model.Descriptor; +import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; +import hudson.model.Result; import hudson.model.User; import hudson.plugins.emailext.plugins.EmailTrigger; import hudson.plugins.emailext.plugins.RecipientProvider; +import hudson.plugins.emailext.plugins.recipients.ListRecipientProvider; +import hudson.plugins.emailext.plugins.recipients.RequesterRecipientProvider; import hudson.plugins.emailext.plugins.trigger.AbortedTrigger; +import hudson.plugins.emailext.plugins.trigger.AlwaysTrigger; import hudson.plugins.emailext.plugins.trigger.FailureTrigger; import hudson.plugins.emailext.plugins.trigger.FirstFailureTrigger; import hudson.plugins.emailext.plugins.trigger.FixedTrigger; @@ -25,11 +24,8 @@ import hudson.plugins.emailext.plugins.trigger.RegressionTrigger; import hudson.plugins.emailext.plugins.trigger.StillFailingTrigger; import hudson.plugins.emailext.plugins.trigger.SuccessTrigger; -import hudson.plugins.emailext.plugins.recipients.ListRecipientProvider; -import hudson.plugins.emailext.plugins.recipients.RequesterRecipientProvider; import hudson.tasks.Builder; import hudson.tasks.Mailer; - import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; @@ -37,34 +33,36 @@ import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; - import javax.mail.Address; +import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; - import net.sf.json.JSONObject; +import static org.hamcrest.CoreMatchers.not; + +import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; +import static org.junit.matchers.JUnitMatchers.containsString; +import static org.junit.matchers.JUnitMatchers.hasItem; +import static org.junit.matchers.JUnitMatchers.hasItems; +import org.jvnet.hudson.test.Bug; import org.jvnet.hudson.test.FailureBuilder; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockBuilder; +import org.jvnet.hudson.test.SleepBuilder; import org.jvnet.mock_javamail.Mailbox; import org.kohsuke.stapler.Stapler; -import static org.junit.Assert.*; - -import org.jvnet.hudson.test.Bug; -import org.jvnet.hudson.test.SleepBuilder; - public class ExtendedEmailPublisherTest { private ExtendedEmailPublisher publisher; private FreeStyleProject project; private List recProviders; - + @Rule public JenkinsRule j = new JenkinsRule() { @Override @@ -79,7 +77,7 @@ public void before() throws Throwable { project = createFreeStyleProject(); project.getPublishersList().add(publisher); - + recProviders = Collections.emptyList(); Mailbox.clearAll(); } @@ -559,7 +557,7 @@ public void testEmergencyRerouteOverridesPresendScript() throws Exception { assertEquals(0, Mailbox.get("kutzi@xxx.com").size()); assertEquals(0, Mailbox.get("slide.o.mix@xxx.com").size()); assertEquals(1, Mailbox.get("emergency@foo.com").size()); - + publisher.getDescriptor().setEmergencyReroute(null); } @@ -614,12 +612,12 @@ public void testPresendScriptModifiesTo() throws Exception { assertEquals(0, Mailbox.get("kutzi@xxx.com").size()); assertEquals(1, Mailbox.get("slide.o.mix@xxx.com").size()); } - + @Test public void testPresendScriptModifiesToUsingProjectExternalScript() throws Exception { - publisher.presendScript = "import javax.mail.Message.RecipientType\n" + - "import hudson.plugins.emailext.ExtendedEmailPublisherTestHelper\n" + - "msg.setRecipients(RecipientType.TO, ExtendedEmailPublisherTestHelper.to())"; + publisher.presendScript = "import javax.mail.Message.RecipientType\n" + + "import hudson.plugins.emailext.ExtendedEmailPublisherTestHelper\n" + + "msg.setRecipients(RecipientType.TO, ExtendedEmailPublisherTestHelper.to())"; publisher.classpath = new ArrayList(); publisher.classpath.add(new GroovyScriptPath("src/test/presend")); SuccessTrigger successTrigger = new SuccessTrigger(recProviders, "$DEFAULT_RECIPIENTS", @@ -644,12 +642,12 @@ public void testPresendScriptModifiesToUsingProjectExternalScript() throws Excep assertEquals(0, Mailbox.get("kutzi@xxx.com").size()); assertEquals(1, Mailbox.get("slide.o.mix@xxx.com").size()); } - + @Test public void testPresendScriptModifiesToUsingGlobalExternalScript() throws Exception { - publisher.presendScript = "import javax.mail.Message.RecipientType\n" + - "import hudson.plugins.emailext.ExtendedEmailPublisherTestHelper\n" + - "msg.setRecipients(RecipientType.TO, ExtendedEmailPublisherTestHelper.to())"; + publisher.presendScript = "import javax.mail.Message.RecipientType\n" + + "import hudson.plugins.emailext.ExtendedEmailPublisherTestHelper\n" + + "msg.setRecipients(RecipientType.TO, ExtendedEmailPublisherTestHelper.to())"; Field f = ExtendedEmailPublisherDescriptor.class.getDeclaredField("defaultClasspath"); f.setAccessible(true); List classpath = new ArrayList(); @@ -707,7 +705,7 @@ public void testPresendScriptNoSecurity() throws Exception { assertThat("Access was done to Jenkins instance with security enabled, so we should see an error", build.getLog(100), not(hasItem("Pre-send script tried to access secured objects: Use of 'jenkins' is disallowed by security policy"))); - + //f.set(ExtendedEmailPublisher.DESCRIPTOR, false); } @@ -869,75 +867,73 @@ public Void call() throws Exception { } }); } - + @Bug(20524) @Test - public void testMultipleTriggersOfSameType() + public void testMultipleTriggersOfSameType() throws Exception { FreeStyleProject prj = j.createFreeStyleProject("JENKINS-20524"); prj.getPublishersList().add(publisher); - + publisher.recipientList = "mickey@disney.com"; publisher.configuredTriggers.add(new SuccessTrigger(recProviders, "$DEFAULT_RECIPIENTS", "$DEFAULT_REPLYTO", "$DEFAULT_SUBJECT", "$DEFAULT_CONTENT", "", 0, "project")); publisher.configuredTriggers.add(new SuccessTrigger(recProviders, "$DEFAULT_RECIPIENTS", "$DEFAULT_REPLYTO", "$DEFAULT_SUBJECT", "$DEFAULT_CONTENT", "", 0, "project")); - - for(EmailTrigger trigger : publisher.configuredTriggers) { + + for (EmailTrigger trigger : publisher.configuredTriggers) { trigger.getEmail().addRecipientProvider(new ListRecipientProvider()); } - + FreeStyleBuild build = prj.scheduleBuild2(0).get(); j.assertBuildStatusSuccess(build); - assertEquals(2, Mailbox.get("mickey@disney.com").size()); + assertEquals(2, Mailbox.get("mickey@disney.com").size()); } - + @Bug(22154) @Test public void testProjectDisable() throws Exception { FreeStyleProject prj = j.createFreeStyleProject("JENKINS-22154"); prj.getPublishersList().add(publisher); - + publisher.disabled = true; publisher.recipientList = "mickey@disney.com"; publisher.configuredTriggers.add(new SuccessTrigger(recProviders, "$DEFAULT_RECIPIENTS", "$DEFAULT_REPLYTO", "$DEFAULT_SUBJECT", "$DEFAULT_CONTENT", "", 0, "project")); - - for(EmailTrigger trigger : publisher.configuredTriggers) { + + for (EmailTrigger trigger : publisher.configuredTriggers) { trigger.getEmail().addRecipientProvider(new ListRecipientProvider()); } - + FreeStyleBuild build = prj.scheduleBuild2(0).get(); j.assertBuildStatusSuccess(build); - - assertEquals(0, Mailbox.get("mickey@disney.com").size()); + + assertEquals(0, Mailbox.get("mickey@disney.com").size()); assertThat("Publisher is disabled, should have message in build log", build.getLog(100), - hasItem("Extended Email Publisher is currently disabled in project settings")); + hasItem("Extended Email Publisher is currently disabled in project settings")); } - - + /* Need to find out why this gets a 404 on the fileprovider.js file - @Test - @Bug(15442) - public void testConfiguredStateNoTriggers() - throws Exception { - FreeStyleProject prj = j.createFreeStyleProject("JENKINS-15442"); - prj.getPublishersList().add(publisher); + @Test + @Bug(15442) + public void testConfiguredStateNoTriggers() + throws Exception { + FreeStyleProject prj = j.createFreeStyleProject("JENKINS-15442"); + prj.getPublishersList().add(publisher); - publisher.recipientList = "mickey@disney.com"; - publisher.configuredTriggers.clear(); + publisher.recipientList = "mickey@disney.com"; + publisher.configuredTriggers.clear(); - final WebClient client = j.createWebClient(); - final HtmlPage page = client.goTo("job/JENKINS-15442/configure"); - final HtmlTextInput recipientList = page.getElementByName("project_recipient_list"); - assertEquals(recipientList.getText(), "mickey@disney.com"); - } - */ - + final WebClient client = j.createWebClient(); + final HtmlPage page = client.goTo("job/JENKINS-15442/configure"); + final HtmlTextInput recipientList = page.getElementByName("project_recipient_list"); + assertEquals(recipientList.getText(), "mickey@disney.com"); + } + */ @Bug(16376) - @Test - public void testConcurrentBuilds() + @Test + public void testConcurrentBuilds() throws Exception { publisher.configuredTriggers.add(new RegressionTrigger(recProviders, "", "", "", "", "", 0, "")); project.setConcurrentBuild(true); @@ -950,24 +946,60 @@ public void testConcurrentBuilds() assertFalse(build2.isBuilding()); j.assertLogContains(Messages.ExtendedEmailPublisher__is_still_in_progress_ignoring_for_purpo(build1.getDisplayName()), build2); } + + @Test + public void testAttachBuildLog() throws Exception { + publisher.attachBuildLog = true; + AlwaysTrigger trigger = new AlwaysTrigger(recProviders, "$DEFAULT_RECIPIENTS", + "$DEFAULT_REPLYTO", "$DEFAULT_SUBJECT", "$DEFAULT_CONTENT", "", 0, "project"); + addEmailType(trigger); + publisher.getConfiguredTriggers().add(trigger); + AbstractBuild build = project.scheduleBuild2(0).get(); + j.assertBuildStatusSuccess(build); + + assertThat("Email should have been triggered, so we should see it in the logs.", build.getLog(100), + hasItems("Email was triggered for: " + AlwaysTrigger.TRIGGER_NAME)); + + Mailbox mbox = Mailbox.get("ashlux@gmail.com"); + assertEquals(1, mbox.size()); + + Message msg = mbox.get(0); + + assertTrue("Message should be multipart", msg instanceof MimeMessage); + assertTrue("Content should be a MimeMultipart", msg.getContent() instanceof MimeMultipart); + + MimeMultipart part = (MimeMultipart) msg.getContent(); + + assertEquals("Should have two body items (message + attachment)", 2, part.getCount()); + + BodyPart attach = part.getBodyPart(1); + assertTrue("There should be a log named \"build.log\" attached", "build.log".equalsIgnoreCase(attach.getFileName())); + } + /** - * Similar to {@link SleepBuilder} but only on the first build. - * (Removing the builder between builds is tricky since you would have to wait for the first one to actually start it.) + * Similar to {@link SleepBuilder} but only on the first build. (Removing + * the builder between builds is tricky since you would have to wait for the + * first one to actually start it.) */ private static final class SleepOnceBuilder extends Builder { - @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { if (build.number == 1) { Thread.sleep(99999); } return true; } + public static final class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() { + + @Override + public String getDisplayName() { return "Sleep once"; } } } - + private void addEmailType(EmailTrigger trigger) { trigger.setEmail(new EmailType() { {