Введение

Public cible : разработчики Gradle, сталкивающиеся с управлением зависимостями в многосборных проектах.

В нашем стремлении создать плагин`site-baker`, мы стремились поддерживать чистую и централизованную кодовую базу. Одной из лучших практик в современной экосистеме Gradle является использованиекаталог версий(libs.versions.toml) для управления зависимостями. Но что происходит, когда ваш проект становится более сложным, какстроить композитгде независимая сборка (наш плагин) должна быть включена в другую ?

Именно там наше приключение приняло неожиданный оборот. Мы хотели, чтобы наш плагин`site-baker`, который сам по себе является проектом Gradle, использует тот же каталог версий, что и наш основной проект. Эта статья, пятая в нашей серии, рассказывает, как мы решили эту проблему.

1. Каталог версий (libs.versions.toml) : напоминание

Файл`gradle/libs.versions.toml`— это функция Gradle, позволяющая централизовать версии и координаты зависимостей вашего проекта. Обычно она состоит из четырёх разделов:

  • [versions]: Определяет псевдонимы для номеров версий (например:`kotlin = "1.9.20"`).

  • [libraries]: Определяет псевдонимы для полных зависимостей, используя версии, указанные выше (например:`kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }`).

  • [bundles]`Объединяет несколько библиотек под одним псевдонимом (например:`jackson = ["jackson-core", "jackson-databind"]).

  • [plugins]: Определяет псевдонимы для плагинов Gradle.

После того как оно определено, Gradle автоматически генерирует типизированные аксессоры, что делает ваш`build.gradle.kts`гораздо более читаемый :

dependencies {
    // Au lieu de : implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
    implementation(libs.kotlin.stdlib)
}
Pоток данных каталога версий
@startuml
!theme plain
file "gradle/libs.versions.toml" as Toml
node "Грэдл" as G
file "build.gradle.kts" as BuildScript

Toml --> G : "читается"
G --> BuildScript : "генерирует аксессор `libs"
BuildScript -> G : "используй `libs` для объявления зависимостей"
@enduml

2. Проблема: композитная сборка и два разделенных мира

Наша структура проекта — этопостроить композит. Главный проект (thymeleaf.cheroliv.com) включает проект плагина (site-baker) через команду`includeBuild("site-baker")в файле`settings.gradle.kts.

Структура композитной сборки
@startuml
!theme plain
package "Главный проект" {
  file "settings.gradle.kts" as MainSettings
  folder "Грэдл" {
    file "libs.versions.toml" as MainToml
  }
}

package "Плагин `site-baker` (Встроено)" {
  file "settings.gradle.kts" as PluginSettings
  file "build.gradle.kts" as PluginBuild
}

MainSettings -> PluginSettings : `includeBuild("site-baker")`
PluginBuild ..> MainToml : **Voulait accéder à...**
note right on link: ...mais ne pouvait pas !
@enduml

Проблема в том, что, по умолчанию, включённый build - этоотдельный мир. У него есть своя конфигурация, свой жизненный цикл, и он не видит файл`libs.versions.toml`главной сборки. Наш`plugin/build.gradle.kts`пытался использовать`libs.plugins.kotlin.jvm`, но объект`libs`Он не был сгенерирован из правильного файла TOML, что привело к ошибкам сборки.

3. Решение: Совместное использование разрешения зависимостей

После нескольких поисков решение оказалось функцией Gradle, специально разработанной для этого случая :`dependencyResolutionManagement`.

В файле`settings.gradle.kts` du включённая сборка(site-baker/settings.gradle.kts), мы можем указать Gradle, где найти каталог версий для использования.

Это конфигурация, которую мы добавили к`site-baker/settings.gradle.kts`:

// site-baker/settings.gradle.kts

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

rootProject.name = "site-baker"
include("plugin")

Давайте проанализируем важную часть:

versionCatalogs {
    create("libs") { // Crée un catalogue nommé 'libs'
        from(files("../gradle/libs.versions.toml")) // En utilisant ce fichier
    }
}
  • create("libs"): Мы объявляем каталог версий, который будет доступен через псевдоним`libs`.

  • from(files("../gradle/libs.versions.toml"))`Это магия. Мы указываем Gradle, что источник этого каталога — файл TOML, расположенный в каталоге`gradle du родительский проект(

)../).

С этой конфигурацией сборка`site-baker`Теперь он знает, что ему нужно использовать каталог версий основного проекта. Объект`libs`сгенерировано правильно, и зависимости разрешены как ожидалось.

4. Вывод: Сила хорошо управляемых композитных сборок

Этот опыт был полон уроков. Каталог версий — фантастический инструмент для поддерживаемости, но его поведение в сценариях комбинированных сборок не всегда интуитивно понятно.

Ключ в том, чтобы помнить, что включённая сборка остаётся независимой. Чтобы делиться конфигурациями, такими как каталог версий, необходимо использовать явные механизмы, предоставляемые Gradle, такие как блок`dependencyResolutionManagement`в`settings.gradle.kts`.

Решив эту проблему, мы не только сделали нашу сборку более чистой, но и усилили целостность нашего проекта, убедившись, что плагин и основной проект используют единым источником правды для своих зависимостей.

В следующей статье мы продолжим обогащать наш плагин, добавляя более сложные задачи, поскольку теперь наше управление зависимостями надёжно и централизовано.

Похожие статьи