소개

대상 : 복잡한 구성을 관리하려는 중급 Gradle 개발자

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에서 데이터 구조를 정의해야 합니다. 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`Jackson의, 구성된`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 객체에 매핑하기

우리는 단위 테스트로 시작합니다`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 "사용자 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 (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 라이브러리를 성공적으로 통합하여 Gradle 플러그인 내에서 YAML 구성 파일을 Kotlin 객체로 파싱했습니다. 이를 통해 우리는 다음과 같이 할 수 있게 되었습니다 :

  • 명확히 모델링우리의 Kotlin 데이터 클래스를 사용한 구성.

  • 파싱 로직 검증대상화된 단위 테스트와 함께.

  • 통합을 보장하다실제 Gradle 환경에서 허메틱 기능 테스트를 통해

이 견고한 기반은 이 구성을 기반으로 하는 기능을 갖춘 우리 플러그인을 확장할 수 있는 큰 확신을 제공하며, 동시에 코드의 유지 관리 가능성과 안정성을 보장합니다. YAML 파싱은 이제 우리 플러그인의 신뢰할 수 있고 테스트된 기능이 되었습니다.site-baker.

관련 기사