Implementing Encapsulation, Inheritance, and Polymorphism in Jenkins Shared Library Pipelines using Groovy
Jenkins shared libraries provide an excellent way to encapsulate code for use across multiple pipelines. By leveraging Java’s object-oriented principles—encapsulation, inheritance, and polymorphism within a groovy script context (like the jenkinsfile
) — you can create reusable pipeline components that exhibit these characteristics. Below is an example of how to apply each concept using Jenkins shared libraries:
Encapsulation Example in Groovy with Shared Libraries
Encapsulation hides data within classes, providing controlled access through methods (getters and setters). Here’s a simple demonstration adapted for use in pipeline code. We have an abstract class that defines properties which are then implemented by subclasses:
package com.examplecompany.builders
abstract class AbstractWidgetBuilder {
protected String color = null // Encapsulated property, initialized to `null`
public def build() {
throw new Exception("Build method must be defined in concrete classes")
}
}
Inheritance can then extend these abstract concepts:
File: WidgetXBuilder.groovy (inherits from AbstractWidgetBuilder)
package com.examplecompany.builders
import org.jenkinsci.plugins.workflow.cps.CpsDirtyContext
class WidgetXBuilder extends AbstractWidgetBuilder {
public def build() {
super.color = "blue" // Accessing encapsulated property from base class
echo "${super.shape} widget with ${this.numLegs} legs."
}
protected String shape = 'round' // Additional attribute specific to WidgetXBuilder, inheriting the concept of polymorphism where both classes can have different shapes but a common interface (build method)
}
The same goes for WidgetYBuilder
:
File: WidgetYBuilder.groovy
package com.examplecompany.builders
import org.jenkinsci.plugins.workflow.cps.CpsDirtyContext
class WidgetYBuilder extends AbstractWidgetBuilder {
public def build() {
super.color = "green" // Accessing encapsulated property from base class
echo "${super.shape} widget with ${this.numLegs} legs."
each attribute like `shape` would differ between subclasses, demonstrating polymorphism as these different classes will respond differently to the same method call due to their inheritance hierarchy and overridden methods:
```groovy
def obj = new WidgetYBuilder("red", 4) // Creates a specific instance of our object with inherited properties. Here 'yellow' would be its unique shape if such is defined within `WidgetYBuilder`.
obj.build() # Builds as per the subclass implementation, showcasing polymorphism (different behavior for WidgetX and Y build processes).
To use this in a Jenkins pipeline (Jenkinsfile
), import these classes from your shared library:
File: jenkinsfile
@Library('shared-library') _ // Load the Maven Shared Library plugin. Replace 'examplecompany' with actual company name and adjust paths as necessary for local installation or repository location of artifacts
import com.examplecompany.builders.WidgetXBuilder
import com.examplecompany.builders.WidgetYBuilder
node { // Define a pipeline within the Jenkins environment
def obj = new WidgetXBuilder("blue",2) # Instantiate our build object
echo "Building widget: ${obj}"
sh(returnStdio: true, script: "${obj.build()}") // Invoke built method and pass through the pipeline steps
}
Here we’ve implemented encapsulation by allowing base class properties to be set within subclasses (inheritance) while also demonstrating polymorphism when different types of Widget builders respond differently due their unique attributes or behavior, yet they share a common interface for building objects.
Note that the exact structure and methods will depend on your specific requirements but this example should give you an idea about encapsulating code within Jenkins shared libraries to provide reusable constructs with inheritance and polymorphism in mind. Remember always to keep sensitive data private as needed, which is a core principle of object-oriented programming — for instance by marking properties like color
or build parameters as final where appropriate (thus not allowing them from being changed after construction), using getters/setters properly within your classes and limit their visibility (private
, protected
), etc.
Happy building!