Сценарий jenkinsfile параллельной стадии
Я пытаюсь написать сценарий Jenkinsfile, используя отличный DSL, который будет иметь параллельные шаги в наборе этапов.
Вот мой файл jenkinsfile:
node {
stage('Build') {
sh 'echo "Build stage"'
}
stage('API Integration Tests') {
parallel Database1APIIntegrationTest: {
try {
sh 'echo "Build Database1APIIntegrationTest parallel stage"'
}
finally {
sh 'echo "Finished this stage"'
}
}, Database2APIIntegrationTest: {
try {
sh 'echo "Build Database2APIIntegrationTest parallel stage"'
}
finally {
sh 'echo "Finished this stage"'
}
}, Database3APIIntegrationTest: {
try {
sh 'echo "Build Database3APIIntegrationTest parallel stage"'
}
finally {
sh 'echo "Finished this stage"'
}
}
}
stage('System Tests') {
parallel Database1APIIntegrationTest: {
try {
sh 'echo "Build Database1APIIntegrationTest parallel stage"'
}
finally {
sh 'echo "Finished this stage"'
}
}, Database2APIIntegrationTest: {
try {
sh 'echo "Build Database2APIIntegrationTest parallel stage"'
}
finally {
sh 'echo "Finished this stage"'
}
}, Database3APIIntegrationTest: {
try {
sh 'echo "Build Database3APIIntegrationTest parallel stage"'
}
finally {
sh 'echo "Finished this stage"'
}
}
}
}
Я хочу иметь 3 этапа: сборка; Интеграционные тесты и системные тесты. На двух этапах тестирования я хочу, чтобы 3 набора тестов выполнялись параллельно, каждый на своей базе данных.
У меня есть 3 доступных исполнителя. Один на мастере, 2 агента и я хочу, чтобы каждый параллельный шаг выполнялся на любом доступном исполнителе.
Я заметил, что после запуска конвейера я вижу только три этапа, каждый из которых выделен зеленым цветом. Я не хочу просматривать журналы для этой стадии, чтобы определить, были ли какие-либо параллельные шаги в этой стадии успешными / нестабильными / неудачными.
Я хочу видеть 3 шага на моих этапах тестирования - помеченных зеленым, желтым или красным (Успешно, нестабильно или неудачно).
Я рассмотрел возможность расширения тестов на их собственные этапы, но понял, что параллельные этапы не поддерживаются (кто-нибудь знает, будет ли это когда-либо поддерживаться?), Поэтому я не могу сделать это, поскольку конвейер может занять слишком много времени для завершения,
Любое понимание будет высоко ценится, спасибо
8 ответов
В скриптовом конвейере Jenkins параллель (...) берет карту, описывающую каждый этап, который будет построен. Поэтому вы можете программно построить этапы сборки заранее, шаблон, который позволяет гибкое последовательное / параллельное переключение.
Я использовал код, похожий на этот, где prepareBuildStages возвращает список карт, каждый элемент списка выполняется последовательно, в то время как карта описывает параллельные этапы в этой точке.
// main script block
// could use eg. params.parallel build parameter to choose parallel/serial
def runParallel = true
def buildStages
node('master') {
stage('Initialise') {
// Set up List<Map<String,Closure>> describing the builds
buildStages = prepareBuildStages()
println("Initialised pipeline.")
}
for (builds in buildStages) {
if (runParallel) {
parallel(builds)
} else {
// run serially (nb. Map is unordered! )
for (build in builds.values()) {
build.call()
}
}
}
stage('Finish') {
println('Build complete.')
}
}
// Create List of build stages to suit
def prepareBuildStages() {
def buildList = []
for (i=1; i<5; i++) {
def buildStages = [:]
for (name in [ 'one', 'two', 'three' ] ) {
def n = "${name} ${i}"
buildStages.put(n, prepareOneBuildStage(n))
}
buildList.add(buildStages)
}
return buildList
}
def prepareOneBuildStage(String name) {
return {
stage("Build stage:${name}") {
println("Building ${name}")
sh(script:'sleep 5', returnStatus:true)
}
}
}
Результирующий конвейер выглядит как:
Существуют определенные ограничения на то, что может быть вложено в параллельный блок, подробные сведения см. В документации конвейера. К сожалению, большая часть ссылок кажется смещенной в сторону декларативного конвейера, несмотря на то, что она довольно менее гибкая, чем сценарий (IMHO). Страница примеров конвейера была наиболее полезной.
Вот простой пример без циклов или функций, основанный на сообщении @Ed Randall:
node('docker') {
stage('unit test') {
parallel([
hello: {
echo "hello"
},
world: {
echo "world"
}
])
}
stage('build') {
def stages = [:]
stages["mac"] = {
echo "build for mac"
}
stages["linux"] = {
echo "build for linux"
}
parallel(stages)
}
}
... что дает следующее:
Обратите внимание, что значения карты не обязательно должны быть этапами. Вы можете указать шаги напрямую.
Вот пример из их документов:
Параллельное исполнение
Пример в приведенном выше разделе выполняет тесты на двух разных платформах в линейной серии. На практике, если выполнение контрольной проверки занимает 30 минут, этап "Тест" теперь занимает 60 минут!
К счастью, Pipeline имеет встроенную функциональность для параллельного выполнения частей Scripted Pipeline, реализованную в метко названном параллельном шаге.
Рефакторинг приведенного выше примера для использования параллельного шага:
// Jenkinsfile (Scripted Pipeline)
stage('Build') {
/* .. snip .. */
}
stage('Test') {
parallel linux: {
node('linux') {
checkout scm
try {
unstash 'app'
sh 'make check'
}
finally {
junit '**/target/*.xml'
}
}
},
windows: {
node('windows') {
/* .. snip .. */
}
}
}
Чтобы упростить ответ @Ed Randall здесь. Помните, что это сценарий Jenkinsfile (не декларативный)
stage("Some Stage") {
// Stuff ...
}
stage("Parallel Work Stage") {
// Prealocate dict/map of branchstages
def branchedStages = [:]
// Loop through all parallel branched stage names
for (STAGE_NAME in ["Branch_1", "Branch_2", "Branch_3"]) {
// Define and add to stages dict/map of parallel branch stages
branchedStages["${STAGE_NAME}"] = {
stage("Parallel Branch Stage: ${STAGE_NAME}") {
// Parallel stage work here
sh "sleep 10"
}
}
}
// Execute the stages in parallel
parallel branchedStages
}
stage("Some Other Stage") {
// Other stuff ...
}
Обратите внимание на фигурные скобки. Это приведет к следующему результату (с плагином BlueOcean Jenkins):
Я также пробовал подобные шаги, чтобы выполнить параллельные этапы и отобразить их все в виде этапа. Вы должны написать этап внутри параллельного шага, как показано в следующем блоке кода.
// Jenkinsfile (Scripted Pipeline)
stage('Build') {
/* .. Your code/scripts .. */
}
stage('Test') {
parallel 'linux': {
stage('Linux') {
/* .. Your code/scripts .. */
}
}, 'windows': {
stage('Windows') {
/* .. Your code/scripts .. */
}
}
}
Приведенный выше пример с FOR неверен, поскольку переменная STAGE_NAME будет перезаписываться каждый раз, у меня была та же проблема, что и у Wei Huang.
Нашел решение здесь:
https://www.convalesco.org/notes/2020/05/26/parallel-stages-in-jenkins-scripted-pipelines.html
def branchedStages = [:]
def STAGE_NAMES = ["Branch_1", "Branch_2", "Branch_3"]
STAGE_NAMES.each { STAGE_NAME ->
// Define and add to stages dict/map of parallel branch stages
branchedStages["${STAGE_NAME}"] = {
stage("Parallel Branch Stage: ${STAGE_NAME}") {
// Parallel stage work here
sh "sleep 10"
}
}
}
parallel branchedStages
Я использовал, как показано ниже, где три этапа параллельны.
def testCases() {
stage('Test Cases') {
def stages = [:] // declaring empty list
stages['Unit Testing'] = {
sh "echo Unit Testing completed"
}
stages['Integration Testing'] = {
sh "echo Integration Testing completed"
}
stages['Function Testing'] = {
sh "echo Function Testing completed"
}
parallel(stages) // declaring parallel stages
}
}
Я использовал stage{}
в параллельных блоках по несколько раз. Затем каждый этап отображается в виде этапа. Родительский этап, который содержит parallel
не включает в себя время для всех параллельных этапов, но каждый параллельный этап отображается в виде этапа.
В синем океане параллельные этапы появляются отдельно вместо показа этапов. Если есть родительский этап, он отображается как родитель параллельных этапов.
Если у вас нет такого опыта, возможно, стоит обновить плагин.