Trouble with test-runtime dependencies: ClassNotFoundExceptions

Hoo boy.

I am trying to add a feature to the os.nebula rpm plugin. This plugin depends on the Redline RPM LIbrary. The feature I am implementing is actually implemented in the Redline Library. So I have to build a version of that to get my feature.

The first step is to build the new version of Redline and install it in my local Maven repository - successfully. (It’s a Maven Build, not Gradle).
The second step is to modify the os.nebula plugin build script to use my version of Redline RPM.
The third step is to add a little code to os.nebula to use the new feature in Redline.

I can’t get past step 2. After modifying the os-nebula build.gradle to use my Redline version I find that the os-nebula code and test code compiles, but when the test code runs, ClassNotFoundExceptions are thrown concerning classes in redline, when the Test Code generates a build script and attempts to run it. The classpath with which the tests run their scripts is somehow not the same as what the tests are expecting.

Looking at the os-nebula source, the problem seems to be some bad interaction between my new dependencies and os-nebula’s integration test runners which do some sort of magic to put together a classpath on which they run test buildscripts generated on the fly.

Ironically, and I don’t remember quite how, about a week ago, I was able to build this thing and get its product into my local maven repo. No code changes have transpired since then.

Here are the changes I made to the build.gradle for os:nebula:

BEFORE:

    buildscript { repositories { jcenter() } } // Some plugin dependencies (namely JFrog) are not in Maven Central
...
dependencies {
    compile 'org.apache.commons:commons-lang3:3.1'
    compile('org.redline-rpm:redline:1.2.2') {

Since my changes to redline are not anywhere yet but my local maven repo, I had to add a repository block to even get the code to compile:

AFTER:

buildscript { repositories { jcenter() } } // Some plugin dependencies (namely JFrog) are not in Maven Central
...
repositories {
    mavenCentral name: "nexus", artifactUrls: ["http://mavencentral.it.corporation.com:8084/nexus/content/groups/corporation-public-group"]
    mavenLocal()
}
dependencies {
    compile 'org.apache.commons:commons-lang3:3.1'
    compile('org.redline-rpm:redline:1.2.3-SNAPSHOT') {

This lets the code compile, but the tests are getting screwed up somehow in the classpath.

I’ve tried all sorts of alternatives:

  1. put all the repos in the buildscript list dispense with my second block. This way it will not even compile. It always looks for my version of redline in jcenter.
  2. put all the repos in both places.

Am I missing something obvious? What is the right way to handle these dependencies when building and testing plugins?

If not, what I would like to do is turn off all or some of the tests temporarily. They are not testing anything I am working on. Then if my changes ever make it into the redline code base, I will look at this again and should be able to have a build script like the original except for redline version number.

To make a very long story short, my question may be rephrased this way:

given that a plugin-building script must draw dependencies from two separate repositories and that artifacts from both of these repositories must be on the classpath at the time the functional tests are run (since the functional tests create build scripts that exercise the built plugin), what is the proper way to achieve this?

I think the real source of the difficulties has to do with line 54 of the plugin’s build script which reads:

apply from: 'https://raw.githubusercontent.com/nebula-plugins/nebula-core/b676bbc026d0053494b5439ba8ef147c16adabba/common.gradle

Applying that URL in turn introduces still more complexity into the classpath:

dependencies {
    compile localGroovy()
    compile gradleApi()
    testCompile('com.netflix.nebula:nebula-test:4.0.0') {
        exclude group: 'org.codehaus.groovy'
    }
}

...

repositories {
    jcenter()
}

What is the effect of applying such a script into the middle of another script? Are the classpaths merged together or does the last-read set of repositories and dependencies override earlier declarations?