Skip to main content

Jenkinsfile — The Assembly Line Recipe

A Jenkinsfile is a text file committed to your Git repository that defines the entire CI/CD pipeline. Think of it as the assembly line recipe — it tells Jenkins exactly what to do, in what order, and where.

Anatomy of a Jenkinsfile​

A real Jenkinsfile for Campus Library
pipeline {
agent {
docker {
image 'node:20-alpine'
}
}

environment {
APP_NAME = 'campus-library'
DOCKER_IMAGE = "riya/${APP_NAME}:${env.BUILD_NUMBER}"
}

stages {
stage('Checkout') {
steps {
checkout scm
}
}

stage('Install') {
steps {
sh 'npm ci'
}
}

stage('Test') {
steps {
sh 'npm test'
}
}

stage('Build Docker Image') {
steps {
sh "docker build -t ${DOCKER_IMAGE} ."
}
}

stage('Push to Registry') {
steps {
withCredentials([usernamePassword(
credentialsId: 'dockerhub',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)]) {
sh "echo \$DOCKER_PASS | docker login -u \$DOCKER_USER --password-stdin"
sh "docker push ${DOCKER_IMAGE}"
}
}
}

stage('Deploy') {
steps {
sh "kubectl set image deployment/${APP_NAME} web=${DOCKER_IMAGE}"
}
}
}

post {
success {
echo 'Pipeline succeeded!'
}
failure {
echo 'Pipeline failed!'
}
}
}

Each section explained​

SectionPurposeAnalogy
agentWhere the pipeline runsWhich workstation
environmentVariables available everywhereThe factory's shared tools
stagesThe sequence of workAssembly line stations
stepsCommands within a stageActions at each station
postActions after the pipeline finishesQuality report after shipping

Environment Variables​

Setting environment variables
environment {
APP_PORT = '3000'
BUILD_NUMBER_TAG = "${env.BUILD_NUMBER}"
}

Jenkins provides built-in variables:

VariableMeaning
env.BUILD_NUMBERUnique build number (1, 2, 3...)
env.BUILD_URLURL of this build
env.JOB_NAMEName of the job
env.GIT_COMMITCurrent Git commit hash
env.GIT_BRANCHCurrent Git branch
Remember

env.BUILD_NUMBER is your best friend for tagging images. Every build gets a unique, traceable tag.

Credentials​

Never hardcode passwords. Use Jenkins credentials:

Using credentials
withCredentials([usernamePassword(
credentialsId: 'dockerhub',
usernameVariable: 'USER',
passwordVariable: 'PASS'
)]) {
sh 'echo $PASS | docker login -u $USER --password-stdin'
}
Using a secret file
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh 'kubectl get pods'
}
Common mistake

Never print credentials in logs. Jenkins masks $PASS in output, but be careful with other variables.

Parallel Execution — Multiple Workstations​

Run independent stages simultaneously:

Parallel stages
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'npm run test:unit'
}
}
stage('Integration Tests') {
steps {
sh 'npm run test:integration'
}
}
}
}
Remember

Parallel stages cut build time in half. Use them for independent tasks (unit tests + integration tests, linting + security scans).

When Conditions — Skip Stations​

Control when a stage runs:

Only on main branch
stage('Deploy') {
when {
branch 'main'
}
steps {
sh 'kubectl apply -f k8s/'
}
}
Only when build succeeds
stage('Notify') {
when {
success()
}
steps {
slackSend message: "Build ${env.BUILD_NUMBER} succeeded!"
}
}
Remember

when prevents unnecessary work. Don't deploy feature branches to production. Don't send failure notifications when the build succeeds.

Post Actions — What Happens After​

The post block runs regardless of success or failure:

Post actions
post {
always {
sh 'docker system prune -f'
}
success {
slackSend message: "Build ${env.BUILD_NUMBER} succeeded!"
}
failure {
mail to: 'team@campuslibrary.dev',
subject: "Build ${env.BUILD_NUMBER} failed",
body: "Check: ${env.BUILD_URL}"
}
}
ConditionWhen it runs
alwaysAlways, regardless of result
successOnly on success
failureOnly on failure
cleanupAlways, after all other post conditions
Remember

always is the place for cleanup (prune Docker images, remove temp files). failure is the place for alerts (email, Slack).

Input — Manual Approval Gate​

Require manual approval before deploying
stage('Deploy to Production') {
input {
message 'Deploy to production?'
ok 'Yes, deploy it!'
}
steps {
sh 'kubectl apply -f k8s/prod/'
}
}
Remember

Manual gates are the "quality inspector's signature." They prevent accidental production deployments.