Jenkins里定时器构建任务使用groovy模板发邮件报错

在Jenkins里build now构建任务成功使用groovy模板发邮件没有问题,但是使用定时器构建任务后使用groovy模板发送邮件报错:

Exception raised during template rendering: Cannot invoke method getUserName() on null object java.lang.NullPointerException: Cannot invoke method getUserName() on null object at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:47) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:34) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:56) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120) at SimpleTemplateScript1.run(SimpleTemplateScript1.groovy:50) at groovy.text.SimpleTemplateEngine$SimpleTemplate$1.writeTo(SimpleTemplateEngine.java:181) at groovy.text.SimpleTemplateEngine$SimpleTemplate$1.toString(SimpleTemplateEngine.java:193) at hudson.plugins.emailext.plugins.content.ScriptContent.renderTemplate(ScriptContent.java:155) at hudson.plugins.emailext.plugins.content.ScriptContent.evaluate(ScriptContent.java:81) at hudson.plugins.emailext.plugins.content.AbstractEvalContent.evaluate(AbstractEvalContent.java:76) at org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro.evaluate(DataBoundTokenMacro.java:205) at org.jenkinsci.plugins.tokenmacro.Parser.processToken(Parser.java:472) at org.jenkinsci.plugins.tokenmacro.Parser.parseDelimitedToken(Parser.java:178) at org.jenkinsci.plugins.tokenmacro.Parser.parseToken(Parser.java:111) at org.jenkinsci.plugins.tokenmacro.Parser.parse(Parser.java:87) at org.jenkinsci.plugins.tokenmacro.Parser.process(Parser.java:75) at org.jenkinsci.plugins.tokenmacro.Parser.process(Parser.java:68) at org.jenkinsci.plugins.tokenmacro.TokenMacro.expand(TokenMacro.java:196) at org.jenkinsci.plugins.tokenmacro.TokenMacro.expandAll(TokenMacro.java:234) at hudson.plugins.emailext.plugins.ContentBuilder.transformText(ContentBuilder.java:79) at hudson.plugins.emailext.ExtendedEmailPublisher.addContent(ExtendedEmailPublisher.java:1013) at hudson.plugins.emailext.ExtendedEmailPublisher.createMail(ExtendedEmailPublisher.java:886) at hudson.plugins.emailext.ExtendedEmailPublisher.sendMail(ExtendedEmailPublisher.java:494) at hudson.plugins.emailext.ExtendedEmailPublisher._perform(ExtendedEmailPublisher.java:444) at hudson.plugins.emailext.ExtendedEmailPublisher.perform(ExtendedEmailPublisher.java:354) at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20) at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:814) at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:763) at hudson.model.Build$BuildExecution.cleanUp(Build.java:189) at hudson.model.Run.execute(Run.java:1943) at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:44) at hudson.model.ResourceController.execute(ResourceController.java:101) at hudson.model.Executor.run(Executor.java:442)

使用的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">The build <%= build.result.toString().toLowerCase() %></p>
                </div>
                <!-- status -->
                        <table>
                                <tbody>
                                        <tr>
                                                <th>项目名称:</th>
                                                <td>${project.name}</td>
                                        </tr>
                                        <tr>
                                                <th>触发原因:</th>
                                        <%
                                                 cause = build.getCause(hudson.model.Cause.UserIdCause.class)
                                                 user_name = cause.getUserName()
                                        %>
                                                <td>Started by ${user_name}   </td>
                                        </tr>
                                        <tr>
                                                <th>构建编号 ${build.displayName}:</th>
                                                <td><a
                                                        href="${rooturl}${build.url}">${rooturl}${build.url}</a></td>
                                        </tr>
                                        <tr>
                                                <th>构建时间:</th>
                                                <td>${it.timestampString}</td>
                                        </tr>
                                        <tr>
                                                <th>构建耗时:</th>
                                                <td>${build.durationString}</td>
                                        </tr>
                                        <tr>
                                                <td colspan="2"> </td>
                                        </tr>
                                </tbody>
 
                        </table>
                <!-- main -->
        <% def artifacts = build.artifacts
            if(artifacts != null && artifacts.size() > 0) { %>
 
                        <b>离线报告:</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>测试结果</h2>
<table>
            <tbody>
                        <tr>
                                    <th>执行用例数:</th>
                                    <td><a href="${allureResultsUrl}">${lastAllureReportBuildAction.getTotalCount()}</a></td>
                        </tr>
                        <tr>
                                    <th>失败:</th>
                                    <td>${lastAllureReportBuildAction.getFailedCount()} </td>
                        </tr>
                        <tr>
                                    <th>成功:</th>
                                    <td>${lastAllureReportBuildAction.getPassedCount()} </td>
                        </tr>
                        <tr>
                                    <th>跳过:</th>
                                    <td>${lastAllureReportBuildAction.getSkipCount()} </td>
                        </tr>
                        <tr>
                                    <th>故障:</th>
                                    <td>${lastAllureReportBuildAction.getBrokenCount()} </td>
                        </tr>
                        <tr>
                                    <th>通过率: </th>
                                    <td>${allureLastBuildSuccessRate}%  </td>
                        </tr>
 
            </tbody>
</table>
<%
    String auth = "user" + ":" + "password"; byte[] encodedAuth = auth.bytes.encodeBase64().toString(); String authHeaderValue = "Basic " + new String(encodedAuth);
    content=new URL("${allureResultsUrl}/graph").getBytes( useCaches: true, allowUserInteraction: false, requestProperties: ["User-Agent": "Groovy Sample Script","Authorization": authHeaderValue])
%>
<img src="data:image/png;base64, ${content.encodeBase64().toString()}"/>
<!-- <img lazymap="${allureResultsUrl}/graphMap" src="${allureResultsUrl}/graph" alt="Allure results trend"/> -->
<% } %>
  <!-- content -->
  <!-- bottom message -->
</body>

基于Monster 组和GPT的调写:

  • 根据错误信息,Groovy脚本中存在一个空对象调用了方法。具体地说,Groovy脚本中的 getUserName() 方法在一个空对象上被调用,这导致了NullPointerException。
  • 要检查脚本中 getUserName() 方法被调用的对象是否已经被正确初始化或赋值。如果对象为 null,要先对其进行初始化或赋值,然后才能调用该对象的方法。
  • 如果无法确定哪个对象为空,可以添加一些调试语句(例如打印输出)来帮助查找问题所在。
  • 另外,可以尝试在 Jenkins 中手动运行相同的 Groovy 脚本,以便快速发现和解决问题。如果在手动运行脚本时没有出现问题,则可能是定时器导致的问题。在这种情况下,要检查定时器配置是否正确,并尝试使用其他方法来构建任务和发送邮件。

参考GPT和自己的思路:根据错误信息,似乎是在Groovy模板中尝试调用一个空对象的getUserName()方法时发生了错误。需要查看你的Groovy模板代码,以确定哪个对象是null并且需要进行非空检查。

如果你确定该对象可能为null,则可以使用Groovy的安全调用运算符(?.)来避免NullPointerException,例如:

${build.getCulprits()?.get(0)?.getDisplayName()}

上面的示例中,如果build.getCulprits()返回null,则表达式将返回null而不是抛出NullPointerException。

你可以将这种安全调用运算符应用于模板中的其他可能为空的对象。如果你需要在模板中进行更复杂的逻辑处理,则可以使用Groovy中的if语句进行非空检查。

希望这可以帮助你解决问题!

根据报错信息第一行提示,应该是由于模板中使用了getUserName()这个函数,但是该函数被调用的对象是null,导致的空指针。

建议检查一下你的模板文件,找到所有使用getUserName()函数的地方,看看确认下是否在这个地方传入了正确的对象(或者该对象是否为空?)


如果以上回答对您有所帮助,望采纳~谢谢

参考GPT和自己的思路,这个错误的根本原因是调用了一个空对象的方法,具体来说就是在渲染groovy模板的时候,调用了一个空对象的getUserName()方法。

可能原因包括:

1.在定时器构建任务时,某些参数被设置为了null。需要检查使用到的参数是否都有正确的值。

2.在渲染groovy模板时,可能会使用到一些Jenkins或插件的API,有时这些API需要在Jenkins构建过程中才能正确执行。如果在构建完成后渲染模板,可能会导致出错。可以尝试将发送邮件的步骤移动到构建的后续步骤中,看看是否能解决问题。

3.可能是groovy模板本身有问题,需要检查模板代码是否正确,是否使用了正确的变量名称。

需要更多的信息才能确定问题的具体原因和解决方案。您可以在问题中提供更多的上下文和代码示例,以便更好地帮助您解决问题。

该回答引用GPTᴼᴾᴱᴺᴬᴵ
这个错误提示表明,在使用groovy模板发送邮件时,getUserName() 方法出现了空指针异常。可能是因为在模板中使用了一个未定义的变量,或者是因为变量的值为 null。
·
你可以检查一下发送邮件的 groovy 模板中的代码,确认其中是否存在未定义的变量或者变量为空的情况。另外,也可以考虑在 groovy 模板中加入一些调试信息,以便更好地定位问题所在。
·
如果还不能解决问题,建议提供更多的信息,例如 groovy 模板的代码,邮件发送的配置信息等,这样有助于更准确地定位问题并提供解决方案。

可能原因有以下几点:

  1. 代码中可能存在语法错误或逻辑错误,导致执行失败。

  2. 可能无法连接邮件服务器,或者邮件服务器配置不正确。

  3. 可能邮件发送过程中出现网络问题,导致发送失败。

  4. 可能邮件帐户的密码已经过期或者错误,导致无法登录邮件帐户。

  5. 可能邮件内容存在错误,如地址、附件等问题。

以上几种原因可能导致邮件发送失败,需要检查代码和环境设置,以确定问题所在。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据错误信息可以看出,出现了NullPointerException,具体来说就是groovy模板中的某个变量为null,而代码尝试调用变量的方法,导致异常。

根据你提供的groovy模板,可以定位到可能的问题:获取触发构建的用户名时,使用的cause.getUserName()可能为null。在Jenkins中触发构建的原因可以有多种,不一定是由用户提交的,因此getCause(hudson.model.Cause.UserIdCause.class)有可能返回null,需要检查一下这个变量是否为null。

解决方法有两种:

  1. 改进模板,处理变量为null的情况:

你可以添加类似下面的代码处理这种情况:

<%
    cause = build.getCause(hudson.model.Cause.UserIdCause.class)
    user_name = cause?.getUserName() ?: "Unknown"
%>

这里使用了Groovy语言的安全调用方式?.,如果cause为null,cause?.getUserName()会返回null。如果获取到了值,则使用?:的缺省值操作符,将变量的值设置为"Unknown",避免在填充邮件内容的时候出错。

  1. 将代码调整到Jenkins pipeline中,在pipeline中添加处理异常的语句:

使用Jenkins pipeline可以更好地管理Jenkins任务的构建过程,你可以将邮件模板的处理逻辑移植到pipeline中,并在处理模板时添加异常处理语句:

def emailContent = ""
try {
    emailContent = emailext body: emailext.fromTemplate('path/to/template.groovy', false)
} catch (Exception e) {
    emailContent = "Error occurred while generating email content: ${e.getMessage()}"
}

在这个例子中,我们将生成邮件内容的代码包含在try-catch代码块中,如果出现异常,则将其记录到邮件内容中。

希望这些解释对你有帮助。至于代码,由于你的代码只是邮件模板,你需要将代码嵌入到Jenkins任务中使用,这个过程需要关注构建过程的具体细节,可以查看Jenkins的pipeline文档,了解如何将邮件模板嵌入到pipeline中。
如果我的回答解决了您的问题,请采纳!