Scripted Control Flow

Groovy Control Flow Inside a Scripted Pipeline

Loops, conditions, maps and try/catch/finally work as in Groovy, which makes dynamic pipelines easy: the parallel step accepts a map of branch names to closures, built at run time:

scr-flow: branches from a loop, and error handlingPython
def genres = ['Fiction', 'Cooking', 'Travel']
def branches = [:]
for (g in genres) {
  def genre = g                                  // a fresh variable for each closure
  branches[genre] = { echo "checking ${genre}" }
}
stage('Per genre') { parallel branches }
stage('Smoke test') {
  try {
    node('linux') { sh 'exit 3' }
  } catch (err) {
    echo "Caught: ${err.message}"
    currentBuild.result = 'UNSTABLE'
  } finally {
    echo 'finally runs either way'
  }
}
Output
checking Fiction
...
checking Cooking
...
checking Travel
...
Caught: script returned exit code 3
...
finally runs either way
Finished: UNSTABLE

The def genre = g line matters. Without it, a test job whose closures used the loop variable g directly printed "checking Travel" three times: every closure captured the same variable, which held the last value by the time the branches ran. The catch turned a failed step into an UNSTABLE build instead of a failure, logic that Declarative can express only through post conditions or a script block.