Jenkins Course
Pipeline Triggers
A pipeline that only runs when someone clicks a button isn't automation — it's just a fancy script. Triggers are what make Jenkins actually hands-free. This lesson covers every trigger type and exactly when to use each one.
This lesson covers
SCM polling vs webhooks → Scheduled builds with cron → Upstream triggers → The before/after comparison that explains why polling is dying out → Setting up a GitHub webhook step by step
Without a trigger, every Jenkins build is a manual action. Someone opens the browser, finds the job, clicks Build Now. That works fine when you're learning. In production it's a liability — humans forget, humans are on holiday, humans are asleep when the 3 AM hotfix goes in.
Triggers are the mechanism that connects an event in the world — a code push, a schedule, another job completing — to a Jenkins pipeline run. Get triggers right and your pipeline runs itself.
Polling vs Webhooks — The Core Choice
Most teams starting out use SCM polling. Most teams who've been running Jenkins for a year switch to webhooks. Here's the analogy that makes the difference obvious:
The Phone Check Analogy
SCM polling is like checking your phone every 5 minutes to see if someone sent you a message. Most of the time there's nothing new. You're wasting effort — but eventually you catch the message.
Webhooks are push notifications. Your phone buzzes the exact moment the message arrives. No polling. No wasted checks. Immediate response.
SCM Polling — The Cost
- Jenkins hits the Git server every N minutes — even with no commits
- Adds load to your Git server at scale
- Delay between push and build (up to the poll interval)
- Works without any external configuration — good for restricted networks
Webhooks — The Right Way
- GitHub/GitLab calls Jenkins instantly on push
- Zero unnecessary requests — Jenkins only wakes when needed
- Build starts within seconds of the push
- Requires Jenkins to be reachable from the internet
All Four Trigger Types at a Glance
pollSCM
Jenkins checks the repo on a schedule. Simple. Works anywhere. Adds latency and server load.
GitHub Webhook
Git server calls Jenkins on push. Instant. Efficient. Requires Jenkins to be network-reachable.
cron Schedule
Run on a time schedule — nightly builds, weekly reports, daily backups. No code change needed.
upstream
Run when another Jenkins job finishes. Chains pipelines — build passes, deploy fires automatically.
All Four Triggers in One Pipeline
The scenario:
You're a DevOps engineer at a fintech company setting up triggers for the risk-engine service. The team wants the pipeline to fire on every push to main via webhook, run a nightly full regression, and automatically trigger a deploy pipeline when tests pass. You also need polling as a fallback while the network team configures the webhook.
New terms in this code:
- pollSCM('H/5 * * * *') — Jenkins checks the SCM for new commits on a schedule.
H/5means every 5 minutes with a random per-job offset so all jobs don't hammer Git at the same second. - cron('H 2 * * 1-5') — runs the pipeline on a fixed schedule at 2 AM on weekdays, regardless of whether any code changed.
- upstream() — fires this pipeline when a named upstream job completes with a given result.
hudson.model.Result.SUCCESSmeans the upstream job must have passed. - githubPush() — activates the GitHub webhook trigger. When GitHub sends a push event to Jenkins' webhook URL, this trigger fires. Requires the GitHub plugin.
- currentBuild.getBuildCauses() — returns a list of objects describing what triggered the build. You can inspect these to change pipeline behaviour based on trigger type.
- triggeredBy 'TimerTrigger' — a
whencondition that only evaluates true when the build was started by a cron schedule. Lets you run extra stages on nightly builds without touching push-triggered builds.
pipeline {
agent { label 'linux' }
triggers {
// Trigger 1: GitHub webhook — fires instantly when code is pushed
// Requires the GitHub plugin and a webhook in the repo settings
// GitHub sends a POST to http://YOUR-JENKINS-URL/github-webhook/
githubPush()
// Trigger 2: SCM polling — fallback while webhook is being set up
// Check every 5 minutes — comment out once webhook is working
pollSCM('H/5 * * * *')
// Trigger 3: Nightly cron — full regression at 2 AM on weekdays
// Runs regardless of whether any code was pushed that day
cron('H 2 * * 1-5')
// Trigger 4: Upstream — fire when risk-engine-build succeeds
// Creates an automated chain: build job passes → this pipeline fires
upstream(
upstreamProjects: 'risk-engine-build',
threshold: hudson.model.Result.SUCCESS
)
}
environment {
APP_NAME = 'risk-engine'
}
stages {
stage('Identify Trigger') {
steps {
script {
// Inspect what triggered this build — useful for logs and decisions
def causes = currentBuild.getBuildCauses()
def triggerType = 'Unknown'
if (causes.any { it._class.contains('GitHubPushCause') }) {
triggerType = 'GitHub Push'
} else if (causes.any { it._class.contains('SCMTrigger') }) {
triggerType = 'SCM Poll'
} else if (causes.any { it._class.contains('TimerTrigger') }) {
triggerType = 'Scheduled (cron)'
} else if (causes.any { it._class.contains('UpstreamCause') }) {
triggerType = 'Upstream Job'
} else if (causes.any { it._class.contains('UserIdCause') }) {
triggerType = 'Manual trigger'
}
echo "Build triggered by: ${triggerType}"
currentBuild.description = "Triggered by: ${triggerType}"
}
}
}
stage('Checkout') {
steps { checkout scm }
}
stage('Test') {
steps { sh './gradlew test' }
post {
always { junit 'build/test-results/**/*.xml' }
}
}
// Only run full regression suite on nightly scheduled builds
// Skipped on push-triggered builds to keep feedback loops fast
stage('Regression Suite') {
when {
triggeredBy 'TimerTrigger'
}
steps {
echo 'Running full nightly regression suite...'
sh './gradlew regressionTest'
}
}
stage('Deploy') {
when { branch 'main' }
steps {
sh "./deploy.sh staging ${BUILD_NUMBER}"
}
}
}
post {
success { echo "${APP_NAME} build ${BUILD_NUMBER} passed" }
failure { echo "${APP_NAME} build ${BUILD_NUMBER} failed" }
always { cleanWs() }
}
}
Where to practice: Start with pollSCM — it works immediately without external configuration. To test webhooks, use a public GitHub repo and go to Settings → Webhooks → Add webhook. Set Payload URL to http://YOUR-JENKINS-URL/github-webhook/, content type to application/json. If your Jenkins is behind a firewall, use ngrok to create a temporary public URL. Full trigger reference at jenkins.io — Pipeline Triggers.
Started by GitHub push by sarah-chen
[Pipeline] Start of Pipeline
[Pipeline] node (agent-linux-01)
[Pipeline] { (Identify Trigger) }
[Pipeline] script
[Pipeline] echo
Build triggered by: GitHub Push
[Pipeline] { (Checkout) }
[Pipeline] checkout
> git checkout main
> HEAD is now at a3f2b1c Fix null pointer in risk calculation
[Pipeline] { (Test) }
[Pipeline] sh
+ ./gradlew test
BUILD SUCCESSFUL in 1m 8s
47 tests completed, 0 failed
[Pipeline] junit — recording test results
[Pipeline] { (Regression Suite) }
Stage "Regression Suite" skipped — not triggered by TimerTrigger
[Pipeline] { (Deploy) }
[Pipeline] sh
+ ./deploy.sh staging 94
Deploying risk-engine:94 to staging...
Deployment complete.
[Pipeline] stage (post - success)
risk-engine build 94 passed
[Pipeline] cleanWs
[Pipeline] End of Pipeline
Finished: SUCCESS
What just happened?
Started by GitHub push by sarah-chen— Jenkins received the webhook from GitHub the moment sarah-chen pushed. The build started within seconds. Jenkins also logged the exact user who made the push — useful for auditing.Build triggered by: GitHub Push— thegetBuildCauses()call identified the trigger type. The build description was set so it's visible in the Jenkins history without opening the build.HEAD is now at a3f2b1c— Jenkins checked out the exact commit that triggered the webhook, not just the latest on main. Every build is tied to a specific code change.Stage "Regression Suite" skipped — not triggered by TimerTrigger— thewhen { triggeredBy 'TimerTrigger' }condition evaluated false because this was a GitHub push, not a cron schedule. The heavy regression only runs nightly. Push builds stay fast.- Deploy ran — the branch was
mainso the deploy stage was not skipped by thewhen { branch 'main' }condition. A push to any feature branch would have skipped this stage automatically.
Setting Up a GitHub Webhook — Step by Step
This takes about three minutes and replaces polling permanently for GitHub-hosted repos.
Install the GitHub plugin in Jenkins
Manage Jenkins → Plugin Manager → Available. Search "GitHub plugin". Install and restart.
Open your GitHub repository settings
Go to Settings → Webhooks → Add webhook.
Configure the webhook
Set Payload URL to http://YOUR-JENKINS-URL/github-webhook/. Set Content type to application/json. Choose Just the push event. Save.
Add githubPush() to your Jenkinsfile triggers block
Commit and push. Verify the next build says "Started by GitHub push" in the console.
Remove pollSCM from the triggers block
Once the webhook is confirmed working, remove polling to avoid duplicate builds and unnecessary Git server load.
Cron Syntax Quick Reference
Jenkins cron uses five fields: minute, hour, day-of-month, month, day-of-week. The H symbol picks a consistent random value per job to spread load.
| Expression | Meaning |
|---|---|
| H * * * * | Once per hour at a consistent random minute |
| H/5 * * * * | Every 5 minutes — most common for SCM polling |
| H 0 * * * | Once per day around midnight |
| H 2 * * 1-5 | At 2 AM on weekdays only (Mon–Fri) |
| H H * * 0 | Once per week at a random time on Sunday |
| H/15 * * * * | Every 15 minutes |
Teacher's Note
Start every project with pollSCM, switch to webhooks before production, use cron for anything time-based that doesn't depend on code changes.
Practice Questions
1. Which Jenkins trigger directive activates a pipeline via a GitHub webhook when code is pushed?
2. In Jenkins cron syntax, what symbol spreads job execution across the hour by picking a consistent random minute per job?
3. What string do you pass to triggeredBy inside a when block to make a stage only run on scheduled cron builds?
Quiz
1. Why are webhooks preferred over SCM polling for triggering Jenkins pipelines?
2. What does the upstream(upstreamProjects: 'risk-engine-build', threshold: hudson.model.Result.SUCCESS) trigger do?
3. Which cron expression runs a Jenkins job at approximately 2 AM on weekdays only?
Up Next · Lesson 20
Pipeline Notifications
Slack, email, and Teams notifications from Jenkins — how to make sure the right person knows about a broken build before they find out the hard way.