Article 3 : Intégration de Jackson pour le Parsing YAML avec TDD dans un Plugin Gradle
Опубликовано 25 September 2025
Введение
В разработке плагинов Gradle управление сложными конфигурациями является обычной задачей. Вместо того чтобы перегружать DSL сотнями свойств, часто чище и поддерживаемее определять конфигурацию во внешнем файле, например, в YAML. Эта статья проведет вас через интеграцию мощной библиотеки Jackson для парсинга файлов YAML в объекты Kotlin, применяя строгий подход TDD, чтобы обеспечить надежность нашего плагина.site-baker.
1. Контекст: Наш плагин `site-baker
Наш плагин`site-baker`предназначен для автоматизации генерации и развертывания статического сайта. Ему необходимо читать файл конфигурации YAML (managed-jbake-context.yml) для получения информации, такой как пути исходных файлов, места развертывания и учетные данные Git.
YAML конфигурация, которую мы хотим разобрать, выглядит так:
bake:
srcPath: "./site/jbake"
destDirPath: "bake"
cname: "cheroliv.com"
pushPage:
from: "bake"
to: "cvs"
repo:
name: "trainings"
repository: "https://github.com/pages-content/pages-content.github.io.git"
credentials:
username: "USERNAME"
password: "SECRET_TOKEN"
branch: "main"
message: "cheroliv.com"
# ... autres configurations (pushMaquette, supabase, etc.)
2. Моделирование конфигурации в Kotlin
Перед парсингом нам нужно определить структуру наших данных на Kotlin. Jackson будет использовать эти классы для автоматического сопоставления содержимого YAML.
// plugin/src/main/kotlin/com/cheroliv/site/baker/data/SiteConfiguration.kt
package com.cheroliv.site.baker.data
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
fun parseSiteConfiguration(yaml: String): SiteConfiguration {
val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
return mapper.readValue(yaml)
}
data class GitPushConfiguration(
val from: String = "",
val to: String = "",
val repo: RepositoryConfiguration = RepositoryConfiguration(),
val branch: String = "",
val message: String = "",
)
data class RepositoryConfiguration(
val name: String = "",
val repository: String = "",
val credentials: RepositoryCredentials = RepositoryCredentials(),
) {
companion object {
const val ORIGIN = "origin"
const val CNAME = "CNAME"
const val REMOTE = "remote"
}
}
data class RepositoryCredentials(val username: String = "", val password: String = "")
data class SiteConfiguration(
val bake: BakeConfiguration = BakeConfiguration(),
val pushPage: GitPushConfiguration = GitPushConfiguration(),
val pushMaquette: GitPushConfiguration = GitPushConfiguration(),
val pushSource: GitPushConfiguration? = null,
val pushTemplate: GitPushConfiguration? = null,
val supabase: SupabaseContactFormConfig? = null
)
data class BakeConfiguration(
val srcPath: String = "",
val destDirPath: String = "",
val cname: String? = null,
)
// ... (autres data classes pour Supabase, si nécessaire)
Функция`parseSiteConfiguration`является нашей точкой входа для десериализации. Она использует`ObjectMapper`Джексона, настроенного с`YAMLFactory`для формата YAML и`registerKotlinModule()`для поддержки особенностей Kotlin (таких как значения свойств по умолчанию).
3. Интеграция Jackson в `build.gradle.kts
Для использования Jackson нам необходимо добавить необходимые зависимости в`build.gradle.kts`нашего модуля`plugin`Пожалуйста, введите текст для перевода.
// plugin/build.gradle.kts
dependencies {
// Jackson for YAML parsing
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3")
// ... autres dépendances
}
Мы используем`jackson-module-kotlin`для поддержки Kotlin и`jackson-dataformat-yaml`pour управления форматом YAML.
4. Подход TDD : Тестирование парсинга YAML
Теперь применим TDD для проверки нашей логики парсинга.
4.1. Тест юнита: Преобразовать YAML в объект Kotlin
Мы начинаем с юнит-теста в`SiteBakerPluginTest.kt`чтобы проверить, что функция`parseSiteConfiguration`может правильно преобразовать строку YAML в объект`SiteConfiguration`.
// plugin/src/test/kotlin/com/cheroliv/site/baker/SiteBakerPluginTest.kt
@Test
fun `can map configuration text to SiteConfiguration object`() {
val yamlString = "../../managed-jbake-context.yml"
.run(::File)
.readText()
.trimIndent()
val config: SiteConfiguration = parseSiteConfiguration(yamlString)
assertEquals("cheroliv.com", config.bake.cname)
assertEquals("main", config.pushPage.branch)
assertEquals("https://github.com/pages-content/pages-content.github.io.git", config.pushPage.repo.repository)
}
Этот тест читает содержимое файла`managed-jbake-context.yml`(которое должно существовать для того, чтобы тест был корректен) и выполняет ассерции над объектом`SiteConfiguration`Полученное. Он подтверждает, что ключевые значения YAML правильно сопоставлены.
4.2. Тест функциональный: Проверить чтение файла конфигурации
Чтобы убедиться, что плагин может читать файл конфигурации через свой DSL и что парсинг работает в реальной среде Gradle, мы добавляем функциональный тест в`SiteBakerPluginFunctionalTest.kt`.
Этот тест важен, поскольку он имитирует выполнение плагина в реальном проекте. Он должен бытьгерметичный, то есть он должен сам создать файл`managed-jbake-context.yml`с контролируемым содержимым, для обеспечения воспроизводимости и изоляции теста
// plugin/src/functionalTest/kotlin/com/cheroliv/site/baker/SiteBakerPluginFunctionalTest.kt
@Test
fun `config file contains good data`(){
val configContent = configFile.readText(UTF_8)
// Vérifications comme dans vos commentaires
assertTrue(configContent.contains("bake"))
assertTrue(configContent.contains("pushPage"))
assertTrue(configContent.contains("repository"))
}
Этот функциональный тест проверяет, что скопированный файл конфигурации во временной директории теста содержит ожидаемые данные. Хотя этот тест не парсит YAML напрямую в объект Kotlin, он проверяет наличие файла и его содержимого, что является необходимым предварительным шагом перед парсингом плагином.
5. Визуализация потока парсинга
Следующая диаграмма иллюстрирует поток данных и взаимодействия при разборе конфигурации YAML:
@startuml
actor "Utilisateur Gradle" as User
participant "build.gradle.kts" as BuildScript
participant "SiteBakerPlugin" as Plugin
participant "SiteExtension" as Extension
participant "managed-jbake-context.yml" as ConfigFile
participant "parseSiteConfiguration()" as Parser
participant "SiteConfiguration (Objet Kotlin)" as KotlinObject
User -> BuildScript : Applique le plugin et configure le DSL
BuildScript -> Plugin : apply()
Plugin -> Extension : Crée et enregistre l'extension 'site'
User -> BuildScript : site { configPath = "..." }
BuildScript -> Extension : Définit configPath
Plugin -> ConfigFile : Lit le fichier (via configPath)
ConfigFile --> Plugin : Contenu YAML
Plugin -> Parser : Appelle parseSiteConfiguration(yamlString)
Parser -> KotlinObject : Mappe le YAML en objet SiteConfiguration
KotlinObject --> Plugin : Retourne l'objet configuré
@enduml
Заключение
Следуя подходу TDD, мы успешно интегрировали библиотеку Jackson для парсинга файлов конфигурации YAML в объекты Kotlin внутри нашего Gradle‑плагина. Этот метод позволил нам:
-
Четко моделироватьнаша конфигурация с data classes Kotlin.
-
Подтвердить логику парсингас целевыми юнит-тестами.
-
Обеспечить интеграциюв реальной среде Gradle благодаря герметичными функциональными тестами
Эта надежная основа дает нам большую уверенность в расширении нашего плагина функционалом, основанным на этой конфигурации, обеспечивая при этом поддерживаемость и надежность кода. Парсинг YAML теперь является надежной и протестированной функцией нашего плагина.site-baker.