Jenkins — Level by Level›02 · Declarative pipelines

Lesson 02 of 8 · Level 1 — Foundations

Declarative pipelines

Write pipelines as code in a Jenkinsfile: the declarative structure (agent, stages, steps, post), conditions with when, parameters and environment variables, credentials without leaking them, timeouts, parallel stages and manual approval.

Beginner → Practitioner
Key wordsJenkinsfiledeclarative pipelineagentstagesstepspostwhenparametersenvironmentcredentials()withCredentialsoptionstimeoutparallelinput

Pipelines belong in the repository

A Jenkinsfile at the root of the repository defines the pipeline. It's versioned, reviewed in pull requests, and every branch can carry its own changes to the build. Jenkins has two syntaxes: declarative (structured, validated, recommended) and scripted (free-form Groovy). Use declarative; drop into script { } only where you must.

A Jenkinsfile is a recipe card stuck to the ingredients box. Whoever opens the box gets the right recipe for exactly those ingredients, and changing the recipe goes through the same checks as changing the food.

The structure

pipeline {
  agent { label 'linux' }                       // where it runs (lesson 06: Kubernetes pods)

  options {
    timeout(time: 30, unit: 'MINUTES')
    buildDiscarder(logRotator(numToKeepStr: '30'))
    disableConcurrentBuilds()
    timestamps()
  }

  parameters {
    booleanParam(name: 'RUN_E2E', defaultValue: false, description: 'Run end-to-end tests')
  }

  environment {
    APP = 'orders-api'
    REGISTRY = 'registry.example.com/shop'
  }

  stages {
    stage('Test') {
      parallel {
        stage('Unit') { steps { sh 'make test' } }
        stage('Lint') { steps { sh 'make lint' } }
      }
    }
    stage('E2E') {
      when { expression { params.RUN_E2E } }
      steps { sh 'make e2e' }
    }
    stage('Publish') {
      when { branch 'main' }
      steps { sh 'make image push' }               // lesson 03 does this properly
    }
  }

  post {
    always  { junit allowEmptyResults: true, testResults: 'reports/**/*.xml' }
    failure { echo "Build failed: ${env.BUILD_URL}" }
    cleanup { cleanWs() }
  }
}
Section Purpose
agent Where the pipeline (or a stage) runs
options Timeouts, retention, concurrency, timestamps
parameters Inputs when triggering manually
environment Variables for all stages (or per stage)
stages / stage / steps The work, in order; parallel for side-by-side
when Conditions: branch, tag, changeset, expression
post always, success, failure, unstable, cleanup handlers

Credentials without leaks

Store secrets in Jenkins credentials (or an external store through a plugin), never in the Jenkinsfile:

environment {
  REG = credentials('registry-creds')    // username/password: REG_USR and REG_PSW
}
steps {
  sh 'echo "$REG_PSW" | docker login -u "$REG_USR" --password-stdin registry.example.com'
  withCredentials([string(credentialsId: 'slack-token', variable: 'SLACK')]) {
    sh 'curl -s -H "Authorization: Bearer $SLACK" https://slack.com/api/auth.test'
  }
}
  • Use single quotes so the shell, not Groovy, expands the secret.
  • Jenkins masks known secret values in logs, but masking is best-effort: never echo a secret or write it to a file in the workspace.
  • Scope credentials to folders so a team's jobs only see their own.

Manual approval

stage('Approve prod') {
  when { branch 'main' }
  steps {
    timeout(time: 1, unit: 'HOURS') {
      input message: 'Promote to production?', submitter: 'release-managers'
    }
  }
}

Keep input steps outside an agent allocation (use agent none at the top level and per-stage agents), otherwise an executor sits idle while waiting for a human. In GitOps setups, the approval is usually a reviewed pull request instead (lesson 03).

Try it: a pipeline from a repository

  1. Put the Jenkinsfile above (with simple echo or make steps) in a Git repository.
  2. Create a Pipeline job with "Pipeline script from SCM" pointing at it, and run it.
  3. Add a username/password credential and use it with credentials(); check the console shows **** where the password would be.
  4. Break the syntax on purpose and validate it with the pipeline-model-converter/validate endpoint before running.

Recap

  • Jenkinsfile in the repo, declarative syntax.
  • agent, options, parameters, environment, stages/steps, when, post.
  • Secrets via credentials() / withCredentials, single-quoted shell steps, folder-scoped credentials.
  • Timeouts, build retention and post { always } for reports; input outside agent allocation.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.