gradle/github-dependency-graph-gradle-plugin

Circular dependency error when build includes itself

Closed this issue · 8 comments

I get the following error when using this on a project that does dependency substitution:

Circular dependency between the following tasks:
:ForceDependencyResolutionPlugin_resolveAllDependencies
\--- :ForceDependencyResolutionPlugin_resolveAllDependencies (*)

Relevant snippet from settings.gradle (it works if I remove this block):

includeBuild(".") {
  dependencySubstitution {
    substitute module("x") using project(':')
  }
}

Thanks for the report. I can reproduce this without any substitution rules, with a simple:
includeBuild('.').

Can you explain the use case for adding the root build as an included build? This is inherently circular.

Thanks for the report. I can reproduce this without any substitution rules, with a simple: includeBuild('.').

Can you explain the use case for adding the root build as an included build? This is inherently circular.

This is mentioned here in the official gradle docs https://docs.gradle.org/current/userguide/composite_builds.html#included_build_declaring_substitutions

@stiost Yes, I understand the use case for using dependencySubstitution. But that's not the cause of the problem in this case.

The error is caused by the fact that the build is including itself, via includeBuild('.'). I'm wondering what the use case is for this pattern. If you can describe what you're achieving with this includeBuild block, it might help me craft a better solution.

Basically it allows you to use

dependencies {
    implementation "company.group:artifact-name"
}

instead of

dependencies {
    implementation project(":artifact-name")
}

Which in our huge composite build looks a lot better and you use the same syntax no matter which composite build project you're in. We need it for our shared convention plugins to work.

@stiost if that's the goal, I'd recommend to use type-safe project accessors instead.

@sschuberth That looks very cool and I'm definitely going to try it, I'm already using a dependency catalogue with type-safe accessors. But it doesn't seem to work with composite builds?

But it doesn't seem to work with composite builds?

I don't know. But you definitely need to opt-in to it first via enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS").

@stiost Thanks for the explanation.

My understanding:

  • You want to substitute a module dependency (like implementation "company.group:artifact-name") with a project dependency (like implementation project(":artifact-name"))
  • The project :artifact-name lives in the same build as the consumer where the module dependency is declared.

The normal way to do this would be to use dependencySubstitution without a wrapping includeBuild, like this. But I can see how includeBuild('.') could be more consistent when you have other substitutions that do involve other included builds.