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

