DevOps Peach

DevOps & CI/CD · Jenkins Pipeline · Lesson 4 of 5

Advanced Pipeline Syntax

Per-stage and Docker agents, options timeout, triggers, when, parallel, matrix, input, script blocks and post with always, success, failure, unstable, fixed, regression and cleanup conditions.

Practice interactively →

pipeline {
  agent none
  options { timeout(time: 1, unit: 'HOURS') }
  triggers { cron('H 2 * * *') }
  parameters { choice(name: 'TARGET', choices: ['dev', 'prod']) }
  stages {
    stage('Test') {
      parallel {
        stage('Unit') {
          agent { docker { image 'node:22-alpine' } }
          steps { sh 'npm test' }
        }
        stage('Lint') {
          agent { label 'linux' }
          steps { sh 'npm run lint' }
        }
      }
    }
    stage('Deploy prod') {
      agent any
      when {
        allOf {
          branch 'main'
          expression { params.TARGET == 'prod' }
        }
      }
      steps {
        input message: 'Deploy to prod?'
        sh './deploy.sh prod'
      }
    }
  }
  post {
    failure { echo 'Build failed' }
    always  { junit 'reports/*.xml' }
  }
}
Block Meaning
Per-stage agent, docker { image ... } Each stage runs on its own agent/container (agent none at the top)
options { timeout(...) } Time limit for the whole pipeline or one stage
triggers cron('H 2 * * *'), pollSCM(...) — webhooks beat polling
when Stage conditions: branch, expression, environment, allOf/anyOf
parallel / matrix Run in parallel; matrix runs every axes combination (OS × browser)
input Pause for a human approval
script { } Embed Scripted-style Groovy for complex logic
flowchart LR
  R["Build result"] --> S{"success?"}
  S -- "yes" --> SU["success"]
  S -- "no" --> F["failure / unstable / aborted"]
  F --> UN["unsuccessful"]
  SU --> CH{"changed since last run?"}
  F --> CH
  CH -- "fail → success" --> FX["fixed"]
  CH -- "success → fail" --> RG["regression"]
  SU --> AL["always → cleanup (last)"]
  F --> AL

post: always, success, failure, unstable (tests failed but the build completed), aborted, changed, fixed, regression, unsuccessful (any result that is not success), cleanup (runs last).

Traps: confusing failure with unsuccessful; thinking cleanup runs before always; forgetting a stage agent when the top is agent none.

Command Meaning
java -jar jenkins-cli.jar -s http://localhost:8080/ -auth @/home/fresher/.jenkins-cli-auth build my-app-ci -p TARGET=prod -s Run with a parameter
java -jar jenkins-cli.jar -s http://localhost:8080/ -auth @/home/fresher/.jenkins-cli-auth console my-app-ci -f Follow the last build log

A matrix build

stage('Test matrix') {
  matrix {
    axes {
      axis { name 'NODE';    values '20', '22' }
      axis { name 'BROWSER'; values 'chrome', 'firefox' }
    }
    excludes {
      exclude {
        axis { name 'NODE'; values '20' }
        axis { name 'BROWSER'; values 'firefox' }
      }
    }
    agent { docker { image "node:${NODE}-alpine" } }
    stages { stage('Run') { steps { sh 'npm ci && npm test -- --browser=$BROWSER' } } }
  }
}

Each combination runs as its own branch in parallel; excludes removes combinations you do not need.

More options

Option Effect
buildDiscarder(logRotator(numToKeepStr: '20')) Keep only the last 20 builds
disableConcurrentBuilds() Never run two builds of this job at once
timestamps() Timestamp every log line
retry(2) Retry the whole pipeline or stage on failure
skipDefaultCheckout() Do not check out automatically; call checkout scm yourself

Approvals with timeouts

stage('Deploy prod') {
  when { branch 'main' }
  options { timeout(time: 1, unit: 'HOURS') }
  input { message 'Deploy to production?'; ok 'Deploy'; submitter 'release-managers' }
  steps { sh './deploy.sh prod' }
}

Without a timeout, an unanswered input holds an executor forever. Put input at stage level (as here) so no agent is allocated while waiting.

More when conditions

changeset 'frontend/**' runs a stage only when those files changed, tag 'v*' only for release tags, changeRequest() only for pull requests, and beforeAgent true evaluates the condition before allocating an agent, saving time on skipped stages.

Shared libraries

A shared library is a Git repository with reusable Groovy steps under vars/, for example vars/buildImage.groovy defining a buildImage() step. After configuring it under Manage Jenkins, any Jenkinsfile uses it with @Library('ci-lib') _ and calls buildImage(name: 'my-app'). This keeps dozens of repositories on one standard pipeline that a platform team can improve centrally.

Practice interactively →