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
相关产品推荐
相关产品推荐

