持续集成 [求助] 如何把 allure 的 index.html 所显示的内容,展示在 jenkins 发送的 Email 中?

strayeagle · 2020年03月19日 · 最后由 电工 回复于 2021年09月02日 · 4019 次阅读

前言

如何把 allure 产生的 index.html 内容(报告在远端 Jenkins 服务器上),显示在 Jenkins 发送的 Email 中呢?

预期效果

但是目前显示的效果如下:

说明:
上图中 error 提示说文件不存在,复制这个地址,是可以正常网络访问的。

如何才能实现预期的效果呢?谢谢~~

Jenkins email html 源码

<h2><center><font>This email generated by Jenkins, please do not reply!</font><center></h2>
<br>

<hr>
 Product Version : ${PRODUCT_VERSION}<br>
 Start Time : ${START_TIME}<br>
 End Time : ${END_TIME}<br>
 Duration Time : ${TIME_DURATION}(s)<br>
<br>

<span style="color: #000000;">Total Cases:&nbsp; &nbsp; ${TEST_COUNTS}</span><br>
<span style="color: #000000; background-color: #008000;">Pass&nbsp; Cases:&nbsp; &nbsp; ${TEST_PASS}</span><br>
<span style="color: #000000; background-color: #ffff00;">Fail&nbsp; &nbsp;Cases:&nbsp; &nbsp; ${TEST_FAIL}</span><br>
<span style="color: #000000; background-color: #3366ff;">Skip&nbsp; Cases:&nbsp; &nbsp; ${TEST_SKIP}</span><br>
<span style="color: #000000; background-color: #ff0000;">Broken Cases:&nbsp; &nbsp; ${TEST_BROKEN}</span><br>
<span style="color: #000000; background-color: #ff0000;">Unknown Cases:&nbsp; &nbsp; ${TEST_UNKNOWN}</span><br>

<br>
 Project Name : ${PROJECT_NAME}<br>
 Build Number : ${BUILD_NUMBER}<br>
 Build Status : ${BUILD_STATUS}<br>
 Trigger Reason : ${CAUSE}<br>
 Build Address : <A HREF="${BUILD_URL}">${BUILD_URL}</A><br>
 Build Log : <A HREF="${BUILD_URL}console">${BUILD_URL}console</A><br>
 Allure Test Report : <A HREF="${PROJECT_URL}${BUILD_NUMBER}/allure">${PROJECT_URL}${BUILD_NUMBER}/allure</a><br>
 <hr>

<div>
   <table> 
       <tr>  
           <th><br />
           <h2>Test Report</h2>
           </th>  
        </tr>

        <tr>
            <td>
                <div>${FILE,path="${PROJECT_URL}${BUILD_NUMBER}/allure/index.html"}</div>
            </td>
        </tr>

    </table> 
</div>
共收到 13 条回复 时间 点赞

启个服务,专门展示这个呗

恒温 回复

我以为用 iframe 能解决,单独打开 jenkins 里的 email(拷贝内容后命名为 show_allure_in_jenkins_mail.html)是 OK 的,但是从邮件(使用过 Outlook 和 foxmail)打开,就不展示了,对应的 iframe 显示一片空白区域。。。

放弃这种思路,邮箱基于安全考虑(防止挂马),不支持 mail 中展示 iframe

这个很简单啊, allure 在 jenkins 上的插件也是用 allure command line 启动的一个服务。 暴露了 http 接口。 你可以从中获取测试结果的。我是写了一段 groovy 脚本来抓取 allure report 的结果的。 可以使用 pipeline 来 执行 groovy 脚本,你也可以在其他 job 中添加 groovy script 这个步骤。 你可以参考我这里的脚本。代码如下:


/**
 * Created by sungaofei on 20/2/8.
 */
@Grab(group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.7')

import groovyx.net.http.HTTPBuilder

import static groovyx.net.http.ContentType.*


import static groovyx.net.http.Method.*
import groovy.transform.Field


//global variable
@Field jenkinsURL = "http://auto.4paradigm.com"
@Field failed = "FAILED"
@Field success = "SUCCESS"
@Field inProgress = "IN_PROGRESS"
@Field abort = "ABORTED"

@NonCPS
def String checkJobStatus() {

    def url = ""

    if (env.BRANCH_NAME!= "" && env.BRANCH_NAME != null){
        String jobName = "${JOB_NAME}".split("/")[0]
        url = "/view/API/job/${jobName}/job/${env.BRANCH_NAME}/${BUILD_NUMBER}/wfapi/describe"
    }else {
        url = "/view/API/job/${JOB_NAME}/${BUILD_NUMBER}/wfapi/describe"
    }
    HTTPBuilder http = new HTTPBuilder(jenkinsURL)
    String status = success

    println("1111111111")
    println("${JOB_NAME}")
    println(url)
    http.get(path: url) { resp, json ->
        if (resp.status != 200) {
            throw new RuntimeException("请求 ${url} 返回 ${resp.status} ")
        }
        List stages = json.stages

        for (int i = 0; i < stages.size(); i++) {
            def stageStatus = json.stages[i].status
            if (stageStatus == failed) {
                status = failed
                break
            }
            if (stageStatus == abort) {
                status = abort
                break
            }
        }
    }

    return status;

}


@NonCPS
def call(String to) {
    println("邮件列表:${to}")

    def reportURL = ""
    String jobName = "${JOB_NAME}"
    String blueOCeanURL = ""

    if (env.BRANCH_NAME!= "" && env.BRANCH_NAME != null){
        jobName = "${JOB_NAME}".split("/")[0]
        reportURL = "/view/API/job/${jobName}/job/${env.BRANCH_NAME}/${BUILD_NUMBER}/allure/"
//            http://auto.4paradigm.com/blue/organizations/jenkins/gitlabtest/detail/master/217/pipeline
        blueOCeanURL = "${jenkinsURL}/blue/organizations/jenkins/${jobName}/detail/${env.BRANCH_NAME}/${BUILD_NUMBER}/pipeline"
    }else{
        reportURL = "/view/API/job/${JOB_NAME}/${BUILD_NUMBER}/allure/"
        blueOCeanURL = "${jenkinsURL}/blue/organizations/jenkins/${JOB_NAME}/detail/${JOB_NAME}/${BUILD_NUMBER}/pipeline"
    }

    def sendSuccess = {
//        blueOCeanURL = "${jenkinsURL}/blue/organizations/jenkins/${JOB_NAME}/detail/${JOB_NAME}/${BUILD_NUMBER}/pipeline"

        def fileContents = ""
        def passed = ""
        def failed = ""
        def skipped = ""
        def broken = ""
        def unknown = ""
        def total = ""
        HTTPBuilder http = new HTTPBuilder('http://auto.4paradigm.com')
        //根据responsedata中的Content-Type header,调用json解析器处理responsedata
        http.get(path: "${reportURL}widgets/summary.json") { resp, json ->
            println resp.status
            passed = json.statistic.passed
            failed = json.statistic.failed
            skipped = json.statistic.skipped
            broken = json.statistic.broken
            unknown = json.statistic.unknown
            total = json.statistic.total

        }

        println(passed)

        emailext body: """
<html>
  <style type="text/css">
  <!--
  ${fileContents}
  -->
  </style>
  <body>
  <div id="content">
  <h1>Summary</h1>
  <div id="sum2">
      <h2>Jenkins Build</h2>
      <ul>
      <li>Job 地址 : <a href='${BUILD_URL}'>${BUILD_URL}</a></li>
       <li>测试报告地址 : <a href='${jenkinsURL}${reportURL}'>${jenkinsURL}${reportURL}</a></li>
       <li>Pipeline 流程地址 : <a href='${blueOCeanURL}'>${blueOCeanURL}</a></li>
      </ul>

      <h2>测试结果汇总</h2>
      <ul>
      <li>用例总数 : ${total}</li>
      <li>pass数量 : ${passed}</li>
       <li>failed数量 :${failed} </li>
       <li>skip数量 : ${skipped}</li>
       <li>broken数量 : ${broken}</li>
      </ul>
  </div>
  </div></body></html>
    """, mimeType: 'text/html', subject: "${JOB_NAME} 测试结束", to: to

    }

    def send = { String subject ->
        emailext body: """
<html>
  <style type="text/css">
  <!--
  -->
  </style>
  <body>
  <div id="sum2">
      <h2>Jenkins Build</h2>
      <ul>
      <li>Job 地址 : <a href='${BUILD_URL}'>${BUILD_URL}</a></li>
        <li>测试报告地址 : <a href='${jenkinsURL}${reportURL}'>${jenkinsURL}${reportURL}</a></li>
       <li>Pipeline 流程地址 : <a href='${blueOCeanURL}'>${blueOCeanURL}</a></li>
      </ul>
  </div>
  </div></body></html>
    """, mimeType: 'text/html', subject: subject, to: to
    }

    String status = checkJobStatus()
//    String status = $BUILD_STATUS
    println("当前job 的运行状态为: ${status}")
    switch (status) {
        case ["SUCCESS", "UNSTABLE"]:
            sendSuccess()
            break
        case "FAILED":
            send("Job运行失败")
            break
        case "ABORTED":
            send("Job在运行中被取消")
            break
        default:
            send("Job运行结束")
    }

}





效果图如下:

孙高飞 回复

Jenkins 发的 Email 是含有具体的测试结果的,展示了 build 环境信息以及 total、pass、fail、broken 等数据,但我更想在这些数据之下,把 Jenkins 对应 build 的 Allure 所展示的 web 界面信息,也体现在邮件里

Summary 一下 Allure Summary Email using Email-ext Jenkins Plugin,具体操作如下:
Jenkins 在发送邮件时,在设置 E-mail 触发里,有一个 Content,在 Content 对应地方,填写如下内容:${SCRIPT, template="allure-report.groovy"}, 如下图所示:

allure-report.groovy 脚本放在哪儿呢? 放在 $JENKINS_HOME/email-templates 目录下,我当前 Jenkins 环境存放路径如下:

jenkins@ubuntu-16:~/email-templates$ ls -l
total 20
-rw-rw-r-- 1 jenkins jenkins  5697 Mar 27 16:30 allure-report.groovy
-rw-rw-r-- 1 jenkins jenkins 10764 Jun 17  2019 email-template.groovy
jenkins@ubuntu-16:~/email-templates$ pwd
/var/lib/jenkins/email-templates
jenkins@ubuntu-16:~/email-templates$ 

email-template.groovy 应该是 Robot Framework 某个插件生成的(我猜测的,vi 里面看到很多关于 RF 的,正好当前 Jenkins 里也有 RF 的 project 在跑)。

allure-report.groovy 脚本内容如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<style type="text/css">
/*base css*/
    body
    {
      margin: 0px;
      padding: 15px;
    }

    body, td, th
    {
      font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Tahoma, sans-serif;
      font-size: 10pt;
    }

    th
    {
      text-align: left;
    }

    h1
    {
      margin-top: 0px;
    }
    a
    {
      color:#4a72af
    }
/*div styles*/

.status{background-color:<%= 
            build.result.toString() == "SUCCESS" ? 'green' : 'red' %>;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}
</style>
<body>
<div class="content round_border">
                <div class="status">
                        <p class="info">pytest automation build <%= build.result.toString().toLowerCase() %></p>
                </div>
                <!-- status -->
                        <table>
                                <tbody>
                                        <tr>
                                                <th>Project:</th>
                                                <td>${project.name}</td>
                                        </tr>
                                        <tr>
                                                <th>Build ${build.displayName}:</th>
                                                <td><a
                                                        href="${rooturl}${build.url}">${rooturl}${build.url}</a></td>
                                        </tr>
                                        <tr>
                                                <th>Product Version:</th>
                                                <td><%=build.environment['PRODUCT_VERSION']%></td>
                                        </tr>
                                        <tr>
                                                <th>Date of build:</th>
                                                <td>${it.timestampString}</td>
                                        </tr>
                                        <tr>
                                                <th>Build duration:</th>
                                                <td>${build.durationString}</td>
                                        </tr>
                                        <tr>
                                                <td colspan="2">&nbsp;</td>
                                        </tr>
                                </tbody>

                        </table>
                <!-- main -->
        <% def artifacts = build.artifacts
            if(artifacts != null && artifacts.size() > 0) { %>

                        <b>Build Artifacts:</b>
                        <ul>
            <%          artifacts.each() { f -> %>
                <li><a href="${rooturl}${build.url}artifact/${f}">${f}</a></li>
            <%          } %>
                        </ul>
        <% } %>
  <!-- artifacts -->

<% 
  lastAllureReportBuildAction = build.getAction(ru.yandex.qatools.allure.jenkins.AllureReportBuildAction.class)
  lastAllureBuildAction = build.getAction(ru.yandex.qatools.allure.jenkins.AllureBuildAction.class)

  if (lastAllureReportBuildAction) {
    allureResultsUrl = "${rooturl}${build.url}allure"
    allureLastBuildSuccessRate = String.format("%.2f", lastAllureReportBuildAction.getPassedCount() * 100f / lastAllureReportBuildAction.getTotalCount())
  }
%>
<% if (lastAllureReportBuildAction) { %>
<h2>Allure Results</h2>
<table>
            <tbody>
                        <tr>
                            <th>Total Allure tests run:</th>
                            <td><a href="${allureResultsUrl}">${lastAllureReportBuildAction.getTotalCount()}</a></td>
                        </tr>
                        <tr>
                            <th><span style="color: #000000; background-color: #ffff00;">Failed:</span></th>
                            <td><span style="color: #000000; background-color: #ffff00;">${lastAllureReportBuildAction.getFailedCount()} </span></td>
                        </tr>
                        <tr>
                            <th><span style="color: #000000; background-color: #008000;">Passed:</span></th>
                            <td><span style="color: #000000; background-color: #008000;">${lastAllureReportBuildAction.getPassedCount()} </span></td>
                        </tr>
                        <tr>
                            <th><span style="color: #000000; background-color: #3366ff;">Skipped:</span></th>
                            <td><span style="color: #000000; background-color: #3366ff;">${lastAllureReportBuildAction.getSkipCount()} </span></td>
                        </tr>
                        <tr>
                            <th><span style="color: #000000; background-color: #ff0000;">Broken:</span></th>
                            <td><span style="color: #000000; background-color: #ff0000;">${lastAllureReportBuildAction.getBrokenCount()} </span></td>
                        </tr>
                        <tr>
                            <th>Success rate: </th>
                            <td>${allureLastBuildSuccessRate}%  </td>
                        </tr>

            </tbody>
</table>
<img lazymap="${allureResultsUrl}/graphMap" src="${allureResultsUrl}/graph" alt="Allure results trend"/>
<% } %>                  
  <!-- content -->
  <!-- bottom message -->
</body>

注意:
脚本内容中有一个 PRODUCT_VERSION 变量,这个是我私有变量,可以通过 ‘Inject environment vairables’ 来定义:

最终邮件效果图如下:

你好我是把测试报告输出到 tomcat 下了,使用

{FILE ,path="http://ip:8080/result/html/ShangHuTongTestReport.html"} 访问和你一样报文件不存在 可是这个路径在浏览器是可以挣才打开的 您是怎么解决的啊
strayeagle 回复

你好 请问下 我在 lastAllureReportBuildAction 这一步 获取到的值为空时为什么呢?我在 jenkins 装了插件 allure 了,是还需要加一些其他配置吗?

田强强 回复

Email 里是无法正常展示 html link 的,这个是 email 自身基于安全考量做的限制的。
如果你想展示,建议在 jenkins 的 email 模板下,放自定义的 email 模板,在模板中将要展示的 link,最好是 link 到具体的图片,这样这个图片是可以正常在 email 里展示的,而这些图片,jenkins allure report 中是有的

切瑞 回复

不是很确定你的具体状况了,是否并没有获取到值,所以才展示为 null,是否可以付个初始值,如果没获取到就展示你的初始值,这样方便你定位问题

请问下你是用 pytest+allure 吗,怎么我使用 ${TEST_COUNTS}是空的

13楼 已删除
strayeagle 回复

大佬,你是怎么把这个趋势图放在邮件的哦

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册