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

此範例展示了如何將建置邏輯組織成可重複使用的部分,並發布到儲存庫中,以便在多倉儲設定的其他專案中重複使用。

還有一個新範例示範如何在這種情境下使用孵化中Test Suite Plugin

使用案例

舉例來說,假設一個組織生產兩種 Java 軟體 - 服務和函式庫。我們想要將一組程式碼品質檢查規則應用於這兩種類型的專案,並為每種類型配置一些特定方面。

組織建置邏輯

此使用案例可以透過分層三個獨立的外掛程式來建模

建置邏輯佈局
├── convention-plugins
│   ├── build.gradle.kts
│   ├── settings.gradle.kts
│   ├── src
│   │   ├── main
│   │   │   └── kotlin
│   │   │       ├── com.myorg.java-conventions.gradle.kts
│   │   │       ├── com.myorg.library-conventions.gradle.kts
│   │   │       └── com.myorg.service-conventions.gradle.kts
...
建置邏輯佈局
├── convention-plugins
│   ├── build.gradle
│   ├── settings.gradle
│   ├── src
│   │   ├── main
│   │   │   └── groovy
│   │   │       ├── com.myorg.java-conventions.gradle
│   │   │       ├── com.myorg.library-conventions.gradle
│   │   │       └── com.myorg.service-conventions.gradle
...
  • com.myorg.java-conventions - 配置組織中任何 Java 專案通用的慣例。這適用於先前識別的兩種軟體類型,因此此外掛程式將應用於後續的兩個外掛程式中。

  • com.myorg.library-conventions - 新增發布配置以發布到組織的儲存庫,並配置強制性文件檢查。

  • com.myorg.service-conventions - 配置整合測試並檢查 README 中的強制性內容。由於服務與函式庫不同,因此在本例中配置了不同的文件要求。

此範例中建立的所有外掛程式都包含功能測試,這些測試使用 TestKit 來驗證其行為。

編譯慣例外掛程式

在此範例中,慣例外掛程式實作為預編譯腳本外掛程式 - 這是最簡單的入門方式,因為您可以直接使用 Gradle 的 DSL 之一來實作建置邏輯,就像外掛程式是常規建置腳本一樣。

為了讓預編譯腳本外掛程式被發現,convention-plugins 專案需要在其 build.gradle 檔案中套用 groovy-gradle-plugin 外掛程式

為了讓預編譯腳本外掛程式被發現,convention-plugins 專案需要在其 build.gradle.kts 檔案中套用 kotlin-dsl 外掛程式

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

發布慣例外掛程式

在此範例中,我們的目標是多倉儲設定。為了將上述外掛程式應用於不同的專案,必須將它們發布到公司的 Artifact 儲存庫。慣例外掛程式是常規的 Gradle 外掛程式 - 因此,它們可以像任何其他 Gradle 外掛程式一樣發布到外部儲存庫

在此,我們配置專案以使用 maven-publish 外掛程式發布外掛程式。為了示範目的,我們發布到本機檔案系統目錄。您可以在 maven-publish 外掛程式的儲存庫章節中找到有關如何發布到遠端儲存庫的資訊。

範例 2. 發布配置
convention-plugins/build.gradle.kts
plugins {
    `kotlin-dsl`
    `maven-publish`
}

group = "com.myorg.conventions"
version = "1.0"

publishing {
    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = uri(layout.buildDirectory.dir("repo"))
        }
    }
}

tasks.publish {
    dependsOn("check")
}
convention-plugins/build.gradle
plugins {
    id 'groovy-gradle-plugin'
    id 'maven-publish'
}

group = 'com.myorg.conventions'
version = '1.0'

publishing {
    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url = layout.buildDirectory.dir('repo')
        }
    }
}

tasks.named('publish') {
    dependsOn('check')
}

外掛程式可以使用以下方式發布:

./gradlew publish

為了在另一個專案中使用它們,請在設定檔中配置外掛程式儲存庫並套用外掛程式

settings.gradle.kts
pluginManagement {
    repositories {
        gradlePluginPortal()
        maven {
            // replace the path with the actual path to the repository
            url = uri("<path-to>/convention-plugins/build/repo")
        }
    }
}
build.gradle.kts
plugins {
    id("com.myorg.service-conventions") version "1.0"
}
settings.gradle
pluginManagement {
    repositories {
        gradlePluginPortal()
        maven {
            // replace the path with the actual path to the repository
            url = uri('<path-to>/convention-plugins/build/repo')
        }
    }
}
build.gradle
plugins {
    id 'com.myorg.service-conventions' version '1.0'
}

注意事項

在慣例外掛程式中套用外部外掛程式

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

SpotBugs 是一個外部外掛程式 - 外部外掛程式需要作為實作相依性新增,然後才能在慣例外掛程式中套用

convention-plugins/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")
}
convention-plugins/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'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test', Test) {
    useJUnitPlatform()
}
  • 外掛程式的相依性 Artifact 坐標 (GAV) 可能與外掛程式 ID 不同。

  • Gradle 外掛程式入口網站 (gradlePluginPortal()) 已新增為外掛程式相依性的儲存庫。

  • 外掛程式版本由相依性版本決定。

一旦新增了相依性,就可以通過 ID 在慣例外掛程式中套用外部外掛程式

convention-plugins/src/main/kotlin/com.myorg.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")
}
convention-plugins/src/main/groovy/com.myorg.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'
}

套用其他慣例外掛程式

慣例外掛程式可以套用其他慣例外掛程式。

com.myorg.library-conventionscom.myorg.service-conventions 外掛程式都套用了 com.myorg.java-conventions 外掛程式

convention-plugins/src/main/kotlin/com.myorg.library-conventions.gradle.kts
plugins {
    `java-library`
    `maven-publish`
    id("com.myorg.java-conventions")
}
convention-plugins/src/main/kotlin/com.myorg.service-conventions.gradle.kts
plugins {
    id("com.myorg.java-conventions")
}
convention-plugins/src/main/groovy/com.myorg.library-conventions.gradle
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'com.myorg.java-conventions'
}
convention-plugins/src/main/groovy/com.myorg.service-conventions.gradle
plugins {
    id 'com.myorg.java-conventions'
}

使用主要來源集中的類別

慣例外掛程式可以使用在外掛程式專案的主要來源集中定義的類別。

在此範例中,com.myorg.service-conventions 外掛程式使用來自 src/main/java 的自訂 Task 類別來配置服務 README 檢查

convention-plugins/src/main/kotlin/com.myorg.service-conventions.gradle.kts
val readmeCheck by tasks.registering(com.example.ReadmeVerificationTask::class) {
    readme = layout.projectDirectory.file("README.md")
    readmePatterns = listOf("^## Service API$")
}
convention-plugins/src/main/groovy/com.myorg.service-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 = ['^## Service API$']
}

有關撰寫自訂 Gradle 外掛程式的更多詳細資訊,請查閱使用者手冊