Труба Дженкинса 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
.