Configures Jenkins declarative pipeline test stages - `Jenkinsfile` with stages, parallel + per-agent execution, post-actions (always / failure / success), pipeline-junit-plugin for test reports, lockable resources for shared infra. Use for Jenkins-based CI (common in enterprise / regulated environments).
67
84%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Jenkins Declarative Pipeline (introduced 2017) is the modern Jenkinsfile syntax - replaces older Scripted Pipeline for most use cases.
A Jenkinsfile defines:
For new projects in 2026+: GitHub Actions / GitLab CI offer better managed-runner experiences. Jenkins shines in self-hosted
Jenkinsfile with a pipeline { agent ...; stages { ... } }
block; choose agent any, a labelled node, or a Docker image
for reproducibility (Steps 1-2).stage('Build') / stage('Test') steps that run your
install + test commands via sh.post {} block to publish JUnit XML, archive artifacts,
and notify per outcome -
references/post-actions.md.environment {} + masked withCredentials, serialize
shared infra with lock(...), and set triggers / options -
references/environment-and-triggers.md.retry(2) only on genuinely non-deterministic steps;
prefer quarantine.// Jenkinsfile
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'npm ci'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
}agent any runs on any available executor; pin via agent { label 'linux' }
or agent { docker { image 'node:22' } }.
pipeline {
agent {
docker {
image 'node:22'
args '-v /tmp:/tmp'
}
}
stages {
stage('Test') {
steps {
sh 'npm ci && npm test'
}
}
}
}Docker agents provide reproducibility - same Node version on every run.
Deeper stage recipes are split into reference files:
post { always / success / failure / unstable }
for JUnit publishing, artifact archiving, and notifications:
references/post-actions.md.environment {}, withCredentials, lock(...), triggers,
options {}:
references/environment-and-triggers.md.stage('Test') {
steps {
retry(2) {
sh 'npm test'
}
}
}Use sparingly - retries hide flake. Prefer
flaky-test-quarantine (in the qa-flake-triage plugin).
A regulated team runs its suite on a self-hosted Jenkins with a shared integration database.
Jenkinsfile pins agent { docker { image 'node:22' } }
so every run uses the same runtime.Tests stage runs Unit and Integration in parallel;
the E2E branch overrides its agent to a
mcr.microsoft.com/playwright:v1.50.0-noble image.Integration step wraps its work in
lock(resource: 'shared-test-database') so only one build
touches the DB at a time.withCredentials([...]) injects the registry token, masked in
logs; environment { CI = 'true' } marks the run as CI.post { always { junit 'reports/junit/*.xml'; archiveArtifacts 'coverage/**' } } publishes results either
way, and failure { slackSend(...) } pings #ci on a red build.options { timeout(time: 30, unit: 'MINUTES') } kills hung
builds so they don't hold executors.Result: reproducible runs, no DB contention across parallel builds, and test reports plus notifications on every outcome.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Scripted pipeline for new code | Declarative is the standard; better tooling support. | Declarative Pipeline (Step 1). |
Plaintext credentials in Jenkinsfile | Secret leak. | withCredentials({...}) (environment-and-triggers). |
No post { always {} } for artifact upload | Failure investigation incomplete. | Always upload (post-actions). |
| Single-agent pipeline for parallel work | No parallelism; slow. | Parallel stages (parallel-and-matrix). |
Missing timeout | Hung jobs consume executors indefinitely. | options { timeout(...) } (environment-and-triggers). |
Skipping agent { docker {...}} | Inconsistent runtime per agent; hard to reproduce. | Docker agents (Step 2). |
jenkins.io/doc/book/pipeline/.github-actions-test-jobs,
gitlab-ci-test-jobs -
alternatives; CircleCI patterns live in ci-test-job-conventions
references/circleci.md.junit-xml-analysis - JUnit XML parser.