| Hello Alex and thank you for your answer  This is the template we are using:
<%
/**
* injected usable variables:
* https://github.com/jenkinsci/email-ext-plugin/blob/master/src/main/java/hudson/plugins/emailext/plugins/content/ScriptContent.java#L120-L125
*/
import hudson.model.Result
import org.jenkinsci.plugins.tokenmacro.TokenMacro;
def getBuildCauses = { c, sc ->
if (c instanceof hudson.model.Cause.UpstreamCause) {
sc.add(c)
c.upstreamCauses.each { upstreamCause ->
owner.call(upstreamCause, sc)
}
} else if (c instanceof java.util.Collection) {
c.each { cause ->
owner.call(cause, sc)
}
} else {
// just add it
sc.add(c)
}
}
def buildCauses = []
getBuildCauses(build.causes, buildCauses)
buildCauses = buildCauses.reverse()
def upstreamBuilds = buildCauses.findAll{ it instanceof hudson.model.Cause.UpstreamCause }
.collect{ return it.getUpstreamRun() }
def changeSetsByBuild = [:]
upstreamBuilds.each{
changeSetsByBuild.put(
it.getParent().name,
['changesets': it.changeSets, 'buildurl': rooturl + it.getUrl()]
)
}
changeSetsByBuild.put(
project.name,
['changesets': build.changeSets, 'buildurl': rooturl + build.getUrl()]
)
%>
<STYLE>
BODY TABLE, TD, TH, P, H1, H2 { margin:0; font:normal normal 100% Georgia, Serif; background-color: #ffffff; }
H1, H2 { border-bottom:dotted 1px #999999; padding:5px; margin-top:10px; margin-bottom:10px; color: #000000; font: normal bold 130% Georgia,Serif; background-color:#f0f0f0; }
H2 { padding:5px; margin-top:5px; margin-bottom:5px; font: italic bold 110% Georgia,Serif; }
.bg2 { color:black; background-color:#E0E0E0; font-size:110%; }
TH { font-weight: bold; }
TR, TD, TH { padding:2px; }
TR.gray { background-color:#f0f0f0; }
TD.test_passed { color:blue; }
TD.test_failed { color:red; }
TD.test_skipped { color:grey; }
.console { font: normal normal 90% Courier New, monotype; padding:0px; margin:0px; }
DIV.content, DIV.header { background: #ffffff; border: line; 1px #666; margin: 2px; content: 2px; padding: 2px; }
TABLE.border, TH.border, TD.border { border: 1px solid black; border-collapse:collapse; }
TD.right { text-align:right; }
</STYLE>
<BODY>
<DIV class="header">
<!-- GENERAL INFO -->
<TABLE width="100%">
<TH><TR><TD colspan="2" valign="center"><H2><IMG SRC="${rooturl}static/e59dfe28/images/24x24/<%= (build.result == null || build.result == Result.SUCCESS) ? 'blue.gif' : build.result == Result.FAILURE ? 'red.gif' : 'yellow.gif' %>" /><B>BUILD ${build.result}</B></TD></TR></TH>
<TR><TD>URL</TD><TD><A href="${rooturl}${build.url}">${rooturl}${build.url}</A></TD></TR>
<TR><TD>Project:</TD><TD>${project.name}</TD></TR>
<TR><TD>Git SHA:</TD><TD><%= TokenMacro.expand( build, listener, '${GIT_REVISION} on branch ${GIT_BRANCH}' ) %></TD></TR>
<TR><TD>Date:</TD><TD>${it.timestampString}</TD></TR>
<TR><TD>Duration:</TD><TD>${build.durationString}</TD></TR>
<TR>
<TD>Build causes:</TD>
<TD>
<% buildCauses.each { buildCause -> %>
${buildCause.shortDescription}<BR/>
<% } %>
</TD>
</TR>
<TR><TD>Built on node:</TD><TD><%= build.builtOnStr == '' ? 'master' : build.builtOnStr %></TD></TD></TR>
</TABLE>
</DIV>
<% if(changeSetsByBuild) { %>
<!-- CHANGE SETS -->
<DIV class="content">
<H2>Changes</H2>
<TABLE width="100%">
<% changeSetsByBuild.each() { projectName, values -> %>
<TR><TD class="bg2" colspan="2"><B>Job: <A href="${values['buildurl']}">${projectName}</B></a></TD></TR>
<%
def changeSet = values['changesets'][0] ?: null
if(changeSet != null && !changeSet.isEmptySet()) {
changeSet.each { cs ->
commitId = cs.id
author = cs.author
commitMsg = cs.msgAnnotated
commitUrl = changeSet.getBrowser().getChangeSetLink(cs)
%>
<TR><TD colspan="2"> <B>${commitMsg}</B> - <A href="${commitUrl}" target="_blank">${commitId}</A> by <%= author %></TD></TR>
<% }
}
else {
%>
<TR><TD colspan="2">No Changes</TD></TR>
<%
}
}
%>
</TABLE>
</DIV>
<% } %>
<% if (build.result != Result.SUCCESS) { %>
<!-- BUILD FAILURE ANALYZER -->
<DIV class="content">
<H2>Build Failure Analyzer</H2>
<%= TokenMacro.expand(build, listener, '${BUILD_FAILURE_ANALYZER, includeTitle=false, includeIndications=true, useHtmlFormat=true, noFailureText="No build failure cause detected."}') %>
</DIV>
<% } %>
<% if (build.result != Result.SUCCESS && !it.JUnitTestResult.isEmpty()) { %>
<!-- JUnit TEMPLATE -->
<DIV class="content">
<A href="${rooturl}${build.url}/testreport"><H2>Failed JUnit Tests</H2></A>
<TABLE class="border">
<TR>
<TH class="border">Package</TH>
<TH class="border">Failed</TH>
<TH class="border">Passed</TH>
<TH class="border">Skipped</TH>
<TH class="border">Total</TH>
</TR>
<% it.JUnitTestResult.each { junitResult -> %>
<% junitResult.getChildren().each { packageResult -> %>
<% if (packageResult.getFailCount() > 0) { %>
<TR>
<TD class="border"><TT>${packageResult.getName()}</TT></TD>
<TD class="border test_failed">${packageResult.getFailCount()}</TD>
<TD class="border test_passed">${packageResult.getPassCount()}</TD>
<TD class="border test_skipped">${packageResult.getSkipCount()}</TD>
<TD class="border"><B>${packageResult.getPassCount()+packageResult.getFailCount()+packageResult.getSkipCount()}</B></TD>
</TR>
<% packageResult.getFailedTests().each { failed_test -> %>
<TR><TD class="test_failed" colspan="5"><TT>${failed_test.getFullName()}</TT></TD></TR>
<% } %>
<% } %>
<% } %>
<% } %>
</TABLE>
<BR />
</DIV>
<% } %>
<% if (build.result != Result.SUCCESS) { %>
<!-- CONSOLE OUTPUT -->
<DIV class="content">
<A href="${rooturl}${build.url}/console"><H2>Console Output</H2></A>
<TABLE class="console">
<% build.getLog(50).each { line -> %>
<TR><TD><TT>${org.apache.commons.lang.StringEscapeUtils.escapeHtml(line)}</TT></TD></TR>
<% } %>
</TABLE>
<BR />
</DIV>
<% } %>
<% if (build.result != Result.SUCCESS && build.artifacts && build.artifacts.size() > 0) { %>
<!-- ARTIFACTS -->
<DIV class="content">
<H2>Build Artifacts</H2>
<UL>
<% build.artifacts.each { artifact -> %>
<LI><A href="${rooturl}${build.url}artifact/${artifact}">${artifact}</A></LI>
<% } %>
</UL>
</DIV>
<% } %>
</BODY>
It's added to the config files using Jobdsl:
configFiles {
groovyTemplateConfig {
id('build-notification-mail-groovy')
name('build-notification-mail-groovy')
comment('Build notification mail template written in Groovy')
content(readFileFromWorkspace('configfiles/emailext/build_notification_template.groovy'))
}
}
And this is the CasC configuration:
unclassified:
extendedemailpublisher:
adminRequiredForTemplateTesting: true
defaultBody: '^${SCRIPT,template="managed:build-notification-mail-groovy"}'
defaultPresendScript: |
def failureCauses = build.actions?.find{ it instanceof com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseBuildAction }
if (failureCauses) {
def retryBuild = build.actions?.find{ it instanceof com.chikli.hudson.plugin.naginator.NaginatorAction }
if (retryBuild && retryBuild.getRetryCount() < retryBuild.getMaxRetryCount()) {
cancel = true
return
}
if (!retryBuild) {
// if no retryBuild, check if failureCauses contains the BFA retries,
// if true, we assume it is the first build where the error occurs because there won't be a NaginatorAction attached to the build
for (def ffc in failureCauses.getFoundFailureCauses()) {
if (ffc.categories.find { it ==~ /(Infrastructure|RFT)+/ }) {
cancel = true
return
}
}
}
}
defaultReplyTo: ''
defaultSubject: '[$PROJECT_NAME] - $BUILD_STATUS - Build #$BUILD_NUMBER'
listId: 'Build Notifications <ci.cloud>'
|