Невозможно запустить команду оболочки в Groovy в Jenkins

Я пытаюсь получить определенные значения от ведомого устройства, выполнив такие команды оболочки, как:

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

Метод, который я попытался написать для этого, следующий:

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

Теперь, когда я пытаюсь запустить первую команду:

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

Я получаю ОШИБКУ:

[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)

Я также пробовал:

output = command.execute().text

Но это ничего не возвращает.

У меня заканчиваются идеи о том, как запускать команды оболочки в Groovy в Jenkins и записывать результат.

ПОДРОБНЕЕ

Я работаю с общими библиотеками Jenkins. Я представил метод для моего Jenkinsfile по имени getLatestBuildDetails(). Этот метод определен в моей библиотеке. Одно из действий в рамках метода - локальное выполнение команд git. Итак, чтобы запускать любую команду оболочки локально, я создал функцию executeCommand, которая принимает фактическую команду для запуска в виде строки, выполняет ее и возвращает результат, который будет использоваться позже getLatestBuildDetails()


person Community    schedule 17.08.2018    source источник
comment
вы пробовали жестко его кодировать напрямую и пытались "git rev-parse HEAD"..execute().text   -  person rohit thomas    schedule 17.08.2018
comment
уверены, что .execute() подходит для jenkins-pipeline?   -  person StephenKing    schedule 17.08.2018
comment
А .. @ Джейсон Стэнли, ты уверен в том, что делаешь? sh - это этап Jenkins Pipelines, но остальная часть того, что вы публикуете, не Звучит не так много, как на самом деле вы используете конвейеры Jenkins. Не могли бы вы добавить более подробную информацию, где вы используете данный код?   -  person StephenKing    schedule 17.08.2018
comment
@StephenKing Я добавил немного больше перспективы. Функция executeCommand работает, только если я вызываю @NonCPS, иначе это не так.   -  person    schedule 17.08.2018


Ответы (2)


Классы библиотеки не могут напрямую вызывать такие шаги, как sh или git. Однако они могут реализовывать методы, выходящие за рамки охватывающего класса, которые, в свою очередь, вызывают шаги конвейера, например:

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

def checkOutFrom(repo) {
  git url: "[email protected]:jenkinsci/${repo}"
}

return this

Что затем можно вызвать из сценария конвейера:

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

У этого подхода есть ограничения; например, он предотвращает объявление суперкласса.

В качестве альтернативы, набор шагов может быть явно передан с помощью этого в библиотечный класс, в конструктор или только один метод:

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}"
  }
}

При сохранении состояния в классах, например, выше, класс должен реализовывать интерфейс Serializable. Это гарантирует, что конвейер, использующий класс, как показано в приведенном ниже примере, может правильно приостановить и возобновить работу в Jenkins.

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

Если библиотеке требуется доступ к глобальным переменным, таким как env, они должны быть явно переданы в классы или методы библиотеки аналогичным образом.

Вместо того, чтобы передавать множество переменных из скриптового конвейера в библиотеку,

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}"
  }
}

В приведенном выше примере показано, что сценарий передается в один статический метод, вызываемый из конвейера со сценариями следующим образом:

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

В вашем случае вы должны написать что-то вроде:

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:

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

Для получения дополнительной информации см. Документацию по общей библиотеке jenkins: https://jenkins.io/doc/book/pipeline/shared-libraries/

person grolegor    schedule 26.08.2018

Попробуйте выполнить этап sh вместо выполнения. :)

РЕДАКТИРОВАТЬ: Я бы выбрал execute() или, как мне кажется, еще лучше, grgit. Я думаю, что вы не получаете никакого вывода при запуске cmd.execute().text, потому что .text возвращает стандартный вывод команды, и ваша команда может использовать только стандартную ошибку в качестве вывода, вы можете проверить оба:

def process = cmd.execute()
def stdOut = process.inputStream.text
def stdErr = process.errorStream.text
person Jonatan Ivanov    schedule 17.08.2018
comment
В традиционном Jenkinsfile, да, это сработает :) но я работаю с общими библиотеками Jenkins, и сценарий оболочки вызывается из библиотеки. - person ; 17.08.2018
comment
К сожалению, я неправильно понял проблему, пожалуйста, проверьте мой обновленный ответ. - person Jonatan Ivanov; 26.08.2018
comment
У меня такая же проблема с Process попыткой выполнить команду curl. Мне нужно избавляться или это? stackoverflow .com / questions / 56574053 /. - person SSF; 13.06.2019