3

I am trying to get certain values from the slave by running shell commands such as :

git rev-parse HEAD
git config --get remote.origin.url

The method that I have tried to write for this is :

def executeCommand(String command) {
    stdout = sh script: command, returnStdout: true
    return stdout.trim()
}

Now when I try to run the first command :

output = executeCommand('git rev-parse HEAD')

I get the ERROR :

[Running] groovy "/Users/user-a/Documents/cmd.groovy"
Caught: groovy.lang.MissingMethodException: No signature of method: cmd.sh() is applicable for argument types: (LinkedHashMap) values: [[script:git rev-parse HEAD, returnStdout:true]]
Possible solutions: is(java.lang.Object), use([Ljava.lang.Object;), run(), run(), any(), tap(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: cmd.sh() is applicable for argument types: (LinkedHashMap) values: [[script:git rev-parse HEAD, returnStdout:true]]
Possible solutions: is(java.lang.Object), use([Ljava.lang.Object;), run(), run(), any(), tap(groovy.lang.Closure)
    at cmd.executeCommand(cmd.groovy:2)
    at cmd.run(cmd.groovy:6)

I also tried:

output = command.execute().text

But this returns nothing.

Im running out of ideas on how to run shell commands in Groovy in Jenkins and record the output.

MORE DETAILS

I am working with Jenkins shared Libraries. I have exposed a method in for my Jenkinsfile by the name getLatestBuildDetails(). This method is defined within my library. One of the actions within the method is to execute the git commands locally. So inorder to run any shell command locally, I have created the executeCommand function which takes the actual command to run as a String and executes it and returns the output to be used later by getLatestBuildDetails()

  • did you try hardcoding it directly and trying `"git rev-parse HEAD"..execute().text` – rohit thomas Aug 17 '18 at 02:47
  • sure that `.execute()` fits to [tag:jenkins-pipeline]? – StephenKing Aug 17 '18 at 04:12
  • Ah.. @Jason Stanley, are you sure about what you are doing? `sh` is a step of the [Jenkins Pipelines](https://jenkins.io/doc/book/pipeline/), but the rest of what you're posting doesn't sound so much as you are actually using Jenkins pipelines. Can you please add more details, where you are using given code? – StephenKing Aug 17 '18 at 04:14
  • @StephenKing I added a bit more perspective. The `executeCommand` function only works if i call @NonCPS otherwise it does not. –  Aug 17 '18 at 13:28

3 Answers3

5

Library classes cannot directly call steps such as sh or git. They can however implement methods, outside of the scope of an enclosing class, which in turn invoke Pipeline steps, for example:

// src/org/foo/Zot.groovy
package org.foo;

def checkOutFrom(repo) {
  git url: "git@github.com:jenkinsci/${repo}"
}

return this

Which can then be called from a Scripted Pipeline:

def z = new org.foo.Zot()
z.checkOutFrom(repo)

This approach has limitations; for example, it prevents the declaration of a superclass.

Alternately, a set of steps can be passed explicitly using this to a library class, in a constructor, or just one method:

package org.foo
class Utilities implements Serializable {
  def steps
  Utilities(steps) {this.steps = steps}
  def mvn(args) {
    steps.sh "${steps.tool 'Maven'}/bin/mvn -o ${args}"
  }
}

When saving state on classes, such as above, the class must implement the Serializable interface. This ensures that a Pipeline using the class, as seen in the example below, can properly suspend and resume in Jenkins.

@Library('utils') import org.foo.Utilities
def utils = new Utilities(this)
node {
  utils.mvn 'clean package'
}

If the library needs to access global variables, such as env, those should be explicitly passed into the library classes, or methods, in a similar manner.

Instead of passing numerous variables from the Scripted Pipeline into a library,

package org.foo
class Utilities {
  static def mvn(script, args) {
    script.sh "${script.tool 'Maven'}/bin/mvn -s ${script.env.HOME}/jenkins.xml -o ${args}"
  }
}

The above example shows the script being passed in to one static method, invoked from a Scripted Pipeline as follows:

@Library('utils') import static org.foo.Utilities.*
node {
  mvn this, 'clean package'
}

In your case you should write something like:

def getLatestBuildDetails(context){
    //...
    executeCommand(context, 'git rev-parse HEAD')
    //...
}

def executeCommand(context, String command) {
    stdout = script.sh(script: command, returnStdout: true)
    return stdout.trim()
}

Jenkins file:

@Library('library_name') _
getLatestBuildDetails(this)

For more info see jenkins shared library documentation: https://jenkins.io/doc/book/pipeline/shared-libraries/

grolegor
  • 1,260
  • 1
  • 16
  • 22
0

I am also using shared libraries. This is how I have used in my code:

String getMavenProjectName() {
    echo "inside getMavenProjectName +++++++"
    // mavenChartName = sh(
    //         script: "git config --get remote.origin.url",
    //         returnStdout: true
    // ).trim()
    def mavenChartName = sh returnStdout:true, script: '''
    #!/bin/bash
    GIT_LOG=$(env -i git config --get remote.origin.url)
    basename "$GIT_LOG" .git; '''
    echo "mavenChartName: ${mavenChartName}"
    return mavenChartName
}

PS: Ignore the commented lines of code.

Pritish
  • 658
  • 3
  • 16
  • 38
-1

Try out the sh step instead of execute. :)

EDIT: I would go with execute() or which I think it is even better, grgit. I think you are not getting any output when you run cmd.execute().text because .text returns the standard output of the command and your command might only use the standard error as its output, you can check both:

def process = cmd.execute()
def stdOut = process.inputStream.text
def stdErr = process.errorStream.text
Jonatan Ivanov
  • 4,895
  • 2
  • 15
  • 30
  • 1
    In a traditional `Jenkinsfile`, yes this will work :) but I'm working with Jenkins Shared Libraries and the shell script is being called from a library. –  Aug 17 '18 at 13:39
  • Oops, sorry, I misunderstood the problem, please check my updated answer. – Jonatan Ivanov Aug 25 '18 at 22:23
  • I am having the same issue with `Process` trying to execute a `curl` command. Do I need to get rid or it? https://stackoverflow.com/questions/56574053/executing-curl-in-shared-library-jenkins-pipeline-using-process – SSF Jun 13 '19 at 06:49