Issue
Im trying to build a pipeline on Jenkins that runs a command on node and informs me of the following error:
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
The source code of Jenkinsfile that I refer is from this https://github.com/nobuoka/jenkins-pipeline-sample-for-android/blob/master/Jenkinsfile. The pipeline success until before stage Assemble
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
}
I found that the suggestion need to install script security plugin but I am not sure. Any suggestion to fix it?
Solution
Without having the line numbers available and what seems very bad formatting in terms of tabs in the Jenkinsfile following the stack trace is quite hard to debug.
However I suspect it might be this line sudo sh './gradlew assemble'
as sudo
isnt a valid groovy command. If you are wanting to run the gradlew as sudo then it would be sh 'sudo ./gradlew assemble'
Answered By - apr_1985
Answer Checked By - Mildred Charles (JavaFixing Admin)