Converting from Maven to Gradle, need more specified dependencies in build.gradle or tests fail

I am trying to convert a Jenkins plugin from building with Maven to building with Gradle, making use of the gradle-jpi-plugin ( https://plugins.gradle.org/plugin/org.jenkins-ci.jpi )

The code for the plugin that I am working with is available at:

To build the code with Maven:

mvn package

or

mvn -DskipTests package

To build the code with Gradle:

gradle build

When converting the Maven pom.xml file to a Gradle build.gradle file,
the confusing part for me is that I had to specify more dependencies in the Gradle file
than in the Maven file, otherwise the build would fail with Gradle.

    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>1.8.5</version>
            <scope>provided</scope> <!-- from jenkins-core -->
        </dependency>
        <dependency>
            <groupId>org.jgrapht</groupId>
            <artifactId>jgrapht-jdk1.5</artifactId>
            <version>0.7.3</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.8.5</version>
            <scope>test</scope>
        </dependency>

        <!-- Add test dependencies for pipeline plugin -->
        <dependency>
            <groupId>org.jenkins-ci.plugins.workflow</groupId>
            <artifactId>workflow-job</artifactId>
            <version>${pipeline.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jenkins-ci.plugins.workflow</groupId>
            <artifactId>workflow-basic-steps</artifactId>
            <version>${pipeline.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jenkins-ci.plugins.workflow</groupId>
            <artifactId>workflow-cps</artifactId>
            <version>${pipeline.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jenkins-ci.plugins.workflow</groupId>
            <artifactId>workflow-durable-task-step</artifactId>
            <version>${pipeline.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

This is the dependency list for build.gradle:

dependencies {
    compile "org.jgrapht:jgrapht-jdk1.5:0.7.3"
    compile 'com.cloudbees:groovy-cps:1.7@jar'
    jenkinsPlugins 'org.jenkins-ci.plugins:matrix-project:1.7@jar'
    jenkinsPlugins 'org.jenkins-ci.plugins:junit:1.13@jar'

    // Test dependencies
    jenkinsTest "org.jenkins-ci.plugins:ant:1.3@jar"
    jenkinsTest "org.mockito:mockito-all:1.8.5@jar"
    jenkinsTest 'org.jenkins-ci.plugins:script-security:1.19@jar'
    jenkinsTest 'org.jenkins-ci.main:maven-plugin:2.12.1@jar'
    jenkinsTest 'org.jenkins-ci.plugins:javadoc:1.3@jar'
    jenkinsTest 'org.jenkins-ci.plugins:mailer:1.17@jar'

    // Test dependencies for pipeline plugin
    jenkinsTest "org.jenkins-ci.plugins:durable-task:1.10@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-api:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-basic-steps:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-cps:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-durable-task-step:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-job:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-scm-step:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-step-api:1.13@jar"
    jenkinsTest "org.jenkins-ci.plugins.workflow:workflow-support:1.13@jar"
}

If I make the build.gradle file have the same dependencies as pom.xml,
then lots of various java.lang.NoClassDefFoundError errors when running the tests.

Any idea what is going on and why pom.xml dependencies are less than build.gradle?

Thanks.

The notation “org.jenkins-ci.plugins.workflow:workflow-support:1.13@jar” is known as an artifact-only notation.

From the documentation:

An artifact only notation creates a module dependency which downloads only the artifact file with the specified extension. Existing module descriptors are ignored.

Since you’re only downloading the jar file and not its associated POM file, you don’t inherit the transitive dependencies hence the need to manually define them in the Gradle script

Thank you @Francois_Ritaly!! I am new to gradle and would not have figured that out.

The gradle-jpi-plugin documentation gives a few examples with @jar notation for depenencies:

and does not mention anything about artifact-only notation. I will follow up with the gradle-jpi-plugin maintainer, but do you have any ideas as to why the artifact-only notation is used in the example and not explained in terms of not downloading all the dependencies?

I took a look inside the source code for gradle-jpi-plugin, and in a few places inside the plugin itself, it uses artifact-only notation for dependencies.

Thank you!!!

You should use the following notation

dependencies {
  jenkinsTest group: 'org.jenkins-ci.plugins', name: 'ant', version: '1.3', ext: 'jar' 
}

If you use jenkinsTest "org.jenkins-ci.plugins:ant:1.3, Gradle will download the POM file, parse it, infer the packaging (hpi) and download the hpi file (not the jar file) but you’ll have the transitive dependencies because you parsed the POM. However the hpi file isn’t what you need because its content is different from the jar file (just compare them)

If you use jenkinsTest "org.jenkins-ci.plugins:ant:1.3@jar", you’re fetching the jar file (which is what you want) however you don’t parse the POM file and therefore don’t pull the transitive dependencies.

By using jenkinsTest group: 'org.jenkins-ci.plugins', name: 'ant', version: '1.3', ext: 'jar' you’re asking Gradle to fetch the jar file and also parse the POM file so you get what you want (jar file + transitive dependencies)

1 Like