Gradle 플러그인 설정 분리하기

게으른 사람·2022년 11월 27일
1

1. 개요

이 글은 Gradle에서 자주 쓰이는 플러그인들의 설정을 파일로 분리해 관리하는 방법을 소개합니다.
Gradle 7.4.1 버전에서 작성한 글입니다.


2. 프로젝트 생성 시 작성하는 스크립트

일반적으로 Spring 프로젝트 생성 시 자주 쓰이는 플러그인, 라이브러리가 있는데 각각 Gradle의 task를 설정해주거나 정의해줘야하는 의존성, 변수들이 있는데 매번 생성 시 정의해야해서 번거로울 때가 많다.
Gradle.gradle 파일을 import할 수 있다. 이를 활용하여 플러그인, 라이브러리별 설정을 파일로 분리하고 적용하는 법을 알아보자.

루트 프로젝트 생성

예시는 멀티 모듈로 작성을 할 것이다. 우리가 만들고 싶은 구조는 다음과 같다.

example
 ㄴ example-domain // 도메인 클래스 (spring-data-jpa, querydsl-jpa)
 ㄴ example-web // 웹에서 사용되는 api (spring-web, spring-restdocs)

위 구조를 구성하기위해 각각 모듈에 build.gradle 스크립트를 작성해야한다.
여기서 분리할 수 있는 설정을 파일로 분리해보겠다.

spring 설정 분리

폴더를 하나 생성하고 다음과 같이 파일을 생성해보자.
앞으로 관리하게 될 spring의 스크립트이다.

// scripts/spring_2.7.6.gradle

// 필요 플러그인 // 1
// id 'java'
// id 'org.springframework.boot' version '2.7.6'
// id 'io.spring.dependency-management' version '1.0.15.RELEASE'

apply plugin: 'java-library' // 2
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

sourceCompatibility = '17'

configurations { // 3
    compileOnly {
        extendsFrom annotationProcessor
    }
}

dependencies { 
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}
  1. 주석을 작성하여 해당 스크립트를 사용하기 위해 필요한 플러그인의 idversion을 명시해두자. 추후 버전업 시 해당 스크립트가 적용이 불가할 수 있으니 꼭 명시해두자.
  2. apply plugin을 사용하여 이 스크립트에 필요한 플러그인을 적용한다. 이 스크립트가 다른 스크립트에서 적용될 시 apply plugin에 명시된 플러그인도 같이 적용된다.
  3. 그외 공통으로 적용되어야할 설정을 작성한다. spring 설정은 최상위 모듈에서 적용되는 경우가 많으므로 전체 모듈에서 사용되면 좋은 설정을 작성해두자. 예시로는 롬복을 적용하였다.

이렇게 작성한 스크립트는 다음과 같이 적용할 수 있다.

// build.gradle

plugins { // 1
    id 'java'
    id 'org.springframework.boot' version '2.7.6'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

allprojects {
    apply from: "$rootDir/scripts/spring_2.7.6.gradle" // 2
}
  1. spring을 사용하기 위한 플러그인들이다. 위에서 작성한 스크립트를 사용하기 위한 버전을 명시하자.
  2. 전체 프로젝트에 spring 스크립트를 적용한다.

spring 설정은 많지가 않아 효율성을 못느낄 수도 있지만 '사내의 spring-boot 2.7.6의 설정을 공유할 수 있다'라는 관점으로 본다면 나쁘지 않게 느껴질 수도 있다. 필자는 롬복외에도 mapstructgradle task를 재정의하는 용도로 사용하고 있다.

querydsl 설정 분리

spring설정 분리와 같이 나머지 설정 역시 동일하게 적용할 수 있다. querydsl 설정을 한번 구성해보자.

// scripts/querydsl_jpa_5.0.0.gradle

dependencies {
    api "org.springframework.boot:spring-boot-starter-data-jpa"
    api "com.querydsl:querydsl-jpa"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
    implementation "jakarta.annotation:jakarta.annotation-api"
}

def generated = 'src/main/generated'

sourceSets {
    main.java.srcDirs += ["$projectDir/$generated"]
}

tasks.withType(JavaCompile) {
    options.annotationProcessorGeneratedSourcesDirectory = provider({
        file("$projectDir/$generated")
    })
}

clean {
    delete file("$projectDir/$generated")
}

example-domain 모듈에 적용해보자

// example-domain/build.gradle

apply from: "$rootDir/scripts/querydsl_jpa_5.0.0.gradle"

dependencies {
 // ...필요한 의존성은 따로 작성하면 된다.
}

querydsl 설정에 관련해서는 따로 언급하지않겠다. 중요한 것은 설정을 파일로 분리할 수 있고 그 파일을 사용할 모듈에 적용할 수 있다는 점이다.

restdocs 설정 분리

추가로 플러그인을 사용하는 경우도 문제없다.

// scripts/asciidoctor_1.5.8.gradle

// 필요 플러그인
// id 'org.asciidoctor.convert' version '1.5.8'

apply plugin: 'org.asciidoctor.convert'

ext {
    set('snippetsDir', file("$buildDir/generated-snippets"))
}

dependencies {
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

tasks.named('test') {
    outputs.dir snippetsDir
    useJUnitPlatform()
}

tasks.named('asciidoctor') {
    inputs.dir snippetsDir
    dependsOn test
}

위 설정은 restdocs를 사용하기 위한 스크립트이다. 스크립트를 적용하기 위해 org.asciidoctor.convert 플러그인이 필요한데 다음과 같이 적용할 수 있다.

// build.gradle

plugins { // 1
    id 'java'
    id 'org.springframework.boot' version '2.7.6'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    id 'org.asciidoctor.convert' version '1.5.8' // 루트 프로젝트에 사용되는 플러그인을 명시해줘야한다.
}
// example-web/build.gradle

apply from: "$rootDir/scripts/asciidoctor_1.5.8.gradle"

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

우리는 기존에 web 모듈에서만 사용하는 플러그인을 루트 모듈에 작성하는 경우가 많았을 것이다. 하지만 이렇게 플러그인 설정을 파일로 분리하고 사용할 모듈에 적용시키면 해당 모듈이 무슨 플러그인을 사용하는지 명시적으로 확인할 수 있으므로 구조파악에 도움이 될 수 있다.

3. 결론

이 방법을 무조건 도입할 필요는 없습니다. 단 전사의 gradle설정을 공유하고 싶거나 가독성을 높이고 싶다면 한번쯤은 도입해보는 것을 추천합니다.

예시의 전체 소스코드는 깃헙에서 확인할 수 있습니다.

profile
웹/앱 백앤드 개발자

0개의 댓글