Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circular POM dependency breaks Licenses task #239

Open
romtsn opened this issue Jul 19, 2022 · 5 comments
Open

Circular POM dependency breaks Licenses task #239

romtsn opened this issue Jul 19, 2022 · 5 comments

Comments

@romtsn
Copy link

romtsn commented Jul 19, 2022

Describe the bug
Circular dependencies in .pom files causes the {Variant}OssLicensesTask to fail. This is the same problem AGP faced and was fixed in version 7.2.1. https://issuetracker.google.com/issues/232075280

To Reproduce
Here's the reproducer https://github.com/d-emrani/Sentry-Bug

In the project both oss-licenses-plugin:0.10.5 and sentry-android-gradle-plugin:3.1.2 are used. The sentry plugin will add a io.sentry:sentry-android-fragment dependency to the POM file of androidx.fragment:fragment. Because io.sentry:sentry-android-fragment itself depends on androidx.fragment:fragment this creates a circle and causes the task to fail.

Expected behavior
The task should handle circular dependencies in POM files gracefully.

Additional context

Here's the stacktrace:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task 'releaseOssLicensesTask'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:147)
        at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:145)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
        at org.gradle.execution.plan.DefaultPlanExecutor.process(DefaultPlanExecutor.java:72)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.executeWithServices(DefaultTaskExecutionGraph.java:144)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.execute(DefaultTaskExecutionGraph.java:129)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:42)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:51)
        at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:54)
        at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:43)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor.execute(BuildOperationFiringBuildWorkerExecutor.java:40)
        at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$executeTasks$7(DefaultBuildLifecycleController.java:165)
        at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:238)
        at org.gradle.internal.model.StateTransitionController.lambda$tryTransition$8(StateTransitionController.java:174)
        at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:44)
        at org.gradle.internal.model.StateTransitionController.tryTransition(StateTransitionController.java:174)
        at org.gradle.internal.build.DefaultBuildLifecycleController.executeTasks(DefaultBuildLifecycleController.java:165)
        at org.gradle.internal.build.DefaultBuildWorkGraphController$DefaultBuildWorkGraph.runWork(DefaultBuildWorkGraphController.java:142)
        at org.gradle.composite.internal.DefaultBuildController.doBuild(DefaultBuildController.java:231)
        at org.gradle.internal.Factories$1.create(Factories.java:31)
        at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:270)
        at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:119)
        at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:124)
        at org.gradle.composite.internal.DefaultBuildController.doRun(DefaultBuildController.java:204)
        at org.gradle.composite.internal.DefaultBuildController.access$000(DefaultBuildController.java:51)
        at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.run(DefaultBuildController.java:264)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
Caused by: java.lang.StackOverflowError
        at org.gradle.internal.operations.MultipleBuildOperationFailures.format(MultipleBuildOperationFailures.java:39)
        at org.gradle.internal.operations.MultipleBuildOperationFailures.<init>(MultipleBuildOperationFailures.java:28)
        at org.gradle.internal.operations.DefaultBuildOperationQueue.markFinished(DefaultBuildOperationQueue.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationQueue.waitForWorkToComplete(DefaultBuildOperationQueue.java:127)
        at org.gradle.internal.operations.DefaultBuildOperationQueue.waitForCompletion(DefaultBuildOperationQueue.java:106)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.executeInParallel(DefaultBuildOperationExecutor.java:143)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAll(DefaultBuildOperationExecutor.java:102)
        at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ParallelResolveArtifactSet$VisitingSet.visit(ParallelResolveArtifactSet.java:66)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.sort(DefaultResolvedDependency.java:129)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getModuleArtifacts(DefaultResolvedDependency.java:107)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getAllModuleArtifacts(DefaultResolvedDependency.java:113)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getAllModuleArtifacts(DefaultResolvedDependency.java:115)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getAllModuleArtifacts(DefaultResolvedDependency.java:115)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getAllModuleArtifacts(DefaultResolvedDependency.java:115)
        at org.gradle.api.internal.artifacts.DefaultResolvedDependency.getAllModuleArtifacts(DefaultResolvedDependency.java:115)
   		...
@jhansche
Copy link

jhansche commented Sep 9, 2022

We're also seeing another StackOverflowError in plugin version 4.3.13, with a different stack trace (but potentially similar root cause).

It may not be directly related, but in this case there is a library dependency that uses a strictly("[17.0,)") version constraint on firebase-messaging.

It also has a platform/BOM dependency that is used for version alignment (the BOM references a constraint on the library, and the library adds the platform() dependency on the BOM project, so they are cross-referenced, as recommended in the Gradle documentation)

And finally, the app module enables Android viewBinding (hence the dataBindingMergeDependencyArtifacts* task):

android {
    buildFeatures {
        viewBinding = true
    }
}

Gradle: 7.3
Android Gradle Plugin: 7.1.0
play-services-plugin: 4.3.13, 4.3.12


The failed task console output:

:app:dataBindingMergeDependencyArtifactsDebug FAILED	
Dependency resolved to an incompatible version: Dependency(fromArtifactVersion=ArtifactVersion(groupId=com.example, artifactId=lib-push-fcm, version=1.2.3), toArtifact=Artifact(groupId=com.google.firebase, artifactId=firebase-messaging), toArtifactVersionString=[[17.0,)])	

And the stack trace:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:dataBindingMergeDependencyArtifactsDebug'.	
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:38)	
    •••
Caused by: org.gradle.internal.event.ListenerNotificationException: Failed to notify dependency resolution listener.	
    at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:89)	
    •••
Caused by: java.lang.StackOverflowError: (No message provided)	
    at com.google.android.gms.dependencies.ArtifactDependencyManager.getDependencies(DataObjects.kt:127)	
    at com.google.android.gms.dependencies.DependencyAnalyzer.getNode(DependencyAnalyzer.java:82)	
    at com.google.android.gms.dependencies.DependencyAnalyzer.getNode(DependencyAnalyzer.java:90)	
    at com.google.android.gms.dependencies.DependencyAnalyzer.getNode(DependencyAnalyzer.java:90)	
    ...
    ...

It appears that DependencyAnalyzer and ArtifactDependencyManager do not handle the potential for circular dependencies, similar to what is described above. I cannot explain why the stack trace is different, for what appears to be the same root cause.

NOTE: the issue does not occur with com.google.gms.google-services plugin version 4.3.10. Versions 4.3.12 and 4.3.13 are affected (there is no 4.3.11 published at maven.google.com).

@caller9
Copy link
Collaborator

caller9 commented Sep 22, 2022

I cloned https://github.com/d-emrani/Sentry-Bug and ran ./gradlew assembleRelease without error.

The second report with incompatible versions is unrelated to the oss licenses plugin and should a new/separate issue.

@romtsn
Copy link
Author

romtsn commented Sep 25, 2022

I cloned d-emrani/Sentry-Bug and ran ./gradlew assembleRelease without error.

I'm not sure what's wrong here, but I just did the same (cloning + running assembleRelease) and it still fails:

image

@caller9
Copy link
Collaborator

caller9 commented Sep 26, 2022

So this is a bit of a weird one. With a clean Docker image with tools installed:

git clone https://github.com/d-emrani/Sentry-Bug.git
cd Sentry-Bug
./gradlew assemble
# Fails with stack overflow
kill `pgrep -f "GradleDaemon"`
./gradlew assemble
# OK
./gradlew assembleRelease
# OK

I accidentally did this the first time because I had JAVA_HOME set to JDK8 and the first build failed, but failed after a point where it had done something with the artifact cache I suppose. When I fixed JAVA_HOME to be a JDK 11 install, Gradle restarted the daemon when I ran ./gradlew assemble again and all subsequent builds succeeded including ./gradlew assembleRelease. Doing it in any other order or skipping directly to assembleRelease doesn't work. It took me a minute to figure out that scenario from my command history, but I made exactly the right mistakes on the first go round.

Maybe caching related to the sentry plugin run for the non-release builds is touching a shared cache file for release builds?

I'm not convinced the OSS licenses plugin can solve this since the entire stack is org.gradle.* code. The plugin already has cycle detection. This stack overflow is happening from ParallelResolveArtifactSet. I think the only way it could avoid it is skipping artifact resolution, but it needs to obtain POM files to get license info.

Having them remove that cycle injection would be ideal.

@romtsn
Copy link
Author

romtsn commented Sep 27, 2022

Alright, thanks for investigating. Yeah, we removed the cycle already, not sure if anything else can be done here, in case there are others who uses this trick with the pom file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants