Gradle on windows is failing with error: “The Command line is too long.” during junitPlatformTest


(Maksim Kostromin) #1

Hello,

TL;DR: In multi-project builds, if app has a lot subproject dependencies in this way: compile(project(':project:path')) some build/test tasks are failing on windows OS with command is too long error…

From requirements, we must build self-contained fat-jar app, but to provide any functionality depends on our customers needs we have to combine customer-specific functionality and reuse a lot of common functionality together to achieve best value. To do so, I have created next multi-project build structure:

# deliverable apps:
apps/customer1
apps/customer2
apps/customer3
....
# reusable non-application modules and libraries:
modules/module1/
modules/module2/submodule1/
modules/module2/submodule2/
modules/module3/
modules/module4/submodules/submodule1/
modules/module4/submodules/submodule2/
modules/module4/submodules/submodule3/
...

settings.gradle

rootProject.name = 'bla-bla'
[
  ':modules:module1',

  ':modules:module2:submodule1',
  ':modules:module2:submodule2',

  ':modules:module3',

  ':modules:module4:submodule1',
  ':modules:module4:submodule2',
  ':modules:module4:submodule3',
  //...

  ':apps:customer1',
  ':apps:customer2',
  ':apps:customer3',
  //...
].each { include it }

so by composing common functionality and customizing specific to particular customers functionality, as result i can finally build and deliver apps: customer1, customer2, customer3 to my different customers…

Short app description:

  • gradle 4.7 (using wrapper), jdk 1.8+
  • customer1, customer2 and customer3 reusing some submodules from modules/**
  • some submodules from modules/** also using other submodules / sub-submodules from modules/
  • for testing I’m using JUnit5 (junitPlatformTest task) together with vintage JUnit4
  • as base framework in my application architecture, I’m using spring-boot 2.x

all submodules from modules/** has configuration like so:

modules/build.gradle:

allprojects {

  apply from: "$rootDir/gradle/subprojects.gradle" // common spring-boot configuration

  plugins.withType(SpringBootPlugin) {
    bootJar {
      enabled = false
    }
    jar {
      enabled = true
    }
  }
}

it allows me apply spring-boot auto-configurations approach and depends on any submodules from modules/** in my other modules/ or apps/** projects with no issues in my spring-boot projects, like so:

apps and non-apps modules could potentially depends on any other modules: modules/module3/build.gradle and apps/customer1/build.gradle both might contains:

dependencies {

  [
      ':modules:module1',
      ':modules:module4:submodules:submodule1',
      ':modules:module4:submodules:submodule3',

  ].each {

    compile(project(it))
    /*
      yeah, I know, ugly, but during some investigation, I found that this configuration is working
      for any of my projects depending. using here configurations together, because in some
      submodules I have annotation processors libraries like lombok and
      spring-boot-configuration-processor. please, let me know if it could be and root cause of
      my main problem in this case. thanks.
     */
    compileOnly(project(it))
    annotationProcessor(project(it))
  }

  // ...
}

finally if for example customer2 module depends on many other project submodules, it rises that annoying windows gradle issue.

please help me reconfigure my modularity to avoid this windows gradle limitation.
as far as I understand unix also potentially could have same limitation, question here is only in amount of dependent modules. So using unix to fix that issue is not an option…

if it can help me make final gradlew command line shorter, I’m thinking if it’s possible to build any non apps modules as collection of jars per customerX project, then in my apps modules depends not on modules projects, but on for example apps/customer2/libs/*.jar files which modules/** project build task will produce

don’t know how to do that, please help

PS: also I would like to know if that error might be produced not because of classpath length, but systemProperties I’m passing into test/junitPlatrofmTest tasks? Theoretically, when gradle wrapper is running junitPlatformTask, it’s may spread all system props as like so:

./gradlew -Dorg.gradle.systemProp.key1=value1 -D...key2=value2 -D... :apps:customer2:junitPlatformTest

if I’m using build configuration like this:

def e2eTestProps = [ ....some key=pairs is comms form here + whole System.properites ... ]
test {
  systemProperties = e2eTestProps
}
junitPlatformTest {
  systemProperties = e2eTestProps
}

I have prepared little example, to show you, what do I mean by this (don’t know if it does matter, but better is show you output of junitPlatformTest task on my mac, see java.class.path system property on page 2):

junitPlatformTask command output (page 1):

junitPlatformTask command output (page 2):

junitPlatformTask command output (page 3):

PS2: I have also found IDEA has interesting feature could shorten command line:

seems like it what It’s exact something I need… can I do similar in my gradle build configuration?

thank you in any advice!


Regards,
Maksim


(Maksim Kostromin) #2

I see my question is not clear…
Okay, seems removing junit5 gradle plugin (and using gradle 4.6+ native support instead) can help. Didn’t test that after repackaging application, but hope it can help someone…