How do I convert from the Spring Dependency Management Plugin to Enforced BOM and Allignment rules?

plugins

(Caleb Cushing) #1

Here’s my original code, that works on older mechanisms

package com.xenoterracide.gradle.plugin;

import io.spring.gradle.dependencymanagement.DependencyManagementPlugin;
import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension;
import org.gradle.api.Plugin;
import org.gradle.api.Project;

import java.util.concurrent.TimeUnit;

import static com.xenoterracide.gradle.plugin.DepConstants.APT;
import static com.xenoterracide.gradle.plugin.DepConstants.COMPILE;
import static com.xenoterracide.gradle.plugin.DepConstants.IMPL;
import static com.xenoterracide.gradle.plugin.DepConstants.LATEST;
import static com.xenoterracide.gradle.plugin.DepConstants.TEST_COMPILE;
import static com.xenoterracide.gradle.plugin.DepConstants.TEST_IMPL;
import static com.xenoterracide.gradle.plugin.Dependencies.AssertJ;
import static com.xenoterracide.gradle.plugin.Dependencies.D;
import static com.xenoterracide.gradle.plugin.Dependencies.EqualsVerifier;

public class DependencyManagement implements Plugin<Project> {
    @Override
    public void apply( Project project ) {
        project.getConfigurations().all( conf -> {
            conf.resolutionStrategy( rs -> rs.cacheChangingModulesFor( 1, TimeUnit.MINUTES ) );
        } );
        project.getPluginManager().apply( DependencyManagementPlugin.class );
        project.getExtensions().configure( DependencyManagementExtension.class, ext -> {
            ext.imports( handler -> {
                handler.mavenBom( "org.springframework.boot:spring-boot-starter-parent:2.0.6.RELEASE" );
            } );
        } );

        project.getDependencies().constraints( dch -> {
            dch.add( TEST_IMPL, String.join( D, AssertJ.G, AssertJ.A, AssertJ.V ) );
            dch.add( TEST_IMPL, String.join( D, EqualsVerifier.G, EqualsVerifier.A, EqualsVerifier.V ) );
            dch.add( COMPILE, "org.immutables:value:2.+" );
            dch.add( IMPL, "com.google.guava:guava:" + LATEST );
            dch.add( APT, "org.immutables:value:2.+" );
            dch.add( APT, "org.immutables:builder:2.+" );
            dch.add( TEST_COMPILE, "org.immutables:value:2.+" );
        } );

This is my new code for handling dep management

package com.xenoterracide.gradle.plugin;

import com.xenoterracide.gradle.allignmentrules.ImmutablesAllignmentRule;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.dsl.DependencyHandler;

import java.util.concurrent.TimeUnit;

import static com.xenoterracide.gradle.plugin.DepConstants.IMPL;
import static com.xenoterracide.gradle.plugin.DepConstants.LATEST;
import static com.xenoterracide.gradle.plugin.DepConstants.TEST_IMPL;
import static com.xenoterracide.gradle.plugin.Dependencies.D;
import static com.xenoterracide.gradle.plugin.Dependencies.EqualsVerifier;

public class DependencyManagement implements Plugin<Project> {
    @Override
    public void apply( Project project ) {
        project.getConfigurations().all( conf -> {
            conf.resolutionStrategy( rs -> rs.cacheChangingModulesFor( 1, TimeUnit.MINUTES ) );
        } );

        DependencyHandler deps = project.getDependencies();
        deps.getComponents().all( ImmutablesAllignmentRule.class );
        deps.constraints( dch -> {
            dch.add( TEST_IMPL, String.join( D, EqualsVerifier.G, EqualsVerifier.A, EqualsVerifier.V ) );
            dch.add( IMPL, "com.google.guava:guava:" + LATEST );
        } );
        deps.enforcedPlatform( "org.springframework.boot:spring-boot-starter-parent:2.1.+" );


    }
}
package com.xenoterracide.gradle.allignmentrules;

import org.gradle.api.artifacts.ComponentMetadataContext;
import org.gradle.api.artifacts.ComponentMetadataDetails;
import org.gradle.api.artifacts.ComponentMetadataRule;

import java.util.Objects;

public class ImmutablesAllignmentRule implements ComponentMetadataRule {
    @Override
    public void execute( ComponentMetadataContext ctx ) {
        ComponentMetadataDetails details = ctx.getDetails();
        String group = "org.immutables";
        details.allVariants( vm -> {
            if ( Objects.equals( details.getId().getGroup(), group ) ) {
                details.belongsTo( group + ":platform:2.+", true );
            }
        } );
    }
}

test runs however show a failure to resolve org.immutables:value or org.springframework.boot:spring-boot-starter-parent.

How do I need to change my code to DWIM?


(Louis Jacomet) #2

First of all, you should really not use a version like 2.+ in the component metadata rule. You are much better with using details.getId().getVersion() that is explain that the module belongs to the platform of the same version.

By browsing your changes, there is nothing that jumps at me as wrong. Did you tweak the repositories declaration as well? Could that be the source of the resolution failures?

And to move forward, could you add information (message and stack trace) about these failures?


(Caleb Cushing) #3

platform is not a real module… immutables has no BOM, yes I have a tweaked repositories… but it hasn’t changed from the previous version. Will come back with a stacktrace in a bit.


(Caleb Cushing) #4
com.xenoterracide.gradle.plugin.bundle.WorkingProjectTest > untagged() FAILED
    org.gradle.testkit.runner.UnexpectedBuildFailure: Unexpected build execution failure in /tmp/junit14758055778979092574/junit7165225919386855632 with arguments [build, --stacktrace, --info]

    Output:
    The client will now receive all logging from the daemon (pid: 5213). The daemon log file: /tmp/.gradle-test-kit-xeno/test-kit-daemon/5.0/daemon-5213.out.log
    Starting 3rd build in daemon [uptime: 9.717 secs, performance: 98%]
    Closing daemon's stdin at end of input.
    The daemon will no longer process any standard input.
    Using 4 worker leases.
    Starting Build
    Settings evaluated using settings file '/tmp/junit14758055778979092574/junit7165225919386855632/settings.gradle'.
    Projects loaded. Root project using build file '/tmp/junit14758055778979092574/junit7165225919386855632/build.gradle.kts'.
    Included projects: [root project 'working']

    > Configure project :
    Evaluating root project 'working' using build file '/tmp/junit14758055778979092574/junit7165225919386855632/build.gradle.kts'.
    JAR_REPOSITORY_URI=https://d3vfm0n2cffdwd.cloudfront.net
    JRS_S3_URI=null
    All projects evaluated.
    Selected primary task 'build' from project :
    Tasks to be executed: [task ':compileJava', task ':processResources', task ':classes', task ':jar', task ':assemble', task ':checkstyleMain', task ':spotbugsMain', task ':compileTestJava', task ':processTestResources', task ':testClasses', task ':test', task ':check', task ':build']
    :compileJava (Thread[Execution worker for ':',5,main]) started.

    > Task :compileJava FAILED
    Deleting stale output file: /tmp/junit14758055778979092574/junit7165225919386855632/build/classes/java/main
    Deleting stale output file: /tmp/junit14758055778979092574/junit7165225919386855632/build/generated/src
    :compileJava (Thread[Execution worker for ':',5,main]) completed. Took 0.023 secs.

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':compileJava'.
    > Could not resolve all files for configuration ':compileClasspath'.
       > Could not find org.immutables:value:.
         Required by:
             project :

    * Try:
    Run with --debug option to get more log output. Run with --scan to get full insights.

    * Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':compileJava'.
    	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:37)
    	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.run(EventFiringTaskExecuter.java:49)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
    	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
    	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:44)
    	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:43)
    	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:337)
    	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:325)
    	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:318)
    	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:304)
    	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:134)
    	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:129)
    	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:202)
    	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:193)
    	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:129)
    	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':compileClasspath'.
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.rethrowFailure(DefaultConfiguration.java:1112)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$2000(DefaultConfiguration.java:127)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getFiles(DefaultConfiguration.java:1087)
    	at org.gradle.api.internal.file.AbstractFileCollection.iterator(AbstractFileCollection.java:72)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.iterator(DefaultConfiguration.java:449)
    	at org.gradle.internal.snapshot.impl.DefaultFileSystemSnapshotter$FileCollectionLeafVisitorImpl.visitCollection(DefaultFileSystemSnapshotter.java:242)
    	at org.gradle.api.internal.file.AbstractFileCollection.visitLeafCollections(AbstractFileCollection.java:233)
    	at org.gradle.api.internal.file.CompositeFileCollection.visitLeafCollections(CompositeFileCollection.java:205)
    	at org.gradle.internal.snapshot.impl.DefaultFileSystemSnapshotter.snapshot(DefaultFileSystemSnapshotter.java:127)
    	at org.gradle.internal.fingerprint.impl.AbstractFileCollectionFingerprinter.fingerprint(AbstractFileCollectionFingerprinter.java:47)
    	at org.gradle.internal.fingerprint.classpath.impl.DefaultCompileClasspathFingerprinter.fingerprint(DefaultCompileClasspathFingerprinter.java:46)
    	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.fingerprintTaskFiles(CacheBackedTaskHistoryRepository.java:336)
    	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.createExecution(CacheBackedTaskHistoryRepository.java:145)
    	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.access$100(CacheBackedTaskHistoryRepository.java:66)
    	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository$1.getCurrentExecution(CacheBackedTaskHistoryRepository.java:106)
    	at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.getStates(DefaultTaskArtifactStateRepository.java:203)
    	at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.isUpToDate(DefaultTaskArtifactStateRepository.java:93)
    	at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:50)
    	at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:49)
    	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:61)
    	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
    	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
    	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:44)
    	at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
    	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:55)
    	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:35)
    	... 20 more
    Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find org.immutables:value:.
    Required by:
        project :
    	at org.gradle.internal.resolve.result.DefaultBuildableComponentResolveResult.notFound(DefaultBuildableComponentResolveResult.java:42)
    	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolveModule(RepositoryChainComponentMetaDataResolver.java:108)
    	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolve(RepositoryChainComponentMetaDataResolver.java:63)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.ComponentResolversChain$ComponentMetaDataResolverChain.resolve(ComponentResolversChain.java:95)
    	at org.gradle.api.internal.artifacts.ivyservice.clientmodule.ClientModuleResolver.resolve(ClientModuleResolver.java:63)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.resolve(ComponentState.java:199)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.getMetadata(ComponentState.java:152)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.EdgeState.calculateTargetConfigurations(EdgeState.java:173)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.EdgeState.attachToTargetConfigurations(EdgeState.java:129)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.attachToTargetRevisionsSerially(DependencyGraphBuilder.java:316)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolveEdges(DependencyGraphBuilder.java:215)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.traverseGraph(DependencyGraphBuilder.java:168)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolve(DependencyGraphBuilder.java:129)
    	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultArtifactDependencyResolver.resolve(DefaultArtifactDependencyResolver.java:121)
    	at org.gradle.api.internal.artifacts.ivyservice.DefaultConfigurationResolver.resolveGraph(DefaultConfigurationResolver.java:169)
    	at org.gradle.api.internal.artifacts.ivyservice.ShortCircuitEmptyConfigurationResolver.resolveGraph(ShortCircuitEmptyConfigurationResolver.java:86)
    	at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver.resolveGraph(ErrorHandlingConfigurationResolver.java:73)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$7.run(DefaultConfiguration.java:566)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
    	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveGraphIfRequired(DefaultConfiguration.java:555)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$600(DefaultConfiguration.java:127)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$6.run(DefaultConfiguration.java:538)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$SafeExclusiveLockImpl.withLock(DefaultProjectStateRegistry.java:244)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveExclusively(DefaultConfiguration.java:534)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveToStateOrLater(DefaultConfiguration.java:529)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$2100(DefaultConfiguration.java:127)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getSelectedArtifacts(DefaultConfiguration.java:1095)
    	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getFiles(DefaultConfiguration.java:1084)
    	... 44 more


    * Get more help at https://help.gradle.org

    BUILD FAILED in 0s
    1 actionable task: 1 executed
        at org.gradle.testkit.runner.internal.DefaultGradleRunner$1.execute(DefaultGradleRunner.java:237)
        at org.gradle.testkit.runner.internal.DefaultGradleRunner$1.execute(DefaultGradleRunner.java:234)
        at org.gradle.testkit.runner.internal.DefaultGradleRunner.run(DefaultGradleRunner.java:298)
        at org.gradle.testkit.runner.internal.DefaultGradleRunner.build(DefaultGradleRunner.java:234)
        at com.xenoterracide.gradle.plugin.bundle.WorkingProjectTest.untagged(WorkingProjectTest.java:82)
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access using Lookup on org.gradle.internal.classloader.ClassLoaderUtils$AbstractClassLoaderLookuper (file:/home/xeno/.gradle/caches/5.0/generated-gradle-jars/gradle-api-5.0.jar) to class java.lang.ClassLoader
WARNING: Please consider reporting this to the maintainers of org.gradle.internal.classloader.ClassLoaderUtils$AbstractClassLoaderLookuper
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Gradle Test Executor 11 finished executing tests.

> Task :spotbugsMain
A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: sun.util.cldr.CLDRCalendarDataProviderImpl@3990fd12 locale: en
A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: sun.util.cldr.CLDRCalendarDataProviderImpl@3990fd12 locale: en
A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: sun.util.cldr.CLDRCalendarDataProviderImpl@3990fd12 locale: en
A locale sensitive service provider returned null for a localized objects,  which should not happen.  provider: sun.util.cldr.CLDRCalendarDataProviderImpl@3990fd12 locale: en

> Task :test FAILED

(Caleb Cushing) #5

btw, all the code is open source, here https://bitbucket.org/xenoterracide/gradle-plugin-bundle/src/use-new-dep-handling/


(Louis Jacomet) #6

The issue is that there is never a version for org.immutables:value that enters the graph.

The goal of ImmutablesAllignmentRule is to make sure that all modules in the org.immutables group end up with the same version. But it does not magically find a version for you if none are specified at all.

So, in order to work, the ImmutablesAllignmentRule should use the version of the module in the belongsTo declaration as I said before.
And two, you need either a version to be added to this line or to add a reference to a specific version of org.immutables:platform as platform dependency.