我可以在多项目构建中一次调用所有项目的 Gradle 属性任务吗?

Can I call the Gradle properties task on all projects at once in a multi-project build?

我想查看 Gradle 项目的属性,以手动确保值看起来正确。

当我从多项目构建的根调用 properties 任务时,它列出了根项目的属性:

$ gradle -q properties

------------------------------------------------------------
Root project
------------------------------------------------------------

allprojects: [root project 'myapp', project ':api', project ':model', project ':ui']
ant: org.gradle.api.internal.project.DefaultAntBuilder@12345
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@12345
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@12345
asDynamicObject: DynamicObject for root project 'myapp'
baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@12345
[...]

我还可以请求每个子项目的属性:

$ gradle -q :api:properties

------------------------------------------------------------
Project :api - The shared API for the application
------------------------------------------------------------

allprojects: [project ':api']
ant: org.gradle.api.internal.project.DefaultAntBuilder@12345
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@12345
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@12345
asDynamicObject: DynamicObject for project ':api'
baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@12345
[...]

但是,我真正想做的是一次列出给定项目及其所有子项目的属性。

我有点惊讶在根级别调用任务只提供根级别属性。这似乎与有关 executing tasks by name in a multi-project build:

的 Gradle 文档相矛盾

The command gradle test will execute the test task in any subprojects, relative to the current working directory, that have that task. If you run the command from the root project directory, you’ll run test in api, shared, services:shared and services:webservice. If you run the command from the services project directory, you’ll only execute the task in services:shared and services:webservice.

The basic rule behind Gradle’s behavior is: execute all tasks down the hierarchy which have this name. Only complain if there is no such task found in any of the subprojects traversed.

如何一次列出项目及其子项目的所有属性?作为奖励,为什么根级别的 properties 任务 运行 也不是子项目的 运行ning?我正在使用当前最新版本的 Gradle (6.7.1)。

可能是我理解错了你的问题。如果您想列出所有属性,包括所有子项目以及根项目,那么您可以创建一个构建文件,如下所示:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

allprojects {
    repositories {
        mavenCentral()
    }

    group = "com.nononsensecode"
    version = "0.0.1"

}

plugins {
    kotlin("jvm") version "1.4.20" apply false
    base
}

configure(subprojects) {
    apply {
        plugin("org.jetbrains.kotlin.jvm")
    }

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

    tasks.withType<KotlinCompile>().configureEach {
        kotlinOptions {
            jvmTarget = "1.8"
            freeCompilerArgs = listOf("-Xjsr305=strict")
        }
    }

    dependencies {
        val implementation by configurations

        implementation(kotlin("stdlib-jdk8"))
        implementation(kotlin("reflect"))
    }

    task("listAllProperties") {
        val subProjectPropertiesMap = mutableMapOf<String, Map.Entry<String, Any?>>()
        subprojects.forEach { subProject ->
            subProject.properties.forEach { property ->
                subProjectPropertiesMap[subProject.name] = property
            }
        }

        val allProperties = AllProperties(properties, subProjectPropertiesMap)
        println(allProperties)
    }
}

data class AllProperties(
    val properties: Map<String, Any?>,
    val subProjectProperties: MutableMap<String, Map.Entry<String, Any?>>
)

然后运行任务gradlew listAllProperties。如果你愿意,你可以创建一个 toString 方法来以漂亮的方式打印所有属性。

根据 this Gradle Forum response, the properties task is not running for subprojects since the impliesSubProjects property of the properties task is true in the property implementation:

The task is configured to ignore subproject tasks by the HelpTasksPlugin using an internal API

[…]

Then TaskNameResolver does not look at subprojects for the task if impliesSubProjects is true.

实验表明,可以在构建文件中配置 impliesSubProjects 属性,允许任务 运行 用于父项目及其所有子项目:

properties {
    impliesSubProjects = false
}

输出

$ gradle -q properties

------------------------------------------------------------
Root project
------------------------------------------------------------

allprojects: [root project 'myapp', project ':api', project ':model', project ':ui']
ant: org.gradle.api.internal.project.DefaultAntBuilder@12345
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@12345
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@12345
asDynamicObject: DynamicObject for root project 'myapp'
baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@12345
[...]

------------------------------------------------------------
Project :api - The shared API for the application
------------------------------------------------------------

allprojects: [project ':api']
ant: org.gradle.api.internal.project.DefaultAntBuilder@12345
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@12345
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@12345
asDynamicObject: DynamicObject for project ':api'
baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@12345
[...]

------------------------------------------------------------
Project :model - Shared object model
------------------------------------------------------------
[...]

但是请注意,impliesSubProjects 属性 是在内部 API 中定义的(org.gradle.api.internal.AbstractTask and is not part of the public Task API (see Avoid using internal Gradle APIs 有关内部 API 的更多详细信息)。因此,如链接论坛回复中所述,这不适用于构建:

keep in mind that it’s an internal implementation detail not intended to be used by builds and there are no guarantees it will keep working in future Gradle releases.

但是,如果一次性 属性 比较不是构建的持久部分,这种意外使用可能是可以接受的。