Gradle 5 Kotlin DSL:多模块项目中的常见任务和 Maven 工件

Gradle 5 Kotlin DSL: Common Tasks & Maven Artifacts in multi-modules projects

我真的很想感谢 Gradle 5,尤其是与新的 Kotlin DSL 结合使用时,但我很难(在我看来)获得一个非常非常简单和通用的构建运行 Gradle.

任务

在 Maven 默认目录布局 as high-质量 Maven artifacts/repository 在一个切中要点的简单 Gradle 构建中(即 DRY)。

因此:有一个根项目作为保护伞,它定义并包含所有常用配置(实际上除了真正的依赖项之外的所有配置)。

我目前的挣扎

我将当前的 "results" 移植到 a sample project on Github and asked this question in the Gradle forum already

目前我没有声明在我的 central 构建中提供标准 -sources-javadoc 工件的必要任务。

例如,这三个 "solutions",你会在寻找基于 Kotlin DSL 的解决方案时找到它们 在多模块场景中都不会(不再)工作 :

不完整的解决方案(/build.gradle.kts

完整示例参见 Github:https://github.com/bentolor/gradle-maven-multimodule-kotlindsl

subprojects {
    apply(plugin = "java-library")
    apply(plugin = "maven-publish")
    group = "de.bentolor.sampleproject"
    version = "0.1.0"

    repositories {
        jcenter()
    }

    dependencies {
        // Dependencies used in EVERY module
        "compile"("commons-logging:commons-logging:1.2")
        "testImplementation"("junit:junit:4.12")
    }

    tasks {
        // not working
        /*register("sourcesJar", Jar::class.java) {
            from(sourceSets.main.get().allJava)
            classifier = "sources"
        }*/

       // not working, eiher
       /* task<Jar>("sourcesJar") {
            from(sourceSets.main.get().allJava)
            classifier = "sources"
       } */
    }

    configure<JavaPluginExtension> {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    configure<PublishingExtension> {
        publications {
            create<MavenPublication>(project.name) {
                from(components["java"])
                // won't work, beause inaccessible declaration in `tasks{}`-Block
                //add("archives", javadocJar)
                //add("archives", sourcesJar)
            }
        }

        repositories {
            mavenLocal()
        }
    }
}

示例子模块 /module2/build.gradle.kts

group = "de.bentolor.sampleproject.module2"

dependencies {
    compile(project(":module1"))
}

试试这个:

subprojects {
    apply<JavaLibraryPlugin>()
    apply<MavenPublishPlugin>()

    group = "de.bentolor.sampleproject"
    version = "0.1.0"

    repositories {
        jcenter()
    }

    dependencies {
        val implementation by configurations
        val testImplementation by configurations

        implementation("commons-logging:commons-logging:1.2")
        testImplementation("junit:junit:4.12")
    }

    // This will work, but as long as these tasks are need only for publishing you can declare them inplace later where you need 
    // tasks {
    //     val sourcesJar by creating(Jar::class) {
    //         val sourceSets: SourceSetContainer by project
    //         from(sourceSets["main"].allJava)
    //         classifier = "sources"
    //     }
    //     val javadoc by getting(Javadoc::class)
    //     val javadocJar by creating(Jar::class) {
    //         from(javadoc)
    //         classifier = "javadoc"
    //     }
    // }

    configure<JavaPluginExtension> {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    configure<PublishingExtension> {
        publications {
            create<MavenPublication>(project.name) {
                from(components["java"])

                // If you configured them before
                // val sourcesJar by tasks.getting(Jar::class)
                // val javadocJar by tasks.getting(Jar::class)

                val sourcesJar by tasks.creating(Jar::class) {
                    val sourceSets: SourceSetContainer by project

                    from(sourceSets["main"].allJava)
                    classifier = "sources"
                }
                val javadocJar by tasks.creating(Jar::class) {
                    from(tasks.get("javadoc"))
                    classifier = "javadoc"
                }

                artifact(sourcesJar)
                artifact(javadocJar)
            }
        }
    }
}

一些注意事项:

  • 为什么要使用基于 Stringapply,当您可以执行 type-safe apply<T>() 时?
  • 为什么在 dependencies 中对 stings 使用调用,当你可以使用委托时,委托更少且可重构性更好。
  • 考虑使用 implementation instead of compile

为什么 sourceSets 没有在 multi-module 项目中工作?

当您使用 Kotlin DSL 时,它会根据应用的插件为项目生成访问器。这是一个 two-step 过程:首先 Gradle 处理插件(这就是为什么建议将它们放在 plugins 块中)并生成访问器,然后您可以在代码中使用它们(访问器生成为ProjectNamedDomainObjectContainer 等的 Kotlin 扩展)。但是如果你配置子项目有两个问题:

  • Parent 项目在 child 之前评估,因此 child 的扩展在 parent 中未知。
  • 应用于parent和child的插件集不同,您需要在parent.
  • 中使用children访问器

sourceSets 是 Kotlin DSL 为 children 生成的访问器之一。它只是在 parent 中不可用。你可以自己试试:在subprojects中只应用java插件。 sourceSets 将在 children 构建脚本中可用,但在 parent.

中不可用

这也是为什么在children中可以使用java,而在parent中配置时必须使用configure<JavaPluginExtension>的原因。

但您可以使用委托获取域 objects 的引用,例如任务、源集、配置等。