All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.tasks.mail.impl.FailureBuildMail Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * Copyright (c) 2011 Oracle Corporation.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *
 *    Anton Kozak
 *
 *******************************************************************************/
package hudson.tasks.mail.impl;

import hudson.FilePath;
import hudson.Functions;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.scm.ChangeLogSet;
import hudson.tasks.ArtifactArchiver;
import hudson.tasks.Mailer;
import hudson.tasks.Messages;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.apache.tools.ant.types.selectors.SelectorUtils;

/**
 * Class used for the mail preparation if build was broken.
 */
public class FailureBuildMail extends BaseBuildResultMail {

    public FailureBuildMail(String recipients, boolean sendToIndividuals,
            List upstreamProjects, String charset) {
        super(recipients, sendToIndividuals, upstreamProjects, charset);
    }

    /**
     * @inheritDoc
     */
    public MimeMessage getMail(AbstractBuild build, BuildListener listener)
            throws MessagingException, InterruptedException {
        MimeMessage msg = createEmptyMail(build, listener);

        msg.setSubject(getSubject(build, Messages.MailSender_FailureMail_Subject()), getCharset());

        StringBuilder buf = new StringBuilder();
        appendBuildUrl(build, buf);

        boolean firstChange = true;
        for (ChangeLogSet.Entry entry : build.getChangeSet()) {
            if (firstChange) {
                firstChange = false;
                buf.append(Messages.MailSender_FailureMail_Changes()).append("\n\n");
            }
            buf.append('[');
            buf.append(entry.getAuthor().getFullName());
            buf.append("] ");
            String m = entry.getMsg();
            if (m != null) {
                buf.append(m);
                if (!m.endsWith("\n")) {
                    buf.append('\n');
                }
            }
            buf.append('\n');
        }

        buf.append("------------------------------------------\n");

        try {
            // Restrict max log size to avoid sending enormous logs over email.
            // Interested users can always look at the log on the web server.
            List lines = build.getLog(MAX_LOG_LINES);

            String workspaceUrl = null, artifactUrl = null;
            Pattern wsPattern = null;
            String baseUrl = Mailer.descriptor().getUrl();
            if (baseUrl != null) {
                // Hyperlink local file paths to the repository workspace or build artifacts.
                // Note that it is possible for a failure mail to refer to a file using a workspace
                // URL which has already been corrected in a subsequent build. To fix, archive.
                workspaceUrl = baseUrl + Util.encode(build.getProject().getUrl()) + "ws/";
                artifactUrl = baseUrl + Util.encode(build.getUrl()) + "artifact/";
                FilePath ws = build.getWorkspace();
                // Match either file or URL patterns, i.e. either
                // c:\hudson\workdir\jobs\foo\workspace\src\Foo.java
                // file:/c:/hudson/workdir/jobs/foo/workspace/src/Foo.java
                // will be mapped to one of:
                // http://host/hudson/job/foo/ws/src/Foo.java
                // http://host/hudson/job/foo/123/artifact/src/Foo.java
                // Careful with path separator between $1 and $2:
                // workspaceDir will not normally end with one;
                // workspaceDir.toURI() will end with '/' if and only if workspaceDir.exists() at time of call
                wsPattern = Pattern.compile("("
                        + Pattern.quote(ws.getRemote()) + "|" + Pattern.quote(ws.toURI().toString())
                        + ")[/\\\\]?([^:#\\s]*)");
            }
            for (String line : lines) {
                line = line.replace('\0',
                        ' '); // shall we replace other control code? This one is motivated by http://www.nabble.com/Problems-with-NULL-characters-in-generated-output-td25005177.html
                if (wsPattern != null) {
                    // Perl: $line =~ s{$rx}{$path = $2; $path =~ s!\\\\!/!g; $workspaceUrl . $path}eg;
                    Matcher m = wsPattern.matcher(line);
                    int pos = 0;
                    while (m.find(pos)) {
                        String path = m.group(2).replace(File.separatorChar, '/');
                        String linkUrl = artifactMatches(path, build) ? artifactUrl : workspaceUrl;
                        String prefix = line.substring(0, m.start()) + '<' + linkUrl + Util.encode(path) + '>';
                        pos = prefix.length();
                        line = prefix + line.substring(m.end());
                        // XXX better style to reuse Matcher and fix offsets, but more work
                        m = wsPattern.matcher(line);
                    }
                }
                buf.append(line);
                buf.append('\n');
            }
        } catch (IOException e) {
            // somehow failed to read the contents of the log
            buf.append(Messages.MailSender_FailureMail_FailedToAccessBuildLog()).append("\n\n").append(
                    Functions.printThrowable(e));
        }
        appendFooter(buf);
        msg.setText(buf.toString(), getCharset());

        return msg;
    }

    /**
     * Check whether a path (/-separated) will be archived.
     */
    public boolean artifactMatches(String path, AbstractBuild build) {
        ArtifactArchiver aa = build.getProject().getPublishersList().get(ArtifactArchiver.class);
        if (aa == null) {
            //LOGGER.finer("No ArtifactArchiver found");
            return false;
        }
        String artifacts = aa.getArtifacts();
        for (String include : artifacts.split("[, ]+")) {
            String pattern = include.replace(File.separatorChar, '/');
            if (pattern.endsWith("/")) {
                pattern += "**";
            }
            if (SelectorUtils.matchPath(pattern, path)) {
                //LOGGER.log(Level.FINER, "DescriptorImpl.artifactMatches true for {0} against {1}",
                //    new Object[]{path, pattern});
                return true;
            }
        }
        //LOGGER.log(Level.FINER, "DescriptorImpl.artifactMatches for {0} matched none of {1}",
        //    new Object[]{path, artifacts});
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy