Gradle Version Catalogs: порядок в зависимостях через libs.versions.toml

В крупном Gradle-проекте одна и та же проблема воспроизводится снова и снова: версия библиотеки прописана в одном модуле, другая версия той же библиотеки — в другом, и через полгода никто не помнит, почему они расходятся. Version catalogs — официальный механизм Gradle для решения этой проблемы. Он централизует управление зависимостями, добавляет типобезопасность и снижает вероятность конфликтов.

Что такое Version Catalog

Version catalog — это файл gradle/libs.versions.toml, в котором описаны все зависимости проекта: версии, координаты библиотек, плагины и группы зависимостей (bundles). Из этого файла Gradle генерирует типобезопасные аксессоры — вместо строки "org.codehaus.groovy:groovy:3.0.5" в build-скрипте пишется libs.groovy.core.

Основные преимущества:

  • Все зависимости видны в одном месте — удобно при code review и аудите
  • Опечатки в именах библиотек превращаются в ошибки компиляции, а не в runtime-проблемы
  • IDE даёт автодополнение по каталогу
  • Версию можно менять в одном месте — она обновляется во всех модулях

Структура libs.versions.toml

Файл состоит из четырёх секций.

versions

Именованные версии, на которые ссылаются библиотеки:

[versions]
groovy = "3.0.5"
kotlin = "2.3.20"
commons-lang3 = { strictly = "[3.8, 4.0[", prefer = "3.9" }

Поддерживаются rich version constraints: require, strictly, prefer, reject.

libraries

Координаты зависимостей. Три способа записи:

[libraries]
# Краткая форма
my-lib = "com.example:mylib:1.4"

# С отдельной ссылкой на версию
groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }

# С rich constraints
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3",
                  version = { strictly = "[3.8, 4.0[", prefer = "3.9" } }

bundles

Группы библиотек, которые часто добавляются вместе:

[bundles]
groovy = ["groovy-core", "groovy-json", "groovy-nio"]

В build-скрипте вместо трёх строк — одна:

dependencies {
    implementation(libs.bundles.groovy)
}

plugins

Плагины с версиями:

[plugins]
versions = { id = "com.github.ben-manes.versions", version = "0.45.0" }
android-application = { id = "com.android.application", version.ref = "agp" }

Как использовать в build-скриптах

Gradle автоматически генерирует аксессоры по имени каталога. Дефисы в именах заменяются точками:

// build.gradle.kts
dependencies {
    implementation(libs.groovy.core)
    implementation(libs.commons.lang3)
    testImplementation(libs.bundles.testing)
}

plugins {
    alias(libs.plugins.versions)
    alias(libs.plugins.android.application)
}

Миграция с прямых версий

Типичный сценарий перехода:

  1. Создать файл gradle/libs.versions.toml
  2. Перенести версии в секцию [versions]
  3. Описать все зависимости в [libraries], сослаться на версии через version.ref
  4. В build-скриптах заменить строковые координаты на libs.* аксессоры
  5. Для плагинов заменить id("...") version "..." на alias(libs.plugins.*)

Для проектов с несколькими модулями файл лежит в корне, все модули обращаются к одному каталогу.

Несколько каталогов

Если нужна разбивка по контексту (например, отдельный каталог для тестовых зависимостей или внутренних инструментов):

// settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("testLibs") {
            from(files("gradle/test.versions.toml"))
        }
        create("tools") {
            from(files("gradle/tools.versions.toml"))
        }
    }
}

В build-скриптах доступны libs.*, testLibs.* и tools.*.

Публикация каталога для нескольких проектов

Если несколько репозиториев должны использовать общий набор версий, каталог можно опубликовать как Maven-артефакт:

// build.gradle.kts (в репозитории-каталоге)
plugins {
    `version-catalog`
    `maven-publish`
}

catalog {
    versionCatalog {
        from(files("gradle/libs.versions.toml"))
    }
}

Потребитель подключает его в settings.gradle.kts:

versionCatalogs {
    create("libs") {
        from("com.mycompany:catalog:1.0")
    }
}

Важные ограничения

Version catalog декларирует запрошенные версии, но не принудительно их применяет. Gradle по-прежнему может выбрать другую версию из-за конфликтов в графе зависимостей. Для жёсткого pinning используйте strictly или платформы (BOM).

TOML-формат не поддерживает classifiers, artifact types (@aar, @zip), exclude rules и capabilities. Для classifiers — variantOf() в build-скрипте:

implementation(variantOf(libs.my.lib) { classifier("test-fixtures") })

В buildSrc каталог не подхватывается автоматически — нужен явный импорт в buildSrc/settings.gradle.kts.

Кому это нужно

Version catalogs полезны в первую очередь для:

  • Multi-module проектов, где одни и те же зависимости используются в нескольких модулях
  • Команд, которым важен контроль версий при code review
  • Организаций с несколькими репозиториями, которые должны использовать согласованный набор библиотек

Для одномодульного небольшого проекта с 10 зависимостями усложнять build-конфигурацию каталогом не обязательно — прямые строки вполне читаемы. Переход имеет смысл, когда управление версиями становится отдельной операционной задачей.


Источник: официальная документация Gradle — docs.gradle.org. Актуальные примеры и поддерживаемые форматы — в официальной документации по версии Gradle вашего проекта.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *