Jenkins动态创建参数报错:groovy.lang.MissingPropertyException
Jenkins动态生成Choice参数后访问params.STEP_1报MissingPropertyException问题解决
问题描述
我尝试基于AWS Parameter Store中的子项目数量动态创建Choice参数,参数已成功生成,但访问params.STEP_1时Jenkins抛出groovy.lang.MissingPropertyException错误。
原代码示例
def jobProperties() { params = jobParams() properties([ parameters( params ) ]) } def jobParams() { def allChoices = [] // 从AWS Parameter Store获取子项目列表 def paramChoices = sh(script:'echo $(aws ssm get-parameter --name "PATH" --query Parameter.Value --region $(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region) --with-decryption | xargs)',returnStdout: true).trim() // def paramChoices = "proj1,proj2,proj3,proj4" def commonChoices = paramChoices.split(",") as List // 动态生成Choice参数 for (int i = 1; i < commonChoices.size(); i++) { def name = "STEP_${i}" allChoices += choice(name: name, choices: commonChoices) } return allChoices } pipeline { agent any stages { stage('Prepare') { steps { script { jobProperties() echo $(params.STEP_1) } } } } }
错误信息
Also: org.jenkinsci.plugins.workflow.actions.ErrorAction$ErrorId: 1c76a536-17b4-4ba2-bf64-9ae0224b51f7 groovy.lang.MissingPropertyException: No such field found: field org.jenkinsci.plugins.workflow.cps.UninstantiatedDescribableWithInterpolation STEP_1 at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.unclassifiedField(SandboxInterceptor.java:402) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:386) at org.kohsuke.groovy.sandbox.impl.Checker$7.call(Checker.java:375) at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:379) at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:342) at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29) at org.jenkinsci.plugins.workflow.cps.LoggingInvoker.getProperty(LoggingInvoker.java:121) at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20) at WorkflowScript.run(WorkflowScript:40) at ___cps.transform___(Native Method) at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:73) at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30) at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:65) at jdk.internal.reflect.GeneratedMethodAccessor263.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21) at com.cloudbees.groovy.cps.Next.step(Next.java:83) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:152) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:146) at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:136) at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:275) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:146) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:187) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:423) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:331) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:295) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:97) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:139) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:68) at jenkins.util.ErrorLoggingExecutorService.lambda$wrap$0(ErrorLoggingExecutorService.java:51) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840)
问题原因及解决方案
1. 动态参数生效时机问题
Jenkins声明式流水线中,properties()方法设置的参数仅会在下一次构建时生效,当前构建无法访问刚设置的参数。如果需要在当前构建中使用动态生成的参数,需调整参数生成逻辑到流水线初始化阶段。
2. 语法错误
原代码中echo $(params.STEP_1)是Shell语法,Groovy中应改为echo "${params.STEP_1}"或echo params.STEP_1。
3. 循环边界问题
原代码for (int i = 1; i < commonChoices.size(); i++)会跳过最后一个参数生成(因为是小于号),应改为i <= commonChoices.size()确保生成对应数量的参数。
修正后的代码示例(当前构建可访问参数)
将参数生成逻辑直接放到声明式流水线的parameters块中,参数会在构建启动前初始化,当前构建可正常访问:
def jobParams() { def allChoices = [] // 从AWS Parameter Store获取子项目列表 def paramChoices = sh(script:'echo $(aws ssm get-parameter --name "PATH" --query Parameter.Value --region $(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region) --with-decryption | xargs)',returnStdout: true).trim() // def paramChoices = "proj1,proj2,proj3,proj4" def commonChoices = paramChoices.split(",") as List // 动态生成Choice参数 for (int i = 1; i <= commonChoices.size(); i++) { def name = "STEP_${i}" allChoices += choice(name: name, choices: commonChoices) } return allChoices } pipeline { agent any // 构建前初始化动态参数 parameters(jobParams()) stages { stage('Prepare') { steps { script { echo "${params.STEP_1}" } } } } }
替代方案(构建过程中动态获取参数)
如果需要在构建过程中动态生成参数并立即使用,可改用input步骤:
pipeline { agent any stages { stage('Prepare') { steps { script { def paramChoices = sh(script:'echo $(aws ssm get-parameter --name "PATH" --query Parameter.Value --region $(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region) --with-decryption | xargs)',returnStdout: true).trim() def commonChoices = paramChoices.split(",") as List // 动态生成选项并获取用户输入 def step1Choice = input( message: '选择STEP_1的项目', parameters: [choice(name: 'STEP_1', choices: commonChoices)] ) echo "STEP_1选择的项目是: ${step1Choice}" } } } } }
内容的提问来源于stack exchange,提问作者Deepakvg
相关产品推荐
相关产品推荐

