每個軟體專案的原始碼和建置邏輯都應該以有意義的方式組織。本頁闡述可產生可讀、可維護專案的最佳實務。以下章節也將觸及常見問題以及如何避免這些問題。

分隔特定語言的原始碼檔案

Gradle 的語言外掛程式為探索和編譯原始碼建立慣例。例如,套用 Java 外掛程式 的專案將自動編譯 src/main/java 目錄中的程式碼。其他語言外掛程式也遵循相同的模式。目錄路徑的最後一部分通常指示原始碼檔案的預期語言。

某些編譯器能夠在同一個原始碼目錄中交叉編譯多種語言。Groovy 編譯器可以處理混合位於 src/main/groovy 中的 Java 和 Groovy 原始碼檔案的情境。Gradle 建議您根據語言將原始碼放置在目錄中,因為建置效能更高,而且使用者和建置都可以做出更強的假設。

以下原始碼樹狀結構包含 Java 和 Kotlin 原始碼檔案。Java 原始碼檔案位於 src/main/java 中,而 Kotlin 原始碼檔案位於 src/main/kotlin 中。

.
├── build.gradle.kts
└── src
    └── main
        ├── java
        │   └── HelloWorld.java
        └── kotlin
            └── Utils.kt
.
├── build.gradle
└── src
    └── main
        ├── java
        │   └── HelloWorld.java
        └── kotlin
            └── Utils.kt

每個測試類型分隔原始碼檔案

專案定義和執行不同類型的測試(例如單元測試、整合測試、功能測試或冒煙測試)非常常見。理想情況下,每種測試類型的測試原始碼都應儲存在專用原始碼目錄中。分隔的測試原始碼對可維護性和關注點分離具有正面影響,因為您可以彼此獨立地執行測試類型。

請查看 範例,其中示範如何將個別的整合測試配置新增至以 Java 為基礎的專案。

盡可能使用標準慣例

所有 Gradle 核心外掛程式都遵循軟體工程範例 慣例優於配置。外掛程式邏輯在特定情況下為使用者提供合理的預設值和標準,即慣例。以 Java 外掛程式 為例。

  • 它定義目錄 src/main/java 作為編譯的預設原始碼目錄。

  • 已編譯原始碼和其他成品(例如 JAR 檔案)的輸出目錄為 build

透過堅持預設慣例,專案的新開發人員可以立即知道如何找到方向。雖然這些慣例可以重新配置,但這會讓建置腳本使用者和作者更難以管理建置邏輯及其結果。盡可能堅持預設慣例,除非您需要適應舊專案的版面配置。請參閱相關外掛程式的參考頁面,以了解其預設慣例。

務必定義設定檔

每次叫用建置時,Gradle 都會嘗試尋找 settings.gradle (Groovy DSL) 或 settings.gradle.kts (Kotlin DSL) 檔案。為此,執行階段會向上走訪目錄樹狀結構的階層,直到根目錄。演算法在找到設定檔後立即停止搜尋。

務必將 settings.gradle 新增至建置的根目錄,以避免初始效能影響。檔案可以是空的,也可以定義專案的所需名稱。

多專案建置必須在多專案階層的根專案中具有 settings.gradle(.kts) 檔案。這是必要的,因為設定檔定義哪些專案參與 多專案建置。除了定義包含的專案之外,您可能還需要它來將程式庫新增至您的建置腳本類別路徑

以下範例顯示標準 Gradle 專案版面配置

.
├── settings.gradle.kts
├── subproject-one
│   └── build.gradle.kts
└── subproject-two
    └── build.gradle.kts
.
├── settings.gradle
├── subproject-one
│   └── build.gradle
└── subproject-two
    └── build.gradle

使用 buildSrc 抽象化命令式邏輯

複雜的建置邏輯通常是封裝為自訂任務或二進制外掛程式的良好候選者。自訂任務和外掛程式實作不應存在於建置腳本中。只要程式碼不需要在多個獨立專案之間共用,使用 buildSrc 就非常方便。

目錄 buildSrc 會被視為包含的建置。在探索目錄後,Gradle 會自動編譯此程式碼並將其放入建置腳本的類別路徑中。對於多專案建置,只能有一個 buildSrc 目錄,該目錄必須位於根專案目錄中。buildSrc 應優先於腳本外掛程式,因為它更容易維護、重構和測試程式碼。

buildSrc 使用適用於 Java 和 Groovy 專案的相同原始碼慣例。它也提供對 Gradle API 的直接存取。其他相依性可以在 buildSrc 下的專用 build.gradle 中宣告。

buildSrc/build.gradle.kts
repositories {
    mavenCentral()
}

dependencies {
    testImplementation("junit:junit:4.13")
}
buildSrc/build.gradle
repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'junit:junit:4.13'
}

包含 buildSrc 的典型專案具有以下版面配置。buildSrc 下的任何程式碼都應使用類似於應用程式碼的套件。或者,如果需要其他配置(例如套用外掛程式或宣告相依性),buildSrc 目錄可以託管建置腳本。

.
├── buildSrc
│   ├── build.gradle.kts
│   └── src
│       ├── main
│       │   └── java
│       │       └── com
│       │           └── enterprise
│       │               ├── Deploy.java
│       │               └── DeploymentPlugin.java
│       └── test
│           └── java
│               └── com
│                   └── enterprise
│                       └── DeploymentPluginTest.java
├── settings.gradle.kts
├── subproject-one
│   └── build.gradle.kts
└── subproject-two
    └── build.gradle.kts
.
├── buildSrc
│   ├── build.gradle
│   └── src
│       ├── main
│       │   └── java
│       │       └── com
│       │           └── enterprise
│       │               ├── Deploy.java
│       │               └── DeploymentPlugin.java
│       └── test
│           └── java
│               └── com
│                   └── enterprise
│                       └── DeploymentPluginTest.java
├── settings.gradle
├── subproject-one
│   └── build.gradle
└── subproject-two
    └── build.gradle

buildSrc 中的變更會導致整個專案過期。

因此,在進行小的增量變更時,--no-rebuild 命令列選項通常有助於更快獲得回饋。請記住定期執行完整建置。

gradle.properties 檔案中宣告屬性

在 Gradle 中,屬性可以在建置腳本、gradle.properties 檔案中或作為命令列上的參數定義。

在命令列上宣告屬性以用於臨時情境很常見。例如,您可能想要傳入特定的屬性值,以僅針對建置的這一次叫用控制執行階段行為。建置腳本中的屬性很容易成為維護難題,並使建置腳本邏輯變得複雜。gradle.properties 有助於將屬性與建置腳本分開,應將其視為可行的選項。它是放置控制建置環境的屬性的好位置。

典型的專案設定會將 gradle.properties 檔案放置在建置的根目錄中。或者,如果您希望它適用於您機器上的所有建置,則該檔案也可以位於 GRADLE_USER_HOME 目錄中。

.
├── gradle.properties
└── settings.gradle.kts
├── subproject-a
│   └── build.gradle.kts
└── subproject-b
    └── build.gradle.kts
.
├── gradle.properties
└── settings.gradle
├── subproject-a
│   └── build.gradle
└── subproject-b
    └── build.gradle

避免重疊的任務輸出

任務應定義輸入和輸出,以獲得增量建置功能的效能優勢。宣告任務的輸出時,請確保用於寫入輸出的目錄在專案中的所有任務中都是唯一的。

混合或覆寫不同任務產生的輸出檔案會損害最新的檢查,導致建置速度變慢。反過來,這些檔案系統變更可能會阻止 Gradle 的建置快取正確識別和快取原本可以快取的任務。

使用自訂 Gradle 發行版本標準化建置

企業通常希望透過定義通用慣例或規則來標準化組織中所有專案的建置平台。您可以使用初始化腳本來實現此目的。初始化腳本使在單一機器上的所有專案中套用建置邏輯變得極其容易。例如,宣告內部儲存庫及其認證。

此方法有一些缺點。首先,您必須在公司中的所有開發人員之間溝通設定程序。此外,統一更新初始化腳本邏輯可能具有挑戰性。

自訂 Gradle 發行版本是解決此問題的實用解決方案。自訂 Gradle 發行版本由標準 Gradle 發行版本加上一個或多個自訂初始化腳本組成。初始化腳本與發行版本捆綁在一起,並且每次執行建置時都會套用。開發人員只需將其簽入的 Wrapper 檔案指向自訂 Gradle 發行版本的 URL 即可。

自訂 Gradle 發行版本也可能在發行版本的根目錄中包含 gradle.properties 檔案,該檔案提供組織範圍的一組控制建置環境的屬性

以下步驟是用於建立自訂 Gradle 發行版本的典型步驟

  1. 實作下載和重新封裝 Gradle 發行版本的邏輯。

  2. 使用所需的邏輯定義一個或多個初始化腳本。

  3. 將初始化腳本與 Gradle 發行版本捆綁在一起。

  4. 將 Gradle 發行版本封存檔上傳到 HTTP 伺服器。

  5. 變更所有專案的 Wrapper 檔案,以指向自訂 Gradle 發行版本的 URL。

build.gradle
plugins {
    id 'base'
}

// This is defined in buildSrc
import org.gradle.distribution.DownloadGradle

version = '0.1'

tasks.register('downloadGradle', DownloadGradle) {
    description = 'Downloads the Gradle distribution with a given version.'
    gradleVersion = '4.6'
}

tasks.register('createCustomGradleDistribution', Zip) {
    description = 'Builds custom Gradle distribution and bundles initialization scripts.'

    dependsOn downloadGradle

    def projectVersion = project.version
    archiveFileName = downloadGradle.gradleVersion.map { gradleVersion ->
        "mycompany-gradle-${gradleVersion}-${projectVersion}-bin.zip"
    }

    from zipTree(downloadGradle.destinationFile)

    from('src/init.d') {
        into "${downloadGradle.distributionNameBase.get()}/init.d"
    }
}