用例
例如,假设一个包含三个子项目的项目生成两个公共 Java 库,这两个库使用第三个子项目作为内部共享库。这是项目结构
├── internal-module
│ └── build.gradle.kts
├── library-a
│ ├── build.gradle.kts
│ └── README.md
├── library-b
│ ├── build.gradle.kts
│ └── README.md
└── settings.gradle.kts
├── internal-module
│ └── build.gradle
├── library-a
│ ├── build.gradle
│ └── README.md
├── library-b
│ ├── build.gradle
│ └── README.md
└── settings.gradle
假设我们所有的项目都将是 Java 项目。在这种情况下,我们希望将一组通用规则应用于所有项目,例如源目录布局、编译器标志、代码样式约定、代码质量检查等等。
三个项目中的两个不仅仅是 Java 项目 - 它们是我们可能想要发布到外部仓库的库。发布配置,例如库的通用组名以及仓库坐标,可能是两个库都需要共享的跨领域问题。对于此示例,我们还假设我们要强制我们的库公开一些具有通用结构的文档。
组织构建逻辑
从上面的用例中,我们已经确定我们有两种类型的项目 - 通用 Java 项目和公共库。我们可以通过分层两个独立的插件来建模此用例,每个插件定义应用它们的项目类型
├── buildSrc
│ ├── build.gradle.kts
│ ├── settings.gradle.kts
│ ├── src
│ │ ├── main
│ │ │ └── kotlin
│ │ │ ├── myproject.java-conventions.gradle.kts
│ │ │ └── myproject.library-conventions.gradle.kts
...
├── buildSrc
│ ├── build.gradle
│ ├── settings.gradle
│ ├── src
│ │ ├── main
│ │ │ └── groovy
│ │ │ ├── myproject.java-conventions.gradle
│ │ │ └── myproject.library-conventions.gradle
...
-
myproject.java-conventions
- 配置组织中任何 Java 项目通用的约定。它应用核心的java
和checkstyle
插件以及外部的com.github.spotbugs
插件,配置通用的编译器选项以及代码质量检查。 -
myproject.library-conventions
- 添加发布配置以发布到组织的仓库,并检查 README 中是否包含强制内容。它应用java-library
和maven-publish
插件以及myproject.java-conventions
插件。
内部库子项目应用 myproject.java-conventions
插件
plugins {
id("myproject.java-conventions")
}
dependencies {
// internal module dependencies
}
plugins {
id 'myproject.java-conventions'
}
dependencies {
// internal module dependencies
}
两个公共库子项目应用 myproject.library-conventions
插件。
plugins {
id("myproject.library-conventions")
}
dependencies {
implementation(project(":internal-module"))
}
plugins {
id("myproject.library-conventions")
}
dependencies {
implementation(project(":internal-module"))
}
plugins {
id 'myproject.library-conventions'
}
dependencies {
implementation project(':internal-module')
}
plugins {
id 'myproject.library-conventions'
}
dependencies {
implementation project(':internal-module')
}
请注意,将约定插件应用于子项目如何有效地声明其类型。通过应用 myproject.java-conventions
插件,我们声明:这是一个“Java”项目。通过应用 myproject.library-conventions
插件,我们声明:这是一个“库”项目。
此示例中创建的所有插件都包含使用 TestKit 验证其行为的功能测试。
此示例没有任何项目源代码,仅布局了一个假设的项目结构,其中两个库子项目依赖于一个共享的内部子项目。
编译约定插件
在此示例中,约定插件被实现为预编译脚本插件 - 这是最简单的入门方式,因为您可以直接使用 Gradle 的 DSL 之一来实现构建逻辑,就像插件是常规构建脚本一样。
为了使预编译脚本插件被发现,buildSrc
项目需要在其 build.gradle.kts
文件中应用 kotlin-dsl
插件
为了使预编译脚本插件被发现,buildSrc
项目需要在其 build.gradle
文件中应用 groovy-gradle-plugin
插件
plugins {
`kotlin-dsl`
}
plugins {
id 'groovy-gradle-plugin'
}
注意事项
在预编译脚本插件中应用外部插件
myproject.java-conventions
插件使用 SpotBugs 插件执行静态代码分析。
SpotBugs 是一个外部插件 - 外部插件需要在预编译脚本插件中应用之前添加为实现依赖项
repositories {
gradlePluginPortal() // so that external plugins can be resolved in dependencies section
}
dependencies {
implementation("com.github.spotbugs.snom:spotbugs-gradle-plugin:5.2.1")
testImplementation("junit:junit:4.13")
}
repositories {
gradlePluginPortal() // so that external plugins can be resolved in dependencies section
}
dependencies {
implementation 'com.github.spotbugs.snom:spotbugs-gradle-plugin:5.2.1'
testImplementation platform("org.spockframework:spock-bom:2.2-groovy-3.0")
testImplementation 'org.spockframework:spock-core'
}
tasks.named('test', Test) {
useJUnitPlatform()
}
-
插件的依赖工件坐标 (GAV) 可能与插件 ID 不同。
-
Gradle 插件门户 (
gradlePluginPortal()
) 被添加为插件依赖项的仓库。 -
插件版本由依赖版本确定。
添加依赖项后,可以通过 ID 在预编译脚本插件中应用外部插件
plugins {
java
checkstyle
// NOTE: external plugin version is specified in implementation dependency artifact of the project's build file
id("com.github.spotbugs")
}
plugins {
id 'java'
id 'checkstyle'
// NOTE: external plugin version is specified in implementation dependency artifact of the project's build file
id 'com.github.spotbugs'
}
应用其他预编译脚本插件
预编译脚本插件可以应用其他预编译脚本插件。
myproject.library-conventions
插件应用 myproject.java-conventions
插件
plugins {
`java-library`
`maven-publish`
id("myproject.java-conventions")
}
plugins {
id 'java-library'
id 'maven-publish'
id 'myproject.java-conventions'
}
使用来自 main source set 的类
预编译脚本插件可以使用在插件项目的主 source set 中定义的类。
在此示例中,myproject.library-conventions
插件使用来自 buildSrc/src/main/java
的自定义 task 类来配置库 README 检查
val readmeCheck by tasks.registering(com.example.ReadmeVerificationTask::class) {
readme = layout.projectDirectory.file("README.md")
readmePatterns = listOf("^## API$", "^## Changelog$")
}
def readmeCheck = tasks.register('readmeCheck', com.example.ReadmeVerificationTask) {
// Expect the README in the project directory
readme = layout.projectDirectory.file("README.md")
// README must contain a Service API header
readmePatterns = ['^## API$', '^## Changelog$']
}
有关编写自定义 Gradle 插件的更多详细信息,请查阅用户手册。