Einleitung

Zielgruppe: Mittelstufe Gradle-Entwickler, die komplexe Konfigurationen verwalten möchten.

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 :

Diagram

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.

Verwandte Artikel