개발을 하면서 모든 코드를 직접 작성하는 경우는 매우 적다. 보통 라이브러리나 프레임워크를 사용하여 바닥에서 부터 코딩하지 않고 많은 기능을 사용할 수 있다. 이러한 코드들은 버전에 따라 기능이 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