مقاله 3: ادغام Jackson برای پارس YAML با TDD در یک پلاگین Gradle
منتشر شده در 25 September 2025
معرفی
در توسعه پلاگینهای Gradle، مدیریت پیکربندیهای پیچیده یک کار رایج است. به جای بارگذاری DSL با صدها ویژگی، اغلب تمیزتر و قابلنگهداریتر است که تنظیمات را در یک فایل خارجی، مانند YAML، تعریف کرد. این مقاله شما را از طریق ادغام کتابخانهی قدرتمند Jackson برای تجزیه فایلهای YAML به اشیاء Kotlin راهنمایی میکند، با رویکرد TDD دقیق برای تضمین استحکام پلاگین ما.site-baker.
به این معنی : پلاگین ما `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`برای مدیریت قالب YAML.
4. روش TDD: تست تجزیه YAML
اکنون، TDD را برای اعتبارسنجی منطق تجزیه و تحلیل ما اعمال کنیم.
4.1. تست واحد: YAML را به شیء Kotlin تبدیل کنید
ما با یک تست unit آغاز میکنیم در`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`با یک محتواcontrolled، برای اطمینان از قابلیت بازتولیدی و انزوالی تست.
// 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 "کاربر Gradle" as User
participant "build.gradle.kts" as BuildScript
participant "SiteBakerPlugin" as Plugin
participant "سامپت اکستنشن" as Extension
participant "managed-jbake-context.yml" as ConfigFile
participant "parseSiteConfiguration()" as Parser
participant "SiteConfiguration (شیء کاتلین)" 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 خود ادغام کردیم. این روش به ما اجازه داد تا:
-
مدلسازی واضحپیکربندی ما با کلاسهای داده Kotlin.
-
منطق تجزیه را تأیید کنیدبا تستهای واحد هدفمند.
-
اطمینان حاصل کردن یکپارچگیدر یک محیط واقعی Gradle به کمک تستهای عملکردی بستهبندی محكم.
این پایه محکم به ما اعتماد بالایی برای گسترش پلاگین خود با ویژگیهایی که بر پایهٔ این تنظیم هستند، میدهد، در حالی که قابلیت نگهداری و استحکام کد را تضمین میکند. تجزیه YAML اکنون یک ویژگی قابل اعتماد و تستشده از پلاگین ما است.site-baker.