Artikel 3: Jackson-Integration zum YAML-Parsing mit TDD in einem Gradle-Plugin
Publié le 25 September 2025
Einleitung
In der Entwicklung von Gradle-Plugins ist die Verwaltung komplexer Konfigurationen eine häufige Aufgabe. Anstatt das DSL mit Hunderten von Eigenschaften zu überladen, ist es oft sauberer und wartbarer, die Konfiguration in einer externen Datei zu definieren, wie z.B. YAML. Dieser Artikel führt Sie durch die Integration der leistungsfähigen Jackson-Bibliothek zum Parsen von YAML-Dateien in Kotlin-Objekte, wobei ein strenger TDD-Ansatz verfolgt wird, um die Robustheit unseres Plugins zu gewährleisten.site-baker.
1. Der Kontext: Unser Plugin `site-baker
Unser Plugin`site-baker` est conçu pour automatiser la génération et le déploiement d’un site statique. Il a besoin de lire un fichier de configuration YAML (managed-jbake-context.yml) um Informationen wie Quellenpfade, Bereitstellungsziele, und Git-Identifikatoren zu erhalten.
Die YAML-Konfiguration, die wir parsen möchten, sieht folgendermaßen aus:
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. Modellierung der Konfiguration in Kotlin
Bevor wir parsen, müssen wir die Struktur unserer Daten in Kotlin definieren. Jackson wird diese Klassen verwenden, um den YAML-Inhalt automatisch zuzuordnen.
// 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)
Die Funktion`parseSiteConfiguration`ist unser Einstiegspunkt für die Deserialisierung. sie verwendet`ObjectMapper`von Jackson, konfiguriert mit`YAMLFactory` pour le format YAML et `registerKotlinModule()`zur Unterstützung der Besonderheiten von Kotlin (wie den Standardwerten von Eigenschaften).
3. Integration von Jackson in `build.gradle.kts
Um Jackson zu verwenden, müssen wir die notwendigen Abhängigkeiten im`build.gradle.kts`unseres Moduls`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
}
Wir verwenden`jackson-module-kotlin`für die Unterstützung von Kotlin und`jackson-dataformat-yaml`für die Verwaltung des YAML-Formats.
4. Der TDD-Ansatz: YAML-Parsing testen
Jetzt wenden wir TDD an, um unsere Parsinglogik zu validieren.
4.1. Einheitstest: YAML in Kotlin-Objekt abbilden
Wir beginnen mit einem Einzeltest in`SiteBakerPluginTest.kt`um zu überprüfen, dass die Funktion`parseSiteConfiguration`kann eine YAML-Zeichenkette korrekt in ein Objekt umwandeln`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)
}
Dieser Test liest den Inhalt der Datei`managed-jbake-context.yml`(der existieren muss, damit der Test gültig ist) und führt Assertionen gegen das Objekt aus`SiteConfiguration` résultant. Il valide que les valeurs clés du YAML sont correctement mappées.
4.2. Funktionstest: Überprüfung des Lesens der Konfigurationsdatei
Um sicherzustellen, dass das Plugin die Konfigurationsdatei über sein DSL lesen kann und das Parsing in einer realen Gradle-Umgebung funktioniert, fügen wir einen funktionalen Test hinzu in`SiteBakerPluginFunctionalTest.kt`.
Dieser Test ist entscheidend, da er die Ausführung des Plugins in einem echten Projekt simuliert. Er muss seinhermetisch, das heißt, er muss die Datei selbst erstellen`managed-jbake-context.yml`mit einem kontrollierten Inhalt, um die Reproduzierbarkeit und Isolation des Tests zu gewährleisten.
// 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"))
}
Dieser funktionale Test überprüft, dass die in das Test-Temporary-Verzeichnis kopierte Konfigurationsdatei die erwarteten Daten enthält. Obwohl dieser Test das YAML nicht direkt in ein Kotlin-Objekt parst, überprüft er die Anwesenheit der Datei und ihres Inhalts, was ein wesentlicher Vorausschritt für das Parsing durch das Plugin ist.
5. Visualisierung des Parsing-Flusses
Das folgende Diagramm veranschaulicht den Datenfluss und die Interaktionen beim Parsen der YAML-Konfiguration :
Fazit
Nach Verfolgung eines TDD-Ansatzes haben wir die Jackson-Bibliothek erfolgreich integriert, um YAML-Konfigurationsdateien in Kotlin-Objekte innerhalb unseres Gradle-Plugins zu parsen. Diese Methode hat es uns ermöglicht :
-
deutlich modellierenunsere Konfiguration mit Kotlin-Datenklassen.
-
Die Parsing-Logik validierenmit gezielten Einzeltests.
-
Die Integration gewährleistenin einer echten Gradle-Umgebung dank hermetischer Funktionaltests
Diese solide Basis gibt uns großes Vertrauen, unser Plugin mit Funktionen zu erweitern, die auf dieser Konfiguration aufbauen, während wir gleichzeitig die Wartbarkeit und Robustheit des Codes gewährleisten. Das YAML-Parsing ist jetzt eine zuverlässige und getestete Funktion unseres Plugins.site-baker.