suppose the following project. the master project is a multi-project, however every part of the larger project can be developed individually or mixed in:
/ma
Starting with elastic-deps and with the help of this answer (also from Peter) I came up with the trick below.
In the top-level build.gradle():
// make sure we've parsed the subproject dependencies
evaluationDependsOnChildren()
def subprojectsByName = subprojects.collectEntries { it -> [it.name, it] }
subprojects.each { p ->
def hacks = [] // list of changes we're going to make
p.configurations.each { c ->
c.dependencies.each { d ->
if (d.group.startsWith("my.group.prefix")) {
def sub = subprojectsByName[d.name]
if (sub != null) {
hacks.add({
// can't do this immediately or we'll get ConcurrentModificationExceptions
c.dependencies.remove(d)
p.dependencies.add(c.name, sub)
})
}
}
}
}
// Now we can safely apply the changes
for (hack in hacks) {
hack()
}
}
The nice thing about this is that unlike elastic-deps you don't have to modify the subprojects.
This still has the problem that once you hit a binary dependency, any purely transitive dependencies are resolved as binary. E.g., say I have a project cyan
which depends directly on green
and blue
and transitively, through green
, on yellow
:
compile - Compile classpath for source set 'main'.
+--- my.shared:blue:+ -> 2.0-SNAPSHOT
+--- my.shared:green:+ -> 2.0-SNAPSHOT
| +--- my.shared:yellow:+ -> 2.0-SNAPSHOT
| \--- my.shared:blue:+ -> 2.0-SNAPSHOT
Now if I add blue
and yellow
to my multi-module project, but not green
, I get:
compile - Compile classpath for source set 'main'.
+--- com.iii.shared:green:+ -> 2.0-SNAPSHOT
| +--- com.iii.shared:yellow:+ -> 2.0-SNAPSHOT
| \--- com.iii.shared:blue:+ -> project :blue
\--- project :blue
Note that blue
is resolved correctly to the project even when it's transitive, but yellow
isn't.
Personally I think this is a feature, not a bug -- it reflects what would actually happen at distribution time. I can make all the changes to yellow
I want, but if I don't put a new yellow
artifact in my repository and also an updated green
with the updated dependency, then the actual release of cyan
isn't going to get those changes.
Working with a dynamic subset of a Gradle build is a planned feature. In the meantime, the best solution I've come up with is to introduce a new dependency notation that gets dynamically mapped to either a project dependency or an external dependency. You can find a proof-of-concept here: https://github.com/pniederw/elastic-deps
PS: Before embarking on implementing this feature on your own, reconsider if you truly need it at this point. You might save yourself some headaches by waiting until it is officially supported.