I've got three modules:
amodule
bmodule
cmodule
There are integration-tests in all of these three modules. The bmodule is the base - it contains BaseClass, which I want to use in integration-tests in amodule and cmodule
The example of my project is on github: https://github.com/ljql/test-deps
I try to add dependency to integration-tests of bmodule in amodule and cmodule.
File build.gradle looks the same in modules amodule and cmodule
sourceSets {
intTest {
java {
srcDir 'src/test-integration/java'
}
resources {
srcDir 'src/test-integration/resources'
}
compileClasspath += rootProject.project('bmodule').sourceSets.intTest.output
runtimeClasspath += rootProject.project('bmodule').sourceSets.intTest.output
}
}
configurations {
intTestCompile {
extendsFrom compile
}
intTestRuntime {
extendsFrom runtime
}
}
dependencies {
intTestCompile project(path: ':bmodule', configuration: 'intTestCompile')
}
But when I try to build amodule I've got an error:
Build file '/test-deps/amodule/build.gradle' line: 10
A problem occurred evaluating project ':amodule'.
> Could not get unknown property 'intTest' for SourceSet container of type org.gradle.api.internal.tasks.DefaultSourceSetContainer.
The build of cmodule, which is the copy of amodule, is completed successfully.
The only difference between amodule and cmodule is in their names. The amodule precedes the bmodule and the cmodule followed by the bmodule
How can I specify a sequence of gradle resolve dependencies in my case? I want gradle to find out about the bmodule first and then about the amodule and the cmodule
Try putting this in the your amdoule's build.gradle
preBuild.dependsOn ":bmodule:build"
You have a project evaluation ordering problem. Since both amodule and cmodule expect to find specific components of bmodule, you need to ask Gradle to make sure bmodule has been evaluated first.
You can add in the build files of amodule and cmodule the following:
evaluationDependsOn(':bmodule')
While Gradle offers an API to resolve this, it will only work if you have no cycle, that is bmodule does not have dependencies on either amodule or cmodule, otherwise you will not be able to find a solution this way.
Another approach would be to leverage proper dependency resolution and declare that you want to share some test classes by having them exposed as test-fixtures for example.
Gradle has three build phases:
Initialization
Configuration
Execution
But the final result of resolving all dependencies appears only when gradle completes all three phases.
The error indicates a string in sourceSets - it is from the phase Configuration. At the start of this phase gradle knows nothing about any configurations in all modules. And gradle learns about the content of each module sequentially module-by-module. Of course when gradle considers the configuration of the amodule for the first time, it doesn't know anything about any configurations in the bmudule.
In the question I want to define compileClasspath and runtimeClasspath in confuguration :amodule:intTest. But there is nothing to stop me to define it in a custom task. Gradle will execute it on the third phase and the final compileClasspath and runtimeClasspath will contain the information from the bmodule:intTest
The result build.gradle of amodule:
sourceSets {
intTest {
java {
srcDir 'src/test-integration/java'
}
resources {
srcDir 'src/test-integration/resources'
}
}
}
configurations {
intTestCompile {
extendsFrom compile
}
intTestRuntime {
extendsFrom runtime
}
}
task intTest {
sourceSets.intTest.compileClasspath += rootProject.project('bmodule').sourceSets.intTest.output
sourceSets.intTest.runtimeClasspath += rootProject.project('bmodule').sourceSets.intTest.output
}
Related
I am trying to create a task in my build that will list all the runtimeClasspath dependencies before it builds the project. So basically, it should be the equivalent of the following command but for all the subprojects:
gradle dependencies --configuration runtimeClasspath
So far I have managed to come up with a task that lists all the dependencies:
subprojects {
task listDependencies(type: DependencyReportTask) {}
complileJava.dependsOn listDependencies
}
It works great in the sense that it lists all the dependencies of all the subprojects, but as mentioned above, it also lists a lot of stuff I don't need to see.
How do I limit the output of the above task to just runtimeClasspath?
Thanks!
Since you are defining a task of type DependencyReportTask, you can configure its configuration property, which will be the equivalent of the --configuration flag on the CLI.
So something like:
subprojects {
def listDeps = tasks.register("listDependencies", DependencyReportTask) {
setConfiguration("runtimeClasspath")
}
tasks.withType(JavaCompile).configureEach {
dependsOn(listDeps)
}
}
Note however that printing the runtimeClasspath before executing compileJava is a bit weird. The classpath used by the compile task will be compileClasspath.
Edited to use lazy task API as there is otherwise an ordering problem with plugin application
A Kotlin version of the above accepted answer:
val listDeps = tasks.register<DependencyReportTask>("listDependencies") {
setConfiguration("compileClasspath")
}
tasks.withType<JavaCompile> {
dependsOn(listDeps)
}
I'm using gradle. I only have one project, broken up into source files, then test files. My test code cannot see the source code. When the test code tries to compile, it just says that the source code packages are not present. What gives?
When running "gradle build", or "gradle test", I get the following:
What went wrong:
Execution failed for task ':compileTestJava'.
Compilation failed; see the compiler error output for details.
Sample compilation error (because there's hundreds of these)
/tst/ContactsTests.java:1: error: package HoaryGuts does not exist
import HoaryGuts.AlertsHandlers;
^
Gradle build.gradle file:
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
task getHomeDir << {
println gradle.gradleHomeDir
}
sourceSets {
source {
java {
srcDir "src"
}
resources {
srcDir "resources"
}
}
test {
java {
srcDir "tst"
}
compileClasspath = compileClasspath + configurations.compileOnly
}
}
test {
println "In the test function"
useTestNG()
testLogging {
exceptionFormat = 'full'
}
afterTest { desc, result ->
println "${desc.className} ${desc.name} ${result.resultType}"
}
outputs.upToDateWhen {false}
}
dependencies {
compile group: 'org.testng', name: 'testng', version: '6.9.10'
}
Just like maven, gradle uses main for production sources. These are normally defined under src/main/java for Java and test includes them just like it includes compile dependencies alongside of testCompile.
There is a reason for having src followed by a named configuration, followed by language: in your setup you do not provide a location for test resources which are very common and you make it more cumbersome to include other JVM languages such as Kotlin or Scala into the project. Maybe you do not need those, but there are rarely no good reasons to strongly deviate from the industry standard.
In any case, you did not move your main to a different location, you introduced a new source set source in addition to main (actually preserving main where they originally were). If you just specified new srcDir for main instead of introducing source (as you did for test) you would not need to extend compileClasspath and your main sources would be found in test.
If you do really want to stick to source rather than using main at a new location, in test you should add source compileClasspath and output to the classpath for test:
compileClasspath += sourceSets.source.compileClasspath + source.output + [whatever else you want to add]
But well, it is a poor choice.
I want to do something like this:
dependencies {
compile project(':projectA', classifier: 'sources')
}
But I couldn't find such functionallity, I've searched in the documentation but there was nothing besides specifying the classifier on real dependencies.
So it there a way on adding the sources from an parent project inside a Gradle multimodules project as dependency?
I'm not aware that there is a feature from Gradle for that, but there is a workaround:
Add an packageSources to the project which should provide sources
// projectA/build.gradle
project.task("packageSources", type: Jar) {
classifier = 'sources'
from { project.sourceSets.main.allSource }
}
Depend the task on compileJava where you need the sources
// projectB/build.gradle
compileJava.dependsOn tasks.getByPath(':projectA:packageSources')
Add the source as dependency
// projectB/build.gradle
dependencies {
compile files(tasks.getByPath(':projectA:packageSources').archivePath)
}
projectA/build.gradle
configurations {
sources
}
dependencies {
sources sourceSets.main.allSource
}
projectB/build.gradle
dependencies {
compile project(path: ':projectA', configuration: 'sources')
}
See DependencyHandler.project(Map)
It is written in manual:
I.e. that src/sourceSet/java is a default path for "Java source for the given source set".
How to utilize this? Suppose I wish to create source set demo.
Can I write
sourceSets {
demo {
java {
srcDir 'src/demo/java'
}
resources {
srcDir 'src/demo/resources'
}
}
}
Can I write somehow without explicit paths?
May be I not required to write anything, just put files into demo subfolder?
UPDATE
I have tested
sourceSets {
demo {
java {
srcDir 'src/demo/java'
}
resources {
srcDir 'src/demo/resources'
}
}
}
and
sourceSets {
demo {
java
resources
}
}
and
sourceSets {
demo
}
In all cases running gradle build does not cause sources compiled.
build.gradle file is follows:
group 'net.inthemoon.tests'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.5
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
}
sourceSets {
demo {
java {
srcDir 'src/demo/java'
}
resources {
srcDir 'src/demo/resources'
}
}
}
Sample project: https://github.com/dims12/MultipleSourceRoots
Gradle default tasks will not build non-default source sets unless there is an explicit dependency on them in the main chain. In order to compile your demo classes you'd have to call gradle demoClasses as per cricket_007's answer - or better yet, just do gradle build demo which will also put the generated classes in the target jar.
All you need is this :
sourceSets {
demo
}
... and the build demo task will indeed create any missing directory as expected, unless you have some weird permission scheme in effect.
Now I have looked at your git project and it seems your demo source set depends on the main classes. You need to make this dependency clear (i.e. add them to the demo classpaths) to avoid compilation errors :
sourceSets {
main
demo {
compileClasspath += main.output
runtimeClasspath += main.output
}
}
This should be all you need:
sourceSets {
demo
}
More configuration may be needed to define the dependencies of these sources and where they should be used.
Brand new IntelliJ Java Gradle project. (Disclaimer: there was a setting to auto-create empty source directories automatically that I checked)
Upon adding this, it created that demo directory and the resources under it.
sourceSets {
demo
}
To compile your additional sourceSet you can run
gradlew demoClasses
As described in gradle's documentation and already mentioned in the other answers, to add a new source set it should be sufficient to write:
sourceSets {
demo {
compileClasspath += main.output
}
}
The Java plugin will automatically add corresponding compileDemoJava and processDemoResources tasks to your build.
To automatically execute these tasks during your regular build, you can add a dependency to the default tasks:
tasks.compileJava.dependsOn compileDemoJava
or the other way around:
tasks.compileJava.finalizedBy compileDemoJava
To add the output of your new source set to some distribution file, you will however need to define a corresponding task and declare this task's output to be an artifact of your build:
task demoJar(type: Jar) {
from sourceSets.demo.output
}
artifacts {
archives demoJar
}
See here for further reading on the publishing stuff
UPDATE:
Added main.output to compile classpath of demo source set as already suggested by #Amine
I would like to control which of my dependencies in a multi-project Java build are transitive. My current solution is to set up an "export" configuration in the root project:
allprojects {
configurations {
export {
description = 'Exported classpath'
}
compile {
extendsFrom export
}
}
}
Project A has multiple file dependencies:
dependencies {
compile files('A.jar', 'B.jar')
export files('C.jar')
}
Project B has a dependency on project A, but only C.jar should be on the classpath for compilation, so add:
dependencies {
export project(path: ':A', configuration:'export')
}
This produces the desired results, A.jar and B.jar are not on the class path, but C.jar is on the classpath for compilation.
I am unsure if this is "gradle" way of doing things. To configure transitivity, I would rather specify an attribute or a configuration closure to the dependency entries in project A, instead of using a different "export" configuration.
Is this possible for file dependencies, or is there another way to achieve this?
If I understand your scenario correctly, then yes it's easy to do this. Just add an options closure to the end of the dependency declaration to prevent transitive dependencies (I've changed A,B,C .jar to X,Y,Z because I'm guessing they don't coincide with projects A and B):
// Project A build.gradle
dependencies {
compile(files('X.jar', 'Y.jar')) { transitive = false }
export files('Z.jar')
}
Which would prevent X.jar and Y.jar from being added to the classpath for project B.
Alternatively, and I don't know how well this would work for you and don't really recommend it (just want you to know of the possibilities) you could do this in project B's build.gradle:
configurations.compile.dependencies.find { it.name == "A.jar" }.exclude(jar: it)
configurations.compile.dependencies.find { it.name == "B.jar" }.exclude(jar: it)
Hope that helps.