Pendahuluan

Target audience: Pengembang Gradle tingkat menengah yang ingin mengelola konfigurasi kompleks.

Dalam pengembangan plugin Gradle, pengelolaan konfigurasi kompleks adalah tugas yang umum. Alih-alih membebani DSL dengan ratusan properti, sering kali lebih bersih dan lebih mudah dipelihara untuk mendefinisikan konfigurasi dalam file eksternal, seperti YAML. Artikel ini memandu Anda melalui integrasi pustaka Jackson yang kuat untuk mengurai file YAML menjadi objek Kotlin, dengan menerapkan pendekatan TDD yang ketat untuk memastikan keandalan plugin kami.site-baker.

1. Konteks: Plugin kami `site-baker

Plugin kami`site-baker`dirancang untuk mengotomatiskan pembuatan dan penyebaran situs statis. Perlu membaca berkas konfigurasi YAML (managed-jbake-context.yml) untuk mendapatkan informasi seperti jalur sumber, tujuan penyebaran, dan identitas Git.

Konfigurasi YAML yang ingin kita parse mirip seperti ini :

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. Pemodelan Konfigurasi dalam Kotlin

Sebelum mem-parse, kita harus menentukan struktur data kita dalam Kotlin. Jackson akan menggunakan kelas ini untuk secara otomatis memetakan konten 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)

Fungsi`parseSiteConfiguration`adalah titik masuk kami untuk deserialisasi. Dia menggunakan`ObjectMapper`Jackson, dikonfigurasi dengan`YAMLFactory`untuk format YAML dan`registerKotlinModule()`untuk dukungan spesifikasi Kotlin (seperti nilai default properti).

3. Integrasi Jackson dalam `build.gradle.kts

Untuk menggunakan Jackson, kita harus menambahkan dependensi yang diperlukan dalam`build.gradle.kts`modul kita`plugin`(Empty output)

// 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
}

Kami menggunakan`jackson-module-kotlin`untuk dukungan Kotlin dan`jackson-dataformat-yaml`untuk pengelolaan format YAML.

4. Pendekatan TDD: Menguji Parsing YAML

Sekarang, mari kita terapkan TDD untuk memvalidasi logika parsing kita.

4.1. Uji Unit : Memetakan YAML menjadi Objek Kotlin

Kami memulai dengan pengujian unit di`SiteBakerPluginTest.kt`untuk memastikan bahwa fungsi`parseSiteConfiguration`Dapat dengan benar mengonversi string YAML menjadi objek.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)
}

Tes ini membaca isi file`managed-jbake-context.yml`(yang harus ada agar uji tersebut valid) dan melakukan asersi pada objek`SiteConfiguration`Hasil. Ia memvalidasi bahwa nilai kunci YAML dipetakan dengan benar.

4.2. Test Fungsional: Memvalidasi pembacaan file konfigurasi

Untuk memastikan bahwa plugin dapat membaca file konfigurasi melalui DSL-nya dan bahwa parsing berfungsi dalam lingkungan Gradle nyata, kami menambahkan sebuah tes fungsional di`SiteBakerPluginFunctionalTest.kt`.

Uji ini sangat penting karena mensimulasikan eksekusi plugin dalam proyek nyata. Haruskedap udara, yaitu dia harus membuat berkas itu sendiri`managed-jbake-context.yml`dengan konten yang terkontrol, untuk memastikan reprodukibilitas dan isolasi uji.

// 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"))
}

Tes fungsional ini memverifikasi bahwa file konfigurasi yang disalin ke direktori sementara tes mengandung data yang diharapkan. Meskipun tes ini tidak secara langsung mem-parse YAML menjadi objek Kotlin, ia memvalidasi keberadaan file dan isinya, yang merupakan langkah prasyarat penting untuk parsing oleh plugin.

5. Visualisasi Alur Parsing

Diagram berikut menggambarkan aliran data dan interaksi saat parsing konfigurasi YAML :

@startuml
actor "Pengguna Gradle" as User
participant "build.gradle.kts" as BuildScript
participant "SiteBakerPlugin" as Plugin
participant "ExtensiSitus" as Extension
participant "managed-jbake-context.yml" as ConfigFile
participant "parseSiteConfiguration()" as Parser
participant "SiteConfiguration (Objek 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

Kesimpulan

Dengan mengikuti pendekatan TDD, kami berhasil mengintegrasikan pustaka Jackson untuk menguraikan file konfigurasi YAML menjadi objek Kotlin dalam plugin Gradle kami. Pendekatan ini memungkinkan kami untuk :

  • Membuat model dengan jelaskonfigurasi kita dengan kelas data Kotlin.

  • Memvalidasi logika parsingdengan tes unit terarah.

  • Memastikan integrasidi lingkungan Gradle yang nyata berkat uji fungsional yang ermetis.

Dasar solid ini memberi kita kepercayaan besar untuk memperluas plugin kami dengan fitur-fitur yang didasarkan pada konfigurasi ini, sekaligus menjamin kemudahan pemeliharaan dan ketahanan kode. Parsing YAML kini merupakan fitur yang andal dan teruji dari plugin kami.site-baker.

Artikel terkait