This message was deleted.
# dependency-management
s
This message was deleted.
g
Constraint on
runtimeClasspath
should break a build so `apiElements`/`runtimeElements` should be broken too. I would think that it should be enough to prevent the sqlite impl propagation. I'm not sure if you should care at all about `compileClasspath`/`compileOnly`/`compileOnlyApi` in this case.
If you use a constraint on the
implementation
it also should break the build preventing propagation if the dependency was brought transitively via `implementation`'s direct dependencies' afaik. Do you want to forbid sqlite in the current module or taint all dependent projects to prevent them using sqlite through other deps? Later case seems more suited for platform with reject constraint.
t
right now we're using the convention plugin approach, so I can add the constraint to my plugin and ensure it is present in every project of the build. Adding it to a platform also sounds like it would make sense
I'm still slightly confused about how these constraints propagate, both through a single project and an entire build, as it turns out. Why doesn't putting the constraint on
implementation
also taint
testImplementation
(testCompileClasspath and testRuntimeClasspath), for example?
g
constraint on
implementation
should apply to
testImplementation
in the same project, at least for a platform applied to the project
not sure how constraints are propagated between dependency bags and resolvable configurations
I either use them for the current project or in the platform definition that has to be applied to bunch of configurations
t
with the constraint as indicated in my code snippet,
compileKotlin
will fail in the expected way, but
compileTestKotlin
will not
to be clear, I do not want it to fail at test time. I want my tests to use this dependency
g
so similar case to the logging deps ,)
t
I've been using this as a reference. It suggests that testImpl should inherit from impl. I should be more clear though, that I'm in an Android project. Nevertheless, I think it follows this form
g
yeah, I use the same doc page as reference) but I'm not familiar with agp at all
maybe one of Gradle devs familar with constraint propagation would point to the right issues and/or code
or I could look into the gradle source tomorrow if you ping me and I have a bit of time for experiments
it'd be evening in your tz btw
t
a-ha, I was wrong, I wasn't using my constraint for Reasons. Tests do fail with the constraint as set up. At least that makes sense. I think I need to be more explicit and set it on the compile and runtime classpaths, since they should be independent of the test classpaths. Let's find out!
👍 1
g
good clue
t
I do find the constraint docs a bit underwhelming, so if gradle dev saw this and chose to enlighten me, I would gladly accept that 🙂
g
same here ,)
i find experiments later backed by some tests to be the best assurance but good kick in the right direction is almost always enlightening
👍 1
j
If you add the constraint in all of your projects through a convention plugin,
implementation
is the best choice imo. You won’t win anything by using
api
. Using
api
would mean that the constraint would propagate, at compile time, as “transitive dependency” to all direct consumers of a project (that’s what apiElements is for). But you would still have to add it to all projects as there is nothing that would allow you to just add it to one project and then propagate it everywhere at compile time. Hence, I would stick with
implementation
.
The
testImplementation
->
implementation
is one of these things that were done in the early days of Gradle to mimic Maven behaviour. (Well to be correct it was
testCompile
->
compile
back then, but this was preserved probably to not break to many existing things.). I wish this could be removed, but I doubt it will every happen (backward compatibility). Imo it meddles with the isolation of variants/sourceSets and makes things harder to understand. It would be much clearer (imo) if tests won’t automatically see all dependencies of
main
. In the end, if something is
implementation
for
main
, why should the test see it (it’s supposed to be internal then).
And if you declare a dependency from
test
to
main
(ie, test variant depends on main variant -
testImplementation(project(path))
- test will not only see your main code, but also everything that is
api
. And ‘test’ would be like a feature variant that behaves similar to other feature variants. It’s still kind of complicated 🙂 but it would be consistent.
If you create a new Source Set (or Test Suite), you won’t have this relationship, unless you manually add it. And you can do the consistent setup. That’s why
test
is special in this regard and that is why other test setups (Kotion, Android) maybe do not have this relationship.
t
thanks Jendrik! so, based on all that, and considering I'm talking about an android project and must not forbid this dependency for test purposes, do you agree I should use compileClasspath and/or runtimeClasspath?
l
You indeed need to put the constraint in a configuration that does not impact tests. I would recommend creating a dedicated configuration for this and have both
compileClasspath
and
runtimeClasspath
extend from it.
👀 1
c
let's see if I understand the suggestion: as testImplementation inherits from implementation, any constraint you add to implementation affect tests. you can create another configuration that inherits from implementation (and compileOnly and runtime if needed) and apply the constraint
oh, no, actually the suggestion fro Louis is not that, bat adding your configuration with the constrain to compileClasspath and runtimeClasspath
👍 1
l
The motivation is to always separate bucket configuration - where you declare dependencies and constraints, cannot be consumer or resolved, from the other ones - the consumable or resolvable ones. It also helps thinking about variant attributes because declaring attributes on bucket configurations has no effect, since they are not carried over.
👌 1
c
"noTestImplementation" or "implementationOnly" 😂
l
Well in this case, I would name it: forbiddenDependencies 😉
c
they are not forbidden for tests! (but I was just kidding anyway)
l
Right,
forbiddenRuntimeDependenciesThatAreAllowedInTest
😛
💀 2
c
I must say the whole "test" idea is quite messy it's used as default unitTest, so if you create more test sourcesets/configurations you have to create your baseTest configuration, duplicate everything or use test as base for your integration tests. and then..most plugins assume everything is only in "test" without providing flexibility to have integrationTest for example. Even JaCoCo and test-fixtures are only configuring
test
IIRC
(sorry, I don't want to change the topic)
t
I'm at a bit of a loss for the moment. Despite putting the constraint on the debugTestRuntimeClasspath, my tests are failing because they can't resolve all the required dependencies. I don't understand why the test runtime classpath (debugUnitTestRuntimeClasspath) is seeing this constraint. It does not (directly) extend debugTestRuntimeClasspath... Printing the extendsFrom hierarchy confirms (I think) that my constraint shouldn't propagate
Copy code
- debugUnitTestRuntimeClasspath extendsFrom:
  * testDebugRuntimeOnly
  * testDebugImplementation
  * testRuntimeOnly
  * testImplementation
  * debugUnitTestRuntimeOnly
    * testRuntimeOnly
    * testDebugRuntimeOnly
  * debugUnitTestImplementation
    * debugUnitTestApi
      * testApi
      * testDebugApi
    * testImplementation
    * testDebugImplementation
j
Maybe in the Android setup “unit test” actually dependents on the corresponding “main” variant(s) which brings in the constraint in your case? Where do you define it now? Is it only on
*Classpath
or also on
*Elements
? The later would make it propagate. A build scan (or running
dependencies
) should give more insights.
t
I followed Louis' suggestion and put it on a new configuration which I then had
debugRuntimeClasspath
extend from. The build scan was not super helpful; I still think these views have usability issues, and recall I used to teach people how to read this stuff. It clearly showed that the dependency was only present on
debugUnitTestRuntimeClasspath
, and then a whole bunch of paths to the constraint that I couldn't parse. Here's a snippet. I've also attached a screencap.
Copy code
Dependency path 'register.common.addons:impl:unspecified' --> 'com.squareup.sqldelight:sqlite-driver:1.5.3'
   Constraint path 'register.common.addons:impl:unspecified' --> 'register.common.addons:impl:unspecified' (debugRuntimeElements) --> 'com.squareup.sqldelight:sqlite-driver:{reject all versions}' because of the following reason: <omitted for brevity>'
...
The "dependency path" in question is
testImplementation com.squareup.sqldelight:sqlite-driver:1.5.3
Does
(debugRuntimeElements)
imply that my test classpath inherits from the runtime classpath and therefore inherits the constraint as well? I could believe it, even though my code walking the
extendsFrom
relationship doesn't show it and it also conflicts with what I'd expect from the relationships described in the java-library plugin docs. I know those aren't exactly relevant for Android, but I was hoping (sigh) that Android was sane here
l
I think Jendrik is right there. It looks like a combination of two things: • Android uses a project dependency to get the main component in the test classpath • Android might define
debugRuntimeElements extendsFrom debugRuntimeClasspath
but that would be really annoying
t
I have this vague recollection that they might do something like that "manually". I'm pretty sure they don't use
extendsFrom
directly, or maybe it's in an afterEvaluate and it's an ordering issue that I can't see it. Well, I guess this idea is just dead in the water
j
Android is also doing some kind of “home made consistent resolution” between production code and test code classpathes. IIRC it creates constraints for the test classpathes based on the resolution result. (If that has not been changed by now.) This could also possibly cause this (rather strange) effect.
👀 1