Beliebte Suchanfragen

Cloud Native

DevOps

IT-Security

Agile Methoden

Java

//

Tutorial: Create a Jenkins Plugin to integrate Jenkins and Nexus Repository

5.8.2012 | 8 minutes of reading time

In this article you will learn how to write a Jenkins CI Plugin and how to use the REST API from the Sonatype Nexus repository. I am using Maven and Jersey (JAX-RS) for the project. The complete source code is hosted on github [2] . I hope this blog will encourage you to write your own Jenkins plugins and share them with the community. Have fun.

There comes a time in every developers life when you need write your own extension, addon or plugin when using open source software. In my case I was looking for a way to improve the Continuous Delivery Pipeline we setup using the Jenkins CI server and the Build Pipeline Plugin in a previous blog series [1] . In particular I wanted to add additional metadata to the deployed artifacts after each successful build step. This blog article will guide you through the creation of a Jenkins plugin. After that we will enhance the plugin to do some actual work and add custom metadata to the artifact in the Nexus repository. The following diagram shows the different steps in the build pipeline (CommitStage, AcceptanceTestStage, PerformanceTestStage). The CommitStage builds the software artifact and deploys it to Nexus. After each successful build step metadata is added to the deployed artifact, i.e. commitStage=success.


Part I: Create your first Jenkins Plugin

Create project skeleton

To get started you can use maven-hpi-plugin to create the project blueprint. I assume you have a working version of Maven installed as well as the Java JDK. In order to use the maven-hpi-plugin you need to add the following to your Maven settings.xml that you find under $HOME/.m2/settings.xml

1<settings>
2  <pluginGroups>
3    <pluginGroup>org.jenkins-ci.tools</pluginGroup>
4  </pluginGroups>
5  <profiles>
6    <profile>
7      <id>jenkins</id>
8      <activation>
9        <activeByDefault>true</activeByDefault>
10      </activation>
11      <repositories>
12        <repository>
13          <id>repo.jenkins-ci.org</id>
14          <url>http://repo.jenkins-ci.org/public/</url>
15        </repository>
16      </repositories>
17      <pluginRepositories>
18        <pluginRepository>
19          <id>repo.jenkins-ci.org</id>
20          <url>http://repo.jenkins-ci.org/public/</url>
21        </pluginRepository>
22      </pluginRepositories>
23    </profile>
24  </profiles>
25</settings>

Once you are done with the configuration you can create the project skeleton using the hpi:create command.

1$ mvn -cpu hpi:create

If you are having problems with the latest Plugin version, you can also specify the version of the plugin that you want to use.

1$ mvn -cpu org.jenkins-ci.tools:maven-hpi-plugin:1.84:create

During the installation Maven will ask you for the groupId and artifactId.

1Enter the groupId of your plugin: de.mb
2...
3Enter the artifactId of your plugin: nexus-metadata-plugin
4...

The generated project should have the following layout. Jenkins uses Apache Jelly as the view technology.

1marcelbirkner@ubuntu:~/workspaces/jenkins/nexus-metadata-plugin$ tree
2.
3├── pom.xml
4└── src
5    └── main
6        ├── java
7        │   └── de
8        │       └── mb
9        │           └── HelloWorldBuilder.java
10        └── resources
11            ├── de
12            │   └── mb
13            │       └── HelloWorldBuilder
14            │           ├── config.jelly
15            │           ├── global.jelly
16            │           ├── help-name.html
17            │           └── help-useFrench.html
18            └── index.jelly

After the project skeleton is set up you can compile and package the plugin.

1$ cd nexus-metadata-plugin
2$ mvn package

After packaging the plugin you should find a .hpi file in the target folder.

Deploy plugin in Jenkins

In order to test the new plugin you need to have Jenkins running.

Update: Use mvn hpi:run and Jenkins will start automatically with your plugin ready for use.

Another way to get Jenkins up and running is to download the WAR file from the Jenkins mirrors [4] and start it using:

1java -jar jenkins.war

Once Jenkins is up and running you can deploy your plugin.

  • Go to http://localhost:8080/
  • Manage Jenkins -> Manage Plugins -> Advanced -> Upload Plugin
  • Select nexus-metadata-plugin/target/nexus-metadata-plugin.hpi and upload to Jenkins server
  • Click “Download now and install after restart”
  • Restart Jenkins

The plugin should be available after restarting Jenkins. Now you can go and configure the plugin.

  • Jenkins Menu -> Manage Jenkins -> Configure System

You will find a section that looks like the following diagram. The plugin will print out “Hello World” if you run it during a build step. You can configure if it should greet you in english or french by selecting the checkbox.

Test Plugin

To test your new plugin you need to follow these steps:

  • Create a new Jenkins Job (i.e. Freestyle)
  • Add Build Step “Say hello world” to the Job
  • Fill out the name field in the build step
  • Build Job
  • Check command line from job

If the build is successful and you see “Hello, World!” in the command line everything is fine. Otherwise start reading from top and try again 😉 or consult the official Jenkins Plugin documentation [3] .

Part II: Install and configure Nexus Repository

Adding custom metadata to artifacts in the Nexus Repository requires Nexus Professional. Another Open Source Repository that offers the same functionality is Artifactory from JFrog. Both offer a REST API and a Professional Version. In both cases you need the Pro Version to add metadata to artifacts.

Setup Nexus

To setup Nexus follow these steps:

  • Download Nexus Pro from Sonatype, http://www.sonatype.com/Products/Nexus-Professional/Purchase/Free-Trial
  • Extract the archive
  • The nexus-custom-metadata-plugin is not enabled by default. To enable it copy it to the plugin-repository folder.

1cp -r nexus-professional-trial-2.0.6/nexus/WEB-INF/optional-plugins/nexus-custom-metadata-plugin-2.0.6/ 
2      nexus-professional-trial-2.0.6/nexus/WEB-INF/plugin-repository/
  • Start Nexus

1nexus-professional-trial-2.0.6/bin$ ./nexus start
  • Open Nexus in your browser and register for the 14 day trial version, http://localhost:8081/nexus
  • You will receive an Email with the Trial registration code via Email within a minute
  • Login with admin/admin123

To verify that the nexus-custom-metadata-plugin was installed successful go to Administration -> Plugin Console. There you should see the following information. If you click the links you should be forwarded to the REST API of the Plugin.

Under the same section you will find the Core Documentation as well. That one contains the Core REST API calls that you can use by default. Unfortunately that API does not allow you to store metadata for artifacts.

Setup Maven Project

Under the REST API documentation you will find a client.jar that provides all the REST Models we need for calling the REST API. Therefore download the JAR and upload it to the ThirdParty repository in Nexus.

  • Download from: http://localhost:8081/nexus/nexus-custom-metadata-plugin/m2/docs/nexus-custom-metadata-plugin-client.jar

Next, you need to configure your Maven $HOME/.m2/settings.xml to use Nexus for resolving Maven artifacts. Add the following lines to the settings.xml.

1<mirrors>
2    <mirror>
3      <!--This sends everything else to /public -->
4      <id>nexus</id>
5      <mirrorOf>*</mirrorOf>
6      <url>http://localhost:8081/nexus/content/groups/public</url>
7    </mirror>
8  </mirrors>
9  <profiles>
10    <profile>
11      <id>nexus</id>
12      <!--Enable snapshots for the built in central repo to direct -->
13      <!--all requests to nexus via the mirror -->
14      <repositories>
15        <repository>
16          <id>central</id>
17          <url>http://central</url>
18          <releases><enabled>true</enabled></releases>
19          <snapshots><enabled>true</enabled></snapshots>
20        </repository>
21      </repositories>
22     <pluginRepositories>
23        <pluginRepository>
24          <id>central</id>
25          <url>http://central</url>
26          <releases><enabled>true</enabled></releases>
27          <snapshots><enabled>true</enabled></snapshots>
28        </pluginRepository>
29      </pluginRepositories>
30    </profile>
31  </profiles>
32  <activeProfiles>
33    <!--make the profile active all the time -->
34    <activeProfile>nexus</activeProfile>
35  </activeProfiles>

After that we are ready to start developing the plugin.

Part III: Integrate Jenkins and Nexus with a custom Jenkins Plugin

Now that we have Jenkins and Nexus up and running we can go back to do some coding. I suggest you clone the code from my github repository. I will explain all changes I made step-by-step.

Add Dependencies

For calling the Nexus REST API’s I decided to use the Jersey Framework. Simply add the following dependencies to your pom.xml.

1<dependency>
2    <groupId>com.sun.jersey</groupId>
3    <artifactId>jersey-client</artifactId>
4    <version>1.12</version>
5</dependency>
6<dependency>
7    <groupId>org.sonatype.nexus</groupId>
8    <artifactId>nexus-rest-api-model</artifactId>
9    <version>2.0.6</version>
10</dependency>
11<dependency>
12    <groupId>org.sonatype.nexus</groupId>
13    <artifactId>nexus-custom-metadata-plugin-client</artifactId>
14    <version>1.0</version>
15</dependency>

Configure Metadata Plugin

Rename the HelloWorldBuilder packages under src/main/java and src/main/resources to NexusMetadataBuilder.

To make the Jenkins Plugin configurable add the following lines to the global.jelly. This allows us to specify the Nexus URL and credentials in the Jenkins configuration.

1<f:section title="Nexus Metadata">
2    <f:entry title="Nexus URL" field="nexusUrl"
3      description="Add Nexus URL">
4      <f:textbox />
5    </f:entry>
6    <f:entry title="User" field="nexusUser"
7      description="Add Nexus User">
8      <f:textbox />
9    </f:entry>
10    <f:entry title="Password" field="nexusPassword"
11      description="Add Nexus Password">
12      <f:textbox />
13    </f:entry>
14  </f:section>

In the next step we add some fields that we can configure on the Job. We need to be able to tell the Plugin the Key/Value we want to store with the artifact and the location of the artifact in the Nexus repository (groupId, artifactId, version, packaging).

1<f:entry title="Key" field="key">
2    <f:textbox />
3  </f:entry>
4  <f:entry title="Value" field="value">
5    <f:textbox />
6  </f:entry>
7  <f:entry title="groupId" field="groupId">
8    <f:textbox />
9  </f:entry>
10    <f:entry title="artifactId" field="artifactId">
11    <f:textbox />
12  </f:entry>
13    <f:entry title="version" field="version">
14    <f:textbox />
15  </f:entry>
16  <f:entry title="packaging" field="packaging">
17    <f:textbox />
18  </f:entry>

Now we can create the NexusMetadataBuilder.java [5] class that will put all the pieces together. This class takes care of reading the plugin configuration (NexusUrl & Credentials) as well as the configuration from the Build Job (groupId, artifactId, version, packaging). In perform Method we create the REST Client that calls out to the Nexus REST API. The first call uses the Nexus Core API and checks the status of Nexus. It should return “200 OK” when its up and running. The REST Mount Point is: /service/local/status

1// setup REST-Client
2ClientConfig config = new DefaultClientConfig();
3Client client = Client.create(config);
4client.addFilter( new HTTPBasicAuthFilter(user, password) ); 
5WebResource service = client.resource( url );
6 
7listener.getLogger().println("Check that Nexus is running");
8String nexusStatus = service.path("service").path("local").path("status").accept(MediaType.APPLICATION_JSON).get(ClientResponse.class).toString();
9listener.getLogger().println(nexusStatus + "\n");

For the custom metadata plugin we need to encode the “subject” (location of the artifact) with Base64, which is not really RESTful in my opinion. The REST Mount Point is: /service/local/index/custom_metadata/{repository}/{subject}

1String artefact = "urn:maven/artifact#"+getGroupId()+":"+getArtifactId()+":"+getVersion()+"::"+getPackaging()+"";
2listener.getLogger().println("GET metadata for artefact " + artefact);
3String encodedString = new String( Base64.encode( artefact.getBytes() ) );
4 
5listener.getLogger().println("POST: add new metadata to artefact " + artefact);
6CustomMetadataRequest customRequest = getCustomMetadataRequest( getKey(), getValue() );
7 
8service.path("service").path("local").path("index").path("custom_metadata").path("releases")
9.path(encodedString).accept( MediaType.APPLICATION_JSON ).post( customRequest );

Build Plugin from Github

If you want to build the project from Github follow these steps:

1git@github.com:marcelbirkner/nexus-metadata-plugin.git
2cd nexus-metadata-plugin
3mvn clean package

Afterwards you will find the nexus-metadata-plugin.hpi plugin in the /target folder. Once you deploy the plugin and configure each build step of the continuous delivery build pipeline the deployed artifact in Nexus will have the metadata attached, see diagram.

Summary

This has been a long tutorial but I tried to cover the most important steps. I hope you could learn a little and feel encouraged to start writing and sharing your own Jenkins Plugins. Check out the Jenkins CI homepage on how to contribute Plugins to the community.

References

[1] Continuous Delivery Pipeline, Continuous Delivery in the cloud
[2] Sourcecode on github, https://github.com/marcelbirkner/nexus-metadata-plugin .
[3] Jenkins Plugin Tutorial, https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial
[4] Jenkins Download, http://mirrors.jenkins-ci.org/war/latest/jenkins.war
[5] NexusMetadataBuilder, nexus-metadata-plugin @ github

share post

Likes

0

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.