Как пройти этап сбоя в синтаксисе декларативного конвейера Jenkins

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

pipeline {
    agent any
    stages {
        stage('stage 1') {
            steps {
                echo "I need to run every time"
            }
        }
        stage('stage 2') {
            steps {
                echo "I need to run every time, even if stage 1 fails"
            }
        }
        stage('stage 3') {
            steps {
                echo "Bonus points if the solution is robust enough to allow me to continue *or* be halted based on previous stage status"
            }
        }
    }
}

Чтобы уточнить, я не ищу, как сделать это с помощью скриптового синтаксиса. Я пытаюсь понять, поддерживается ли этот вид управления потоком и формализован ли он в декларативном синтаксисе. С этой целью я постараюсь точно определить, что я ищу:

Необходимый

  • Нет попытки / уловить. Я не хочу опускаться в режим сценария или «оборачивать» свой декларативный конвейер в другой разделяемой библиотеке или блоке сценария.
  • Никаких махинаций. Я хочу действительно нескольких этапов, а не одного этапа с post always этапом, который содержит всю мою остальную логику

По желанию

  • Неудачный этап следует признать несостоявшимся; Я не хочу, чтобы неудавшийся этап отображался зеленым, потому что он был «пропущен» или «продолжен».
  • Сборка с любой неудачной стадией должна быть помечена красным (или желтым, или другим, кроме зеленого).

Связано, но недостаточно


person dolphy    schedule 10.07.2017    source источник
comment
Я думаю, что некоторые из ваших требований являются взаимоисключающими с концептуальной точки зрения. 1) Труба (линия) имеет два отверстия. Если он сломается, ничто не пройдет мимо точки останова, если вы не выполните некоторые работы, например try/catch. 2) Думая о Maven с его декларативными POM, если одна фаза (этап) выходит из строя, вся сборка терпит неудачу, без шанса преодолеть это, кроме устранения причины и повторной попытки. [продолжение следует]   -  person Gerold Broser    schedule 11.07.2017
comment
[продолжение] 3) Если посмотреть на пример конвейера Плагин Stage View с BuildDeployTestПродвигать этапы, это не имеет смысла продолжить, если один из этапов выйдет из строя.   -  person Gerold Broser    schedule 11.07.2017
comment
Хотя я полностью понимаю эту точку зрения, я не согласен с ней лично. Для меня управление потоком конвейера является абсолютно важной частью конструкции ... в противном случае оно слишком ограничительно, чтобы быть очень полезным. Даже наличие команды try / catch в синтаксисе сценариев кажется намеком на это; мой вопрос в том, как этот элемент управления потоком формализован декларативно. Может быть, ответа нет, я не знаю.   -  person dolphy    schedule 11.07.2017
comment
Я думаю (не) пока является ключевым словом в этом отношении, поскольку Справочник по синтаксису конвейера говорит: Declarative Pipeline - относительно недавнее дополнение к Jenkins Pipeline ‹sup› [1] ‹/sup›, которое представляет более упрощенный и самоуверенный синтаксис поверх конвейера. подсистемы. [...] 1. Версия 2.5 плагина Pipeline представляет поддержку синтаксиса декларативного конвейера   -  person Gerold Broser    schedule 13.07.2017


Ответы (4)


Теперь это возможно:

pipeline {
    agent any
    stages {
        stage('1') {
            steps {
                sh 'exit 0'
            }
        }
        stage('2') {
            steps {
                catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                    sh "exit 1"
                }
            }
        }
        stage('3') {
            steps {
                sh 'exit 0'
            }
        }
    }
}

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

Пример конвейера

Как вы уже догадались, вы можете свободно выбирать buildResult и stageResult, если вы хотите, чтобы он был нестабильным или что-то еще. Вы даже можете завершить сборку и продолжить выполнение конвейера.

Просто убедитесь, что ваш Jenkins обновлен, так как это довольно новая функция.

РЕДАКТИРОВАТЬ: Это вопрос, для которого изначально был написан этот ответ. Это также правильный ответ на несколько других вопросов, поэтому я и разместил там этот ответ. Это правильное решение для множества похожих проблем. Чтобы прояснить это, я адаптировал свои другие ответы к их конкретным вопросам. Я только скопировал ответ, чтобы сэкономить время. Это не значит, что это плохой правильный ответ.

person Erik B    schedule 10.07.2019

Возможно, мне что-то не хватает, но идея декларативного, упрямого конвейера состоит в том, чтобы охватить наиболее простые варианты использования. В тот момент, когда вам понадобится что-то, что самоуверенный не охватил, вы ДОЛЖНЫ прибегнуть к сценарию конвейера, это относится только к «требованию» «декларативного конвейера»: этого не произойдет сейчас.

Что касается других ваших «требований», они не имеют большого смысла, поскольку вся идея состоит в том, чтобы обернуть низкоуровневое уродство в разделяемые библиотеки, предоставляя пользователям такие конструкции, как:

    mylib.failable_stages({
      stages {
        stage('stage 1') {
          steps {
            echo "I need to run every time"
          }
        }
        stage('stage 2') {
          steps {
            echo "I need to run every time, even if stage 1 fails"
          }
        }
        stage('stage 3') {
          steps {
            echo "Bonus points if the solution is robust enough to allow me to continue *or* be halted based on previous stage status"
          }
        }
      }
    })

Естественно, вам нужно будет найти или реализовать такой mylib класс, и failable_stages получит закрытие и обернет его различными частями кода сантехники / шаблонов.

Надеюсь, это будет полезно.

person mvk_il    schedule 11.07.2017
comment
Спасибо за ответ. Технический ответ - это именно то, почему я сформулировал вопрос именно так. Я пытаюсь понять, формализован ли этот вид управления потоком в декларативном синтаксисе. Каждый раз, когда задают что-то близкое к этому вопросу, обычно вы отвечаете вот как это делается в сценарии. Это решение, но не ответ на вопрос. Это похоже на то, как я спрашиваю, как мне получить список каталогов в Python, и мне говорят просто использовать subprocess.check_output ([ls]). Это решение, но не ответ на вопрос. - person dolphy; 11.07.2017
comment
Я со всем уважением не согласен с целью разделяемых библиотек. Насколько я понимаю, они предназначены для абстрагирования кода для совместного использования, а не для уродливого кода. Если код помещен в общую библиотеку только для того, чтобы скрыть его, без намерения повторно использовать его в нескольких местах, то это ошибка языка или разработчика, или того и другого. Возможно, это всего лишь случай двух разных точек зрения, и, возможно, ответ на мой вопрос действительно таков: «Вы не можете этого сделать», но я действительно хочу знать это. Я задаю этот вопрос, потому что знаю, что я здесь не самый умный парень. - person dolphy; 11.07.2017
comment
В любом случае, тот факт, что ваша интерпретация вопроса не та, которую я хотел представить, означает, что мне нужно что-то переформулировать. Я добавил пояснение, дайте мне знать, поможет это или нет! - person dolphy; 11.07.2017
comment
Привет, @dolphy. Мне сейчас лучше. Удален параграф «Этика». По-прежнему не понятно, почему вы застряли на декларативности. Также есть другой путь: 1. Хакерство: выполняйте этапы внутри parallel шагов с одним элементом. У них есть параметр, запрещающий сборку в случае сбоя внутренних шагов. 2. Истинным решением было бы расширить stage, добавив к нему дополнительный логический параметр. - person mvk_il; 14.07.2017
comment
@dolphy, на этот раз моя плохая фраза. Так получилось, что код, которым вы часто делитесь, без абстракции делает вашу работу более приятной. Это само по себе некрасиво. К тому же «обертки» делают код вложенным, что тоже некрасиво. Так что даже если отбросить красоту, чистую логику и структуру, визуальная привлекательность и удобочитаемость будут хуже без разделяемых библиотек. ИМХО конечно. - person mvk_il; 14.07.2017
comment
@dolphy, забыл упомянуть, что мои клиенты обычно уже работают вольным стилем. Так что заставить их учиться хорошо не всегда вызывает у сотрудников крайний восторг. Так что заставлять их поддерживать короткие рабочие места - большой плюс. - person mvk_il; 14.07.2017

Я думаю, это зависит от того, насколько рабочие места зависят друг от друга. Исходя из вашего примера, я бы предположил, что

  • этап 1 не зависит от всех остальных этапов, поскольку он является первым
  • этап 2 не зависит от всех других этапов, потому что этап 1 может немедленно выйти из строя, а этап 2 все равно потребуется для запуска
  • этап 3 зависит от результата этапа 1 и этапа 2

Таким образом, соответствующий конвейер может быть

pipeline {
    stages {
        stage('Independent tasks') {
            parallel {
                stage('stage 1') {
                    steps {
                        sh 'exit 1' // failure
                    }
                }
                stage('stage 2') {
                    steps {
                        echo 'Happens even so stage 1 fails'
                        sh 'exit 0' // success
                    }
                }
            }
            post {  // 'stage 3'
                failure {
                    echo "... at least one failed"
                }
                success {
                    echo "Success!"
                }
            }
        }
        stage ('stage 4') {
            steps {
                echo 'Happens only if all previous succeed'
            }
        }
    }
}

этап 1 и этап 2 будут выполняться всегда, этап 3 реагирует на их совокупный успех / неудачу.


Дополнительная мысль: эта концепция работает только «в конце» вашего конвейера. Если он вам нужен где-то посередине и сборка должна продолжаться, вы можете переместить его в отдельную работу и использовать _ 2_ плагин.

pipeline {
    stages {
    stage('Start own job for stage 1, 2, 3') {
        steps {
            build job: 'stageOneTwoThree', propagate: false, wait: true
        }
    }
    stage ('stage 4') {
        steps {
            echo 'Happens always, because "propagate: false"'
        }
    }
}
person newur    schedule 09.03.2019

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

@Library('instanceGroups')
import x.z.y.jenkins.libraries.SlackNotifier

def slackHelper = new x.z.y.jenkins.libraries.SlackNotifier(env)
final String projectName = "pomeranian"
final String featureBranchPattern = "f_"

pipeline {
    agent any
    options { disableConcurrentBuilds() }

    stages {
        stage('clean') {
            steps {
                script {
                    try {
                        echo 'Current Branch...' + env.BRANCH_NAME
                        sh 'rm -rf /var/lib/jenkins/.gradle/caches'
                        sh './gradlew clean'
                    } catch (e) {
                        currentBuild.result = 'FAILURE'
                        slackHelper.buildGenericJobFailureNotificationMessage()
                        throw e
                    }
                }
            }
        }

        stage('compile') {
            steps {
                script {
                    try {
                        sh "./gradlew compileJava"
                    } catch (e) {
                        currentBuild.result = 'FAILURE'
                        slackHelper.getCompilationFailureSlackNotificationMessage()
                        throw e
                    }
                }
            }
        }

        stage('test') {
            steps {
                script {
                    try {
                        sh "./gradlew test"
                    } finally {
                        junit 'build/test-results/test/*.xml'

                        slackHelper.getTestStatuses(currentBuild)
                        slackHelper.buildUnitTestSlackNotificationMessage()
                    }
                }
            }
        }

        stage('publish 2 nexus') {
            steps {
                script {
                  // some code
                }
            }
        }

        stage('git tagging') {
            steps {
                script {
                    // some more code...
            }
        }
    }


    post {
        always {
            script {
                slackHelper.finalBuildStatusMessage(currentBuild)
                slackSend(channel: '#ci-cd', attachments: slackHelper.getFinalSlackMessage())
            }
        }
    }
}
person smaikap    schedule 24.10.2019