首先安装 Email-ext plugin插件
在jenkins中配置Jenkins->Manage Jenkins->Configure System
由于测试脚本基于java语言,所以需要Junit插件来发布测试结果,生成数据。在Jenkins->Manage Jenkins->Manage Plugins中安装junit插件
Email-ext插件可以用groovy脚本来自定义邮件。功能很强大,并且作者已经提供了一些模板Templates,然后就可以开始你的构建了。
Jenkins file:
pipeline{
agent any
tools {
maven 'M 3'
}
stages{
stage("checkout code"){
steps {
script{
//pull your code
}}
}
stage("run test case"){
steps {
script{
//withMaven(maven: 'M 3') {
// bat 'mvn test'
// }
//bat "cd C:\\Users\\liul5\\Desktop\\test\\project"
bat "mvn test"
}}
}
}
post('Generate report') {
always {
script{
cucumber fileIncludePattern: '**/cucumber-default-reports/*.json', sortingMethod: 'ALPHABETICAL'
junit '**/cucumber-default-reports/*.xml' //必须有这一步,否则没有数据
emailext subject: "Automation Result5: Job '${env.JOB_NAME} - ${env.BUILD_NUMBER}'",
body:'''${SCRIPT,template="groovy-html-larry-refactor.template"}''',
to:'$DEFAULT_RECIPIENTS'
emailext subject: "Automation Result6: Job '${env.JOB_NAME} - ${env.BUILD_NUMBER}'",
body:''' ${SCRIPT,template="groovy-html-refactor.template"}''',
to:'$DEFAULT_RECIPIENTS'
emailext subject: "Automation Result: Job '${env.JOB_NAME} - ${env.BUILD_NUMBER}'",
body:'''
total:${TEST_COUNTS,var="total"},
pass:${TEST_COUNTS,var="pass"},
fail:${TEST_COUNTS,var="fail"}
''',
to:'$DEFAULT_RECIPIENTS'
}}}
}
引用邮件模板在body中使用${SCRIPT,template="groovy-html-refactor.template"}
,必须用三引号括起来,可以直接使用作者提供的模板,${SCRIPT,template="模板名"}
如果想要自定义模板的话,需要在jenkins的根目录下创建一个email-templates
文件夹,将模板放到该目录中(jenkins非msi的安装方式下的Windows的路径:C:\Users\用户名\.jenkins\email-templates
,msi安装方式:C:\Program Files (x86)\Jenkins\email-templates
)。自定义邮件的语法请查看插件文档document,或者作者的模板Templates。
最终结果图:
模板一:
<STYLE>
BODY, TABLE, TD, TH, P {
font-family: Calibri, Verdana, Helvetica, sans serif;
font-size: 12px;
color: black;
}
.console {
font-family: Courier New;
}
.filesChanged {
width: 10%;
padding-left: 10px;
}
.section {
width: 100%;
border: thin black dotted;
}
.td-title-main {
color: white;
font-size: 200%;
padding-left: 5px;
font-weight: bold;
}
.td-title {
color: white;
font-size: 120%;
font-weight: bold;
padding-left: 5px;
text-transform: uppercase;
}
.td-title-tests {
font-weight: bold;
font-size: 120%;
}
.td-header-maven-module {
font-weight: bold;
font-size: 120%;
}
.td-maven-artifact {
padding-left: 5px;
}
.tr-title {
background-color: <%= (build.result == null || build.result.toString() == 'SUCCESS') ? '#27AE60' : build.result.toString() == 'FAILURE' ? '#E74C3C' : '#f4e242' %>;
}
.test {
padding-left: 20px;
}
.test-fixed {
color: #27AE60;
}
.test-failed {
color: #E74C3C;
}
STYLE>
<BODY>
<table class="section">
<tr class="tr-title">
<td class="td-title-main" colspan=2>
BUILD ${build.result ?: 'COMPLETED'}
td>
tr>
<tr>
<td>Project:td>
<td>${project.name}td>
tr>
<tr>
<td>Build #${build.number}:td>
<td><A href="${rooturl}${build.url}">${rooturl}${build.url}A>td>
tr>
<tr>
<td>Date:td>
<td>${it.timestampString}td>
tr>
<tr>
<td>Duration:td>
<td>${build.durationString}td>
tr>
<tr>
<td>Cause:td>
<td><% build.causes.each() { cause -> %> ${cause.shortDescription} <% } %>td>
tr>
<tr>
<td>Report:td>
<td><A href="${rooturl}${build.url}cucumber-html-reports/overview-features.html">${rooturl}${build.url}cucumber-html-reports/overview-features.htmlA>td>
tr>
table>
<br/>
<%
def junitResultList = it.JUnitTestResult
try {
def cucumberTestResultAction = it.getAction("org.jenkinsci.plugins.cucumber.jsontestsupport.CucumberTestResultAction")
junitResultList.add( cucumberTestResultAction.getResult() )
} catch(e) {
//cucumberTestResultAction not exist in this build
}
if ( junitResultList.size() > 0 ) { %>
<table class="section">
<tr class="tr-title">
<td class="td-title" colspan="5">${junitResultList.first().displayName}td>
tr>
<tr>
<td class="td-title-tests">Totaltd>
<td class="td-title-tests">Passedtd>
<td class="td-title-tests">Failedtd>
<td class="td-title-tests">Skippedtd>
<td class="td-title-tests">Success Ratetd>
tr>
<% junitResultList.each {
junitResult -> junitResult.getChildren().each {
packageResult -> %>
<%
def passed = packageResult.getPassCount()
def failed = packageResult.getFailCount()
def skipped = packageResult.getSkipCount()
def total = passed + failed + skipped
def rate = 0
if(total != 0){
def temp = passed / total
rate = Math.round(temp*10000)/100
}
%>
<tr>
<td>${total}td>
<td>${passed}td>
<td>${failed}td>
<td>${skipped}td>
<td>${rate}%td>
tr>
<% packageResult.getPassedTests().findAll({it.getStatus().toString() == "FIXED";}).each{
test -> %>
<tr>
<td class="test test-fixed" colspan="5">
${test.getFullName()} ${test.getStatus()}
td>
tr>
<% } %>
<% packageResult.getFailedTests().sort({a,b -> a.getAge() <=> b.getAge()}).each{
failed_test -> %>
<tr>
<td class="test test-failed" colspan="5">
${failed_test.getFullName()} (Age: ${failed_test.getAge()})
td>
tr>
<% }
}
} %>
table>
<br/>
<% } %>
<%
def changeSets = build.changeSets
if(changeSets != null) {
def hadChanges = false %>
<table class="section">
<tr class="tr-title">
<td class="td-title" colspan="2">CHANGEStd>
tr>
<% changeSets.each() {
cs_list -> cs_list.each() {
cs -> hadChanges = true %>
<tr>
<td>
Revision
<%= cs.metaClass.hasProperty('commitId') ? cs.commitId : cs.metaClass.hasProperty('revision') ? cs.revision : cs.metaClass.hasProperty('changeNumber') ? cs.changeNumber : "" %>
by <B><%= cs.author %>B>
td>
<td>${cs.msgAnnotated}td>
tr>
<% cs.affectedFiles.each() {
p -> %>
<tr>
<td class="filesChanged">${p.editType.name}td>
<td>${p.path}td>
tr>
<% }
}
}
if ( !hadChanges ) { %>
<tr>
<td colspan="2">No Changestd>
tr>
<% } %>
table>
<br/>
<% } %>
<%
def artifacts = build.artifacts
if ( artifacts != null && artifacts.size() > 0 ) { %>
<table class="section">
<tr class="tr-title">
<td class="td-title">BUILD ARTIFACTStd>
tr>
<% artifacts.each() {
f -> %>
<tr>
<td>
<a href="${rooturl}${build.url}artifact/${f}">${f}a>
td>
tr>
<% } %>
table>
<br/>
<% } %>
<%
try {
def mbuilds = build.moduleBuilds
if ( mbuilds != null ) { %>
<table class="section">
<tr class="tr-title">
<td class="td-title">BUILD ARTIFACTStd>
tr>
<%
try {
mbuilds.each() {
m -> %>
<tr>
<td class="td-header-maven-module">${m.key.displayName}td>
tr>
<%
m.value.each() {
mvnbld -> def artifactz = mvnbld.artifacts
if ( artifactz != null && artifactz.size() > 0) { %>
<tr>
<td class="td-maven-artifact">
<% artifactz.each() {
f -> %>
<a href="${rooturl}${mvnbld.url}artifact/${f}">${f}a><br/>
<% } %>
td>
tr>
<% }
}
}
} catch(e) {
// we don't do anything
} %>
table>
<br/>
<% }
} catch(e) {
// we don't do anything
} %>
<%
if ( build.result == hudson.model.Result.FAILURE ) { %>
<table class="section" cellpadding="0" cellspacing="0">
<tr class="tr-title">
<td class="td-title">CONSOLE OUTPUTtd>
tr>
<% build.getLog(100).each() {
line -> %>
<tr>
<td class="console">${org.apache.commons.lang.StringEscapeUtils.escapeHtml(line)}td>
tr>
<% } %>
table>
<br/>
<% } %>
BODY>
模板二:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Build from Jenkisntitle>
<style type="text/css">
/*base css*/
a{color:#4a72af}
body{background-color:#e4e4e4}
body,p{margin:0;padding:0}
img{display:block}
h1,h2,h3,h4,h5,h6{margin:0 0 .8em 0}
h3{font-size:28px;color:#444!important;font-family:Arial,Helvetica,sans-serif}
h4{font-size:22px;color:#4a72af!important;font-family:Arial,Helvetica,sans-serif}
h5{font-size:18px;color:#444!important;font-family:Arial,Helvetica,sans-serif}
p{font-size:12px;color:#444!important;font-family:"Lucida Grande","Lucida Sans","Lucida Sans Unicode",sans-serif;line-height:1.5}
ol li img{display:inline;height:20px}
/*div styles*/
/*.news{text-align:center;padding-top:15px;}*/
.content{width:720px;background-color:white;margin-left: auto; margin-right: auto ;}
.round_border{margin-bottom:5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;margin-top:0;font-size:14px;padding:6px;border:1px solid #ccc}
.status{background-color:green;font-size:28px;font-weight:bold;color:white;width:720px;height:52px;margin-bottom:18px;text-align:center;vertical-align:middle;border-collapse:collapse;background-repeat:no-repeat}
.status .info{color:white!important;text-shadow:0 -1px 0 rgba(0,0,0,0.3);font-size:32px;line-height:36px;padding:8px 0}
.main img{width:38px;margin-right:16px;height:38px}
.main table{font-size:14px;}
.main table th{text-align:left;}
.bottom-message{width:720px;cellpadding:5px;cellspacing:0px}
.bottom-message .message{font-size:13px;color:#aaa;line-height:18px;text-align:center}
.bottom-message .designed{font-size:13px;color:#aaa;line-height:18px;font-style: italic;text-align:right}
img.cartoon {width: 36px; display:inline}
style>
head>
<body>
<div class="content round_border">
<div class="status">
<p class="info">The build ${build.result ?: 'completed'}p>
div>
<%
import hudson.tasks.junit.TestResultAction
//import hudson.tasks.test.AbstractTestResultAction
//AbstractTestResultAction result = build.getAction(AbstractTestResultAction.class)
TestResultAction testResultAction = build.getAction(TestResultAction.class)
def total = " "
def passed = " "
def failed = " "
def skipped = " "
//if(result != null){
// passed = testResultAction.totalCount
//}
if(testResultAction){
total = testResultAction.totalCount
failed = testResultAction.failCount
skipped = testResultAction.skipCount
passed = total - failed - skipped }
%>
<div class="main round_border">
<table>
<tbody>
<tr>
<th>Project:th>
<td>${project.name}td>
tr>
<tr>
<th>Build #${build.number}:th>
<td><A href="${rooturl}${build.url}">${rooturl}${build.url}A>td>
tr>
<tr>
<th>Date of build:th>
<td>${it.timestampString}td>
tr>
<tr>
<th>Build duration:th>
<td>${build.durationString}td>
tr>
<tr>
<th>Build cause:th>
<td><% build.causes.each() { cause -> %> ${cause.shortDescription} <% } %>td>
tr>
<tr>
<th>Test results:th>
<td>Total: ${total}; Passed:${passed}; Failed:${failed}; Skipped:${skipped}td>
tr>
tbody>
table>
div>
<div class="artifacts round_border">
<b>Report Artifacts:b>
<ul>
<li><A href="${rooturl}${build.url}cucumber-html-reports/overview-features.html">${rooturl}${build.url}cucumber-html-reports/overview-features.htmlA>li>
<li><a href="#">display in new pagea>li>
ul>
div>
div>
<table class="bottom-message" align="center">
<tr>
<td class="message">You are receiving this email because you
are relavent with this build<br>
<p>
<a href="#">support teama> | <a href="#">QAa>
p>
td>
tr>
table>
body>
html>
参考:
https://wiki.jenkins.io/display/JENKINS/Email-ext+plugin#Email-extplugin-TemplateExamples
http://ikeptwalking.com/using-email-ext-plugin-in-jenkins-pipeline/
https://github.com/jenkinsci/email-ext-plugin/tree/master/src/main/resources/hudson/plugins/emailext/templates
https://gist.github.com/arjabbar/c6f27c64fd18153680f3b52102688c13