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).
76
95%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
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,
circleci-test-configs -
alternatives.junit-xml-analysis - JUnit XML parser.