groovy.lang.MissingPropertyException:类groovy.lang.Binding没有这



我试图在Jenkins上构建一个管道,该管道在节点上运行命令并通知我以下错误:

groovy.lang.MissingPropertyException: No such property: sh for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:270)
at org.kohsuke.groovy.sandbox.impl.Checker$7.call(Checker.java:353)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:357)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:333)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:333)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:333)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.run(WorkflowScript:57)
at WorkflowScript.withGheStatusSender(WorkflowScript:150)
at WorkflowScript.run(WorkflowScript:56)
at WorkflowScript.withSlackNotifier(WorkflowScript:178)
at WorkflowScript.run(WorkflowScript:23)
at ___cps.transform___(Native Method)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
at sun.reflect.GeneratedMethodAccessor560.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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:174)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
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:185)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:400)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:312)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:276)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:136)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE

我引用的Jenkinsfile的源代码来自https://github.com/nobuoka/jenkins-pipeline-sample-for-android/blob/master/Jenkinsfile。管道成功,直到阶段前组装

Jenkinsfile:

stage 'Assemble'
withGheStatusSender('Assemble', env.GIT_COMMIT, 'Building') {
sudo sh './gradlew assemble'
}
stage 'Lint'
withGheStatusSender('Lint', env.GIT_COMMIT, 'Checking') {
// If you run the lint task, lint will be run for all variants, but with only one output.
// For the time being, specify each variant and lint it.
def pfs = ['']
def bts = ['release', 'debug']
List<String> variants = []
pfs.each { pf -> bts.each{ bt -> variants.add(pf + (pf.isEmpty() ? bt : bt.capitalize())) } }
// I want to use the List # collect method, but it doesn't work on Pipeline due to a bug in the groovy-cps library.
// See : https://issues.jenkins-ci.org/browse/JENKINS-26481
List<GString> gradleTasks = []
List<GString> outputFiles = []
variants.each {
gradleTasks.add(":app:lint${it.capitalize()}")
outputFiles.add("lint-results-${it}.html")
}
// テスト失敗時にも結果を保存するように try-catch する。
// Try-catch to save the result even if the test fails.
Throwable error = null
try { sh "./gradlew --stacktrace ${gradleTasks.join(' ')}" } catch (e) { error = e }
try {
publishHTML([
target: [
reportName: 'Android Lint Report',
reportDir: 'app/build/outputs/',
reportFiles: outputFiles.join(','),
],
// Lint でエラーが発生した場合はリポートファイルがないことを許容する。
// Allow Lint to have no report file if an error occurs.
allowMissing: error != null,
alwaysLinkToLastBuild: true,
keepAll: true,
])
} catch (e) { if (error == null) error = e }
if (error != null) throw error
}
stage 'Local Unit Test'
withGheStatusSender('Local Unit Test', env.GIT_COMMIT, 'Testing') {
runTestAndArchiveResult(':app:test', 'app/build/test-results', '*/TEST-*.xml')
}
// Emulator にバージョンアップで以下のものが使えなくなったので一旦コメントアウト。
// 社内では shell スクリプトで AVD の起動や終了をするようにした。
// Since the following items can no longer be used with the version upgrade to Emulator, comment out once.
// In-house, the shell script is used to start and stop AVD
/*
stage 'Instrumented Test'
try {
sh './gradlew :avd:startAvd'
sh './gradlew connectedAndroidTest'
} finally {
sh './gradlew :avd:killAvd'
}
*/
}   
}
/** GHE にステータスを通知する。 */
void postGheStatus(Map<String, String> params) {
// 送信する JSON をファイルに書き出しておく。
String jsonFileName = 'jenkins_pipeline_input_json.temp'
String jsonContent = groovy.json.JsonOutput.toJson([
state: params['state'],
target_url: env.BUILD_URL,
description: params['description'],
context: params['context'],
])
writeFile file: jsonFileName, text: jsonContent
// 実際に送信する際にはここのコメントアウトを外す。
/*
sh 'curl --insecure -H "Authorization: token ' + C.GHE_TOKEN + '" ' +
'"' + C.GHE_API + '/repos/' + C.GHE_REPO + '/statuses/' + params['commitHash'] + '" ' +
'-X POST ' +
'-d @' + jsonFileName
*/
}
/**
* GHE へのステータス通知を行ってタスクの実行を行う。
The chair of the GHE chair.
* タスク実行前に pending 状態を通知し、タスク完了後に、タスクの結果に応じて成功か失敗の状態を通知する。
Notify the pending status before executing the task, and notify the success or failure status after the task is completed, depending on the result of the task.
*/
void withGheStatusSender(String context, String commitHash, String firstDescription, Closure task) {
postGheStatus(context: context, commitHash: commitHash, state: 'pending', description: firstDescription)
try {
task()
postGheStatus(context: context, commitHash: commitHash, state: 'success', description: 'Success')
} catch (e) {
postGheStatus(context: context, commitHash: commitHash, state: 'failure', description: 'Failure')
throw e
}
}
/** Slack に投稿する。 */
/** Post to Slack. */
void postSlack(String text, boolean useNgJenkinsIcon) {
String slackUrl = C.SLACK_WEBHOOK_URL
String iconImageUrl = useNgJenkinsIcon ?
'成功時の Jenkins アイコン' :
'失敗時の Jenkins アイコン'
String payload = groovy.json.JsonOutput.toJson([
text: text,
icon_url: iconImageUrl,
])
// 実際に送信する際にはここのコメントアウトを外す。//Uncomment here when actually sending.
//sh "curl -X POST --data-urlencode 'payload=${payload}' ${slackUrl}"
}
/** タスクを実行し、実行後に成功か失敗かを Slack に投稿する。 */
//Execute the task and post to Slack whether it succeeded or failed after execution.
void withSlackNotifier(Closure task) {
echo "branch name : ${env.BRANCH_NAME}"
try {
task()
postSlack("Job for branch `${env.BRANCH_NAME}` succeeded! (<${env.BUILD_URL}|Open>)", false)
} catch (e) {
postSlack("Job for branch `${env.BRANCH_NAME}` failed! (<${env.BUILD_URL}|Open>)", true)
throw e
}
}
void runTestAndArchiveResult(String gradleTestTask, String resultsDir, String resultFilesPattern) {
// `test` タスクの入力と出力の両方とも更新がなければ `test` タスクがスキップされる (UP-TO-DATE) ので、
// スキップされないように出力ディレクトリを消しておく。
// The `test` task will be skipped (UP-TO-DATE) if both the input and output of the` test` task are not updated.
// Delete the output directory so that it will not be skipped.
sh "rm -rf ${resultsDir}"
// テスト失敗時にも結果を保存するように try-catch する//// Try-catch to save the result even if the test fails.
Throwable error = null
try { sh "./gradlew --stacktrace ${gradleTestTask}" } catch (e) { error = e }
try {
step $class: 'JUnitResultArchiver', testResults: "${resultsDir}/${resultFilesPattern}"
} catch (e) { if (error == null) error = e }
if (error != null) throw error
}

我发现这个建议需要安装脚本安全插件,但我不确定。有什么建议吗?

如果没有可用的行号,并且在堆栈跟踪之后的Jenkinsfile中的选项卡格式似乎非常糟糕,那么很难调试。

然而,我怀疑可能是这行sudo sh './gradlew assemble',因为sudo不是一个有效的groovy命令。如果你想像sudo一样运行gradlew,那么它将是sh 'sudo ./gradlew assemble'

相关内容

最新更新