Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

groovy.lang.MissingMethodException: No signature of method: sh() is applicable for argument types while testing AWS CLI commands in Groovy

$ groovy --version
Groovy Version: 2.4.15 JVM: 1.8.0_171 Vendor: Oracle Corporation OS: Mac OS X

I want execute some AWS CLI commands in Groovy, eventually in a Jenkinsfile to run in Jenkins of course.

But for prototyping, I want to code it on my Mac and execute it as a plain Groovy script. So I have this, for example.

#!/usr/bin/env groovy

def getEBSVolumes(awsRegion) {
  def regions
  if (awsRegion == "all") {
    regions = sh(returnStdout: true, script: """#!/usr/bin/env bash
                   aws ec2 describe-regions --output text|awk '{print \$3}'
                 """
                )
  }
  else {
    regions = awsRegion
  }
  echo "Regions: regions"
}

getEBSVolumes("all")

When I execute it, I get

$ ./x.groovy 
Caught: groovy.lang.MissingMethodException: No signature of method: x.sh() is applicable for argument types: (java.util.LinkedHashMap) values: [[returnStdout:true, script:#!/usr/bin/env bash
                   aws ec2 describe-regions --output text|awk '{print $3}'
                 ]]
Possible solutions: use([Ljava.lang.Object;), is(java.lang.Object), run(), run(), any(), each(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: x.sh() is applicable for argument types: (java.util.LinkedHashMap) values: [[returnStdout:true, script:#!/usr/bin/env bash
                   aws ec2 describe-regions --output text|awk '{print $3}'
                 ]]
Possible solutions: use([Ljava.lang.Object;), is(java.lang.Object), run(), run(), any(), each(groovy.lang.Closure)
    at x.getEBSVolumes(x.groovy:9)
    at x$getEBSVolumes.callCurrent(Unknown Source)
    at x.run(x.groovy:20)

Can someone please explain the cryptic error message? Thanks!

Note the code works when executed in a Jenkinsfile, hence I specifically asked about CLI Groovy.

like image 815
Chris F Avatar asked Jun 06 '18 13:06

Chris F


1 Answers

You wont be able to run this script locally with Groovy only, because it fails due to missing sh method in your script. This sh method is a step provided by Jenkins Pipeline DSL library - https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#code-sh-code-shell-script

I would suggest you running your local Jenkins - the easiest way to do it is to use an existing Docker image. I use for example following docker-compose.yml file:

jenkins:
  image: jenkins:2.60.3-alpine
  container_name: jenkins
  ports:
    - 8080:8080
  volumes:
    - ./home:/var/jenkins_home

and whenever I want to run my local Jenkins I just go the directory where I have this file stored, e.g.

cd ~/workspace/jenkins

and I simply call

docker-compose up -d

which boots Jenkins I can access via http://localhost:8080 In this local instance I am able to test pipeline scripts inside Groovy Sandbox or by setting up a scripted pipeline.

Alternative: JenkinsPipelineUnit testing library

If you want to unit test your pipeline scripts you can use JenkinsPipelineUnit library which allows you to unit test the flow of your pipeline. However in this case you would have to register your own sh method, because the BasePipelineTest class mocks it with NOOP:

helper.registerAllowedMethod("sh", [Map.class], null)

It means that each interaction with sh step gets counted but it does not trigger the script defined with script: '' property.

I would say that setting up your own local Jenkins sandbox where you can play around with Jenkinsfile scripts is the easiest way to start with.

like image 182
Szymon Stepniak Avatar answered Dec 31 '22 12:12

Szymon Stepniak