logging-capabilities icon indicating copy to clipboard operation
logging-capabilities copied to clipboard

Regression in Gradle 6.7+ using selectXxx API (not with enforceXxx)

Open tbroyer opened this issue 2 years ago • 2 comments

Working on adding proper multi version testing (#7), two tests fail in all versions of Gradle starting with 6.7-rc-1 (I might have not tested all of them, but most I think).

See https://github.com/tbroyer/logging-capabilities/actions/runs/2253199669

can select logback in case of conflict (with extra [org.slf4j:slf4j-jcl:1.7.27, org.slf4j:slf4j-log4j12:1.7.27])
* What went wrong:
Execution failed for task ':doIt'.
> Could not resolve all files for configuration ':runtimeClasspath'.
   > Could not resolve org.slf4j:slf4j-simple:1.7.27.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-jcl' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-log4j12:1.7.27(runtime)]
   > Could not resolve org.slf4j:slf4j-jcl:1.7.27.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-jcl' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-log4j12:1.7.27(runtime)]
   > Could not resolve org.slf4j:slf4j-log4j12:1.7.27.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-jcl' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-log4j12:1.7.27(runtime)]
   > Could not resolve ch.qos.logback:logback-classic:1.2.3.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-jcl' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-simple:1.7.27(runtime), org.slf4j:slf4j-log4j12:1.7.27(runtime)]
can select logback in case of conflict (with extra [org.slf4j:slf4j-log4j12:1.7.27])
* What went wrong:
Execution failed for task ':doIt'.
> Could not resolve all files for configuration ':runtimeClasspath'.
   > Could not resolve org.slf4j:slf4j-simple:1.7.27.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-log4j12' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime)]
   > Could not resolve org.slf4j:slf4j-log4j12:1.7.27.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-log4j12' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime)]
   > Could not resolve ch.qos.logback:logback-classic:1.2.3.
     Required by:
         project :
      > Module 'org.slf4j:slf4j-log4j12' has been rejected:
           Cannot select module with conflict on capability 'dev.jacomet.logging:slf4j-impl:1.0' also provided by [org.slf4j:slf4j-simple:1.7.27(runtime)]

Adding logs to the getCapabilitiesResolutionAction, we can see it's called several times with different sets of candidates (no idea if this is the actual problem, I haven't checked the tests that pass)

resolution.withCapability(dev.jacomet.logging:slf4j-impl)
 - candidate: org.slf4j:slf4j-simple:1.7.27
 - candidate: org.slf4j:slf4j-jcl:1.7.27
resolution.withCapability(dev.jacomet.logging:slf4j-impl)
 - candidate: org.slf4j:slf4j-simple:1.7.27
 - candidate: org.slf4j:slf4j-jcl:1.7.27
 - candidate: org.slf4j:slf4j-log4j12:1.7.27
resolution.withCapability(dev.jacomet.logging:slf4j-impl)
 - candidate: org.slf4j:slf4j-simple:1.7.27
 - candidate: org.slf4j:slf4j-jcl:1.7.27
 - candidate: org.slf4j:slf4j-log4j12:1.7.27
 - candidate: ch.qos.logback:logback-classic:1.2.3
 -> select(ch.qos.logback:logback-classic:1.2.3(runtime))
Diff of the added logging instructions
diff --git a/src/functionalTest/groovy/dev/jacomet/gradle/plugins/logging/AbstractLoggingCapabilitiesPluginFunctionalTest.groovy b/src/functionalTest/groovy/dev/jacomet/gradle/plugins/logging/AbstractLoggingCapabilitiesPluginFunctionalTest.groovy
index 2e28e26..a6ce567 100644
--- a/src/functionalTest/groovy/dev/jacomet/gradle/plugins/logging/AbstractLoggingCapabilitiesPluginFunctionalTest.groovy
+++ b/src/functionalTest/groovy/dev/jacomet/gradle/plugins/logging/AbstractLoggingCapabilitiesPluginFunctionalTest.groovy
@@ -42,7 +42,7 @@ abstract class AbstractLoggingCapabilitiesPluginFunctionalTest extends Specifica
                 .withGradleVersion(testGradleVersion.version)
                 .withPluginClasspath()
                 .withProjectDir(testFolder.toFile())
-                .withArguments(args + ["-s"])
+                .withArguments(args + ["-s", "--info"])
     }
 
     void withBuildScript(String content) {
diff --git a/src/main/java/dev/jacomet/gradle/plugins/logging/extension/LoggingCapabilitiesExtension.java b/src/main/java/dev/jacomet/gradle/plugins/logging/extension/LoggingCapabilitiesExtension.java
index 2785179..12c09cb 100644
--- a/src/main/java/dev/jacomet/gradle/plugins/logging/extension/LoggingCapabilitiesExtension.java
+++ b/src/main/java/dev/jacomet/gradle/plugins/logging/extension/LoggingCapabilitiesExtension.java
@@ -17,6 +17,8 @@ import org.gradle.api.artifacts.dsl.DependencyHandler;
  * Project extension that enables expressing preference over potential logging capabilities conflicts.
  */
 public class LoggingCapabilitiesExtension {
+       private final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(LoggingCapabilitiesExtension.class);
+
     private final ConfigurationContainer configurations;
     private final DependencyHandler dependencies;
     private final Runnable alignmentActivation;
@@ -463,15 +465,17 @@ public class LoggingCapabilitiesExtension {
 
     private Action<CapabilitiesResolution> getCapabilitiesResolutionAction(String capabilityId, ExternalDependency target, String because) {
         return resolution -> resolution.withCapability(capabilityId, details -> {
+               logger.info("resolution.withCapability({})", capabilityId);
             details.getCandidates().stream().filter(candidate -> {
                 ComponentIdentifier id = candidate.getId();
+                   logger.info(" - candidate: {}", id);
                 if (!(id instanceof ModuleComponentIdentifier)) {
                     return false;
                 }
                 ModuleComponentIdentifier moduleId = (ModuleComponentIdentifier) id;
                 return moduleId.getGroup().equals(target.getGroup())
                         && moduleId.getModule().equals(target.getName());
-            }).findFirst().ifPresent(candidate -> details.select(candidate).because(because));
+            }).findFirst().ifPresent(candidate -> { logger.info(" -> select({})", candidate); details.select(candidate).because(because); });
         });
     }

This is possibly a regression in Gradle itself, but it manifests itself only in this particular test (the only one not using enforceXxx API calls, but selectXxx instead)

tbroyer avatar May 01 '22 15:05 tbroyer

Damn, that's not good. I am not sure when I'll have the time to follow up properly on this, especially if a change is needed on the Gradle side.

ljacomet avatar May 04 '22 20:05 ljacomet

This is caused by a capability conflict ordering issue in Gradle.

A workaround is to make sure that the dependency that resolves the conflict is seen before any dependency it conflicts with.

ljacomet avatar Feb 23 '24 13:02 ljacomet

I am closing this as the issue is in Gradle itself. I have been working on fixing those issues. I am hoping the changes can be released with Gradle 8.11.

ljacomet avatar Sep 08 '24 13:09 ljacomet