Topic 3.2
The Jenkinsfile & Declarative Pipelines
In one line
A Jenkinsfile, committed directly into your repository, defines the entire pipeline as code — the same 'pipeline config lives in the repo, reviewed like any other change' principle every platform in this course shares.
Key ideas
- 01
A JENKINSFILE is a text file (conventionally named exactly
Jenkinsfile, no extension) committed to the ROOT of your repository, defining the complete pipeline — Jenkins reads and executes it directly, meaning the pipeline definition itself is version-controlled, reviewed via pull requests, and lives right alongside the code it builds, exactly the same principle Git's own course established for CI/CD configuration generally (Phase 4.4). - 02
DECLARATIVE PIPELINE syntax (the modern, recommended approach) uses a structured, predictable format built around
pipeline { agent { } stages { stage('Name') { steps { } } } }— genuinely more readable and more restrictive (in a good way) than Jenkins' older SCRIPTED pipeline syntax, which is a much more free-form Groovy script offering more raw power at the cost of being considerably harder to read and maintain. - 03
A
stageis a named, logical section of the pipeline (directly the same concept as Phase 0.2's universal 'stage') — Jenkins' own web UI visualizes each stage's status individually as the pipeline runs, making it immediately visible exactly which part of a multi-stage pipeline succeeded, failed, or is still in progress. - 04
A
postblock defines actions that run AFTER the main pipeline stages complete, regardless of outcome —post { success { } failure { } always { } }— genuinely useful for sending a notification, archiving test results, or cleaning up a workspace, specifically differentiated by whether the pipeline actually succeeded or failed. - 05
PARAMETERS (
parameters { string(name: 'VERSION', defaultValue: '1.0.0') }) let a pipeline accept input values when triggered manually — directly analogous to GitHub Actions'workflow_dispatchinputs (Phase 1.1) — genuinely useful for a deployment pipeline that needs a human to specify exactly which version to deploy, rather than always deploying whatever's most recent. - 06
sh(orbaton Windows agents) runs a raw shell command exactly like GitHub Actions'run:step — the vast majority of a Jenkinsfile's actual WORK typically happens through these plain shell commands (invoking Maven/Gradle, Phase 0.3, or a Docker build), with the Jenkinsfile's own declarative structure providing the surrounding orchestration, stages, and control flow around them.
Code & diagrams
A genuinely complete, realistic declarative pipeline — stages, a parameter, and differentiated post actions.
pipeline {
agent { label 'linux' }
parameters {
string(name: 'VERSION', defaultValue: '1.0.0', description: 'Version to build')
}
stages {
stage('Checkout') {
steps {
checkout scm // checks out the SAME commit that triggered this build
}
}
stage('Build') {
steps {
sh "mvn clean package -Dversion=${params.VERSION}"
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
post {
success {
echo "Build ${params.VERSION} succeeded"
}
failure {
echo "Build ${params.VERSION} failed — notifying the team"
// a real pipeline would send a Slack/email notification here
}
always {
cleanWs() // clean the agent's workspace regardless of outcome
}
}
}Explain it without notes
Why does committing the Jenkinsfile directly into the repository (rather than configuring the pipeline only through Jenkins' own web UI) matter for the same reasons Git's own course emphasized for CI/CD config generally?
What's the practical difference between a post block's success, failure, and always conditions?
Practice
Write a Jenkinsfile for a hypothetical project with at least three stages (checkout, build, test) and a post block differentiating success from failure.
If you have access to a Jenkins instance, commit a real Jenkinsfile to a test repository, configure a Pipeline job pointing at it, and run it, watching each stage's status update live in Jenkins' UI.
Trade-offs
- ↔
Declarative pipeline syntax is more readable and structured, but genuinely more restrictive than Jenkins' older scripted pipeline syntax — for a build with real, complex conditional logic or loops that declarative syntax struggles to express cleanly, a
script { }block WITHIN a declarative pipeline lets you drop into genuine Groovy scripting for just that specific piece, a pragmatic middle ground between the two styles rather than being forced to choose one exclusively.
Done when you can
I can write a declarative Jenkinsfile with multiple named stages.
I understand why committing the Jenkinsfile to the repository matters, same as any other CI/CD config.
I can use a post block to differentiate actions on success, failure, and always.