Updating Your Maven Parent POM
This site is the new docs site currently being tested. For the actual docs in use please go to https://www.jenkins.io/doc. |
Most Jenkins plugins use Apache Maven as their build tool. Here are some tips on bringing your plugin up to current recommendations.
Using the 2.x (or newer) parent POM
Properly maintained Jenkins plugins are expected to use a 2.x-series (or newer) parent POM,
the later the better, to define the basic structure of pom.xml
.
You can use Maven itself to create a new plugin:
If you are instead upgrading an older plugin, replace a header such as
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.625</version>
</parent>
with the new format:
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.33</version>
<relativePath />
</parent>
<properties>
<jenkins.version>1.625</jenkins.version>
</properties>
Understanding requireUpperBoundDeps
failures and fixes
Sometimes after changing dependency versions in a POM and building,
you will encounter Maven Enforcer errors referring to a rule named RequireUpperBoundDeps
.
This rule means that if your plugin depends on some component (such as another plugin) A in version 13,
and another component B in version 7,
yet A version 13 expressed a dependency on B version 9 or newer,
then you may have a problem.
The practical impact could vary depending on the situation,
but in some cases it could mean LinkageError
s at runtime.
Transitive dependency plugin too old
For example, changing only the git
test dependency version from 3.9.1
to 4.0.0-rc
in the kubernetes
plugin might print:
--- maven-enforcer-plugin:3.0.0-M2:enforce (display-info) @ kubernetes ---
Adding ignore: module-info
Rule 5: org.apache.maven.plugins.enforcer.RequireUpperBoundDeps failed with message:
Failed while enforcing RequireUpperBoundDeps. The error(s) are [
Require upper bound dependencies error for org.jenkins-ci.plugins:git-client:2.7.5 paths to dependency are:
+-org.csanchez.jenkins.plugins:kubernetes:1.17.3-SNAPSHOT
+-org.jenkinsci.plugins:pipeline-model-definition:1.3.7
+-org.jenkins-ci.plugins:git-client:2.7.5
and
+-org.csanchez.jenkins.plugins:kubernetes:1.17.3-SNAPSHOT
+-org.jenkins-ci.plugins:git:4.0.0-rc
+-org.jenkins-ci.plugins:git-client:2.7.5 (managed) <-- org.jenkins-ci.plugins:git-client:3.0.0-rc
and
+-org.csanchez.jenkins.plugins:kubernetes:1.17.3-SNAPSHOT
+-org.jenkins-ci.plugins:git:3.9.1
+-org.jenkins-ci.plugins:git-client:2.7.5 (managed) <-- org.jenkins-ci.plugins:git-client:2.7.3
and
+-org.csanchez.jenkins.plugins:kubernetes:1.17.3-SNAPSHOT
+-org.jenkinsci.plugins:pipeline-model-definition:1.3.7
+-org.jenkins-ci.plugins.workflow:workflow-cps-global-lib:2.9
+-org.jenkins-ci.plugins:git-client:2.7.5 (managed) <-- org.jenkins-ci.plugins:git-client:2.7.0
and
+-org.csanchez.jenkins.plugins:kubernetes:1.17.3-SNAPSHOT
+-org.jenkinsci.plugins:pipeline-model-definition:1.3.7
+-org.jenkins-ci.plugins.workflow:workflow-cps-global-lib:2.9
+-org.jenkins-ci.plugins:git-server:1.7
+-org.jenkins-ci.plugins:git-client:2.7.5 (managed) <-- org.jenkins-ci.plugins:git-client:2.3.0
]
It takes a while to read the meaning behind this message,
but it is saying that git:4.0.0-rc
depends on git-client:3.0.0-rc
and yet we are currently using git-client:2.7.5
in our classpath.
Plugin tests in this configuration are likely to fail even if the Enforcer rule were suppressed,
since code added to Git 4 might be expecting to use APIs added to Git Client 3.
In this case (a bad plugin → plugin dependency),
the InjectedTest
in Jenkins 2.12 or later would also catch the mistake,
albeit more slowly (so less suitably for quick iteration):
… jenkins.InitReactorRunner$1 onTaskFailed
SEVERE: Failed Loading plugin Jenkins Git plugin v4.0.0-rc (git)
java.io.IOException: Jenkins Git plugin version 4.0.0-rc failed to load.
- Jenkins Git client plugin version 2.7.5 is older than required. To fix, install version 3.0.0-rc or later.
at hudson.PluginWrapper.resolvePluginDependencies(PluginWrapper.java:868)
at hudson.PluginManager$2$1$1.run(PluginManager.java:544)
at org.jvnet.hudson.reactor.TaskGraphBuilder$TaskImpl.run(TaskGraphBuilder.java:169)
at org.jvnet.hudson.reactor.Reactor.runTask(Reactor.java:296)
at jenkins.model.Jenkins$5.runTask(Jenkins.java:1091)
at org.jvnet.hudson.reactor.Reactor$2.run(Reactor.java:214)
at org.jvnet.hudson.reactor.Reactor$Node.run(Reactor.java:117)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
…
java.lang.Error: Plugin git failed to start
at org.jvnet.hudson.test.PluginAutomaticTestBuilder$OtherTests.testPluginActive(PluginAutomaticTestBuilder.java:99)
In other cases you might get a more cryptic NoSuchMethodError
error during tests;
or, worse, all tests might pass yet your plugin might throw an endless stream of errors at runtime.
The standard POM defines this Enforcer rule to reduce the likelihood of such mistakes.
The fix here is to also update the git-client
plugin version.
That in turn might also require another plugin to be updated.
This process can get tedious,
so you could consider using the “Bill of Materials” for plugins (under development):
At least for commonly encountered dependencies, the BOM can eliminate the need to specify individual versions and check that they work together.
Improper attempt to use core component
TODO unless using pluginFirstClassLoader
, a dep on a dep of jenkins-core
will be ignored at runtime
Test-scoped dependency mismatch
TODO if using a plugin and its <classifier>tests</classifier>
JAR too, introduce a POM property to make sure both are at the same version
Picking up fixes to dependency plugins
TODO if a problematic dep’s trail includes another plugin, check whether that plugin is built using a new POM and best practices