groovy.lang.MisingPropertyException: No existe tal propiedad: sh para clase: groovy. Lang. Binding

Estoy tratando de construir un oleoducto en Jenkins que ejecute un comando en nodo y me informa del siguiente 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

El código fuente de Jenkinsfile que me refiero es de este https://github.com/nobuoka/jenkins-pipeline-sample-for-android/blob/master/Jenkinsfile. El éxito de la tubería hasta antes de la etapa 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 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 gradleTasks = []
            List 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 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
}

Encontré que la sugerencia necesita instalar plugin de seguridad del script pero no estoy seguro. ¿Alguna sugerencia de arreglarlo?

Pregunta hecha hace 3 años, 4 meses, 25 días - Por devepicenter


3 Respuestas:

  • Sin tener los números de línea disponibles y lo que parece muy mal formato en términos de pestañas en el archivo Jenkins siguiendo el rastro de la pila es bastante difícil de depurar.

    Sin embargo, sospecho que podría ser esta línea. sudo sh './gradlew assemble' como sudo no es un comando groovy válido. Si quieres correr el gris como sudo, entonces sería sh 'sudo ./gradlew assemble'

    Respondida el Dec 21, 2020 a las 03:47 - por codejuggernaut

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás viendo indica que el script que estás ejecutando en Jenkins está tratando de acceder a una propiedad llamada sh, pero no puede encontrar esta propiedad en la clase groovy.lang.Binding. Esto suele ocurrir cuando estás usando comandos de shell en un script de Jenkins Pipeline sin importar el método adecuado para hacerlo.

    Para ejecutar comandos de shell en un Jenkins Pipeline, debes usar el método sh proporcionado por Jenkins Pipeline. Este método no está directamente disponible en un script Groovy estándar, por lo que es posible que necesites importarlo explícitamente en tu script.

    Para solucionar este problema, puedes hacer lo siguiente:

    • Asegúrate de que estás importando el método `sh` al principio de tu Jenkinsfile. Puedes hacerlo con la siguiente línea:

    groovy
       import hudson.*
       

    • Modifica tus llamadas a comandos de shell para que utilicen el método `sh` correctamente. En lugar de `sudo sh './gradlew assemble'`, deberías usar:

    groovy
       sh "sudo ./gradlew assemble"
       

    • Verifica que tengas instalado el plugin de seguridad del script en tu instancia de Jenkins. Este plugin es necesario para ejecutar scripts de Groovy de forma segura en Jenkins.

    Una vez que hayas realizado estos cambios, prueba nuevamente ejecutar tu pipeline en Jenkins y verifica si el error ha sido solucionado. Espero que esta información te haya sido útil. ¡Buena suerte!

    Respondida el Dec 22, 2020 a las 03:44 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error groovy.lang.MissingPropertyException: No such property: sh for class: groovy.lang.Binding indica que el script de Jenkinsfile está intentando acceder a una propiedad sh que no existe en el contexto de ejecución actual. Aquí tienes algunas posibles soluciones:

    • Comprueba la sintaxis: El error podría deberse a un error tipográfico en el script. Comprueba si has escrito correctamente `sh` y si has incluido los paréntesis correctos.
    • Importa la API de Shell: El método `sh` no está disponible en el contexto de ejecución predeterminado de Jenkinsfile. Necesitas importarlo usando la siguiente declaración:

    groovy
       import groovy.transform.Field
       

    Asegúrate de colocar esta declaración al principio del script de Jenkinsfile.

    • Configura el plugin de Seguridad de Scripts: El plugin de Seguridad de Scripts de Jenkins proporciona un entorno seguro para ejecutar scripts de Jenkinsfile. Es posible que debas instalar y configurar este plugin para habilitar el uso seguro del método `sh`.

    Instala el plugin desde el Centro de actualizaciones de Jenkins. Una vez que el plugin esté instalado, ve a Administrar Jenkins > Configurar sistema. En la sección Seguridad de scripts, marca la casilla Activar seguridad de scripts. Haz clic en Guardar para aplicar los cambios.

    • Utiliza el método `withEnv`: Si estás intentando ejecutar un comando de shell que requiere variables de entorno personalizadas, puedes utilizar el método `withEnv` para establecerlas temporalmente:

    groovy
       withEnv(["ENVVAR": "value"]) {
          sh "yourcommand"
       }
       

    Si has verificado la sintax is y has importado la API de Shell, pero sigues obteniendo el error, es posible que haya un problema con el plugin de Seguridad de Scripts. Intenta desinstalar y volver a instalar el plugin para ver si eso resuelve el problema.

    Respondida el Dec 22, 2020 a las 03:51 - por Gemini

    Votos positivos: 0 | Votos negativos: 0