Gradle plugin dependency hell
DLL hell hasn’t gone away; it’s a bit like a cold, always coming back to bite you in ass
Recently I’ve started using the gradle axion-release plugin; it’s a nice idea since I agree with its core precepts. It means that I don’t have to think about what the next version number will be since that is now derivable from git history. This post isn’t about that though, it’s about gradle plugin dependency management and the rabbit hole I found myself in.
A recent PR generated by dependabot to bump axion-release-plugin to 1.14.1
failed; this was somewhat unexpected for a point release, the failure doesn’t seem obvious and you can’t even ask gradle for the buildEnvironment.
$ gradle buildEnvironment
NOTE: Picked up JDK_JAVA_OPTIONS: -Dpolyglot.engine.WarnInterpreterOnly=false -Dlog4j2.Script.enableLanguages=javascript
Daemon will be stopped at the end of the build
FAILURE: Build failed with an exception.
* Where:
Build file 'C:\storage\work\monkbond\graalvm-binding\build.gradle' line: 190
* What went wrong:
A problem occurred evaluating root project 'graalvm-binding'.
> class "org.eclipse.jgit.transport.JschConfigSessionFactory"'s signer information does not match signer information of other classes in the same package
...
BUILD FAILED in 16s
I’m also using grgit to avoid having to do commandline git commands as part of my build.gradle
. This meant that the problem was semi-obvious to me, grgit-5.0 was interfering with axion-release-plugin-1.14.1. They are both git related, and I expect they are both dependent on eclipse jgit.
The TLDR; solution for me was to pin jgit to the version dictated by axion-release-plugin; grgit-5.0 works quite happily with it for my limited use of it (which was to figure out the branch name). Equally I could have pinned grgit to 4.11 since the release notes indicate that this depends on jgit-5.13.0
Doing this has the side-effect of causing dependabot to not consider
jgit
as a dependency that needs to be checked for updates (this is coincidental, but desirable)
buildscript {
dependencies {
classpath ("org.eclipse.jgit:org.eclipse.jgit") {
version {
strictly "5.13.1.202206130422-r"
because "axion-release is more important than grgit"
}
}
classpath ("org.eclipse.jgit:org.eclipse.jgit.ssh.jsch") { version { strictly "5.13.1.202206130422-r" }}
classpath ("org.eclipse.jgit:org.eclipse.jgit.ssh.apache") { version { strictly "5.13.1.202206130422-r" }}
classpath ("org.eclipse.jgit:org.eclipse.jgit.gpg.bc") { version { strictly "5.13.1.202206130422-r" }}
classpath ("org.eclipse.jgit:org.eclipse.jgit.ui") { version { strictly "5.13.1.202206130422-r" }}
}
}
plugins {
id 'java-library'
id 'maven-publish'
id 'jacoco'
id 'org.ajoberstar.grgit' version '5.0.0'
id 'pl.allegro.tech.build.axion-release' version '1.14.1'
}
If we dig deeper into the dependency tree, then it turns out eclipse-jgit is now at 6.3.x (Java11+?), grgit-5.0 depends on jgit-6.0.0 and is Java11+ only, axion-release-plugin depends on jgit-5.13.1 but presumably remains Java8 compatible. Since axion-release is able to push tags it also depends on additional packages org.eclipse.jgit.ssh.jsch
amongst other things. So org.eclipse.jgit
is being optimistically updated to 6.0.0, but org.eclipse.jgit.ssh.jsch
remains pinned at 5.13.1 since there is no explicit dependency via grgit.
The actual exception stems from duplicate packages in separate jars, where one jar is signed, the other isn’t, or they’re signed with different certificates. I didn’t bother looking too deeply at this but signing jars surely has to mean sorting out your java package hierarchy properly; there’s little reason to have the same package in 2 separate jars, that’s just crazy talk and open to all sorts of classloading tomfoolery and exactly this problem. Living in the same package because of package-level visibility is a code smell and implies you need to rethink your packages.
It does annoy me that a point release of a plugin wasted half an hour of my life; it’s not the plugin developers fault but interacting with git via gradle isn’t an unusual use-case. In the end the fix wasn’t hard, but I have to document it because the reason will be non-obvious to the next developer that picks up my work.