[JAVA] How to make a Jenkins plugin

Introduction

I wrote it because there were few Japanese documents that describe how to develop the Jenkins plugin. It summarizes the knowledge you will need if you try to go one step further from the Tutorial (https://jenkins.io/doc/developer/tutorial/prepare/). Information as of April 2018.

Create a development environment

Install the required tools

JDK and maven are required for plugin development. Install jdk and maven by referring to Plugin Development Tutorial.

Make a template for the project

Generate a project template with maven.

mvn -U archetype:generate -Dfilter=io.jenkins.archetypes:

When you execute the command, you will be asked some questions such as the type of template and artifact ID (plug-in name) interactively, so please answer appropriately. After creating the template, check that Jenkins starts at http: // localhost: 8080 / jenkins with the following command.

mvn hpi:run

The developed plug-in will be inserted in Jenkins started here. You can check the operation of the plugin on this Jenkins.

Basic flow of plugin development

Make a body class

Plugins are a class that inherits Jenkins extension points. When creating a plug-in, select an extension point that matches the function to be extended by the plug-in, and create a class that inherits it. Then, we will implement the function by overriding the method of the extension point. For example, if you override the perform method in a class that inherits Builder, which is an extension point of the build procedure, a plugin that adds a new build procedure. You can make an inn.

Extension point list allows you to see actual examples of plugins created by inheriting it for each extension point. Useful for selecting and implementing extension points.

Inform Jenkins of the existence of the plugin

You cannot use the plugin from Jenkins just by creating the main body class. In order to use the plugin, you need to notify Jenkins of the existence of the plugin. To do this, you need to create a Desctiptor as the inner class of the body class and annotate it with @Extention.

For example, if you look at AWS CodeBuild Plugin Body Class, the DescriptorImpl class is It is defined as an inner class and annotated with @Extension. DescriptorImpl inherits BuildStepDescriptor, but Descriptor defined as an inner class like this must inherit from the existing Descriptor. The Descriptor to inherit is different for each extension point. You can find out which Descriptor should be inherited from the example in Extension points list.

Add settings to the plugin

Plugins can have two settings, global and per job. Global settings are displayed in "Jenkins Management-> System Settings" on the Jenkins top page, and job-specific settings are displayed in "Settings" for each job. Here's how to add each setting.

Add global settings

Create global.jelly to display the settings input form. If the body of the plugin is located in src / main / java / jenkins / plugins / hoge / fuga, then global.jelly should be located in src / main / ** resources ** / jenkins / plugins / hoge / fuga .. It is good to refer to the existing plugin for how to write global.jelly. For example, if you want to add the name of MyPlugin as a setting, create the following global.jelly.

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">

  <f:section title="${%MyPlugin}" name="MyPlugin">
    <f:entry title="${%name}" field="name">
      <f:textbox />
    </f:entry>
  </f:section>

</j:jelly>

Next, modify the Descriptor so that it can read the entered settings. The settings are passed as an argument of type JSONObject to the configure method of Descriptor. In the case of global.jelly above, you can retrieve the name by modifying the Descriptor as follows.

@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Builder> {

    private String name;

    public DescriptorImpl(){
        load(); //Load previously saved global settings
    }

    @Override
    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
        json = json.getJSONObject("MyPlugin"); //Global settings are passed in the json argument
        name = json.getString("name");
        save();//Save global settings
        return true;
    }

    public String getName(){ //Prepare a getter so that the body class can retrieve the name
        return name;
    }
    .
    .
    .

The body class must retrieve the value from the Descriptor to take advantage of the global settings. To do this, make the following modifications to the body class.

public class MyPlugin extends Builder implements SimpleBuildStep {

    @Override
    public Descriptor getDescriptor() { //Descriptor getter
        return (Descriptor) super.getDescriptor();
    }

    @Override
    public void perform(Run<?, ?> run, FilePath workspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException {
        getDescriptor().getName(); //Get name from Descriptor
    }
    .
    .
    .
}

Add settings for each job

Create config.jelly to display the configuration input form. As with adding global settings, if the plugin body is located in src / main / java / jenkins / plugins / hoge / fuga, config.jelly will be src / main / ** resources ** / Place it in jenkins / plugins / hoge / fuga. For example, if you want to add color as a setting, create the following config.jelly.

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">

    <f:entry title="${%Color}" field="color">
        <f:textbox />
    </f:entry>

</j:jelly>

In order to use the settings for each job in the body class, it is necessary to annotate the constructor with @DataBoundConstructor and add an argument.

@DataBoundConstructor
public class MyPlugin extends Builder implements SimpleBuildStep {

    final private String color;

    @DataBoundConstructor
    public MyPlugin(String color){
        this.color = color; //Job-specific settings are passed as arguments
    }
    .
    .
    .
}

in conclusion

I explained the basic development method of the Jenkins plugin. For more practical things, I think you should learn from the examples in Extension Points.

Reference: Official documentation to help you develop plugins

document URL
Jenkins developer documentation https://jenkins.io/doc/developer/
Plugin creation tutorial https://jenkins.io/doc/developer/tutorial/
List of functions that can be extended by plugins https://jenkins.io/doc/developer/extensions/jenkins-core/
Jenkins developer wiki https://wiki.jenkins.io/display/JENKINS/Extend+Jenkins
Jenkins JavaDoc http://javadoc.jenkins-ci.org/

Recommended Posts

How to make a Jenkins plugin
How to make a Java container
How to make a splash screen
How to make a Maven project
How to make a Java array
How to make a Discord bot (Java)
How to make shaded-jar
How to make a lightweight JRE for distribution
How to make Unity Native Plugin (Android version)
How to make a follow function in Rails
How to make an app with a plugin mechanism [C # and Java]
How to leave a comment
[Rails] How to make seed
How to insert a video
How to create a method
How to make JavaScript work on a specific page
How to make a cache without thinking too much
How to make a mod for Slay the Spire
How to add columns to a table
How to make a Vagrant Plugin that you learned when you forked and published vagrant-mutagen
Try to make a simple callback
How to sign a Minecraft MOD
Learning Ruby with AtCoder 13 How to make a two-dimensional array
[Java] How to create a folder
How to write a ternary operator
[Swift] How to send a notification
Try to make a peepable iterator
[Android] How to make Dialog Fragment
How to make a hinadan for a Spring Boot project using SPRING INITIALIZR
How to make a jar file with no dependencies in Maven
[Unity] I tried to make a native plug-in UniNWPathMonitor using NWPathMonitor
How to identify the path that is easy to make a mistake
How to make a groundbreaking diamond using Java for statement wwww
[Xcode] How to add a README.md file
How to execute a contract using web3j
How to sort a List using Comparator
[Basic] How to write a Dockerfile Self-learning ②
How to insert a video in Rails
How to add a new hash / array
How to create a Maven repository for 2020
How to print a Java Word document
[Swift5] How to create a splash screen
[rails] How to create a partial template
How to make asynchronous pagenations using Kaminari
How to publish a library in jCenter
[SpringBoot] How to write a controller test
How to deploy
JVM Performance Tuning: What is Tuning and How to Make a Good Plan
Rails: How to write a rake task nicely
How to create a database for H2 Database anywhere
[Rails] How to write when making a subquery
How to deploy a container on AWS Lambda
[Rails] How to create a graph using lazy_high_charts
[Android] How to convert a character string to resourceId
Make a margin to the left of the TextField
How to get a heapdump from a Docker container
How to display a web page in Java
How to make Spring Boot Docker Image smaller
How to delete a controller etc. using a command
[Ethereum] How to execute a contract using web3j-Part 2-
How to create pagination for a "kaminari" array