Very similar to https://github.com/spring-projects/spring-boot/issues/8308
That's an old issue however and details such as the name of the task and how exactly it is configured in build.gradle
has changed. So rather than re-opening that issue I figured its probably better just to treat it as a new issue.
To reproduce:
- create a new gradle boot project using intializr wizard. Select starters web, 'actuator' and devtools (actuator is probably not needed). All other settings leave at default (so using boot version
2.3.1
at the time of this writing). - edit 'build.gradle' and add this:
bootJar {
excludeDevtools = false
}
Build a jar:
./gradlew build
Expectation:
- the jar should contain devtools
Realtity:
- the jar doesn't contain devtools.
To verify this we looked for devtools dependency in the jar like so:
$ jar tf build/libs/gradle-paddle-0.0.1-SNAPSHOT.jar | grep dev
The bug also affects docker image build, which is were we discovered it, while trying to implement 'devtools integration' for STS with STS docker support.
This bug is a blocker for us as it means implementing devtools integration for gradle-based docker deployment of a boot project is not possible at the moment (which means we will only be (able to) supporting it for maven project for the time being).
Somewhat related to this. I wonder if it would be possible to allow controlling this option via a commandline parameter as well? E.g. most convenient for us would be that it obeys the same system property that the maven plugin obeys, so that basically we can make devtools be included into a build by adding -Dspring-boot.repackage.excludeDevtools=false
on the build command for maven and gradle in the exact same way. Slightly less convenient would be another system property or command-line parameter, the most inconvenient would be that it requires the ide to make an actual change in the user's build.gradle
file on disk. (I can raise this as a separate issue, just wanted to get a sense on whether it sounds reasonable to you first).
Comment From: wilkinsona
excludeDevtools
is deprecated and is only applicable if you're not following the recommended way of adding Devtools to a Gradle project. If you follow the recommended approach using the developmentOnly
configuration (as an app from start.spring.io does), then Devtools can be included in a fat jar or war by adding the developmentOnly
configuration to the archive's classpath. In your case, using bootJar
, that would look like the following:
bootJar {
classpath configurations.developmentOnly
}
I wonder if it would be possible to allow controlling this option via a commandline parameter as well?
While it would be possible for us to add a property to automatically add the developmentOnly configuration to a fat jar or war, I'm not sure that it's warranted. If you control the command line that is used to launch Gradle (as I presume you do if a command line parameter is of interest), you can use an init script to customise the build to meet your needs. For example, that init script could automatically add the developmentOnly
configuration to the classpath of every BootJar
or BootWar
task in the project.
Comment From: kdvolder
Thanks Andy. Adding this to build.gradle
:
bootJar {
classpath configurations.developmentOnly
}
... works nicely. But this requires we modify build.gradle
file.
We tried then to do something similar via an init script. We've tried a few variants:
Variant 1:
bootJar {
classpath configurations.developmentOnly
}
Variant 2:
initscript {
bootJar {
classpath configurations.developmentOnly
}
}
Variant 3:
allprojects {
bootJar {
classpath configurations.developmentOnly
}
}
None of these works and results each time with an error which seems to say that 'bootJar' is not a known method.
My 'gradle fu' is very limited and googling docs about gradle init scrips didn't really help much. If you know how to do this so it works, could you please share the details?
Thanks for the help.
Comment From: wilkinsona
The init script runs at a point when the bootJar
task hasn't been defined. Rather than assuming that the bootJar
task already exists, you need to react to tasks being created and configure them at that point. The following will configure all BootJar
tasks to include Devtools:
allprojects {
tasks.matching {
it.class.name == 'org.springframework.boot.gradle.tasks.bundling.BootJar_Decorated'
}.all { bootJar ->
bootJar.classpath configurations.developmentOnly
}
}
Alternatively, if you only want to change the configuration of the default bootJar
task (rather than also configuring any custom BootJar
tasks that the user has defined themselves), you could use the following:
allprojects {
tasks.matching { task ->
task.name == 'bootJar'
}.all { bootJar ->
bootJar.classpath configurations.developmentOnly
}
}
Comment From: kdvolder
Thanks Andy, eventually we figured out that this also seems to work:
allprojects {
afterEvaluate {
bootJar {
classpath configurations.developmentOnly
}
}
}
Comment From: wilkinsona
👍 afterEvaluate
defers things long enough for the bootJar
task to have been created. It's roughly equivalent to my second suggestion.