gradle/github-dependency-graph-gradle-plugin

handleBuildOperationTypeRaw masks failed build operations

Closed this issue · 3 comments

The routine handleBuildOperationTypeRaw conflates finishedEvent.result not having the expected type with it being null.

As a result, buildOperation.details & finishedEvent.result were unexpected types is thrown if finishedEvent.failure is non-null, even though nothing was wrong with their types.

Example to reproduce:

Using repository / commit https://github.com/OpenVidu/openvidu-tutorials/tree/0f80b654742f37eed83f2881056643509f646cb6

In directory https://github.com/OpenVidu/openvidu-tutorials/tree/0f80b654742f37eed83f2881056643509f646cb6/openvidu-react-native/android

Run

./gradlew --no-daemon -Dorg.gradle.configureondemand=false -Dorg.gradle.dependency.verification=off -Dorg.gradle.warning.mode=none --init-script /tmp/dep-graph.gradle ForceDependencyResolutionPlugin_resolveAllDependencies --stacktrace -DGITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR=dep-graph -DGITHUB_DEPENDENCY_GRAPH_JOB_ID=unknown -DGITHUB_DEPENDENCY_GRAPH_SHA=unknown -DGITHUB_DEPENDENCY_GRAPH_REF=unknown -DGITHUB_DEPENDENCY_GRAPH_WORKSPACE=/tmp/openvidu-tutorials/ -DDEPENDENCY_GRAPH_REPORT_DIR=/tmp/output

Result: we get the buildOperation.details & finishedEvent.result were unexpected types message.

However if we patch the routine handleBuildOperationTypeRaw:

diff --git a/plugin/src/main/kotlin/org/gradle/dependencygraph/extractor/DependencyExtractor.kt b/plugin/src/main/kotlin/org/gradle/dependencygraph/extractor/DependencyExtractor.kt
index f47221f..2c3a8ee 100644
--- a/plugin/src/main/kotlin/org/gradle/dependencygraph/extractor/DependencyExtractor.kt
+++ b/plugin/src/main/kotlin/org/gradle/dependencygraph/extractor/DependencyExtractor.kt
@@ -103,10 +103,13 @@ abstract class DependencyExtractor :
         val result: R? = finishEvent.result.let {
             if (it is R) it else null
         }
+        val failure = finishEvent.failure
         if (details == null && result == null) {
             return
+        } else if (details != null && failure != null) {
+            throw failure
         } else if (details == null || result == null) {
-            throw IllegalStateException("buildOperation.details & finishedEvent.result were unexpected types")
+            throw IllegalStateException("buildOperation.details & finishedEvent.result were unexpected types " + buildOperation.details?.javaClass + " / " + finishEvent.result?.javaClass)
         }
         handler(details, result)
     }

Then we get the more informative error: MissingResourceException: Could not read script '/private/tmp/openvidu-tutorials/openvidu-react-native/node_modules/@react-native-community/cli-platform-android/native_modules.gradle' as it does not exist.

Gradle's exception handling here is a bit odd -- for reasons I don't fully understand, if we throw an exception without a cause, like the buildOperation.details & finishedEvent.result were unexpected types message, that seems to replace the exception provided in the FinishEvent, whereas if we throw one with finishEvent.failure as a cause it seems to be replaced by that cause. So I'm not sure exactly what the right answer looks like here, but we (a) shouldn't be complaining about types when there's nothing actually wrong with the types (actually, finishEvent.result was null because finishEvent.failure was defined instead), and (b) it would be useful to somehow expose the real underlying cause of the failure.

Thanks for your detailed report. Yes, the logic here is a bit broken.
I'll get this fixed in an upcoming release.

Gradle's exception handling here is a bit odd ...

If you mean that the failure reported by Gradle lacks the full chain of causes, then yes, Gradle has some special handling to reduce the verbosity of reported failures. If this is the issue, you will likely see all of the causes if you execute with --stacktrace.

I just worked on a fix for a similar issue, where failures to write the dependency graph lacked the underlying cause (unless run with --stacktrace).

@smowton did you by chance figure out the actual problem with Could not read script '@react-native-community/cli-platform-android/native_modules.gradle' as it does not exist.? I'm seeing the same issue in a react-native project.

@leoschweizer better ask the authors, but it looks like there's an npm setup step that needs to happen prior to building the Gradle project.