spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
696 stars 87 forks source link

Support configuration-specific dependency management with Gradle's Kotlin DSL #320

Open feelform opened 2 years ago

feelform commented 2 years ago
plugins {
    `java-library`
    `maven-publish`
    id("io.spring.dependency-management")
}

repositories {
    mavenLocal()
    maven {
        url = uri("https://repo.maven.apache.org/maven2/")
    }

    maven {
        url = uri("https://jcenter.bintray.com")
    }

    maven {
        url = uri("https://repository.jboss.org/nexus/content/repositories/thirdparty-releases/")
    }
}

dependencies {
    testImplementation("junit:junit:${Versions.junit}")
    testImplementation("org.hamcrest:hamcrest:2.2")
    testImplementation("org.mockito:mockito-core:2.28.2")
}

group = "com.exampleexample"
version = "1.0.0-SNAPSHOT"

publishing {
    publications.create<MavenPublication>("maven") {
        from(components["java"])
    }
}

tasks.withType<JavaCompile>() {
    options.encoding = "UTF-8"
}

dependencyManagement {
    dependencies {
        dependency("org.springframework:spring-core:${Versions.spring}") {
            exclude("commons-logging:commons-logging")
        }
        dependency("org.springframework:spring-beans:${Versions.spring}")
        dependency("org.springframework:spring-context:${Versions.spring}")
        dependency("org.springframework:spring-orm:${Versions.spring}")
    }

    testImplementation {
        dependencies {
            dependency("org.springframework:spring-test:${Versions.spring}")
        }
    }
}

java-conventions.gradle.kts

$> ./gradlew dependencyManagement --info
java-conventions.gradle.kts: (51, 5): Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
internal fun ArtifactHandler.testImplementation(artifactNotation: Any): PublishArtifact defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun ArtifactHandler.testImplementation(artifactNotation: Any, configureAction: ConfigurablePublishArtifact.() -> Unit): PublishArtifact defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyConstraintHandler.testImplementation(constraintNotation: Any): DependencyConstraint? defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyConstraintHandler.testImplementation(constraintNotation: Any, block: DependencyConstraint.() -> Unit): DependencyConstraint? defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun <T : ModuleDependency> DependencyHandler.testImplementation(dependency: TypeVariable(T), dependencyConfiguration: TypeVariable(T).() -> Unit): TypeVariable(T) defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyHandler.testImplementation(dependencyNotation: Any): Dependency? defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyHandler.testImplementation(group: String, name: String, version: String? = ..., configuration: String? = ..., classifier: String? = ..., ext: String? = ..., dependencyConfiguration: Action<ExternalModuleDependency>? = ...): ExternalModuleDependency defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyHandler.testImplementation(dependencyNotation: String, dependencyConfiguration: Action<ExternalModuleDependency>): ExternalModuleDependency defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyHandler.testImplementation(dependencyNotation: Provider<*>, dependencyConfiguration: Action<ExternalModuleDependency>): Unit defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
internal fun DependencyHandler.testImplementation(dependencyNotation: ProviderConvertible<*>, dependencyConfiguration: Action<ExternalModuleDependency>): Unit defined in gradle.kotlin.dsl.accessors._f4124090576aed771f557cac1ca7fd48
:buildSrc:compileKotlin (Thread[Execution worker for ':buildSrc',5,main]) completed. Took 0.797 secs.

https://docs.spring.io/dependency-management-plugin/docs/current-SNAPSHOT/reference/html/#working-with-managed-versions-dependency-management-task

dependencyManagement {
    dependencies {
        dependency 'org.springframework:spring-core:4.1.5.RELEASE'
    }
    testImplementation {
        dependencies {
            dependency 'org.springframework:spring-beans:4.1.5.RELEASE'
        }
    }
}

I can't build testImplementation DSL in precompiled scripts. How can I use testImplementation likes maven test scope in dependency management?

wilkinsona commented 2 years ago

Unfortunately, I don't think you can at the moment. The support is built using Groovy's method missing feature which doesn't translate correctly to the Kotlin DSL. You have two options for the time being:

  1. Use Groovy for your build scripts
  2. Declare all your dependency management globally rather than trying to make some of it configuration-specific

The second option would leave your example looking like this:

dependencyManagement {
    dependencies {
        dependency("org.springframework:spring-core:${Versions.spring}") {
            exclude("commons-logging:commons-logging")
        }
        dependency("org.springframework:spring-beans:${Versions.spring}")
        dependency("org.springframework:spring-context:${Versions.spring}")
        dependency("org.springframework:spring-orm:${Versions.spring}")
        dependency("org.springframework:spring-test:${Versions.spring}")
    }
}

As a slight aside, instead of declaring dependency management for each of Spring Framework's modules individually, you may want to consider importing org.springframework:spring-framework-bom instead.

pbit commented 1 year ago

A workaround is to call propertyMissing on the extension (not methodMissing as mentioned above) This method delegates to the private method handlerForConfiguration.

Define some extension functions:

fun StandardDependencyManagementExtension.withConfiguration(name: String, action: Action<DependencyManagementHandler>) {
    (propertyMissing(name) as? DependencyManagementHandler)?.let {
        action(it)
    }
}
fun StandardDependencyManagementExtension.withConfiguration(configuration: Configuration, action: Action<DependencyManagementHandler>) {
    withConfiguration(configuration.name, action)
}

This enables management of dependencies by configuration object or name:

var configOne = configurations.create("configOne") {
    isCanBeConsumed = false
    isCanBeResolved = true
}
configurations.create("configTwo") {
    isCanBeConsumed = false
    isCanBeResolved = true
}

dependencyManagement {
    withConfiguration(configOne) {
        imports {
            mavenBom("org.springframework:spring-framework-bom:6.0.4")
        }
    }
    withConfiguration("configTwo") {
        imports {
            mavenBom("org.springframework:spring-framework-bom:6.0.4")
        }
    }
}