package hudson.plugins.emailext.plugins.content; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.plugins.emailext.EmailType; import hudson.plugins.emailext.ExtendedEmailPublisher; import hudson.plugins.emailext.Util; import hudson.plugins.emailext.Util.PrintfSpec; import hudson.plugins.emailext.plugins.EmailContent; import hudson.scm.ChangeLogSet; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; public class ChangesSinceLastBuildContent implements EmailContent { private static final String TOKEN = "CHANGES"; private static final String SHOW_PATHS_ARG_NAME = "showPaths"; private static final boolean SHOW_PATHS_DEFAULT_VALUE = false; private static final String FORMAT_ARG_NAME = "format"; private static final String FORMAT_DEFAULT_VALUE = "[%a] %m\\n"; private static final String FORMAT_DEFAULT_VALUE_WITH_PATHS = "[%a] %m%p\\n"; private static final String PATH_FORMAT_ARG_NAME = "pathFormat"; private static final String PATH_FORMAT_DEFAULT_VALUE = "\\t%p\\n"; public String getToken() { return TOKEN; } public List<String> getArguments() { return Arrays.asList(SHOW_PATHS_ARG_NAME, FORMAT_ARG_NAME, PATH_FORMAT_ARG_NAME); } public String getHelpText() { return "Displays the changes since the last build.\n" + "<ul>\n" + "<li><i>" + SHOW_PATHS_ARG_NAME + "</i> - if true, the paths " + "modified by a commit are shown.<br>\n" + "Defaults to " + SHOW_PATHS_DEFAULT_VALUE + ".\n" + "<li><i>" + FORMAT_ARG_NAME + "</i> - for each commit listed, " + "a string containing %X, where %X is one of %a for author, " + "%d for date, %m for message, %p for paths, or %r for revision. " + "Not all revision systems support %d and %r. If specified, " + "<i>" + SHOW_PATHS_ARG_NAME + "</i> is ignored.<br>\n" + "Defaults to \"" + FORMAT_DEFAULT_VALUE + "\".\n" + "<li><i>" + PATH_FORMAT_ARG_NAME + "</i> - a string containing " + "%p to indicate how to print paths.<br>\n" + "Defaults to \"" + PATH_FORMAT_DEFAULT_VALUE + "\".\n" + "</ul>\n"; } public <P extends AbstractProject<P, B>, B extends AbstractBuild<P, B>> String getContent(AbstractBuild<P, B> build, ExtendedEmailPublisher publisher, EmailType emailType, Map<String, ?> args) { boolean showPaths = Args.get(args, SHOW_PATHS_ARG_NAME, SHOW_PATHS_DEFAULT_VALUE); String formatStringDefault = showPaths ? FORMAT_DEFAULT_VALUE_WITH_PATHS : FORMAT_DEFAULT_VALUE; String formatString = Args.get(args, FORMAT_ARG_NAME, formatStringDefault); String pathFormatString = Args.get(args, PATH_FORMAT_ARG_NAME, PATH_FORMAT_DEFAULT_VALUE); StringBuffer buf = new StringBuffer(); for (ChangeLogSet.Entry entry : build.getChangeSet()) { appendEntry(buf, entry, formatString, pathFormatString); } return buf.toString(); } private void appendEntry(StringBuffer buf, final ChangeLogSet.Entry entry, final String formatString, final String pathFormatString) { Util.printf(buf, formatString, new PrintfSpec() { public boolean printSpec(StringBuffer buf, char formatChar) { switch (formatChar) { case 'a': buf.append(entry.getAuthor().getFullName()); return true; case 'd': { try { Method getDateMethod = entry.getClass().getMethod("getDate"); buf.append(getDateMethod.invoke(entry)); } catch (NoSuchMethodException e) { // getMethod() // If it is not implemented, swallow the %d } catch (IllegalAccessException e) { // invoke() // in case getDate is not public } catch (InvocationTargetException e) { // invoke() // various possible reasons } return true; } case 'm': { String m = entry.getMsg(); buf.append(m); if (!m.endsWith("\n")) { buf.append('\n'); } return true; } case 'p': { Collection<String> affectedPaths = entry.getAffectedPaths(); for (final String affectedPath : affectedPaths) { Util.printf(buf, pathFormatString, new PrintfSpec() { public boolean printSpec(StringBuffer buf, char formatChar) { if (formatChar == 'p') { buf.append(affectedPath); return true; } else { return false; } } }); } return true; } case 'r': { try { Method getRevisionMethod = entry.getClass().getMethod("getRevision"); buf.append(getRevisionMethod.invoke(entry)); } catch (NoSuchMethodException e) { // getMethod() // If it is not implemented, swallow the %r } catch (IllegalAccessException e) { // invoke() // in case getRevision is not public } catch (InvocationTargetException e) { // invoke() // various possible reasons } return true; } default: return false; } } }); } public boolean hasNestedContent() { return false; } }