您可以在支援 Gradle 的 IDE 中開啟此範例。

此範例示範如何在多專案建置中將建置邏輯組織成可重複使用的外掛程式。

使用案例

舉例來說,假設一個包含三個子專案的專案產生兩個公開 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 專案通用的慣例。它套用核心 javacheckstyle 外掛程式以及外部 com.github.spotbugs 外掛程式,配置通用編譯器選項以及程式碼品質檢查。

  • myproject.library-conventions - 新增發布配置以發布到組織的儲存庫,並檢查 README 中是否有強制性內容。它套用 java-librarymaven-publish 外掛程式以及 myproject.java-conventions 外掛程式。

內部程式庫子專案套用 myproject.java-conventions 外掛程式

internal-module/build.gradle.kts
plugins {
    id("myproject.java-conventions")
}

dependencies {
    // internal module dependencies
}
internal-module/build.gradle
plugins {
    id 'myproject.java-conventions'
}

dependencies {
    // internal module dependencies
}

兩個公開程式庫子專案套用 myproject.library-conventions 外掛程式。

library-a/build.gradle.kts
plugins {
    id("myproject.library-conventions")
}

dependencies {
    implementation(project(":internal-module"))
}
library-b/build.gradle.kts
plugins {
    id("myproject.library-conventions")
}

dependencies {
    implementation(project(":internal-module"))
}
library-a/build.gradle
plugins {
    id 'myproject.library-conventions'
}

dependencies {
    implementation project(':internal-module')
}
library-b/build.gradle
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 外掛程式

buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}
buildSrc/build.gradle
plugins {
    id 'groovy-gradle-plugin'
}

注意事項

在預先編譯的腳本外掛程式中套用外部外掛程式

myproject.java-conventions 外掛程式使用 SpotBugs 外掛程式來執行靜態程式碼分析。

buildSrc/build.gradle.kts
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")
}
buildSrc/build.gradle
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 在預先編譯的腳本外掛程式中套用外部外掛程式

buildSrc/src/main/kotlin/myproject.java-conventions.gradle.kts
plugins {
    java
    checkstyle

    // NOTE: external plugin version is specified in implementation dependency artifact of the project's build file
    id("com.github.spotbugs")
}
buildSrc/src/main/groovy/myproject.java-conventions.gradle
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 外掛程式

buildSrc/src/main/kotlin/myproject.library-conventions.gradle.kts
plugins {
    `java-library`
    `maven-publish`
    id("myproject.java-conventions")
}
buildSrc/src/main/groovy/myproject.library-conventions.gradle
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'myproject.java-conventions'
}

使用主要原始碼集中的類別

預先編譯的腳本外掛程式可以使用在外掛程式專案的主要原始碼集中定義的類別。

在此範例中,myproject.library-conventions 外掛程式使用來自 buildSrc/src/main/java 的自訂工作類別來配置程式庫 README 檢查

buildSrc/src/main/kotlin/myproject.library-conventions.gradle.kts
val readmeCheck by tasks.registering(com.example.ReadmeVerificationTask::class) {
    readme = layout.projectDirectory.file("README.md")
    readmePatterns = listOf("^## API$", "^## Changelog$")
}
buildSrc/src/main/groovy/myproject.library-conventions.gradle
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 外掛程式的更多詳細資訊,請參閱使用者手冊