- Part I: Create your first Jenkins Plugin
- Part II: Install and configure Nexus Repository
- Part III: Integrate Jenkins and Nexus with a custom Jenkins Plugin
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.
- Nexus Professional Plugin :: Custom Metadata
- http://localhost:8081/nexus/nexus-custom-metadata-plugin/m2/docs/index.html
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.
- Nexus : Core Plugins : Core Documentation
- http://localhost:8081/nexus/nexus-core-documentation-plugin/core/docs/index.html
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
More articles
fromMarcel Birkner
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
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.
Blog author
Marcel Birkner
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.