If you use Jenkins Pipeline a lot, you’re bound to encounter a lot of duplicate code in several different pipelines, and often we copy and paste it directly into different pipelines for convenience, but in the long run this code becomes more and more troublesome to maintain. To solve this problem, Jenkins provides the concept of shared libraries to solve the problem of duplicate code, we just need to extract the common parts, and then we can refer to the code under these shared libraries in all Pipelines.

What is a shared library?

A shared library is a collection of independent Groovy scripts that we can fetch when we run a Pipeline. The best way to use shared libraries is also to host the code in a Git repository so that we can version it. Of course, you need some basic knowledge of the Groovy language, but you don’t need to go too deep into it, just the basic syntax.

There are generally only three steps to using a shared repository.

  • first create a Groovy script and add it to your Git repository
  • Then configure the shared repository in Jenkins to add it to Jenkins
  • Finally, import the shared library you need to use in our pipeline: @Library('your-shared-library') so that you can use the code in the shared library.

Shared library content

There will be two general types of code in shared libraries.

  • Steps: These Steps are called global variables in Jenkins, and we can use these custom Steps in all Jenkins Pipelines.

For example, we can write a standard Step to deploy an application or send message notifications, etc. We can just add the code to the vars/YourStepName.groovy file and then implement a call function to.

1
2
3
4
5
6
#!/usr/bin/env groovy
// vars/YourStepName.groovy

def call() {
  // Do something here...
}
  • Other generic code: we can add some helper classes here, and also define static constants used throughout the pipeline, etc.

This code needs to be placed under the src/your/package/name directory, and then you can use the regular Groovy syntax, e.g.

1
2
3
4
5
6
7
#!/usr/bin/env groovy
// com/qikqiak/GlobalVars.groovy
package com.qikqiak

class GlobalVars {
   static String foo = "bar"
}

We can use import in the Jenkins Pipeline to import the above class and reference the static variables in it, such as GlobalVars.foo.

Example

Create a new folder called pipeline-library-demo and add the project to the Git repository. First create a directory called vars, and a custom step is a .groovy file under the vars directory. These are called global variables, for example, we add a sayHi.groovy file, and the code looks like this

1
2
3
4
5
#!/usr/bin/env groovy

def call(String name='QIKQIAK') {
  echo "Hello, ${name}."
}

Note that you need to implement the call method, adding a parameter named name with the default value QIKQIAK, which can be accessed with ${name}.

Then create a file named src/com/qikqiak/GlobalVars.groovy with the following contents.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/usr/bin/env groovy
package com.qikqiak

class GlobalVars {
  static String foo = "bar"

  // 在 Pipeline 中可以引用这里的静态变量:
  // 
  // import com.qikqiak.GlobalVars
  // println GlobalVars.foo
}

The complete code directory is shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ tree .
.
├── README.md
├── src
│   └── com
│       └── qikqiak
│           └── GlobalVars.groovy
└── vars
    └── sayHi.groovy

4 directories, 3 files

The complete code is uploaded to the GitHub repository at https://github.com/cnych/pipeline-library-demo.

Once the shared repository is created, we need to let Jenkins know about the shared repository, which we can add from the Jenkins web page. From the Jenkins home page -> System Administration -> System Configuration, configure the shared repository in the Global Pipeline Libraries area.

Save it and you can use the configuration shared library. Next, create a new pipeline project called share-lib-demo and add the following code to the Pipeline script area.

1
2
3
4
5
6
7
8
9
@Library('pipeline-library-demo')_

import com.qikqiak.GlobalVars

stage('Demo') {
    echo 'Hello world'
    sayHi '阳明'
    println GlobalVars.foo
}

Note that there is an underscore _ at the end of @Library('pipeline-library-demo')_, this underscore is not a mistake, if the line immediately after @Libray is not an import statement, then this underscore is needed, here we have an import statement, so we can omit this underscore here.

After the configuration is done, build the Pipeline and you will see the following build result as normal.

This completes the writing of a shared library.