Friday, 21 February 2020

Shared groovy library in Jenkins jobs

How to use a shared library in Jenkins, to allow you to share common code and steps across multiple pipelines. Includes a demo Git repo that you can fork.

you're getting up to speed with Jenkins now and you’re mastering the art of the pipeline. But now you’ve got a few projects up and running, how do you avoid repeating the same common code across different pipelines?
I often write code that I know will be reused across several different pipelines in Jenkins. Copying and pasting the same code into different pipelines can quickly become a maintenance headache.
So to avoid this, you store your “reusable bits” (technical term!) in a Shared Library in Jenkins. You only need to write some code once, and then you can reference the same code in all of your pipelines.
This Jenkins pipeline shared library tutorial will tell you the basics of setting up a shared pipeline, how to load the library, and how to use it in your pipelines.

What to reuse in Jenkins

If you’re already writing code in your pipelines to do anything like this:
  • verify the deployment environment
  • perform a deployment
  • read a configuration file (e.g. a Maven POM file)
  • perform a code review of the application (e.g. using a tool like SonarQube)
…then you’ll probably be better off putting the code for these into a shared library so that lots of different projects can use them.
Over time, you’ll build up a collection of these reusable functions in your Library.

What is a Shared Library

A shared library is a collection of independent Groovy scripts that you pull into your Jenkinsfile at runtime.
The best part is, the Library can be stored, like everything else, in a Git repository. This means you can version, tag, and do all the cool stuff you’re used to with Git.
  1. First, you create your Groovy scripts (see below for details on this), and add them into your Git repository.
  2. Then, you add your Shared Library into Jenkins from the Manage Jenkins screen.
  3. Finally, you pull the Shared Library into your pipeline using this annotation (usually at the top of your Jenkinsfile):
    @Library('your-library-name')

What’s inside a Shared Library

Inside your Library, you’ll probably have two types of common code.
  • Steps: These are called Global Variables in Jenkins terminology, but these are the custom steps that you want to be available to all your Jenkins pipelines.
    For example, you might write a standard step to deploy an application or perform a code review. To do this, add your code into vars/YourStepName.groovy and then implement a def call function:
    #!/usr/bin/env groovy
    // vars/YourStepName.groovy
    
    def call() {
      // Do something here...
    }
    
  • Other common code: This might include helper classes or common code that you might want to include inside pipeline steps themselves (meta!). You could also use it as a place to store static constants that you use throughout your pipelines.
    Code like this needs to go in the src/your/package/name directory, and then you can use normal Groovy syntax, e.g.:
    #!/usr/bin/env groovy
    // com/cleverbuilder/GlobalVars.groovy
    package com.cleverbuilder
    
    class GlobalVars {
       static String foo = "bar"
    }
    
    You can then import this class into your Jenkinsfile and reference the static variable like GlobalVars.foo:

Example: Creating and using a Jenkins shared library

Setting up a shared library is fairly easy, and in this section, I’ll show you how, with a quick example.
  1. Create the shared library
    First, you need to create a Git repository that will contain your library of functions (steps). You can also use Subversion.
    In your repository, create a directory called vars. This will hold your custom steps. Each of them will be a different .groovy file underneath your vars directory, e.g.:
    vars/
        deployApplication.groovy
        parseFile.groovy
        sayHello.groovy
        readSystemCredentials.groovy
        doCodeReview.groovy
    
    I’m using Git to store my repository. I’ve created a sample repo on GitHub, which includes one function, the sayHello example from the official Jenkins documentation.
  1. Add your custom steps
    Each of your custom steps is a different .groovy file inside your vars/ directory. In Jenkins terminology, these are called Global Variables, which is why they are located inside vars/.
    Create a file for your custom step, and fill in the code. For example, a simple greeting function would look like this:
    #!/usr/bin/env groovy
    
    def call(String name = 'human') {
      echo "Hello, ${name}."
    }
    
    Notice how the Groovy script must implement the method. Then you should write your custom code within the braces { }. You can also add parameters to your method - the example above has one parameter- name, with a default value of human.
  2. Set up the library in Jenkins
    Now you’ve created your library with custom steps, you need to tell Jenkins about it.
    You can define a shared library within a Jenkinsfile, or you can configure the library using the Jenkins web console. I think it’s better to add from the web console because you then you can share the library across all of your build jobs.
    To add your shared library (I’m using my demo on GitHub as an example):
    In Jenkins, go to Manage Jenkins → Configure System. Under Global Pipeline Libraries, add a library with the following settings:
    • Name: pipeline-library-demo
    • Default version: Specify a Git reference (branch or commit SHA), e.g. master
    • Retrieval method: Modern SCM
    • Select the Git type
    • Project repository: https://github.com/monodot/pipeline-library-demo.git
  3. Use the library in a pipeline
    To use the shared library in a pipeline, you just add @Library('your-library-name') to the top of your pipeline definition, or Jenkinsfile. Then call your step by name, e.g. sayHello:
    @Library('pipeline-library-demo')_
    
    stage('Demo') {
        echo 'Hello world'
        sayHello 'Dave'
    }
    
    NOTE: The underscore (_) is not a typo! You need this underscore if the line immediately after the @Library annotation is not an import statement.
    If you’re using declarative pipeline syntax….
    libraries {
      lib('pipeline-library-demo')
    }
    
    pipeline {
    
    }
    
    
  4. Run the pipeline above, and the output should look something like this:
Jenkins job output
That’s it for my intro to Shared Libraries in Jenkins! As you can see they’re a useful way to share common code that you might use across different Jenkinsfiles.
Here are the important things to remember:
  • You need to use Groovy to write your custom functions or steps
  • To write pipeline steps that you can call from your pipelines (e.g. deployApplicationreadConfigFile, etc.):
    • Create a file in the vars/ directory in your repository, with the name of your custom step
    • The file should implement the def call() method; you can also define parameters to your step
  • To write other common Groovy code, add it into src/
  • Add your Shared Library in Jenkins using the Configure System screen
Thanks for reading!