Skip to main content

Applying Jenkinsfile Best Practices

1. Storing Jenkinsfile in SCM

Aspect Description Best Practice
Location Where the Jenkinsfile is stored Store in the root of your source code repository
Version Control How the Jenkinsfile is managed Use Git or another SCM system to track changes
Branching Strategy Handling Jenkinsfile in different branches Keep Jenkinsfile in the same branch as the code it builds
Access Control Permissions for Jenkinsfile Restrict write access to authorized users only

Example: Jenkinsfile in Git Repository

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building...'
            }
        }
    }
}
Note: Storing Jenkinsfile in SCM ensures that the build process is versioned and can be reviewed, audited, and rolled back if needed.

2. Using Declarative vs Scripted Syntax

Aspect Declarative Scripted
Syntax Style Structured, pipeline-as-code format Full Groovy scripting
Readability Highly readable and intuitive Can be complex and less readable
Flexibility Less flexible, predefined structure Highly flexible, full scripting power
Error Handling Automatic error handling in stages Manual error handling required
Use Case Simple to moderately complex pipelines Complex logic, dynamic behavior

Example: Declarative Pipeline

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building...'
            }
        }
    }
}

Example: Scripted Pipeline

node {
    stage('Build') {
        echo 'Building...'
    }
}

Choosing the Right Syntax

  • Use Declarative for simpler, more structured pipelines with clear stages.
  • Use Scripted for complex logic, dynamic behavior, or when full Groovy control is needed.

3. Implementing Pipeline as Code

Aspect Description Best Practice
Declarative Pipeline Syntax Uses a structured, readable syntax for defining pipelines. Use declarative syntax for better readability and maintainability.
Scripted Pipeline Syntax Allows more complex logic and control flow using Groovy. Use scripted syntax for advanced use cases or dynamic behavior.
Jenkinsfile Location Must be placed in the root of the project repository. Keep Jenkinsfile in the root directory for easy access and version control.

Example: Basic Declarative Pipeline

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building...'
            }
        }
    }
}

Example: Scripted Pipeline with Conditional Logic

node {
    if (env.BRANCH_NAME == 'main') {
        echo 'Running on main branch'
    } else {
        echo 'Running on feature branch'
    }
}
Note: Jenkinsfile should be treated as code and version-controlled alongside the source code.

4. Using Shared Libraries for Reusability

Shared libraries in Jenkins allow teams to define and reuse common pipeline logic across multiple jobs. They are particularly useful for standardizing build processes, reducing duplication, and improving maintainability.

Feature Description Usage
library.name Name of the shared library to be used in a pipeline. @Library('my-shared-library') _
library.version Version or revision of the library to use. @Library('my-shared-library@v1.0') _
library.changelog Indicates whether to include the changelog in the library usage. library(changelog: true)

Example: Using a Shared Library in Jenkinsfile

@Library('my-shared-library@v1.0') _

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                script {
                    myBuild()
                }
            }
        }
    }
}
Note: Shared libraries must be defined in Jenkins under Manage Jenkins > Configure System under the Global Tool Configuration or via Jenkinsfile using library directive.

Best Practices for Shared Libraries

  • Organize shared logic into modular functions or steps.
  • Version libraries to ensure stability and prevent breaking changes.
  • Use library directive with specific versions to avoid unexpected behavior.
  • Document library usage and maintain a changelog for each version.

5. Implementing Error Handling

Method Description Usage
try Used to define a block of code to be tested for errors
try {
    // Code that might throw an error
} catch (e) {
    // Handle the error
}
catch Used to define a block of code to be executed if an error occurs in the try block
try {
    // Code that might throw an error
} catch (e) {
    // Handle the error
}
finally Used to define a block of code that will be executed regardless of whether an error occurred
try {
    // Code that might throw an error
} catch (e) {
    // Handle the error
} finally {
    // Code that always runs
}
error Used to throw an error in the pipeline error 'Build failed'

Example: Basic Error Handling in Jenkins Pipeline

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                script {
                    try {
                        sh 'echo "Starting build..."'
                        sh 'exit 1' // Simulate a failure
                    } catch (e) {
                        echo "Build failed with error: ${e}"
                        currentBuild.result = 'FAILURE'
                    } finally {
                        echo "Build process completed."
                    }
                }
            }
        }
    }
}

Example: Using Error to Fail Pipeline

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                script {
                    try {
                        sh 'echo "Deploying application..."'
                        sh 'exit 1' // Simulate deployment failure
                    } catch (e) {
                        error "Deployment failed: ${e}"
                    }
                }
            }
        }
    }
}

6. Using Proper Stage Naming

Stage Name Description Best Practice
build Compiles source code into executable binaries Use descriptive names like build-backend or build-frontend
test Runs unit and integration tests Include test type in name: test-unit, test-integration
deploy Deploys artifacts to target environments Specify environment: deploy-staging, deploy-production
cleanup Cleans up temporary files or resources Use cleanup for general cleanup tasks

Example: Stage Naming in Jenkinsfile

pipeline {
    agent any
    stages {
        stage('build') {
            steps {
                sh 'make'
            }
        }
        stage('test-unit') {
            steps {
                sh 'npm test'
            }
        }
        stage('deploy-staging') {
            steps {
                sh 'ansible-playbook deploy.yml -e env=staging'
            }
        }
    }
}
Note: Stage names should be descriptive and consistent across pipelines to improve readability and maintainability.

7. Implementing Timeout Strategies

Strategy Description Configuration Notes
timeout Applies a timeout to the entire pipeline or a specific block timeout(time: 10, unit: 'MINUTES') { ... } Can be applied to stages or the entire pipeline
timeout.time Duration of the timeout in specified units time: 30 Valid units: SECONDS, MINUTES, HOURS, DAYS
timeout.unit Time unit for the timeout value unit: 'HOURS' Default is MINUTES if not specified

Example: Timeout on a Stage

pipeline {
    agent any
    stages {
        stage('Build') {
            timeout(time: 10, unit: 'MINUTES') {
                steps {
                    sh 'make'
                }
            }
        }
    }
}

Example: Timeout on Entire Pipeline

pipeline {
    agent any
    timeout(time: 2, unit: 'HOURS') {
        stages {
            stage('Build') {
                steps {
                    sh 'make'
                }
            }
            stage('Test') {
                steps {
                    sh 'make test'
                }
            }
        }
    }
}
Note: If a timeout occurs, the pipeline will be marked as failed and any ongoing steps will be terminated.

8. Using Cleanup Actions

Cleanup actions in Jenkins are essential for maintaining a clean and efficient build environment. They help remove temporary files, artifacts, and other resources that are no longer needed after a build completes.

Action Description Usage Example
clean() Removes the workspace directory before the build starts.
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                clean()
                sh 'echo "Building..."'
            }
        }
    }
}
deleteDir() Deletes the entire workspace directory at the beginning of a stage.
pipeline {
    agent any
    stages {
        stage('Clean and Build') {
            steps {
                deleteDir()
                sh 'echo "Workspace cleaned, now building..."'
            }
        }
    }
}
post Executes actions after a build completes, regardless of success or failure.
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'echo "Building..."'
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
}

Example: Using cleanWs() in Post Section

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'mkdir -p build/output'
                sh 'echo "Building project..." > build/output/log.txt'
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
}
Note: The cleanWs() step removes all files in the workspace, including any artifacts or logs that might be needed for debugging. Use it carefully and ensure that important data is archived before cleanup.

9. Optimizing Pipeline Performance

Optimization Area Description Best Practice
Parallel Stages Running stages in parallel to reduce total execution time Use parallel directive for independent tasks
Resource Allocation Efficient use of agents and executors Use agent none for non-agent steps
Caching Strategies Reusing artifacts or dependencies to avoid redundant work Use archiveArtifacts and stash for caching
Pipeline Caching Reusing pipeline steps or stages across builds Implement cache blocks for expensive operations

Example: Parallel Execution

pipeline {
    agent any
    stages {
        stage('Build') {
            parallel {
                stage('Frontend') {
                    steps {
                        echo 'Building frontend...'
                    }
                }
                stage('Backend') {
                    steps {
                        echo 'Building backend...'
                    }
                }
            }
        }
    }
}

Example: Caching Artifacts

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'npm install'
                sh 'npm run build'
                archiveArtifacts artifacts: 'dist/**', fingerprint: true
            }
        }
        stage('Deploy') {
            steps {
                stash name: 'dist', includes: 'dist/**'
            }
        }
    }
}

10. Documenting Pipeline Logic

Element Description Usage
pipeline Defines the Jenkins Pipeline pipeline { ... }
agent Specifies where the pipeline runs agent any
stages Contains all the stages of the pipeline stages { ... }
stage Represents a single stage in the pipeline stage('Build') { steps { ... } }
steps Defines actions to be executed in a stage steps { ... }
parameters Allows passing parameters to the pipeline parameters { ... }
environment Defines environment variables for the pipeline environment { ... }
options Configures pipeline options options { ... }

Example: Basic Pipeline Structure

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building...'
            }
        }
    }
}
Note: Use descriptive names for stages and include comments to explain complex logic.

Best Practices for Documentation

  • Use clear and descriptive stage names
  • Include comments in the Jenkinsfile to explain complex logic
  • Document parameters and their expected values
  • Use environment variables for configuration
  • Keep stages focused on a single task

Was this article helpful?