You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jenkins Emailext插件中${FILE, path=""}令牌报错问题排查

问题原因与解决方案

这个报错的核心原因是Groovy字符串插值和emailext令牌宏的语法冲突:

在Jenkins声明式流水线的Groovy代码中,双引号(")包裹的字符串会触发Groovy的变量插值——也就是说,Groovy会尝试解析${}里的内容作为Groovy变量或表达式。但你使用的${FILE, path="..."}是emailext插件专属的令牌宏(Token Macro),不是Groovy的合法表达式,所以Groovy会把它识别为语法错误,抛出unexpected token: FILE的异常。

解决方法有两种,根据你的需求选择:


方法1:用单引号包裹令牌宏,避免Groovy插值

把body的内容用单引号(')包裹,这样Groovy会把整个字符串原封不动地传给emailext插件,由插件自己解析令牌宏:

post {
    always {
        emailext (
            to: 'bar@foo.com',
            subject: "${currentBuild.currentResult}: ${env.JOB_NAME} - build ${currentBuild.number}",
            body: '${FILE, path="$WORKSPACE/results/summary.txt"}'
        )
    }
}

如果需要让$WORKSPACE被Groovy解析为实际的工作空间路径,你可以混合转义写法:

body: "\${FILE, path=\"${WORKSPACE}/results/summary.txt\"}"

这里\${FILE}的反斜杠会告诉Groovy不要解析这个$,而${WORKSPACE}会正常被Groovy替换为实际路径。


方法2:直接读取文件内容作为邮件正文

如果不需要依赖emailext的令牌宏,也可以用Jenkins的readFile步骤直接读取文件内容,然后赋值给body:

post {
    always {
        emailext (
            to: 'bar@foo.com',
            subject: "${currentBuild.currentResult}: ${env.JOB_NAME} - build ${currentBuild.number}",
            body: readFile("${WORKSPACE}/results/summary.txt")
        )
    }
}

这种方式更直观,而且不需要处理令牌宏和Groovy插值的冲突,适合简单读取文件内容的场景。

额外提示

emailext的令牌宏(比如${FILE}、${BUILD_LOG}等)是插件自身的语法,只有当插件拿到完整的字符串后才会解析。所以在Groovy代码中使用时,一定要确保Groovy不会提前解析这些${}表达式——要么用单引号,要么转义$符号。

内容的提问来源于stack exchange,提问作者pipppoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:40:38