build.gradle
로 Eclipse 프로젝트를 가정하고 있다.apply plugin: 'java' apply plugin: 'eclipse' ext { javaVersion='1.6' } buildDir = 'build' repositories { mavenCentral() } dependencies { compile '원하는 모듈' testCompile group: 'junit', name: 'junit', version: '4.+' } task initSrc << { project.sourceSets*.allSource.srcDirTrees.flatten().dir.each { dir -> dir.mkdirs() } } sourceCompatibility = javaVersion targetCompatibility = javaVersion // 소스 인코딩 지정방법 1 [compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8' // 소스 인코딩 지정밥법 2 tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } javadoc { options.encoding = 'UTF-8' } /* Eclipse 관련 설정들 */ tasks.eclipse.dependsOn cleanEclipse tasks.eclipse.dependsOn initSrc eclipse { classpath { downloadSources = true defaultOutputDir = file("${buildDir}/classes/main") } }
src/main/java
, src/main/resources
src/test/java
, src/test/resources
build/*
buildDir
를 프로젝트에 상대적인 경로로 바꿔줄 수 있다. buildDir = 'target'
export GRADLE_OTPS=“-Dorg.gradle.project.buildDir=/path/to/custom-build-dir
System Property 옵션으로 buildDir
을 명령행에서 변경할 수 있다. 명령행에 지정하면 안 됐고, 항상 환경변수로 해야만 했다.clean
: build 디렉토리 삭제compileJava
, compileTestJava
: 소스 컴파일assemble
: 컴파일 하고 jar 생성. 웹 프로젝트일 경우에는 war 생성. 단위 테스트 실행 안함.check
: 컴파일하고 단위테스트 실행.repositories { mavenCentral() } dependencies { compile group: 'commons-collections', name: 'commons-collections', version: '3.2' testCompile group: 'junit', name: 'junit', version: '4.+' }
// 저장소를 지정하고, uploadArchives { repositories { flatDir { dirs 'repos' } } }
gradle uploadArchives
명령으로 퍼블리싱한다.
자바 프로젝트의 기본 프로젝트 레이아웃은 다음과 같다.
src/main/java
: 실행 자바 소스src/main/resources
: 실행 리소스src/test/java
: 테스트 자바 소스src/test/resources
: 테스트 리소스src/소스셋/java
: 특정 소스 셋의 Java 소스src/소스셋/resources
: '특정 소스 셋의 리소스다음과 같은 의존성 설정(configurations)이 추가되다. 이 의존성 설정은 자바 플러그인의 태스크들에 의해 참조 된다.
이름 | 부모 | 사용하는 태스크 | 의미 |
---|---|---|---|
compile | - | compileJava | 컴파일 시점 의존성 |
runtime | compile | - | 실행시 의존성 |
testCompile | compile | compileTestJava | 테스트를 컴파일할 때 필요한 추가적인 의존성 |
testRuntime | runtime, testCompile | test | 테스트만 실행할 때 필요한 추가적인 의존성 |
archives | - | uploadArchives | 해당 프로젝트가 생성한 Artifact(jar 등) |
default | runtime | - | 이 프로젝트에서 기본으로 사용되는 의존성. 이 프로젝트의 실행시에 필요한 Artifact들과 의존성을 포함한다. |
소스 셋을 추가하면 다음과 같은 의존성 설정도 함께 추가된다.
이름 | 부모 | 사용하는 태스크 | 의미 |
---|---|---|---|
소스셋Compile | - | compile소스셋Java | 특정 소스셋의 컴파일시점 의존성 |
소스셋Runtime | 소스셋Compile | - | 특정 소스셋의 실행시 의존성 |
Gradle 문서 참조. JavaPluginConvention, BasePluginConvention 참조.
sourceSets
프라퍼티로 접근할 수 있다. SourceSetContainer 타입.println sourceSets.main.output.classesDir println sourceSets['main'].output.classesDir sourceSets { println "Sources Sets " + main.output.classesDir } sourceSets { main { println "Source Sets main " + output.classesDir } } sourceSets.all { println "Iterate all Source Sets : " + name }
// main java 소스셋의 디렉토리 추가 sourceSets { main { java { srcDir 'src/java' } resources { srcDir 'src/resources' } } }
저기서 main 은 SourceSet이다.
저기서 'java'와 'resources'는 SourceDirectorySet이며 srcDir()
메소드는 소스 디렉토리를 추가하는 것이다.
프라퍼티 이름 | Type | 기본값 | 설명 |
---|---|---|---|
name | String(read-only) | not null | 소스셋 이름 |
output | SourceSetOutput | not null | 소스셋의 출력 디렉토리. 컴파일된 클래스와 리소스를 저장할 곳 |
output.classesDir | File | buildDir/classes/name | 소스셋의 클래스를 생성할 디렉토리 |
output.resourcesDir | File | buildDir/resources/name | 소스셋의 리소스를 생성할 디렉토리 |
compileClasspath | FileCollection | compileSourceSet configuration | 소스를 컴파일할 때 사용할 클래스패스 |
runtimeClasspath | FileCollection | output + runtimeSourceSet configuration | 클래스 실행시의 클래스패스 |
java | SourceDirectorySet (read-only) | not null | 소스셋의 자바 소스파일들. *.java 파일만 포함호며 그 외 파일은 제외된다. |
java.srcDirs | Set<File>, Project.files()에서 사용할 수 있는 모든 값 | [projectDir/src/name/java] | 자바 소스 파일을 포함하고 있는 소스 디렉토리들, srcDir() 로 추가가능 |
resources | SourceDirectorySet (read-only) | not null | 소스셋의 리소스들. *.java 파일은 제외된다. 플러그인에 때라 제외되는 목록이 추가된다. |
resources.srcDirs | Set<File>, Project.files()에서 사용할 수 있는 모든 값 | [projectDir/src/name/resources] | 리소스를 포함하고 있는 소스 디렉토리들 |
allJava | SourceDirectorySet (read-only) | java | 모든 *.java 파일들. 플러그인에 따라 더 추가 될 수 있음 |
allSource | SourceDirectorySet (read-only) | resources + java | 모든 소스 파일들(리소스 + *.java). 플러그인에 따라 더 추가 될 수 있음. |
때로는 src/main/java
를 리소스에 포함시켜야 할 경우가 있다. 개발자들이 resources에 리소스를 넣지 않고 java에 넣고서 클래스와 리소스간의 결합성을 쉽게 파악할 수 있고자 할 경우가 있기 때문이다(iBATIS SqlMapper 사용하는 경우 등).
sourceSets { main { resources { srcDir "${project.projectDir}/src/main/java" // exclude "**/*.java" : 하지 말것. Gradle에서 문제 없지만 Eclipse에서 문제를 일으킴. } } }
sourceSets { }
블럭 안에 정의하면 된다.sourceSets { intTest } // 의존성 설정 dependencies { intTestCompile 'junit:junit:4.8.2' intTestRuntime 'org.ow2.asm.asm-all:4.0' }
gradle intTestClasses
형태로 실행.task intTestJar(type: Jar) { from sourceSets.intTest.output }
task intTestJavadoc(type: Javadoc) { source sourceSets.intTest.allJava }
task intTest(type: Test) { testClassesDir = sourceSets.intTest.output.classesDir classpath = sourceSets.intTest.runtimeClasspath }
// eclipse 플러그인 실행시 자동으로 기본 Java 디렉토리 구조를 생성하도록 한다. task baseDirs << { sourceSets.each { set -> set.java.srcDirs.each { dir -> if (!dir.exists()) dir.mkdirs() } set.resources.srcDirs.each { dir -> if (!dir.exists()) dir.mkdirs() } } if (!buildDir.exists()) buildDir.mkdirs() } tasks.eclipse.dependsOn baseDirs
태스크 프라퍼티 | 타입 | 기본값 |
---|---|---|
classpath | FileCollection | sourceSets.main.output + sourceSets.main.compileClasspath |
source | FileTree | sourceSets.main.allJava]] |
destincationDir | File | |
title | String | 프로젝트 이름과 버전 |
* StandardJavadocDocletOptions (Gradle API 1.10) 참조하여 javadoc 옵션들 지정.
javadoc { options.addBooleanOption('html5', true) }
task javadoc(type: Javadoc) { source subprojects.collect {project -> project.sourceSets.main.allJava } destinationDir = new File(buildDir, 'javadoc') // Might need a classpath classpath = files(subprojects.collect {project -> project.sourceSets.main.compileClasspath}) } }
ext { lombokVersion = '1.12.4' } configurations { lombok } dependencies { lombok "org.projectlombok:lombok:${lombokVersion}" } task delombok { ext.srcJava = 'src/main/java' ext.srcDelomboked = "${buildDir}/src-delomboked" inputs.files file(srcJava) outputs.dir file(srcDelomboked) doLast { // 보통은 configurations.runtime만으로 충분하지만, 가끔 provided 등의 사용자정의 configuration이 // 존재 할 경우 classpath에 존재하지 않는 라이브러리라서 경고를 보여줄 수 있으므로 // 모든 configurations의 의존성을 하나로 모아서 classpath로 지정한다. def allDependencies = configurations.lombok.asFileTree configurations.all { configuration -> allDependencies = allDependencies + configuration.asFileTree } // 구버전 Task class : lombok.delombok.ant.DelombokTask // 최신버전 Task class: lombok.delombok.ant.Tasks$Delombok ant.taskdef(name: 'delombok', classname: 'lombok.delombok.ant.Tasks$Delombok', classpath: configurations.lombok.asPath) ant.delombok(from: srcJava, to: srcDelomboked, verbose: true, encoding: 'UTF-8', classpath: allDependencies.asPath) } }
javadoc { dependsOn delombok source = fileTree(dir: delombok.srcDelomboked, includes: ['**/*.java', '**/*.html']) options.encoding = 'utf-8' } // 불필요한 리소스가 복사되는 경우에 대비해 java/html 파일만 include
태스크 프라퍼티 | 타입 | 기본값 |
---|---|---|
dir | File | buildDir |
태스크 프라퍼티 | 타입 | 기본값 |
---|---|---|
srcDirs | files()가 받을 수 있는 모든 값 | sourceSet.resources |
destinationDir | File | sourceSet.output.resourcesDir |
compileTestJava
에도 공통 적용된다.태스크 프라퍼티 | 타입 | 기본값 |
---|---|---|
classpath | FileCollection | sourceSet.compileClasspath |
source | FileTree files()가 받을 수 있는 모든 인자]] | sourceSet.java |
sourceCompatibility | String | Java 소스의 Java 언어 레벨 (…, 1.4,1.5,1.6,1.7 …) project.sourceCompatibilty |
targetCompatibility | Strign | Java 클래스의 Java 언어레벨 project.targetCompatibility |
destinationDir | File | sourceSet.output.classesDir |
options | CompileOptions | 컴파일 관련 각종 옵션 설정 |
options.useAnt=false
로 바꾸면 Ant를 건너뛰고 Gradle 기본 컴파일러로 수행한다.options.fork=true
로 설정하면 독립 컴파일러 프로세스가 뜨게 된다. 성능이 떨어질 수 있다.options
에서 소스 인코딩 등을 지정할 수 있다.아래 값들은 Java 플러그인을 적용한 뒤에 설정해야 한다. 그렇지 않으면 Java 플러그인이 값을 초기화 해 버릴 수도 있다. 아래 값들은 ext 블럭으로 만들면 “안” 된다.
compileJava.options.encoding = 'UTF-8' // 혹은 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
// project 단위 sourceCompatibility = '1.6' targetCompatibility = '1.6' // compileJava 단위 compileJava { sourceCompatibility = '1.6' targetCompatibility = '1.6' }
compileJava.options.compilerArgs = ["-Xlint:unchecked", "-Xlint:deprecation", ...] // 혹은 tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" }
test
태스크는 Test의 인스턴스이다.test.debug
프라퍼티를 true
로 설정하면 디버그모드로 실행되며 5005 포트로 디버깅할 수 있다.maxParallelForks
프라퍼티로 테스트 프로세스 갯수를 설정할 수 있다. 기본값은 1이다.(병렬 테스트 안함)org.gradle.test.worker
시스템 프라퍼티를 설정한다.forkEvery
프라퍼티로 몇개의 테스트를 수행한뒤에 프로세스를 재시작 할지 정할 수 있다. 단위 테스트가 JVM Heap을 너무 많이 소모할 경우 이 값을 작게준다. 기본은 재시작 안함.ignoreFailures
프라퍼티는 테스트 실패시 행위를 정의한다. 기본값은 false
이며 테스트가 실패하면 build를 실표로 표시한다. 단, 실패한 테스트에서 즉시 빌드를 멈추지는 않는다. true
일 경우 테스트가 실패해도 멈추지 않고 다음으로 넘어가며 빌드를 진행하고 성공으로 표시한다.failFast
: true
이면 테스트 실패건에서 즉시 빌드를 중단한다. 테스트 실행시 –fail-fast
옵션을 줘도 된다.testLogging
프라퍼티는 테스트의 로깅 레벨을 설정한다. 기본적으로 모든 실패한 테스트에 대한 요약 메시지를 보여준다. TestLoggingContainer 참조.testLogging.showStandardStreams = true
설정 필요.cleanTest
태스크를 먼저 실행하고 테스트를 하면 된다.gradlew cleanTest test
gradle -D프라퍼티이름=값
형태로 지정한다.taskName.single=testNamePattern
형태를 지정하면 testNamePattern
에 일치하는 테스트만 실행된다.taskName
은 멀티프로젝트 패스 형태(:sub1:sub2:test
)로 기술하거나 그냥 태스크 이름만 기술해도 된다.testNamePattern
은 **/testNamePattern*.class
형태로 기술한다.gradle -Dtest.single=ThisUniquelyNamedTest test gradle -Dtest.single=a/b/ test gradle -DintegTest.single=*IntegrationTest integTest gradle -Dtest.single=:proj1:test:Customer build gradle -DintegTest.single=c/d/ :proj1:integTest
scanForTestClasses
를 false
로 하면 자동감지를 수행하지 않는다. 이 경우 명시적으로 포함/제외 시킨 클래스만 실행한다.scanForTestClasses=false
이면서 포함/제외 클래스를 명시하지 않으면 기본적으로 **/*Tests.class
와 **/*Test.class
를 실행하고, **/Abstract*.class
는 제외한다.@RunWith
어노테이션 적용@Test
어노테이션을 가진 메소드가 있는 클래스@Test
어노테이션을 가진 메소드가 있는 클래스*Test
와 *IntegrationTest
를 분리해서 실행하고자 하는 경우가 있을 수 있다.test { exclude '**/*IntegrationTest.class' } task integrationTest(type: Test, dependsOn: testClasses) { description = 'Integration test' group = 'verification' include '**/*IntegrationTest.class' testReportDir file("${buildDir}/reports/integration-test") } tasks.withType(Test) { // Test 들의 공통 설정 useJUnit() maxHeapSize '2048m' jvmArgs '-XX:MaxPermSize=256m' testLogging { events 'started', 'passed' } }
// 별도 소스셋 구성 sourceSets { integrationTest { java { compileClasspath += main.output + test.output runtimeClasspath += main.output + test.output srcDir file('src/integration-test/java') } groovy { // for Spock compileClasspath += main.output + test.output runtimeClasspath += main.output + test.output srcDir file('src/integration-test/groovy') } resources.srcDir file('src/integration-test/resources') } } // integrationTest 전용 configuration 지정. // integrationTest에만 필요한 의존성 지정 가능. configurations { integrationTestCompile.extendsFrom testCompile integrationTestRuntime.extendsFrom testRuntime } // Task 생성 task integrationTest(type: Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs // 구버전에서는 Dir 단수형으로만 지정됨. classpath = sourceSets.integrationTest.runtimeClasspath reports { // reports 는 원하는대로만. junitXml.enabled = true html.enabled = true ignoreFailures = true } } // 의존성 지정으로 check 실행시 자동 테스트 check.dependsOn integrationTest
태스크 프라퍼티 | 타입 | 기본값 |
---|---|---|
testClassesDir | File | sourceSets.test.output.classesDir |
classpath | FileCollection | sourceSets.test.runtimeClasspath |
testResultsDir | File | testResultsDir |
testReportDir | File | testReportDir |
testSrcDirs | List<File> | sourceSets.test.java.srcDirs |
jvmArgs | List<String> | [], 문자열 배열로 JVM 옵션을 지정한다. |
maxHeapSize | String | null, '256m' 형태 |
systemProperty | 키, 값 | 키, 값 쌍을 인자로 테스트 수행 JVM의 시스템 프라퍼티 지정 |
include | String[] | [], '**/*IntgrationTest.class', 'org/foo/**', … |
exclude | String[] | [], '**/*IntgrationTest.class', 'org/foo/**', … |
test { testLogging { // set options for log level LIFECYCLE events "failed" exceptionFormat "short" showStandardStreams true // set options for log level DEBUG debug { events "started", "skipped", "failed" exceptionFormat "full" } } }
gradle build -x test
처럼 -x test
옵션을 준다.Creating a unit test report for subprojects
subprojects { apply plugin: 'java' // Disable the test report for the individual test task test { reports.html.enabled = false } } task testReport(type: TestReport) { destinationDir = file("$buildDir/reports/allTests") // Include the results from the `test` task in all subprojects reportOn subprojects*.test }
ignoreFailures=true
로 두고 테스트를 진행하고 빌드를 완료하지만, 실패건이 있는지 여부를 나중에 알고자 할 때test { ignoreFailures = true afterSuite { TestDescriptor desc, TestResult result -> if (result.failedTestCount > 0) { rootProject.buildDir.mkdir() File testFailed = rootProject.file("${rootProject.buildDir}/testFailedMarker") if (!testFailed.exists()) { testFailed.createNewFile() testFailed.text = "이 파일이 존재하면 테스트중 실패한 건이 존재한다는 의미입니다." } logger.warn("testFailedMarker - {}", result.failedTestCount) } } }
<project-root>/build/testFailedMarker
파일의 존재여부를 체크해서 존재하면 테스트 실패로 간주한다.if [ -f "build/testFailedMarker" ]; then echo "file exists" exit 1 fi
jar { archiveName = 'nameWhatIWant.jar' }
manifest
프라퍼티가 있다.MANIFEST.MF
파일이 함께 저장된다.jar { manifest { attributes("Implementation-Title": "Gradle", "Implementation-Version": version) } }
ext.sharedManifest = manifest { attributes("Implementation-Title": "Gradle", "Implementation-Version": version) } task fooJar(type: Jar) { manifest = project.manifest { from sharedManifest } }
Manifest
객체나 파일이 될 수 있다.task barJar(type: Jar) { manifest { attributes key1: 'value1' from sharedManifest, 'src/config/basemanifest.txt' from('src/config/javabasemanifest.txt', 'src/config/libbasemanifest.txt') { eachEntry { details -> if (details.baseValue != details.mergeValue) { details.value = baseValue } if (details.key == 'foo') { details.exclude() } } } } }
from
절에 기술한 순서에 따라 병합된다.eachEntry
를 통해 ManifestMergeDetails 객체를 받아서 조정 가능하다.writeTo
아니면 effectiveManifest
가 호출되는 시점에 늦은 초기화 방식으로 수행된다.jar.manifest.writeTo("$buildDir/mymanifest.mf")
Java 클래스를 실행할 때 Ant를 사용하는 방법과 JavaExec를 사용하는 방법이 있다.
project.javaexec()
메소드를 호출해도 된다. javaexec
메소드는 Closure를 인자로 받는데 거기 들어가는 내용은 JavaExec
설정과 같다. How to use in gradle javaexec with classpath dependency
Gradle Application Plugin도 참조한다.
// 외부 의존성 지정 필요시 configurations { newConfForJavaexec } dependencies { newConfForJavaexec "xxxx:xxx:1.1" // ... } task someTask(type: JavaExec) { main = 'xxx.yyy.MainClass' // 외부 의존성의 Java 클래스 실행시 classpath = configurations.newConfForJavaexec // 외부 jar가 아닌 현재 프로젝트의 Java 클래스 실행시 - 1번 방식 classpath = configurations.runtime classpath += sourceSets.main.output // 외부 jar가 아닌 현재 프로젝트의 Java 클래스 실행시 - 2번 방식 classpath = sourceSets.main.runtimeClasspath args '인자1', '인자2', ..... systemProperty 'simple.message', 'Hello ' jvmArgs '-Xmx512m' }
classpath
는 FileCollection 객체이다.Gradle을 통해 실행되는 Java Application에 Gradle의 System Properties를그대로 전달하기 - Gradle Goodness: Pass Java System Properties To Java Tasks
// The run task added by the application plugin // is also of type JavaExec. tasks.withType(JavaExec) { // Assign all Java system properties from // the command line to the JavaExec task. systemProperties System.properties }