Как продолжить прошлый этап неудачи в синтаксисе декларации 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 step shenanigans. Я хочу истинные несколько этапов, а не один этап с шагом post always, который содержит всю мою другую логику.

Дополнительно

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

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

Ответ 1

Возможно, мне что-то не хватает, но идея декларативного, упрямого конвейера должна обеспечить покрытие самых простых случаев использования. В тот момент, когда вам нужно что-то, о чем не относится, вам нужно прибегнуть к сценарию, связанного с сценарием, это относится только к "требованию" "декларативного конвейера": теперь это не произойдет.

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

    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 получит замыкание и обернет его в различные фрагменты сантехники/шаблона.

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

Ответ 2

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

  • Этап 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 реагирует на их совокупный успех/неудачу.


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

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"'
        }
    }
}

Ответ 3

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

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 будет показан как неудачный:

Pipeline Example

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

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

Ответ 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 будет показан как неудачный:

Pipeline Example

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

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

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