Как вы устанавливаете статус параллельной ветви Jenkins stage или pipeline (нестабильный, сбой и т. д.) для использования в Stage view и Blue Ocean UI?

обзор

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

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

прогресса

в его нынешнем виде мой конвейер достигает этого, позволяя пользователю включать/исключать платформы в начале конвейера и разрешать конвейеру продолжать строительство, если платформа терпит неудачу (но помечая конвейер как сбой). Это позволяет архивировать файлы сборки / публикации gtests и т. д., которые могут выполняться на последующих этапах/шагах. Вот мой Jenkinsfile:

// Specify whether or not to build platform by default
def buildDefinitions = [ 'windows' : true , 'macos' : true , 'ubuntu' : true ]

// Keep track of builds that fail
def failedBuilds = [:]

stage('Build Customisation') {
    try {
        // Wait limited amount of time for user input
        timeout(time: 30, unit: 'SECONDS') {

            // Update the build definitions based on user input
            buildDefinitions = input(
                message: 'Toggle which builds to run (Abort will use default)',

                // Use custom global function to generate boolean input parameters based on a map
                // Sets default value to value in input map
                parameters: generateInputBoolParams( buildDefinitions )
            )
        }

    // Continue pipeline if user input not provided within time limit
    } catch ( error ) {
        echo 'Using default pipeline configuration...'
    }

    // Check that at least one build platform is selected
    if ( !mapContainsTrue( buildDefinitions ) ) {
        error 'No builds selected, aborting pipeline'
    }
}

stage('Conditional Build') {
    parallel (
        'Windows' : {
            // Prevent a build failure from terminating the pipeline after this stage
            try {
                // Check if windows build is set to run
                if ( buildDefinitions['windows'] ) {

                    node('windows') {
                        checkout(scm)
                        bat 'build.bat default-windows'
                    }
                } else {
                    echo 'Build was disabled by user'
                }

            // Catch an error in the build
            } catch ( error ) {
                // Make note that the build failed
                failedBuilds['windows'] = true

                // Set the pipeline status as failure
                currentBuild.result = 'FAILURE'
            }
        },

        'MacOS' : {
            try {
                if ( buildDefinitions['macos'] ) {
                    node('macos') {
                        checkout(scm)
                        sh './build.sh default-macos'
                    }
                } else {
                    echo 'Build was disabled by user'
                }
            } catch ( error ) {
                failedBuilds['macos'] = true
                currentBuild.result = 'FAILURE'
            }
        },

        'Ubuntu' : {
            try {
                if ( buildDefinitions['ubuntu'] ) {
                    node('ubuntu') {
                        checkout(scm)
                        sh './build.sh default-ubuntu'
                    }
                } else {
                    echo 'Build was disabled by user'
                }
                error 'test error'
            } catch ( error ) {
                failedBuilds['ubuntu'] = true
                currentBuild.result = 'FAILURE'
            }
        }
    )

    // Check if any builds have been marked as failed
    if ( mapContainsTrue( failedBuilds ) ) {

        // Remove failed builds from the original map of enabled builds
        def updatedBuildDefinitions = subtractMap( buildDefinitions, failedBuilds )

        // Check that there are builds left to run
        if ( mapContainsTrue( updatedBuildDefinitions ) ) {

            // Update the original build map
            buildDefinitions = updatedBuildDefinitions

            // Lists the failed builds and asks whether to continue or abort the pipeline
            timeout(time: 30, unit: 'SECONDS') {
                input(
                    message: 'Builds failed ' + getKeyset( failedBuilds ) + ', do you want to continue the pipeline and skip failed builds?'
                )
            }
        } else {
            // Throw an error to terminate the pipeline if no builds are left to run
            error 'No builds left to run'
        }
    }
}

stage('Conditional Downstream') {
    parallel (
        'Windows' : {
            if ( buildDefinitions['windows'] ) {
                echo 'You chose to run the windows build!'
            } else {
                echo 'The windows build was skipped'
            }
        },

        'MacOS' : {
            if ( buildDefinitions['macos'] ) {
                echo 'You chose to run the macos build!'
            } else {
                echo 'The macos build was skipped'
            }
        },

        'Ubuntu' : {
            if ( buildDefinitions['ubuntu'] ) {
                echo 'You chose to run the ubuntu build!'
            } else {
                echo 'The ubuntu build was skipped'
            }
        }
    )
}

и мой глобальный функции:

// subtractMap.groovy
def call ( map1, map2 ) {
    return map1 - map2
}

// mapContainsTrue.groovy
boolean call ( array ) {
    for ( entry in array ) {
        if ( entry.value == true ) {
            isBuildConfigValid = true
            return true
        } else {
            return false
        }
    }
}

// getKeyset.groovy
def call ( map ) {
    return map.keySet() as String[]
}

// generateInputBoolParams.groovy
def call ( array ) {
    def parameterList = []
    for ( item in array ) {
        parameterList.add( booleanParam(defaultValue: item.value, name: item.key) )
    }
    return parameterList
}

в то время как общая функциональность работает, ответ пользовательского интерфейса не делает, кроме маркировки конвейера как сбой. Я хотел бы отметить параллельную ветвь как сбой, чтобы в Blue Ocean UI было легко увидеть, какая платформа не удалось построить.

Blue Ocean UI с неудачной параллельной веткой в блоке try / catch

было бы также полезно отметить этап как неудачный, поэтому, когда не в Blue Ocean UI, вид сцены показывает, какой из них не удался (если это не произойдет, только если конвейер будет завершен на этом этапе), хотя после того, как Blue Ocean выйдет из бета-версии, это больше не будет проблемой.

Stage View failed stage (выше) и как есть (ниже)

вопрос

  • как я могу отметить параллельную ветвь как неудачную, чтобы она отображалась в Blue Ocean UI с красным крестом? Возможно, с переменной среды, такой как currentBuild.result

  • возможно ли подобное со всей сценой, чтобы она отображалась в виде сцены? (Менее важно)

1 ответов


ответ пользовательского интерфейса может быть достигнут путем обертывания как параллельного шага, так и шага этапа в блоке try, выбрасывая ошибку из блока try/catch в параллельной ветви до блока stage. Не так чисто, как установка свойства, но имеет правильный ответ пользовательского интерфейса для синего океана и представления сцены.

try {
    stage('example') {
        try {
            parallel (
                'A' : {
                    try {
                        // Example...
                    }
                    catch (error) {
                        // Mark branch as failed somewhere
                        throw error
                    }
                },
                'B' : {
                    try {
                        // Example...
                    }
                    catch (error) {
                        // Mark branch as failed somewhere
                        throw error
                    }
                }
            )
        }
        catch (error) {
            throw (error)
        }
        finally {
            // Parallel branch A failed, do you want to continue? etc...
        }
    }
}
catch (error) {
    println (error)
}