我有一个Jenkins CI设置,我们使用Perforce作为SCM。
我已经配置了电子邮件文本插件,以便在构建中断时以及修复时通知开发人员。
目前,通知电子邮件正文只使用$DEFAULT_CONTENT,但我真的很想在电子邮件内容中指明最新的Perforce更改列表,因为这对开发人员更有帮助。
我在想变更列表编号、更改列表标题和提交人。
有什么想法吗?
在詹金斯邮件列表的某个地方,我发现了这个模板,我认为它符合您的要求。在jenkins根目录中创建一个文件夹"emailtemplates",将文件放在那里,并将其命名为"p4htmlmail.elly"。然后在jenkins配置中,将${JELLY_SCRIPT,template="p4htmlmail"}
放在电子邮件文本插件配置的DEFAULT_CONTENT字段中。
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define">
<link type="text/css" rel="stylesheet" href="${rooturl}static/e59dfe28/css/style.css"/>
<link type="text/css" rel="stylesheet" href="${rooturl}static/e59dfe28/css/color.css"/>
<STYLE>
a:link,a:visited {
text-decoration: underline;
<!--color: #3B5998;-->
color: #8B9DC3
}
a.success:link,a.success:visited {
text-decoration: underline;
color: #338033;
}
a.failure:link,a.failure:visited {
text-decoration: underline;
color: #900;
}
a.unstable:link,a.unstable:visited {
text-decoration: underline;
color: #F0C000;
}
<!--
body {
background-color: #DFE3EE;
}-->
.pane {
margin-top: 4px;
white-space: nowrap;
}
.pane TD {
padding: 4px 4px 3px 4px;
}
TABLE.pane {
width: 100%;
border: none;
}
TD.style1 {
color: #3B5998;
width: 10%;
}
TD.pane {
padding: 3px 4px 3px 4px;
vertical-align: middle;
}
TD.pane-header {
border-top: 1px #8B9DC3 solid;
border-bottom: 1px #8B9DC3 solid;
background-color: #DFE3EE;
font-weight: bold;
font-family: Verdana, Helvetica, sans serif;
font-size: 11px;
color: #8B9DC3;
padding-top: 10px;
padding-bottom: 10px;
}
TD.pane-header-success {
border-top: 1px #338033 solid;
border-bottom: 1px #338033 solid;
background-color: #E0FFE0;
font-weight: bold;
font-family: Verdana, Helvetica, sans serif;
font-size: 11px;
color: #338033;
padding-top: 10px;
padding-bottom: 10px;
}
TD.pane-header-failure {
border-top: 1px #900 solid;
border-bottom: 1px #900 solid;
background-color: #FCC;
font-weight: bold;
font-family: Verdana, Helvetica, sans serif;
font-size: 11px;
color: #900;
padding-top: 10px;
padding-bottom: 10px;
}
TD.pane-header-unstable {
border-top: 1px #F0C000 solid;
border-bottom: 1px #F0C000 solid;
background-color: #FFFFCE;
font-weight: bold;
font-family: Verdana, Helvetica, sans serif;
font-size: 11px;
color: #F0C000;
padding-top: 10px;
padding-bottom: 10px;
}
TH.pane {
font-weight: bold;
}
SPAN.style1 {
font-weight: bold;
color: #8B9DC3;
}
SPAN.success {
color: #338033;
}
SPAN.failure {
color: #900;
}
LI.style1 {
list-style: cirle outside;
}
LI.failure {
list-style: cirle outside;
color: #900;
}
</STYLE>
<BODY>
<j:set var="spc" value="&nbsp;&nbsp;" />
<!-- GENERAL INFO -->
<TABLE class="pane">
<TBODY>
<TR>
<j:choose>
<j:when test="${build.result=='SUCCESS'}">
<TD colspan="2" class="pane-header-success">
<SPAN>Build Result Summary - <A class="success" href="${rooturl}${build.url}">See full build details</A></SPAN>
</TD>
</j:when>
<j:when test="${build.result=='FAILURE'}">
<TD colspan="2" class="pane-header-failure">
<SPAN>Build Result Summary - <A class="failure" href="${rooturl}${build.url}">See full build details</A></SPAN>
</TD>
</j:when>
<j:otherwise>
<TD colspan="2" class="pane-header-unstable">
<SPAN>Build Result Summary - <A class="unstable" href="${rooturl}${build.url}">See full build details</A></SPAN>
</TD>
</j:otherwise>
</j:choose>
</TR>
<TR>
<TD class="style1">Project:</TD>
<TD><A href="${rooturl}${project.url}">${project.name}</A></TD>
</TR>
<TR>
<TD class="style1">Completion:</TD>
<TD>${it.timestampString}</TD>
</TR>
<TR>
<TD class="style1">Duration:</TD>
<TD>${build.durationString}</TD>
</TR>
<TR>
<TD class="style1">Status:</TD>
<TD>
<j:choose>
<j:when test="${build.result=='SUCCESS'}">
<IMG SRC="${rooturl}static/e59dfe28/images/16x16/blue.png"/>
</j:when>
<j:when test="${build.result=='FAILURE'}">
<IMG SRC="${rooturl}static/e59dfe28/images/16x16/red.png"/>
</j:when>
<j:otherwise>
<IMG SRC="${rooturl}static/e59dfe28/images/16x16/yellow.png"/>
</j:otherwise>
</j:choose>
${build.result}
</TD>
</TR>
<TR>
<TD class="style1">Help:</TD>
<TD>
Help text goes here.
</TD>
</TR>
</TBODY>
</TABLE>
<BR/>
<!-- CHANGE SET -->
<j:set var="changeSet" value="${build.changeSet}" />
<j:if test="${changeSet!=null}">
<j:set var="hadChanges" value="false" />
<TABLE class="pane">
<TBODY>
<TR>
<TD colspan="2" class="pane-header">
<SPAN>Code Changes - <A href="${rooturl}${build.url}/changes">See full change details</A></SPAN>
</TD>
</TR>
<j:forEach var="cs" items="${changeSet}" varStatus="loop">
<j:set var="hadChanges" value="true" />
<j:set var="aUser" value="${cs.hudsonUser}"/>
<TR>
<TD colspan="2">
<SPAN class="style1">
Change <B>${cs.changeNumber}</B> by
<B>${aUser!=null?aUser.displayName:cs.author.displayName}: </B>
'${cs.msgAnnotated}'
</SPAN>
</TD>
</TR>
<j:forEach var="p" items="${cs.affectedFiles}">
<TR>
<TD width="2%">
<j:switch on="${p.editType.name}">
<j:case value="add">
<IMG SRC="${rooturl}plugin/perforce/icons/action-ADD.gif"/>
</j:case>
<j:case value="branch">
<IMG SRC="${rooturl}plugin/perforce/icons/action-BRANCH.gif"/>
</j:case>
<j:case value="delete">
<IMG SRC="${rooturl}plugin/perforce/icons/action-DELETE.gif"/>
</j:case>
<j:case value="edit">
<IMG SRC="${rooturl}plugin/perforce/icons/action-EDIT.gif"/>
</j:case>
<j:case value="import">
<IMG SRC="${rooturl}plugin/perforce/icons/action-IMPORT.gif"/>
</j:case>
<j:case value="integrate">
<IMG SRC="${rooturl}plugin/perforce/icons/action-INTEGRATE.gif"/>
</j:case>
<j:case value="move_add">
<IMG SRC="${rooturl}plugin/perforce/icons/action-MOVE_ADD.gif"/>
</j:case>
<j:case value="move_delete">
<IMG SRC="${rooturl}plugin/perforce/icons/action-MOVE_DELETE.gif"/>
</j:case>
<j:default>
${p.editType.name}
</j:default>
</j:switch>
</TD>
<TD><SPAN>${p.path}</SPAN></TD>
</TR>
</j:forEach>
</j:forEach>
<j:if test="${!hadChanges}">
<TR><TD colspan="2">No Changes</TD></TR>
</j:if>
</TBODY>
</TABLE>
<BR/>
</j:if>
<!-- JUNIT TEST OUTPUT -->
<j:set var="junitResultList" value="${it.JUnitTestResult}" />
<j:if test="${junitResultList.isEmpty()!=true}">
<TABLE class="pane">
<TBODY>
<TR>
<TD colspan="2" class="pane-header">
<SPAN>Unit Tests - <A href="${rooturl}${build.url}/testReport">See full test details</A></SPAN>
</TD>
</TR>
<j:forEach var="junitResult" items="${it.JUnitTestResult}">
<j:forEach var="packageResult" items="${junitResult.getChildren()}">
<TR>
<TD>
Name: ${packageResult.getName()}, Failed: <SPAN class="failure">${packageResult.getFailCount()}</SPAN> test(s), Passed: <SPAN class="success">${packageResult.getPassCount()}</SPAN> test(s), Skipped: ${packageResult.getSkipCount()} test(s), Total: ${packageResult.getPassCount()+packageResult.getFailCount()+packageResult.getSkipCount()} test(s)
</TD>
</TR>
<j:forEach var="failed_test" items="${packageResult.getFailedTests()}">
<TR>
<TD>
<UL>
<B>
<LI class="failure">Failed: ${failed_test.getFullName()}</LI>
</B>
</UL>
</TD>
</TR>
</j:forEach>
</j:forEach>
</j:forEach>
</TBODY>
</TABLE>
<BR/>
</j:if>
<!-- CONSOLE OUTPUT -->
<j:getStatic var="resultFailure" field="FAILURE" className="hudson.model.Result"/>
<j:if test="${build.result==resultFailure}">
<TABLE class="pane">
<TBODY>
<TR>
<TD colspan="2" class="pane-header">
<SPAN>Console Output - <A href="${rooturl}${build.url}/console">See full console details</A></SPAN>
</TD>
</TR>
<j:forEach var="line" items="${build.getLog(100)}">
<TR>
<TD>${line}</TD>
</TR>
</j:forEach>
</TBODY>
</TABLE>
<BR/>
</j:if>
</BODY>
</j:jelly>