jenkins发送emailext 邮件

  1. 配置和插件
# 插件
Extended E-mail Notification
Email Extension Template Plugin

#模板地址
https://github.com/jenkinsci/email-ext-plugin/tree/master/src/main/resources/hudson/plugins/emailext/templates
https://github.com/jenkinsci/email-ext-plugin/blob/master/src/main/resources/hudson/plugins/emailext/templates
https://plugins.jenkins.io/email-ext/

# 简单说明
为Jenkins API提供了一个pull,包括hudson.model.AbstractBuild和hudson.model.AbstractProject


#配置Jelly
1. 创建Jelly脚本。脚本的名称应该是<name> .jelly。名字以.jelly结尾非常重要。
2.让您的Jenkins管理员将脚本放置在$ JENKINS_HOM\email-templates这个路径中。
3.使用模板参数等于您的脚本文件名而不带.jelly扩展名的Jelly标记。例如,如果脚本文件名是foobar.jelly,则电子邮件内容将如下所示:$ {JELLY_SCRIPT,template =“foobar”}。



  1. 整体的pipeline


import jenkins.model.*

@NonCPS
def getJobNames() {
Hudson.instance.getAllItems(org.jenkinsci.plugins.workflow.job.WorkflowJob)*.fullName 
}
    
pipeline {
    agent any
    stages {
        
        stage('Test Stage') {
            steps {
                sh '''
                    pwd
                '''
            }
            
        }
    

        stage('getJobNames') {
            
            steps {
                
                script {
                    
                    def jobNames = getJobNames()
                    def matchjobs = jobNames.findAll{ name -> name =~ /(test)\w*/ }
                    // println matchjobs
                    matchjobs.each {
                        try {
                            println(it)
                            res = jenkins.model.Jenkins.instance.getItem(it).lastBuild.getResult()
                            println res     
                        } catch (NullPointerException e1) {
                                e1.printStackTrace();
                        }
                    }
        
                }  
              
            }
        
        }

        
    }//stages
    
    post {
        always {
            echo 'This will always run'
            script {                   
                    emailext (subject:'${ENV, var ="JOB_NAME"}',
                                body:'${FILE ,path="email.html"}',
                                to:'sgamize@sina.com',)         
                }          
        }
        success {
            echo 'This will run only if successful'
        }
        failure {
            echo 'This will run only if failed'
        }
        unstable {
            echo 'This will run only if the run was marked as unstable'
        }
        changed {
            echo 'This will run only if the state of the Pipeline has changed'
            echo 'For example, if the Pipeline was previously failing but is now successful'
        }
    }
}


1.模板调用pipeline

// 说明:
// ${ENV, var="JOB_NAME"}
// 这个写法其实和${JOB_NAME}、$JOB_NAME是等价的
// 可以理解成:
// ${ENV(var:JOB_NAME)}
// 因为参数就一个所以可以简写为:
// ${JOB_NAME}或者$JOB_NAME


always {
    echo 'This will always run'
    script {                   
            emailext (subject:'${ENV, var ="JOB_NAME"}',
                        // body:'${FILE ,path="email.html"}',
                        // body:' ${JELLY_SCRIPT,template="foobar"}',
                        body:' ${SCRIPT,template="foobar.template.groovy"}',
                        
                        to:'sgamize@sina.com,amize.zhou@nokia-sbell.com',)         
        }          
}
  1. html模板
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

    <style>
        * {
            margin: 10px;
            /*background: #1b6d85;*/
        }

        #d2 {
            background: #4cae4c;
        }

        #d3 {
            background: #8a6d3b;
        }
    </style>
    <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>

<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
    offset="0">
    <table width="95%" cellpadding="0" cellspacing="0"
        style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
        <tr>
            <td>(本邮件是程序自动下发的,请勿回复!)</td>
        </tr>
        <tr>
            <td><h2>
                    <font color="#0000FF">构建结果 - ${BUILD_STATUS}</font>
                </h2>
            </td>
        </tr>
        <tr>
            <td><br />
            <b><font color="#0B610B">构建信息</font></b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>
                <ul>
                    <li>项目名称&nbsp;:&nbsp;${PROJECT_NAME}</li>
                    <li>构建编号&nbsp;:&nbsp;第${BUILD_NUMBER}次构建</li>
                    <li>SVN&nbsp;版本:&nbsp;${SVN_REVISION}</li>
                    <li>触发原因:&nbsp;${CAUSE}</li>
                    <li>构建日志:&nbsp;<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                    <li>构建&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${BUILD_URL}">${BUILD_URL}</a></li>
                    <li>工作目录&nbsp;:&nbsp;<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
                    <li>项目&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
                    <li>Amize&nbsp;:&nbsp;${jobNames}:${BUILD_NUMBER}</li>
                    <j:set var="customMsg" value="${buildenv.get('jobNames')}"/>
                    <li>Amize&nbsp;:&nbsp;${customMsg}:${BUILD_NUMBER}</li>
                    <li>Amize&nbsp;:&nbsp;${buildenv.get('jobNames')}</li>

                </ul>
            </td>
        </tr>
        <tr>
            <td><b><font color="#0B610B">Changes Since Last
                        Successful Build:</font></b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>
                <ul>
                    <li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
                </ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"}
            </td>
        </tr>
        <tr>
            <td><b>Failed Test Results</b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td><pre
                    style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
                <br /></td>
        </tr>
        <tr>
            <td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>Test Logs (if test has ran): <a
                href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
                <br />
            <br />
            </td>
        </tr>
        <tr>
            <td><textarea cols="80" rows="30" readonly="readonly"
                    style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea>
            </td>
        </tr>
    </table>
</body>
</html>

3.jelly模板

<?jelly escape-by-default='true'?>
<!DOCTYPE html [
    <!ENTITY nbsp "&#38;nbsp;">
]>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define">
 
<STYLE>
BODY, TABLE, TD, TH, P {
  font-family:Verdana,Helvetica,sans serif;
  font-size:11px;
  color:black;
}
h1 { color:black; }
h2 { color:black; }
h3 { color:black; }
TD.bg1 { color:white; background-color:#0000C0; font-size:120% }
TD.bg2 { color:white; background-color:#4040FF; font-size:110% }
TD.bg3 { color:white; background-color:#8080FF; }
TD.test_passed { color:blue; }
TD.test_failed { color:red; }
TD.console { font-family:Courier New; }
</STYLE>


<BODY>
 
<!-- GENERAL INFO -->
 
<TABLE>
  <TR><TD align="right">
    <j:choose>
      <j:when test="${build.result=='SUCCESS'}">
        <IMG SRC="${rooturl}static/e59dfe28/images/32x32/blue.gif" />
      </j:when>
	  <j:when test="${build.result=='FAILURE'}">
        <IMG SRC="${rooturl}static/e59dfe28/images/32x32/red.gif" />
      </j:when>
      <j:otherwise>
        <IMG SRC="${rooturl}static/e59dfe28/images/32x32/yellow.gif" />
      </j:otherwise>
    </j:choose>
  </TD><TD valign="center"><B style="font-size: 200%;">BUILD ${build.result}</B></TD></TR>
  <TR><TD>Build 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>Date of build:</TD><TD>${it.timestampString}</TD></TR>
  <TR><TD>Build duration:</TD><TD>${build.durationString}</TD></TR>
</TABLE>
<BR/>
 
 
<!-- CHANGE SET -->
 
<j:set var="changeSet" value="${build.changeSet}" />
<j:if test="${changeSet!=null}">
  <j:set var="hadChanges" value="false" />
  <TABLE width="100%">
    <TR><TD class="bg1" colspan="2"><B>CHANGES</B></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" class="bg2">  Revision <B>${cs.commitId?:cs.revision?:cs.changeNumber}</B> by
          <B>${aUser!=null?aUser.displayName:cs.author.displayName}: </B>
          <B>(${cs.msgAnnotated})</B>
         </TD>
      </TR>
      <j:forEach var="p" items="${cs.affectedFiles}">
        <TR>
          <TD width="10%">  ${p.editType.name}</TD>
          <TD>${p.path}</TD>
        </TR>
      </j:forEach>
    </j:forEach>
    <j:if test="${!hadChanges}">
      <TR><TD colspan="2">No Changes</TD></TR>
    </j:if>
  </TABLE>
<BR/>
</j:if>
 
 
<!-- ARTIFACTS -->
 
<j:set var="artifacts" value="${build.artifacts}" />
<j:if test="${artifacts!=null and artifacts.size()>0}">
  <TABLE width="100%">
    <TR><TD class="bg1"><B>BUILD ARTIFACTS</B></TD></TR>
    <TR>
      <TD>
        <j:forEach var="f" items="${artifacts}">
      	  <li>
      	    <a href="${rooturl}${build.url}artifact/${f}">${f}</a>
      	  </li>
      	</j:forEach>
      </TD>
    </TR>
  </TABLE>
<BR/>  
</j:if>
 
 
<!-- MAVEN ARTIFACTS -->
 
<j:set var="mbuilds" value="${build.moduleBuilds}" />
<j:if test="${mbuilds!=null}">
  <TABLE width="100%">
      <TR><TD class="bg1"><B>BUILD ARTIFACTS</B></TD></TR>
      <j:forEach var="m" items="${mbuilds}">
        <TR><TD class="bg2"><B>${m.key.displayName}</B></TD></TR>
        <j:forEach var="mvnbld" items="${m.value}">
        <j:set var="artifacts" value="${mvnbld.artifacts}" />
        <j:if test="${artifacts!=null and artifacts.size()>0}">
      <TR>
        <TD>
      	  <j:forEach var="f" items="${artifacts}">
      	    <li>
      	      <a href="${rooturl}${mvnbld.url}artifact/${f}">${f}</a>
      	    </li>
      	  </j:forEach>
      	</TD>
      </TR>
        </j:if>
        </j:forEach>
      </j:forEach>
  </TABLE>
<BR/>  
</j:if>
 
 
<!-- JUnit TEMPLATE -->
 
<j:set var="junitResultList" value="${it.JUnitTestResult}" />
<j:if test="${junitResultList.isEmpty()!=true}">
  <TABLE width="100%">
    <TR><TD class="bg1" colspan="2"><B>JUnit Tests</B></TD></TR>
    <j:forEach var="junitResult" items="${it.JUnitTestResult}">
      <j:forEach var="packageResult" items="${junitResult.getChildren()}">
        <TR><TD class="bg2" colspan="2"> Name: ${packageResult.getName()} Failed: ${packageResult.getFailCount()} test(s), Passed: ${packageResult.getPassCount()} test(s), Skipped: ${packageResult.getSkipCount()} test(s), Total: ${packageResult.getPassCount()+packageResult.getFailCount()+packageResult.getSkipCount()} test(s)</TD></TR>
        <j:forEach var="test" items="${packageResult.getPassedTests()}">
          <j:if test="${test.status == 'FIXED'}">
            <TR bgcolor="white"><TD class="test_passed" colspan="2"><B><li>Fixed: ${test.getFullName()} (${test.getAge()})</li></B></TD></TR>
          </j:if>
        </j:forEach>
        <j:forEach var="failed_test" items="${packageResult.getFailedTests()}">
          <TR bgcolor="white"><TD class="test_failed" colspan="2"><B><li>Failed: ${failed_test.getFullName()} (${failed_test.getAge()})</li></B></TD></TR>
        </j:forEach>
      </j:forEach> 
    </j:forEach>  
  </TABLE>	
<BR/>
</j:if>
 
 
<!-- COBERTURA TEMPLATE -->
 
<j:set var="coberturaAction" value="${it.coberturaAction}" />
<j:if test="${coberturaAction!=null}">
  <j:set var="coberturaResult" value="${coberturaAction.result}" />
  <j:if test="${coberturaResult!=null}">
  	<table width="100%"><TD class="bg1" colspan="2"><B>Cobertura Report</B></TD></table>
	<table width="100%"><TD class="bg2" colspan="2"><B>Project Coverage Summary</B></TD></table>
            <table border="1px" class="pane">
                <tr>
                    <td>Name</td>
                    <j:forEach var="metric" items="${coberturaResult.metrics}">
                        <td>${metric.name}</td>
                    </j:forEach>
                </tr>
                <tr>
                    <td>${coberturaResult.name}</td>
                    <j:forEach var="metric" items="${coberturaResult.metrics}">
                        <td data="${coberturaResult.getCoverage(metric).percentageFloat}">${coberturaResult.getCoverage(metric).percentage}%
                            (${coberturaResult.getCoverage(metric)})
                        </td>
                    </j:forEach>
                </tr>
            </table>
 
            <j:if test="${coberturaResult.sourceCodeLevel}">
                <h2>Source</h2>
                <j:choose>
                    <j:when test="${coberturaResult.sourceFileAvailable}">
                        <div style="overflow-x:scroll;">
                            <table class="source">
                                <thead>
                                    <tr>
                                        <th colspan="3">${coberturaResult.relativeSourcePath}</th>
                                    </tr>
                                </thead>
                                ${coberturaResult.sourceFileContent}
 
                            </table>
                        </div>
                    </j:when>
                    <j:otherwise>
                        <p>
                            <i>Source code is unavailable</i>
                        </p>
                    </j:otherwise>
                </j:choose>
            </j:if>
 
            <j:forEach var="element" items="${coberturaResult.childElements}">
                <j:set var="childMetrics" value="${coberturaResult.getChildMetrics(element)}"/>
               <table width="100%"><TD class="bg2" colspan="2">Coverage Breakdown by ${element.displayName}</TD></table>
                <table border="1px" class="pane sortable">
                    <tr>
                        <td>Name</td>
                        <j:forEach var="metric" items="${childMetrics}">
                            <td>${metric.name}</td>
                        </j:forEach>
                    </tr>
                    <j:forEach var="c" items="${coberturaResult.children}">
                        <j:set var="child" value="${coberturaResult.getChild(c)}"/>
                        <tr>
 
                            <td>
                                ${child.xmlTransform(child.name)}
                            </td>
                            <j:forEach var="metric" items="${childMetrics}">
                                <j:set var="childResult" value="${child.getCoverage(metric)}"/>
                                <j:choose>
                                    <j:when test="${childResult!=null}">
                                        <td data="${childResult.percentageFloat}">${childResult.percentage}%
                                            (${childResult})
                                        </td>
                                    </j:when>
                                    <j:otherwise>
                                        <td data="101">N/A</td>
                                    </j:otherwise>
                                </j:choose>
                            </j:forEach>
                        </tr>
                    </j:forEach>
                </table>
            </j:forEach>
  </j:if>
<BR/>
</j:if>
 
 
<!-- CONSOLE OUTPUT -->
 
<j:getStatic var="resultFailure" field="FAILURE" className="hudson.model.Result"/>
<j:if test="${build.result==resultFailure}">
<TABLE width="100%" cellpadding="0" cellspacing="0">
<TR><TD class="bg1"><B>CONSOLE OUTPUT</B></TD></TR>
<j:forEach var="line" items="${build.getLog(100)}"><TR><TD class="console">${line}</TD></TR></j:forEach>
</TABLE>
<BR/>
</j:if>
 
</BODY>
</j:jelly>

4.groovy模板

<STYLE>
BODY, TABLE, TD, TH, P {
  font-family:Verdana,Helvetica,sans serif;
  font-size:11px;
  color:black;
}
h1 { color:black; }
h2 { color:black; }
h3 { color:black; }
TD.bg1 { color:white; background-color:#0000C0; font-size:120% }
TD.bg2 { color:white; background-color:#4040FF; font-size:110% }
TD.bg3 { color:white; background-color:#8080FF; }
TD.test_passed { color:blue; }
TD.test_failed { color:red; }
TD.console { font-family:Courier New; }
</STYLE>
<BODY>

<TABLE>
  <TR><TD align="right"><IMG SRC="${rooturl}static/e59dfe28/images/32x32/<%= (build.result == null || build.result.toString() == 'SUCCESS') ? "blue.gif" : build.result.toString() == 'FAILURE' ? 'red.gif' : 'yellow.gif' %>" />
  </TD><TD valign="center"><B style="font-size: 200%;">BUILD ${build.result ?: 'SUCCESSFUL'}</B></TD></TR>
  <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>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>
                <ul>


                </ul>
            </td>
  </tr>
</TABLE>
<BR/>

<!-- CHANGE SET -->
<% def changeSets = build.changeSets
if(changeSets != null) {
    def hadChanges = false %>
    <TABLE width="100%">
    <TR><TD class="bg1" colspan="2"><B>CHANGES</B></TD></TR>

<%  changeSets.each() { cs_list ->
      cs_list.each() { cs ->
          hadChanges = true %>
        <TR>
          <TD colspan="2" class="bg2">&nbsp;&nbsp;Revision <B><%= cs.metaClass.hasProperty('commitId') ? cs.commitId : cs.metaClass.hasProperty('revision') ? cs.revision :
          cs.metaClass.hasProperty('changeNumber') ? cs.changeNumber : "" %></B> by
            <B><%= cs.author %>: </B>
            <B>(${cs.msgAnnotated})</B>
           </TD>
        </TR>
<%      cs.affectedFiles.each() { p -> %>
        <TR>
          <TD width="10%">&nbsp;&nbsp;${p.editType.name}</TD>
          <TD>${p.path}</TD>
        </TR>
<%      }
      }
  }

    if(!hadChanges) { %>
        <TR><TD colspan="2">No Changes</TD></TR>
<%  } %>
  </TABLE>
<BR/>
<% } %>

<!-- ARTIFACTS -->
<% def artifacts = build.artifacts
if(artifacts != null && artifacts.size() > 0) { %>
  <TABLE width="100%">
    <TR><TD class="bg1"><B>BUILD ARTIFACTS</B></TD></TR>
    <TR>
      <TD>
<%      artifacts.each() { f -> %>
          <li>
            <a href="${rooturl}${build.url}artifact/${f}">${f}</a>
          </li>
<%      } %>
      </TD>
    </TR>
  </TABLE>
<BR/>
<% } %>

<!-- MAVEN ARTIFACTS -->
<%
try {
  def mbuilds = build.moduleBuilds
  if(mbuilds != null) { %>
  <TABLE width="100%">
      <TR><TD class="bg1"><B>BUILD ARTIFACTS</B></TD></TR>
<%
    try {
        mbuilds.each() { m -> %>
        <TR><TD class="bg2"><B>${m.key.displayName}</B></TD></TR>
<%      m.value.each() { mvnbld ->
            def artifactz = mvnbld.artifacts
            if(artifactz != null && artifactz.size() > 0) { %>
      <TR>
        <TD>
<%              artifactz.each() { f -> %>
            <li>
              <a href="${rooturl}${mvnbld.url}artifact/${f}">${f}</a>
            </li>
<%              } %>
        </TD>
      </TR>
<%          }
        }
       }
    } catch(e) {
    // we don't do anything
    }  %>
  </TABLE>
<BR/>
<% }

}catch(e) {
    // we don't do anything
}
%>

<!-- JUnit TEMPLATE -->

<% 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 width="100%">
 <TR><TD class="bg1" colspan="2"><B>${junitResultList.first().displayName}</B></TD></TR>
 <% junitResultList.each{
  junitResult -> %>
     <% junitResult.getChildren().each { packageResult -> %>
        <TR><TD class="bg2" colspan="2"> Name: ${packageResult.getName()} Failed: ${packageResult.getFailCount()} test(s), Passed: ${packageResult.getPassCount()} test(s), Skipped: ${packageResult.getSkipCount()} test(s), Total: ${packageResult.getPassCount()+packageResult.getFailCount()+packageResult.getSkipCount()} test(s)</TD></TR>
        <% packageResult.getFailedTests().each{ failed_test -> %>
          <TR bgcolor="white"><TD class="test_failed" colspan="2"><B><li>Failed: ${failed_test.getFullName()} </li></B></TD></TR>
        <% }
      }
 } %>
 </TABLE>
 <BR/>
<%
} %>

<!-- CONSOLE OUTPUT -->
<% if(build.result==hudson.model.Result.FAILURE) { %>
<TABLE width="100%" cellpadding="0" cellspacing="0">
<TR><TD class="bg1"><B>CONSOLE OUTPUT</B></TD></TR>
 <TR><TD class="console">${jenkins.model.Jenkins.instance.getJobNames().findAll{ name -> println name }}</TD></TR>
 
<%  build.getLog(100).each() { line -> %>
    <TR><TD class="console">${org.apache.commons.lang.StringEscapeUtils.escapeHtml(line)}</TD></TR>
<%  } %>
</TABLE>
<BR/>
<% } %>

</BODY>
posted @ 2021-05-16 16:13  该显示昵称已被使用了  阅读(142)  评论(0编辑  收藏  举报