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

Jenkins任务执行Groovy脚本时出现groovy.lang.MissingPropertyException错误排查

问题分析

报错groovy.lang.MissingPropertyException: No such property: writer for class: groovy.lang.Binding的核心原因是变量作用域不匹配:

  • writer变量在try代码块内部定义,属于局部变量,作用域仅限于try块内部。
  • finally代码块在try块的作用域之外,无法访问try内定义的writer变量,导致找不到该属性的错误。

你推测的write对象并非问题根源,实际是基础语法层面的变量作用域问题。

解决方案

将writer变量的定义移到try代码块外部,确保finally块可以访问到该变量,同时添加空值判断避免未初始化的情况。

完整修改后的脚本

import hudson.model.*
import hudson.FilePath
import groovy.xml.MarkupBuilder
import java.text.SimpleDateFormat

// make variable bindings available in this script
binding.variables

// Timestamp format for output 
def tsformat = "yyyy-MM-dd HH:mm:ss"
def to_ts_format = new SimpleDateFormat(tsformat)

// Integrity time format 
def from_integrity_format = new SimpleDateFormat ("MMM dd, yyyy hh:mm:ss aa")

def today = Calendar.getInstance().getTime()

// get current build
def thr = Thread.currentThread()
def build = thr?.executable

// Get parameters 

// reportname must be given as parameter binding - s. Jenkins groovy script extended ("erweitert") settings
String reportname = "${build.envVars.WORKSPACE}"+ "\\" + "${build.envVars.par_reportname}" 

// Get job name from environment 
String srcjobname = "${build.envVars.PAR_JOB}"

// Get from and to
int to = "${build.envVars.PAR_TO}".toInteger ()
int last_to = "${build.envVars.PAR_FROM}".toInteger () 
int from = last_to + 1

// End get parameters 

// Get the job object ... 
def job = Hudson.instance.getJob (srcjobname)

println ("\nCreating report for '"+ job.name + "' builds: " + from + " to " + to + "\n")

// Get job time preceding earliest job in range  
def frompredecessorbuild = job.getNearestOldBuild (last_to)
def predectime
if (frompredecessorbuild != null) {
   println ("\nGot predecessor build: " + frompredecessorbuild.number + ".\n")
   predectime = frompredecessorbuild.getTime ()
} else {
   println ("\nDidn't get predecessor time, no cut off!\n")
   predectime = to_ts_format.parse ("1900-01-01 00:00:00")
}

// Get builds from jobs (alternative way, because getBuildByNumber () seems not to work reliably)
def builds = job.builds

def freport = new FilePath (build.workspace, reportname)
def stream = freport.write()

//
// Create the xml ... 
//
println ("Now create xml.")
// 提前定义writer,让finally代码块可访问
def writer = new StringWriter()
try {
  def xml = new MarkupBuilder(writer)
  xml.changereport (job:srcjobname, time:today.format (tsformat), predecessortime:predectime.format (tsformat)) {
    for (def b in builds) {
      b_no = b.getNumber ()
      if (b_no < from || b_no > to) {
        println ("Skipped build: " + b_no)
        continue
      } else {
        println ("Processing build: " + b_no)
      }

      buildinfo (number:b.number, time:b.getTime ().format (tsformat)) {
        for (cs in b.changeSet) {
          for (ci in cs) {
            citime =  from_integrity_format.parse (ci.date)
            if (citime > predectime) {
              // Add only entries whose date is bigger than the cut-off date
              changeinfo (time:to_ts_format.format (citime), stime:ci.date, action:ci.action, author:ci.getAuthor().getDisplayName()) {
                changedfile (fname:ci.file.toString (), "rev":ci.rev, ci.msg)
              } // changeinfo
            } // if 
          } // for ci ...
        } // for cs ...
      } // buildinfo
    } // for i ...
  } // changereport

} // try 

finally {
  if (writer) {
    // Need an encoding ... due to umlauts ... 
    stream.write ("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>".getBytes ())
    stream.write (writer.toString ().getBytes ())
    stream.flush ()
    stream.close ()
  }
}
额外注意事项
  • 即便服务器和任务无显性变更,也可能因Jenkins Groovy沙箱规则隐性更新触发这类问题,但本次核心是语法层面的作用域问题,与沙箱无关。
  • 后续维护脚本时,需严格注意变量的作用域范围,避免跨代码块访问局部变量的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 05:31:17