수많은 task와 의존성 관리를 위한 build.gradle 분리하기

임현규·2023년 5월 10일
1

Meca project 개발 일지

목록 보기
18/27

설정이 많아지면서 생긴 문제점

rest docs build시 자동으로 .adoc 파일을 .html로 build하고 static파일에 옮기려면 build.gradle에 여러 설정을 해야한다. 그래서 build.gradle에 쓰이는 코드가 비대해지고 어떤 설정을 했는지 한눈에 파악하기가 쉽지 않다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    id "org.asciidoctor.jvm.convert" version "3.3.2" // asciidoc
}

group = 'com.almondia'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    asciidoctorExtensions // asciidoc
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    // aws S3
    implementation 'com.amazonaws:aws-java-sdk-s3:1.12.429'
    testImplementation 'io.findify:s3mock_2.13:0.2.6'

    // querydsl
    implementation 'com.querydsl:querydsl-jpa'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"

    // json object
    implementation 'org.json:json:20211205'

    // db
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'com.mysql:mysql-connector-j'

    // lombok
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testCompileOnly 'org.projectlombok:lombok:'
    testAnnotationProcessor 'org.projectlombok:lombok'

    // jwt
    implementation 'io.jsonwebtoken:jjwt-api:0.11.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.3'

    // webflux
    implementation 'org.springframework.boot:spring-boot-starter-webflux'

    // ulid-creator
    implementation group: 'com.github.f4b6a3', name: 'ulid-creator', version: '5.1.0'

    // mock web server
    testImplementation("com.squareup.okhttp3:mockwebserver:4.10.0")

    // asciidoc
    asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor:2.0.6.RELEASE'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:2.0.6.RELEASE'

    // reactor test
    testImplementation 'io.projectreactor:reactor-test'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
}

clean {
    delete file('src/main/generated')
}

// 전역 변수
ext {
    snippetsDir = file('build/generated-snippets') // rest-docs 스니펫 위치 설정
}

asciidoctor {
    inputs.dir snippetsDir
    configurations 'asciidoctorExtensions'
    dependsOn test
    sources {
        include("**/index.adoc", "**/common/*.adoc")
    }
    baseDirFollowsSourceDir()
}

asciidoctor.doFirst {
    delete file('src/main/resources/static/docs')
}

task copyDocument(type: Copy) {
    dependsOn asciidoctor
    from file("build/docs/asciidoc")
    into file("src/main/resources/static/docs")
}

build {
    dependsOn copyDocument
}

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

이것은 기존 프로젝트에 rest docs를 적용한 build.gradle의 모습이다. 일일히 뜯어보면 이해할 수 있기는 하지만 전체 설정과 rest docs의 설정이 뒤엉켜서 관리하기가 쉽지 않다. 그래서 주석으로 asciidoc의 설정이라고 구분지어 줬지만 역시 가독성은 떨어졌다.

만약 더욱더 많은 라이브러리와 task가 등록된다면...

점점 많아지면 build.gradle은 설정을 감당하기 힘들것이고 해당 스크립트가 여러 task가 뒤죽박중 엉키면서 스파게티 코드를 생성할 우려가 있다. 그래서 다음과 같이 개선하면 좋을 것 같다는 생각이 들었다.

다행히도 gradle에서는 apply를 활용해 분리된 gradle 등록이 가능하다!!

apply from을 활용해 gradle을 분리하기

apply from을 통해 build.gradle을 3개의 gradle로 분리했다. 그 중 중요한 asciidoc.gradle과 build.gradle을 확인해보자

// asciidoc.gradle

configurations {
    asciidoctorExtensions
}

// 변수 선언
ext {
    snippetsDir = file('build/generated-snippets') // rest-docs 스니펫 위치 설정
}

dependencies {
    asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor:2.0.6.RELEASE'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:2.0.6.RELEASE'
}


asciidoctor {
    inputs.dir snippetsDir
    configurations 'asciidoctorExtensions'
    dependsOn test
    sources {
        include("**/index.adoc", "**/common/*.adoc")
    }
    baseDirFollowsSourceDir()
}

asciidoctor.doFirst {
    delete file('src/main/resources/static/docs')
}

task copyDocument(type: Copy) {
    dependsOn asciidoctor
    from file("build/docs/asciidoc")
    into file("src/main/resources/static/docs")
}

build {
    dependsOn copyDocument
}

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

위의 코드는 asciidoc.gradle로 분리한 코드이다. 자동으로 adoc로부터 html을 생성하고 resources/static/docs로 파일을 복사까지의 과정을 자동화한 코드로 asciidoc에 관련된 내용만 담겨 있다. 이를 메인 gradle인 build.gradle에선 apply만 해주면 된다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    id "org.asciidoctor.jvm.convert" version "3.3.2"
}

group = 'com.almondia'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

apply from: 'asciidoc.gradle' // asciidoc
apply from: 'default-dependencies.gradle'

가독성이 훨씬 좋아지고 dependency와 task를 해당 라이브러리에 포커싱을 맞추어서 다룰 수 있게 되었다. gradle의 분리를 통해 커스텀 task나 여러 설정시에 부담되는 긴 스크립트를 짧게 줄일 수 있어서 큰 도움이 됬다.

참고

gradle 의존성 분리 by toss
restdocs 적용하기 by backtony

profile
엘 프사이 콩그루

0개의 댓글