Skip to content

jenkins sharedlib

ghdrako edited this page Feb 7, 2023 · 9 revisions

Shared libraries provide a way to encapsulate the repeated code and create helper functions.

A shared library is a collection of folders and files stored in a source code management system (SCM). These can be stored in any SCM, but we will use a Git repository in GitHub as we have been doing throughout the book.

A Git repository containing a shared library has three folders: vars, src, and resources:

  • vars directory - containing the functions that the Jenkinsfiles can call. The common utility functions such as helper functions for Slack are stored in the vars directory.The files in the vars directory become available to Jenkinsfiles as variables.For example, if we have vars/slack.groovy that has a function named send(), we can call the function slack.send(), referencing the slack.groovy filename as a variable.
  • src directory - the Groovy classes with the complex business logic are stored. The src directory uses the Java source structure.
  • resources directory contains the static files that can be referenced from the code in the shared library. For example, if there are several functions that need a reference to the list of hosts in our environment, the list can be saved in a file in this directory.

in “Jenkinsfile”:

@Library (‘opstree-library@master’) _
opstreePipeline()

The structure of shared library is as follows:

opstree-library
├── resources #Static files which can be used by
shared library
│ └── input.yaml
├── src # Sources file for groovy classpath
│ └── org
│ └── opstree
│ └── JavaCIPipeline.groovy
└── vars # Vars file for src libraries
└── JavaCIPipelineVars.groovy

Create Shared Libraries workflow

  1. Initiate a new empty Git Repository.
mkdir reusable-pipeline-library
cd reusable-pipeline-library
git init
  1. Create the necessary directory structure for your Shared Library
mkdir vars
  1. create a new Groovy file named pipeline.groovy
def call() {
pipeline {
  agent none
  stages {
    stage('Build & Test') {
      agent {
        node {
          label 'docker'
        }
      }
      steps {
        sh 'mvn -Dmaven.test.failure.ignore clean package'
        stash(name: 'build-test-artifacts', \
        includes: '**/target/surefire-reports/TEST-*.xml,target/*.jar')
      }
    }
    stage('Report & Publish') {
      parallel {
        stage('Report & Publish') {
          agent {
            node {
              label 'docker'
            }
          }
          steps {
            unstash 'build-test-artifacts'
            junit '**/target/surefire-reports/TEST-*.xml'
            archiveArtifacts(onlyIfSuccessful: true, artifacts: 'target/*.jar')
          }
        }
        stage('Publish to Artifactory') {
          agent {
            node {
              label 'docker'
            }
          }
          steps {
            script {
              unstash 'build-test-artifacts'
              def server = Artifactory.server 'Artifactory'
              def uploadSpec = """{
                "files": [
                  {
                    "pattern": "target/*.jar",
                    "target": "example-repo-local/ \
                    ${JOB_NAME}/${BRANCH_NAME}/${BUILD_NUMBER}/"
                  }
                ]
              }"""
              server.upload(uploadSpec)
            }
          }
        }
      }
    }
  }
}
}
  1. Add to repo
git add .
git commit -m "Added initial files to the Shared Library."
git remote add origin <Remote Git Repository URL>
git push -u origin master
  1. Make the necessary configurations inside Jenkins to retrieve your new Shared Library.

Retrieving Shared Libraries Using Pre-Configured Settings in Jenkins

Load implicitly - if checked, scripts inevitably have access to your Shared Library without needing to request it via @Library. Allow default version to be overridden - if checked, it allows you to select a custom version of your Shared Library by using @someversion in the @Library annotation. By default, you’re restricted to use the version that you specify using the Default version field. Include @Library changes in job recent changes - allows you to include changes on the Shared Library, if any, in the changesets of your build. You can also override this setting during the Pipeline runtime by specifying the following inside your Jenkinsfile: ``@Library(value="name@version", changelog=true|false)```.

Retrieving Shared Libraries Directly During the Pipeline Runtime

Retrivinf library in dynamic wey during the Pipeline runtime

library identifier: '<custom name for the Shared Library>@<version>', retriever: modernSCM(
  [$class: 'GitSCMSource',
   remote: '<Git repository URL>',
   credentialsId: '<Credential ID for the above remote repository>'])
library identifier: 'jenkins-shared-libraries@master', retriever: modernSCM(
  [$class: 'GitSCMSource',
   remote: 'https://git.com/jenkins-shared-libraries.git',
   credentialsId: 'none'])
  1. Use lib in jenkinsfile
@Library('my-shared-library') _
call()

@Library('<Shared Library Name>@<version>') _

you can add a branch name, a tag, or a commit hash

@Library('jenkins-shared-libraries@master') _

Creating Shared Libraries

/vars/log.groovy:
def info(message) {
    echo "INFO: ${message}"
}
def warning(message) {
    echo "WARNING: ${message}"
}

# Jenkinsfile:
@Library('jenkins-shared-libraries') _
pipeline {
    agent none
    stage ('Example') {
        steps {
             script {
                 log.info 'Starting.'
                 log.warning 'Nothing to do!'
              }
        }
    }
}
/vars/email.groovy:
import hudson.model.Result
import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
def call(RunWrapper currentBuild, List<String> emailList) {
    if (!emailList) {
        return
    }
    def currentResult = currentBuild.currentResult
    def previousResult = currentBuild.getPreviousBuild()?.getResult()
    def buildIsFixed =
        currentResult == Result.SUCCESS.toString() &&
        currentResult != previousResult &&
        previousResult != null
     def badResult =
        currentResult in [Result.UNSTABLE.toString(), Result.FAILURE.toString()]
    if (buildIsFixed || badResult) {
        emailext (
            recipientProviders: [[$class: "RequesterRecipientProvider"]],
            to: emailList.join(", "),
            subject: "\$DEFAULT_SUBJECT",
            body: "\$DEFAULT_CONTENT"
        )
    }
}

Jenkinsfile:
pipeline {
    agent { label "master" }
    libraries {
        lib('jenkins-shared-libraries')
    }
    stages {
        stage("echo") {
            steps {
               echo "You are using Shared Libraries."
            }
  }
    }
    post {
        always {
            script {
                email(currentBuild, ['user@organization.com'])
            }
        }
    }
}"""

Providing shared libraries

  • Folder-level shared libraries A shared library can be made available to the pipelines in a specific folder by configuring it in the folder's configuration page. When a specific project's pipelines have repeated code, the helper functions that modularize the project's repeated code should be stored in a folder-level shared library, not a global shared library.
  • Global shared libraries A global shared library is configured in the System Configuration under Global Pipeline Libraries. Everything in the global shared libraries run outside of the sandbox, which means that the code inside a global shared library has full access to Jenkins without any security oversight. This includes activities such as deleting a pipeline, decrypting secrets, or shutting down Jenkins.

It is very important that the source Git repository for a global shared library is secured at the same level as administrator access to Jenkins.

Using shared libraries

  • Static loading

There are two syntax options to statically load a shared library in a Jenkinsfile. Let's start with the form for loading the classes in the src directory.

  1. Annotating an import statement
Jenkinsfile:
@Library('my-global-shared-lib')
import ca.lvin.books.jenkins.RandomWord
pipeline {
    agent any
    stages {
        stage('src test 1') {
            steps { 
                script {
                    RandomWord rw = new RandomWord(this)
                    echo rw.get()
                }
            } 
        }
    }
}
  1. Annotating nothing but still using the side effect
@Library('my-global-shared-lib') _
pipeline {
    agent any
    stages {
        stage('src test 2') {
            steps { 
                script {
                    RandomWord rw = new RandomWord(this)
                    echo rw.get()
                }
            } 
        }
        stage('vars test 2') {
            steps { 
                script {
                    randomWordFromVars.echo()
                } 
            }
        }
    }
}

Test

Clone this wiki locally