index

plugins

그레이들은 플러그인 기반으로 빌드 스크립트를 동작하며, 플러그인은 빌드 스크립트에 적용되어 빌드 프로세스를 제어하거나 빌드 스크립트에 추가적인 기능을 제공한다

플러그인은 제공자와 위치에 따라 3가지 유형으로 나뉜다

gradle core plugin: 그레이들에서 제공하는 플러그인으로 java, java-library, kotlin-dsl 등이 있다

gradle community plugin: gradle plugin portal에 등록된 커스텀 플러그인으로 대표적으로 스프링에서 제공하는 org.springframework.boot 플러그인이 있다

convention plugin: 사용자가 빌드에 적용하기 위해 로컬에서 만든 플러그인으로 빌드 로직을 중앙화할 때 유용하다

플러그인을 프로젝트에 적용하려면 아래와 같이 빌드 파일의 plugins 블록을 통해 적용할 수 있다

코어 플러그인은 string 값만 설정해도 적용되고 컨벤션 플러그인은 id값만, 커뮤니티 플러그인은 id와 version(optional)을 설정해야 한다

plugins {
    java // gradle core plugin
    id("org.springframework.boot") version("3.4.3") // gradle community plugin
    id("my-java-plugin") // convention plugin
}

그레이들에서 특정 언어(java, kotlin, c++ 등)로 개발 및 빌드를 진행하려면 해당 언어에 대한 플러그인을 필수로 적용해야 한다

만약 추가하지 않으면 해당 언어의 소스 코드를 그레이들이 인식하지 못하고 컴파일과 패키징이 불가능해진다

일례로 자바 프로젝트를 만들려면 java 또는 application 플러그인을, 코틀린 프로젝트는 org.jetbrains.kotlin.jvm 플러그인을 추가해야 그레이들이 빌드를 수행할 수 있으며 ide 또한 해당 언어와 관련된 기능을 지원할 수 있다

plugin extension

plugin extension은 그레이들 플러그인의 동작을 커스텀할 수 있도록 제공하는 설정 api로, 사용자가 빌드 스크립트에서 플러그인의 동작을 설정할 수 있도록 만들어준다

예를 들어 java 플러그인을 적용하면 빌드 파일에 java {} 블록을 통해 플러그인과 관련된 추가 설정을 할 수 있다

java 블록이 java 플러그인의 extension이며, 이런 extension은 dsl 형태로 제공되고 이후에 그레이들의 ExtensionContainer를 통해 등록된다

// java plugin extension을 통해 그레이들이 컴파일/런타임 시점에 사용할 자바 버전을 명시한다 
java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}

plugin hierarchy

플러그인은 다른 플러그인을 의존성으로 포함할 수 있다

즉, 특정 플러그인을 적용하면 내부적으로 포함된 모든 플러그인이 해당 프로젝트에 적용된다

플러그인의 상속 관계를 파악해놓으면 불필요한 중복 적용을 피하고 효율적으로 플러그인을 구성할 수 있다

convention plugin

컨벤션 플러그인은 각 서브 프로젝트에서 중복되는 빌드 로직을 유지보수하기 쉽도록 중앙화하고, 캡슐화하기 위해 로컬에 만드는 플러그인을 말한다

프로젝트와 별도의 디렉토리에 만들거나 루트 프로젝트의 특정 위치 또는 buildSrc에 컨벤션 플러그인을 정의할 수 있으며 buildSrc가 아닌 특정 위치에 정의하는 경우 그 위치를 명시해야 한다

컨벤션 플러그인 정의 예제, 컨벤션 플러그인 사용 예제

common plugins

gradle core plugins

gradle plugin portal

java: java 애플리케이션 또는 라이브러리를 위한 기본 플러그인

java-library: api와 implementation 의존성을 구분할 수 있는 java 라이브러리 플러그인 (java 플러그인 포함)

application: 실행 가능한 java 애플리케이션을 만들기 위한 플러그인 (java 플러그인 포함)

java-gradle-plugin: 그레이들 플러그인을 개발하기 위한 플러그인 (java 플러그인 포함)

maven-publish: maven 리포지토리에 빌드 결과(아티팩트)를 배포하는 플러그인

checkstyle: 자바 코드 스타일을 검사하는 정적 분석 플러그인

pmd: PMD 정적 코드 분석을 수행하는 플러그인

jacoco: 자바 코드의 테스트 커버리지를 측정하는 플러그인

org.jetbrains.kotlin.jvm: jvm용 코틀린 프로젝트를 위한 필수 플러그인

org.jetbrains.kotlin.kapt: 코틀린 어노테이션 프로세서(dagger, room) 지원 플러그인

io.gitlab.arturbosch.detekt: 코틀린 정적 분석 도구 플러그인

org.jilleitschuh.gradle.ktlint: 코틀린 코드 스타일 검사 플러그인 (구글 코틀린 스타일 가이드 기반)

org.jetbrains.kotlinx.kover: 코틀린 프로젝트용 코드 커버리지 측정 플러그인

org.springframework.boot: 스프링 부트 플러그인

io.spring.dependency-management: 스프링 프로젝트 bom(bill of materials) 적용 플러그인

com.palantir.docker: 도커 컨테이너 빌드 자동화 플러그인

com.bmuschko.docker-remote-api: 그레이들에서 도커 api를 직접 호출할 수 있게 해주는 플러그인

com.google.cloud.tools.jib: 자바/코틀린 프로젝트를 컨테이너 이미지로 빠르게 빌드해주는 플러그인

useful community plugins

com.github.ben-manes.versions: 사용 중인 라이브러리의 최신 버전을 체크해주는 플러그인

dependencies

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter")
}

dependency는 프로젝트 소스 코드에서 의존하는 라이브러리를 말하며 빌드 파일의 dependencies 블록에서 프로젝트 코드에서 의존하는 jar, plugin, 라이브러리 또는 빌드 스크립트 자체에서 필요로 하는 의존성을 선언한다

이후 그레이들의 의존성 해결 메커니즘을 거치면서 프로젝트에서 의존하는 라이브러리들을 사용하게 된다

의존성의 종류는 크게 direct dependency와 transitive dependency로 나뉜다

direct dependency: 프로젝트에서 직접 선언한 의존성 implementation("org.junit.jupiter:junit-jupiter")

transitive dependency: 직접 의존한 라이브러리에서 의존하는 다른 라이브러리 (그레이들과 메이븐 같은 빌드 도구는 의존성을 해결할 때 전이 의존성도 포함함)

--- org.junit.jupiter:junit-jupiter
    +--- org.junit.jupiter:junit-jupiter-params
    \--- org.junit.jupiter:junit-jupiter-engine

또한 의존성은 용도에 따라 클래스 패스에 포함될 범위를 지정될 수 있다 configurations

platform(): pom, bom

dependency version management

version catalog

dependency locking

dependency resolution mechanism

그레이들의 dependency management 메커니즘에 의해 해결되어 해당 의존성을 프로젝트의 클래스패스에 포함할 수 있게 된다

dependency cache

dependencies task

java 플러그인을 통해 추가되는 dependencies task는 프로젝트의 클래스패스에 포함되는 라이브러리들을 표시한다

아래는 예시 프로젝트의 dependencies 태스크를 실행한 결과이다

dependencies {
    testImplementation(platform("org.junit:junit-bom:5.11.4"))
    testImplementation("org.junit.jupiter:junit-jupiter")
}
------------------------------------------------------------
Root project 'gradle-basic-project-example'
------------------------------------------------------------

testCompileClasspath - Compile classpath for source set 'test'.
+--- org.junit:junit-bom:5.11.4
|    +--- org.junit.jupiter:junit-jupiter:5.11.4 (c)
|    +--- org.junit.jupiter:junit-jupiter-api:5.11.4 (c)
|    +--- org.junit.jupiter:junit-jupiter-params:5.11.4 (c)
|    \--- org.junit.platform:junit-platform-commons:1.11.4 (c)
\--- org.junit.jupiter:junit-jupiter -> 5.11.4
     +--- org.junit:junit-bom:5.11.4 (*)
     +--- org.junit.jupiter:junit-jupiter-api:5.11.4
     |    +--- org.junit:junit-bom:5.11.4 (*)
     |    +--- org.opentest4j:opentest4j:1.3.0
     |    +--- org.junit.platform:junit-platform-commons:1.11.4
     |    |    +--- org.junit:junit-bom:5.11.4 (*)
     |    |    \--- org.apiguardian:apiguardian-api:1.1.2
     |    \--- org.apiguardian:apiguardian-api:1.1.2
     \--- org.junit.jupiter:junit-jupiter-params:5.11.4
          +--- org.junit:junit-bom:5.11.4 (*)
          +--- org.junit.jupiter:junit-jupiter-api:5.11.4 (*)
          \--- org.apiguardian:apiguardian-api:1.1.2

testCompileOnly - Compile only dependencies for source set 'test'. (n)
No dependencies

testImplementation - Implementation only dependencies for source set 'test'. (n)
+--- org.junit:junit-bom:5.11.4 (n)
\--- org.junit.jupiter:junit-jupiter (n)

testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- org.junit:junit-bom:5.11.4
|    +--- org.junit.jupiter:junit-jupiter:5.11.4 (c)
|    +--- org.junit.jupiter:junit-jupiter-api:5.11.4 (c)
|    +--- org.junit.jupiter:junit-jupiter-params:5.11.4 (c)
|    +--- org.junit.jupiter:junit-jupiter-engine:5.11.4 (c)
|    +--- org.junit.platform:junit-platform-commons:1.11.4 (c)
|    \--- org.junit.platform:junit-platform-engine:1.11.4 (c)
\--- org.junit.jupiter:junit-jupiter -> 5.11.4
     +--- org.junit:junit-bom:5.11.4 (*)
     +--- org.junit.jupiter:junit-jupiter-api:5.11.4
     |    +--- org.junit:junit-bom:5.11.4 (*)
     |    +--- org.opentest4j:opentest4j:1.3.0
     |    \--- org.junit.platform:junit-platform-commons:1.11.4
     |         \--- org.junit:junit-bom:5.11.4 (*)
     +--- org.junit.jupiter:junit-jupiter-params:5.11.4
     |    +--- org.junit:junit-bom:5.11.4 (*)
     |    \--- org.junit.jupiter:junit-jupiter-api:5.11.4 (*)
     \--- org.junit.jupiter:junit-jupiter-engine:5.11.4
          +--- org.junit:junit-bom:5.11.4 (*)
          +--- org.junit.platform:junit-platform-engine:1.11.4
          |    +--- org.junit:junit-bom:5.11.4 (*)
          |    +--- org.opentest4j:opentest4j:1.3.0
          |    \--- org.junit.platform:junit-platform-commons:1.11.4 (*)
          \--- org.junit.jupiter:junit-jupiter-api:5.11.4 (*)

testRuntimeOnly - Runtime only dependencies for source set 'test'. (n)
No dependencies

(c) - A dependency constraint, not a dependency. The dependency affected by the constraint occurs elsewhere in the tree.
(*) - Indicates repeated occurrences of a transitive dependency subtree. Gradle expands transitive dependency subtrees only once per project; repeat occurrences only display the root of the subtree, followed by this annotation.

(n) - A dependency or dependency configuration that cannot be resolved.

configurations

repositories

tasks