New plugin developer: A View Plugin

51 views
Skip to first unread message

Sverre Moe

unread,
Apr 18, 2018, 5:18:45 PM4/18/18
to Jenkins Developers
Let me begin starting with I have never written a plugin to Jenkins before.
I have plenty of insight into the Jenkins API for Groovy scripting in script console and scripting Pipeline scripts.
I am a Java developer for over 10 years (API/Spring, Swing/JavaFX), and have been using Jenkins for most of those years. Most of our inhouse software is C++ though, and a few Java.

I was thinking of creating a custom view plugin to Jenkins for our company. Our developers are not happy with the Jenkins UI (Blue Ocean is a step forward, but it is still slow and doesn't support customization on pipelines view). They feel it is difficult to get an overview which release branches has failed, as all the user branches are getting in the way of that on Multibranch Pipeline jobs. 

It is hard to convince my peers that Jenkins is much better than our inhouse legacy CI system (bunch of ruby scripts, which a single developer now has revamped with a Vue.js frontend) for people that has never used a third party CI system like Jenkins. The arguments I frequent hear is why use resources with Jenkins when there is already a functional CI system. They (He) feels all the work I have put in pipelines is wasted, and that we should abandon Jenkins to build releases. Well, enough about that (I just had to went a little about my reason for creating a custom view plugin).

The plugin I was thinking of creating should list projects with branches status. Usually with multibranch pipelines you would have to click on the project to get the list of branches, but I wanted the view plugin to list branches along with the project on the view page.

Currently I want to start simple, by just listing all the projects and get it up and running on Jenkins.

I am seeking some good documentation, howto's for creating Jenkins plugins, specifically a View plugin.
This tutorial revolves around creating a Builder. Could not find a tutorial for creating a view plugin, so I will start with this one.

Even a visual simple view plugin like jenkins-build-monitor-plugin, looks very complex. I am getting lost in all the source code. Most of it probably not relevant for my plugin.
A reckon a view plugin is half Java code, half HTML/Javascript/CSS code, and some jelly it seems also.

Having browsed this jenkins-build-monitor-plugin on GitHub I am overwhelmed. It has almost chased me away, but not quite. I think I must start small, just the few bits I need to get a view plugin up to display some projects, get the basic feel of the building blocks.


Generating the maven project
mvn archetype:generate -Dfilter=io.jenkins.archetypes:plugin
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> io.jenkins.archetypes:empty-plugin (Skeleton of a Jenkins plugin with a POM and an empty source tree.)
2: remote -> io.jenkins.archetypes:global-configuration-plugin (Skeleton of a Jenkins plugin with a POM and an example piece of global configuration.)
3: remote -> io.jenkins.archetypes:hello-world-plugin (Skeleton of a Jenkins plugin with a POM and an example build step.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1
Choose io.jenkins.archetypes:empty-plugin version:  
1: 1.0
2: 1.1
3: 1.2
4: 1.3
5: 1.4
Choose a number: 5: 5

I Went through the pom.xml and updated some values
 <jenkins.version>2.117</jenkins.version>
 
<java.level>8</java.level>

Currently no source files yet in my plugin, nor tests. Running mvn install fails:
[ERROR] Errors:  
[ERROR] org.junit.runner.manipulation.Filter.initializationError(org.junit.runner.manipulation.Filter)
[ERROR]   Run 1: Filter.initializationError »  No tests found matching Method org.jvnet.hudson....
[ERROR]   Run 2: Filter.initializationError »  No runnable methods
[ERROR]   Run 3: Filter.initializationError »  No runnable methods
[ERROR]   Run 4: Filter.initializationError »  No runnable methods
[INFO]  
[ERROR]   FailedTest.org.jvnet.hudson.test.JellyTestSuiteBuilder$JellyTestSuite » FailingHttpStatusCode
[INFO]  
[ERROR] Tests run: 2, Failures: 0, Errors: 2, Skipped: 0


What kind of test is this? There is nothing in my newly created project.

Jesse Glick

unread,
Apr 18, 2018, 6:52:15 PM4/18/18
to Jenkins Dev
On Wed, Apr 18, 2018 at 5:18 PM, Sverre Moe <sverr...@gmail.com> wrote:
> What kind of test is this? There is nothing in my newly created project.

The Jenkins plugin build harness generates a synthetic test to verify
basic sanity aspects of your plugin. I am not sure what specifically
the `FailingHttpStatusCodeException` is—that would be included in test
details under `target/surefire-reports/`.

Sverre Moe

unread,
Apr 20, 2018, 2:27:16 PM4/20/18
to Jenkins Developers
target/surefire-reports/TEST-InjectedTest.xml

WARNING: Failed to instantiate Key[type=org.jenkinsci.main.modules.instance_identity.PageDecoratorImpl, annotation=[none]]; skipping this component
com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Error injecting constructor, java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
  at org.jenkinsci.main.modules.instance_identity.PageDecoratorImpl.<init>(PageDecoratorImpl.java:21)

1 error
        at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:52)
        at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:145)
        at hudson.ExtensionFinder$GuiceFinder$FaultTolerantScope$1.get(ExtensionFinder.java:424)
        at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41)
        at com.google.inject.internal.InjectorImpl$2$1.call(InjectorImpl.java:1016)
        at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
        at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1012)
        at hudson.ExtensionFinder$GuiceFinder._find(ExtensionFinder.java:386)
        at hudson.ExtensionFinder$GuiceFinder.find(ExtensionFinder.java:377)
        at hudson.ClassicPluginStrategy.findComponents(ClassicPluginStrategy.java:482)
        at hudson.ExtensionList.load(ExtensionList.java:366)
        at hudson.ExtensionList.ensureLoaded(ExtensionList.java:304)
        at hudson.ExtensionList.iterator(ExtensionList.java:158)
        at hudson.diagnosis.NullIdDescriptorMonitor.verify(NullIdDescriptorMonitor.java:72)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at hudson.init.TaskMethodFinder.invoke(TaskMethodFinder.java:104)
        at hudson.init.TaskMethodFinder$TaskImpl.run(TaskMethodFinder.java:175)
        at org.jvnet.hudson.reactor.Reactor.runTask(Reactor.java:296)
        at jenkins.model.Jenkins$5.runTask(Jenkins.java:1062)
        at org.jvnet.hudson.reactor.Reactor$2.run(Reactor.java:214)
        at org.jvnet.hudson.reactor.Reactor$Node.run(Reactor.java:117)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
        at org.jenkinsci.main.modules.instance_identity.pem.PEMHelper.writeEncoded(PEMHelper.java:188)
        at org.jenkinsci.main.modules.instance_identity.pem.PEMHelper.encodePEM(PEMHelper.java:113)
        at org.jenkinsci.main.modules.instance_identity.InstanceIdentity.write(InstanceIdentity.java:96)
        at org.jenkinsci.main.modules.instance_identity.InstanceIdentity.<init>(InstanceIdentity.java:66)
        at org.jenkinsci.main.modules.instance_identity.InstanceIdentity.<init>(InstanceIdentity.java:40)
        at org.jenkinsci.main.modules.instance_identity.PageDecoratorImpl.<init>(PageDecoratorImpl.java:22)
        at org.jenkinsci.main.modules.instance_identity.PageDecoratorImpl$$FastClassByGuice$$68618106.newInstance(<generated>)
        at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40)
        at com.google.inject.internal.DefaultConstructionProxyFactory$1.newInstance(DefaultConstructionProxyFactory.java:61)
        at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:105)
        at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:85)
        at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:267)
        at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
        at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103)
        at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
        ... 26 more
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
        ... 41 more


This made me suspect that I was using OpenJDK and Java 9.
I set JAVA_HOME to Oracle JDK 8 and I was able to run mvn install without any test errors.

Jesse Glick

unread,
Apr 20, 2018, 3:01:45 PM4/20/18
to Jenkins Dev
On Fri, Apr 20, 2018 at 2:27 PM, Sverre Moe <sverr...@gmail.com> wrote:
> This made me suspect that I was using OpenJDK and Java 9.

Oh, well Jenkins does not run on Java 9. At all. So there is that.
Reply all
Reply to author
Forward
0 new messages