Skip to content
Back to skills

Jenkins Pipelines

ASecurity

Jenkins is an open-source automation server that runs CI/CD pipelines defined as code in a Jenkinsfile. Use when the user wants to write or fix a Jenkinsfile (declarative or scripted), set up multibranch pipelines, run stages in Docker or Kubernetes agents, create shared libraries, bind credentials and secrets, run stages in parallel, gate a deployment behind an approval, validate a Jenkinsfile with the linter, or troubleshoot build failures. Trigger words: jenkins, jenkinsfile, jenkins pipel...

  • 142 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 29, 2026
devopsrustgojavashellbashsqlnodedockerkubernetesgit

Works with

  • terminal
  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill jenkins-pipelines --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Jenkins Pipelines?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Jenkins Pipelines
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-jenkins-pipelines/badge)](https://www.skillsdirectory.com/skills/terminalskills-jenkins-pipelines)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: jenkins-pipelines
description: >-
  Jenkins is an open-source automation server that runs CI/CD pipelines defined
  as code in a Jenkinsfile. Use when the user wants to write or fix a
  Jenkinsfile (declarative or scripted), set up multibranch pipelines, run
  stages in Docker or Kubernetes agents, create shared libraries, bind
  credentials and secrets, run stages in parallel, gate a deployment behind an
  approval, validate a Jenkinsfile with the linter, or troubleshoot build
  failures. Trigger words: jenkins, jenkinsfile, jenkins pipeline, jenkins
  agent, jenkins shared library, jenkins docker, jenkins kubernetes,
  multibranch pipeline, jenkins credentials, jenkins groovy.
license: Apache-2.0
compatibility: "Jenkins LTS 2.555.1 or newer (controller and agents run on Java 21 or 25) with the Pipeline plugin suite; other plugins as noted per step."
metadata:
  author: terminal-skills
  version: "1.1.0"
  category: devops
  repository: https://github.com/jenkinsci/jenkins
  tags: ["jenkins", "ci-cd", "pipelines", "automation"]
---

# Jenkins Pipelines

## Overview

Creates and manages Jenkins CI/CD pipelines using both Declarative and Scripted syntax. Covers Jenkinsfile authoring, multibranch pipelines, shared libraries, Docker and Kubernetes agents, credential management, parallel execution, artifact handling, notifications, and production-grade pipeline patterns. Checked against Jenkins LTS 2.580.1.

## Instructions

### 1. Declarative Pipeline

Steps outside the Pipeline suite come from plugins: `agent { docker }` and `docker.build` (Docker Pipeline), `timestamps()` (Timestamper), `cleanWs()` (Workspace Cleanup), `slackSend` (Slack Notification), `junit` (JUnit).

```groovy
pipeline {
    agent none   // each stage picks its agent; no executor is held while waiting for approval
    options {
        timeout(time: 30, unit: 'MINUTES')   // also aborts a pending approval
        disableConcurrentBuilds()
        buildDiscarder(logRotator(numToKeepStr: '20'))
        timestamps()
    }
    environment {
        APP_NAME = 'api-server'
        REGISTRY = 'registry.northwind.dev'
        IMAGE = "${REGISTRY}/${APP_NAME}"
    }
    stages {
        stage('Verify') {
            agent { docker { image 'node:24-alpine' } }
            environment { npm_config_cache = "${WORKSPACE}/.npm" }   // Jenkins runs the container as the agent's uid, which has no writable home
            stages {
                stage('Install') { steps { sh 'npm ci' } }
                stage('Lint & Test') {
                    parallel {
                        stage('Lint') { steps { sh 'npm run lint' } }
                        stage('Unit Tests') {
                            steps { sh 'npm test -- --coverage' }
                            post { always { junit 'reports/junit.xml' } }
                        }
                        stage('Security') { steps { sh 'npm audit --audit-level=high' } }
                    }
                }
            }
        }
        stage('Build Image') {
            agent { label 'docker' }   // agent with the Docker CLI and daemon access
            steps {
                script {
                    def tag = env.GIT_COMMIT.take(8)
                    docker.build("${IMAGE}:${tag}")
                    docker.withRegistry("https://${REGISTRY}", 'registry-credentials') {
                        docker.image("${IMAGE}:${tag}").push()
                        if (env.BRANCH_NAME == 'main') docker.image("${IMAGE}:${tag}").push('latest')
                    }
                }
            }
            post { cleanup { cleanWs() } }
        }
        stage('Deploy Staging') {
            when { branch 'main'; beforeAgent true }
            agent { label 'docker' }
            steps {
                withCredentials([file(credentialsId: 'kubeconfig-staging', variable: 'KUBECONFIG')]) {
                    sh "helm upgrade --install ${APP_NAME} ./charts/${APP_NAME} -n staging --set image.tag=${GIT_COMMIT.take(8)} --wait"
                }
            }
        }
        stage('Deploy Production') {
            when { branch 'main'; beforeInput true }   // without beforeInput, every branch would prompt
            input { message 'Deploy to production?'; ok 'Deploy'; submitter 'admin,platform-team' }
            agent { label 'docker' }
            steps {
                withCredentials([file(credentialsId: 'kubeconfig-prod', variable: 'KUBECONFIG')]) {
                    sh "helm upgrade --install ${APP_NAME} ./charts/${APP_NAME} -n production --set image.tag=${GIT_COMMIT.take(8)} --wait --timeout 10m"
                }
            }
        }
    }
    post {
        success { slackSend(channel: '#deployments', color: 'good', message: "Deployed: ${env.BUILD_URL}") }
        failure { slackSend(channel: '#deployments', color: 'danger', message: "Failed: ${env.BUILD_URL}") }
    }
}
```

### 2. Multibranch Pipeline

`when { branch }` and `changeRequest()` only match in multibranch jobs. GitHub Branch Source already reports each build as a commit status on the branch or pull request; `withChecks` (GitHub Checks plugin, needs GitHub App credentials) adds a named check. The older `githubNotify` step is no longer recommended by its own maintainers.

```groovy
stage('Deploy') {
    when { anyOf { branch 'main'; branch pattern: 'release/.*', comparator: 'REGEXP' } }
    steps { sh './scripts/deploy.sh' }
}
stage('PR Checks') {
    when { changeRequest target: 'main' }
    steps {
        withChecks('Unit Tests') {
            sh 'npm test'
            junit 'reports/junit.xml'
        }
    }
}
```

### 3. Shared Libraries

A library repository holds global steps in `vars/` (one file per step, e.g. `buildDockerImage.groovy`, `deployToK8s.groovy`, `notifySlack.groovy`), classes in `src/` and non-Groovy files in `resources/`.

**vars/buildDockerImage.groovy:**
```groovy
def call(Map config) {
    def tag = config.tag ?: env.GIT_COMMIT.take(8)
    def registry = config.registry ?: 'registry.northwind.dev'
    def image = "${registry}/${config.name}:${tag}"
    stage('Build Image') {
        docker.build(image, "-f ${config.dockerfile ?: 'Dockerfile'} .")
        docker.withRegistry("https://${registry}", config.credentialsId ?: 'registry-creds') {
            docker.image(image).push()
            if (env.BRANCH_NAME == 'main') docker.image(image).push('latest')
        }
    }
    return image
}
```

**Usage** (register the library under Manage Jenkins → System as a Global Trusted or Untrusted Pipeline Library; pin a tag or branch after `@`):
```groovy
@Library('company-pipeline-lib@v1.4.0') _
pipeline {
    agent any
    stages {
        stage('Build') {
            steps { script { def image = buildDockerImage(name: 'api-server') } }
        }
    }
    post { always { notifySlack() } }
}
```

### 4. Kubernetes Agents

Requires the Kubernetes plugin and a configured cloud. Containers that should wait for steps need a long-running command such as `sleep`.

```groovy
pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: node
      image: node:24-alpine
      command: ['sleep', '99d']
    - name: docker
      image: docker:29-dind
      securityContext: { privileged: true }
    - name: helm
      image: alpine/helm:4.3.0
      command: ['sleep', '99d']
'''
            defaultContainer 'node'
        }
    }
    stages {
        stage('Build') { steps { sh 'npm ci && npm run build' } }
        stage('Docker') { steps { container('docker') { sh 'docker build -t api-server .' } } }
        stage('Deploy') { steps { container('helm') { sh 'helm upgrade --install api-server ./charts/api-server' } } }
    }
}
```

### 5. Credentials Management

Use single-quoted `sh` strings so the shell, not Groovy, expands the secret.

```groovy
// Username/password
withCredentials([usernamePassword(credentialsId: 'db-creds', usernameVariable: 'DB_USER', passwordVariable: 'DB_PASS')]) {
    sh 'PGPASSWORD=$DB_PASS psql -U $DB_USER -h db.internal.northwind.dev -c "select 1"'
}
// Secret text
withCredentials([string(credentialsId: 'api-key', variable: 'API_KEY')]) {
    sh 'curl -H "Authorization: Bearer $API_KEY" https://api.northwind.dev/v1/deployments'
}
// SSH key
withCredentials([sshUserPrivateKey(credentialsId: 'deploy-key', keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
    sh 'ssh -i $SSH_KEY $SSH_USER@deploy.northwind.dev "./deploy.sh"'
}
// File, e.g. a kubeconfig: see the deploy stages in section 1
```

### 6. Pipeline Patterns

Retry with a timeout, roll back on failure, and move files between agents with stash/unstash (meant for small files):

```groovy
stage('Build') {
    steps { sh 'npm run build'; stash includes: 'dist/**', name: 'build-artifacts' }
}
stage('Deploy') {
    agent { label 'deploy-node' }
    steps {
        unstash 'build-artifacts'
        retry(3) { timeout(time: 5, unit: 'MINUTES') { sh './deploy.sh dist/' } }
    }
    post { failure { sh './rollback.sh' } }
}
```

## Examples

### Example 1: Monorepo — build only what changed

**Request:** "Our monorepo has api, web and worker services plus a shared library. Build only the services whose files changed, and all of them when libs/shared changes."

```groovy
pipeline {
    agent any
    stages {
        stage('Services') {
            parallel {
                stage('api') {
                    when { anyOf { changeset 'services/api/**'; changeset 'libs/shared/**' } }
                    steps { sh 'make -C services/api build test' }
                }
                stage('web') {
                    when { anyOf { changeset 'services/web/**'; changeset 'libs/shared/**' } }
                    steps { sh 'make -C services/web build test' }
                }
                // 'worker' follows the same pattern
            }
        }
    }
}
```

**Result:** a commit touching only `services/api/` runs `api`; the console shows `Stage "web" skipped due to when conditional`. The first build of a job or branch has an empty changelog (`Warning, empty changelog. Probably because this is the first build.`), so every `changeset` stage is skipped — trigger a full build for new branches.

### Example 2: Validate a Jenkinsfile without running a build

**Request:** "Check my Jenkinsfile for syntax errors before I push."

```bash
# JENKINS_AUTH holds "username:api_token" (the token is created on your user's Security page)
curl -s -X POST --user "$JENKINS_AUTH" -F "jenkinsfile=<Jenkinsfile" \
  "$JENKINS_URL/pipeline-model-converter/validate"
```

**Result:** `Jenkinsfile successfully validated.`, or the errors with line and column:

```text
Errors encountered validating Jenkinsfile:
WorkflowScript: 21: Missing required parameter: "description" @ line 21, column 19.
           success { githubNotify(status: 'SUCCESS') }
                     ^
```

The linter checks Declarative structure and the required parameters of known steps. It does not flag unknown step names, and a Scripted Pipeline is rejected with "did not contain the 'pipeline' step".

## Guidelines

- Use Declarative syntax unless you need complex Groovy logic
- Always set `timeout` and `disableConcurrentBuilds` in options
- Clean workspaces with `cleanWs()` in a stage-level `post`; with `agent none` a pipeline-level `post` has no workspace
- Keep Jenkinsfiles in the repository, not configured in Jenkins UI
- Use shared libraries for common patterns — avoid copy-pasting; pin the library version. Anyone who can push to a trusted library's repository gets unlimited access to Jenkins, so protect that repository
- Use `withCredentials` — never hardcode secrets, and never put a secret in a double-quoted Groovy string: it is interpolated before the shell runs and leaks into process listings
- Prefer Docker or Kubernetes agents over permanent agents; a privileged `docker:dind` container can take over its Kubernetes node, so keep it off shared clusters
- Use `when` conditions to skip unnecessary stages on branches/PRs; add `beforeAgent true` or `beforeInput true` so skipped stages neither allocate an agent nor ask for approval
- Put `input` on a stage without a held agent (`agent none` at the top) so a pending approval does not block an executor
- Archive test reports with `junit` step for trend tracking
- Set up Jenkins Configuration as Code (JCasC) — no manual UI configuration
- Controllers and agents need Java 21 or 25 since LTS 2.555.1; upgrade the JVM before upgrading from an older LTS. Blue Ocean is deprecated — do not build new workflows around it

Files in this skill

  • SKILL.md8.7 KB
  • _scores.json1.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…