개발을 하면서 모든 코드를 직접 작성하는 경우는 매우 적다. 보통 라이브러리나 프레임워크를 사용하여 바닥에서 부터 코딩하지 않고 많은 기능을 사용할 수 있다. 이러한 코드들은 버전에 따라 기능이 deprecate 되거나 regression이 발생하거나 다른 의존성의 버전끼리 충돌하는 등 다양한 문제가 있을 수 있기 때문에 안정화된 버전을 관리 하는 것이 중요하다.
가장 기초적인 버전 관리 방법은 버전을 명시하는 것이다
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-html:0.9.1")
}
각 의존성마다 버전을 명시하기 때문에 단일 모듈로 구성된 프로젝트의 경우에는 앞에서 언급한 방법이 가장 쉽고 직관적이다. 하지만 멀티 모듈 프로젝트를 구성한다면 build.gradle 파일이 여러개 생기기 때문에 버전을 여러번 작성해줘야 한다.
// moduleA/build.gradle.kts
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-html:0.9.1")
}
// moduleB/build.gradle.kts
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-html:0.9.1")
}
만약 버전 업그레이드를 하고 싶다면? 두 파일을 모두 수정해야하는 문제가 있다. 따라서 아래와 같이 버전을 별도 파일로 분리하여 관리할 수 있다.
// gradle.properties
kotlinXVersion=0.9.1
// moduleA/build.gradle.kts
val kotlinXVersion: String by project
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-html:${kotlinXVersion}")
}
// moduleB/build.gradle.kts
val kotlinXVersion: String by project
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-html:${kotlinXVersion}")
}
위와 같이 수정하면 이제 gradle.properties 파일을 한 번만 수정하면 모든 프로젝트의 버전을 변경할 수 있다. 다만 kotlinXVersion 변수를 계속 선언해줘야 하는 보일러 플레이트 코드가 있다.
플러그인의 버전 관리는 약간 다른 방식으로 해야한다. 단일 모듈 프로젝트에서 플러그인은 아래와 같이 사용할 수 있다.
// build.gradle.kts
plugins {
kotlin("jvm") version 1.8.22
}
만약 플러그인 버전도 gradle.properties에서 다른 의존성 버전과 같이 관리하고 싶다면? 아쉽게도 plugins 블록에서는 명시적으로 버전을 작성할 수만 있어서 아래와 같이 settings.gradle에서 별도로 관리해야했다. 여러 파일을 왔다 갔다 해야 하고 불편하다.
// gradle.properties
kotlinVersion=1.8.22
// settings.gradle.kts
pluginManagement {
val kotlinVersion: String by settings
plugins {
kotlin("jvm") version kotlinVersion
}
}
// build.gradle.kts
plugins {
kotlin("jvm")
}
이외에도 기존 gradle에는 ext, buildSrc, composite build를 통해 의존성의 버전을 관리할 수 있었지만 모두 여러 파일을 왔다 갔다 해야하는 불편함이 있다.
gradle은 여러 의존성을 한 곳에서 관리할 수 있도록 Version Catalog라는 기능을 gradle 7.4에서 추가했다. type-safe한 accessor를 생성해 주기 때문에 더 이상 문자열을 매번 작성할 필요도 없다.
// gradle.properties
kotlinVersion=1.8.22
springBootVersion=3.2.0
// settings.gradle.kts
dependencyResolutionManagement {
val kotlinVersion: String by settings
val springBootVersion: String by settings
versionCatalogs {
create("kt") {
plugin("jvm", "org.jetbrains.kotlin.jvm").version(kotlinVersion)
}
create("spring") {
plugin("kotlin", "org.jetbrains.kotlin.plugin.spring").version(kotlinVersion)
plugin("boot", "org.springframework.boot").version(springBootVersion)
plugin("dependency-management", "io.spring.dependency-management").version(springDependencyManagementVersion)
library("boot-starter-jpa", "org.springframework.boot", "spring-boot-starter-data-jpa").version(springBootVersion)
library("boot-starter-thymeleaf", "org.springframework.boot", "spring-boot-starter-thymeleaf").version(springBootVersion)
library("boot-starter-web", "org.springframework.boot", "spring-boot-starter-web").version(springBootVersion)
}
}
create({catalogName}) : 버전 카탈로그를 생성한다plugin({alias}, {id}).version({version}) : 플러그인의 alias를 설정하고 버전을 명시한다library({alias}, {group}, {artifact}).version({version}) : 의존성의 alias를 설정하고 버전을 명시한다. 버전 명시가 필요하지 않은 경우 .withoutVersion()을 사용할 수 있다버전 카탈로그를 생성 했다면 이제 사용할 차례이다. 먼저 플러그인은 alias()를 통해 자동 생성된 type-safe accessor를 사용할 수 있다.
plugins {
alias(kt.plugins.jvm)
alias(spring.plugins.kotlin)
alias(spring.plugins.boot)
alias(spring.plugins.dependencyManagement)
}
주의!
Gradle 버전에 따라 컴파일은 정상적으로 뜨는데 IDE에서can't be called by implicit receiver라고 에러가 뜰 수 있다. 리그레션 문제 이므로 Gradle 버전을 업그레이드 하자.
https://github.com/gradle/gradle/issues/22797
의존성에서는 type-safe accessor를 바로 사용하면 된다. 버전 카탈로그에서 작성한 alias의 하이픈(-)은 점(.)으로 변환된다.
dependencies {
implementation(spring.boot.starter.jpa)
implementation(spring.boot.starter.thymeleaf)
implementation(spring.boot.starter.web)
}
주의!
코틀린 DSL에서는allprojects,subprojects와 같은 블록 내에서 accessor 직접 사용할 수 없고 rootProject를 통해 호출해야한다allprojects { dependencies { implementation(rootProject.spring.boot.starter.jpa) implementation(rootProject.spring.boot.starter.thymeleaf) implementation(rootProject.spring.boot.starter.web) } }
이 글에서 소개하지는 않지만, 여러 의존성을 묶어서 하나로 사용할 수 있는 bundle 기능도 제공한다. 더 자세한 설명은 gradle의 공식 문서를 참고하자. https://docs.gradle.org/current/userguide/platforms.html