Труба Дженкинса sh, похоже, не уважает трубку в команде оболочки

Я использую файл Jenkins в конвейере версии 2.32.2.

По разным причинам я хочу извлечь строку версии из pom. Я надеялся, что мне не придется добавлять плагин поддержки maven и использовать оценку.

Я быстро придумал небольшое выражение sed, чтобы вытащить его из pom, который использует трубы и работает на командной строке в рабочем пространстве jenkins на исполнителе.

$ sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g' 1.0.0-SNAPSHOT

Вероятно, он может быть оптимизирован, но я хочу понять, почему конвейер, кажется, терпит неудачу при использовании команд shed. Я играл с различными строковыми форматами, и в настоящее время я использую строку slashy в долларах.

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

script {
    def ver_script = $/sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g'/$
    echo "${ver_script}"
    POM_VERSION = sh(script: "${ver_script}", returnStdout: true)
    echo "${POM_VERSION}"
}

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

[Pipeline] script
[Pipeline] {
[Pipeline] echo
sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g'
[Pipeline] sh
[FRA-198-versioned-artifacts-44SD6DBQOGOI54UEF7NYE4ECARE7RMF7VQYXDPBVFOHS5CMSTFLA] Running shell script
+ sed -n /<version>/,/<version/p pom.xml
+ head -1
+ sed s/[[:blank:]]*<\/*version>//g
sed: couldn't write 89 items to stdout: Broken pipe
[Pipeline] }
[Pipeline] // script

Есть ли какое-нибудь руководство по правильному использованию команд с каналами в файле jenkins?

Ответ 1

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

script {
    def ver_script = $/eval "sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g'"/$
    echo "${ver_script}"
    POM_VERSION = sh(script: "${ver_script}", returnStdout: true)
    echo "${POM_VERSION}"
}   

Ответ 2

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

script.sh:

#!/bin/sh
kubectl exec --container bla -i $(kubectl get pods | awk '/foo-/{ print $1 }') -- php /code/dostuff

Jenkinsfile:

stage('Run script with pipes') {
  steps {
    sh "./script.sh"
  }
}

Ответ 3

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

stage('Preparation') {
 version = getVersion()
 print "version : " + version
}
def getVersion() {
  def matcher = readFile('pom.xml') =~ '<version>(.+)</version>'
  matcher ? matcher[0][1] : null
}

дает вам:

[Pipeline] echo
releaseVersion : 0.1.24
[Pipeline] sh

Ответ 4

plug-utility-steps теперь включает readMavenPom, что позволяет получить доступ к версии следующим образом:

version = readMavenPom.getVersion()

Ответ 5

Поэтому ничто из вышеперечисленного не сработало для меня, используя скриптовый синтаксис Jenkinsfile с Groovy. Однако я смог заставить его работать. Тип цитат, которые вы используете, важен. В приведенном ниже примере я пытаюсь получить последний тег git из GitHub.

...

stage("Get latest git tag") {
  if (env.CHANGE_BRANCH == 'master') {
    sh 'git fetch --tags'
    TAGGED_COMMIT = sh(script: 'git rev-list --branches=master --tags --max-count=1', returnStdout: true).trim()
    LATEST_TAG = sh(script: 'git describe --abbrev=0 --tags ${TAGGED_COMMIT}', returnStdout: true).trim()
    VERSION_NUMBER = sh(script: "echo ${LATEST_TAG} | cut -d 'v' -f 2", returnStdout: true).trim()
    echo "VERSION_NUMBER: ${VERSION_NUMBER}"
    sh 'echo "VERSION_NUMBER: ${VERSION_NUMBER}"'
  }
}
...

Обратите внимание на то, как выполнение оболочки для назначения LATEST_TAG работает должным образом (назначение переменной для v2.1.0). Если бы мы попробовали одно и то же (с одинарными кавычками) назначить VERSION_NUMBER, это НЕ сработало бы - pipe все испортила. Вместо этого мы заключаем скрипт в двойные кавычки.

Первый эхо печатает VERSION_NUMBER: 2.1.0, а второй печатает VERSION_NUMBER:. Если вы хотите, чтобы VERSION_NUMBER был доступен в командах оболочки, вы должны назначить вывод команды оболочки для env.VERSION_NUMBER, как показано ниже:

...

stage("Get latest git tag") {
  if (env.CHANGE_BRANCH == 'master') {
    sh 'git fetch --tags'
    TAGGED_COMMIT = sh(script: 'git rev-list --branches=master --tags --max-count=1', returnStdout: true).trim()
    LATEST_TAG = sh(script: 'git describe --abbrev=0 --tags ${TAGGED_COMMIT}', returnStdout: true).trim()
    env.VERSION_NUMBER = sh(script: "echo ${LATEST_TAG} | cut -d 'v' -f 2", returnStdout: true).trim()
    echo "VERSION_NUMBER: ${VERSION_NUMBER}"
    sh 'echo "VERSION_NUMBER: ${VERSION_NUMBER}"'
  }
}
...

Первый эхо печатает VERSION_NUMBER: 2.1.0, а второй печатает VERSION_NUMBER: 2.1.0.

Ответ 6

Я знаю такой поздний ответ, но кто бы вы ни нуждались в решении без eval, вы можете использовать /bin/bash -c "script" для изготовления pipe

script {
    POM_VERSION = sh(script: "/bin/bash -c 'sed -n \'/<version>/,/<version/p\' pom.xml | head -1 | sed \'s/[[:blank:]]*<\/*version>//g\'\''", returnStdout: true)
    echo "${POM_VERSION}"
}

Единственная проблема этого метода - hellish escape, но наш мальчик будет обрабатывать подоболу pipes /bin/bash -c.