From c5dfa90ab39a0765eeadde942d5142dffd8c3dd3 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 03:02:14 +0900 Subject: [PATCH 01/13] =?UTF-8?q?[#31]=20feat:=20Jenkinsfile=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..e69de29 From 504430bcd14f74541cff8b9c08f9ac9a19585f3f Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 03:03:50 +0900 Subject: [PATCH 02/13] Jenkinsfile test --- Jenkinsfile | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index e69de29..c348d56 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -0,0 +1,23 @@ +pipeline { + agent any + + stages { + stage('github clone') { + steps { + git branch: '${BUILD_BRANCH}', url: 'https://github.com/beaniejoy/dongne-cafe-api.git' + } + } + + stage('Test') { + steps { + sh 'gradle :dongne-service-api:test' + } + } + + stage('Build') { + steps { + sh 'gradle clean :dongne-service-api:build -x test' + } + } + } +} \ No newline at end of file From 45e99554d48c8db95749d8d1df91fff7ba6dcee7 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 21:37:12 +0900 Subject: [PATCH 03/13] =?UTF-8?q?[#31]=20feat:=20gradle=20=ED=94=8C?= =?UTF-8?q?=EB=9F=AC=EA=B7=B8=EC=9D=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c348d56..c929b61 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,13 +10,13 @@ pipeline { stage('Test') { steps { - sh 'gradle :dongne-service-api:test' + sh './gradlew :dongne-service-api:test' } } stage('Build') { steps { - sh 'gradle clean :dongne-service-api:build -x test' + sh './gradlew clean :dongne-service-api:build -x test' } } } From 833cc25c4a8543deb4c53ea9d1b816c8a3ff495c Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 21:37:12 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[#31]=20feat:=20gradle=20build=EA=B9=8C?= =?UTF-8?q?=EC=A7=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index e69de29..c929b61 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -0,0 +1,23 @@ +pipeline { + agent any + + stages { + stage('github clone') { + steps { + git branch: '${BUILD_BRANCH}', url: 'https://github.com/beaniejoy/dongne-cafe-api.git' + } + } + + stage('Test') { + steps { + sh './gradlew :dongne-service-api:test' + } + } + + stage('Build') { + steps { + sh './gradlew clean :dongne-service-api:build -x test' + } + } + } +} \ No newline at end of file From 8b7a39aea9b25dfd2e8aa6d2878d1e8abfe39538 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 22:31:46 +0900 Subject: [PATCH 05/13] merge --- build.gradle.kts | 15 +++++++++++++++ .../domain/cafe/service/CafeServiceTest.kt | 15 ++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0e2608e..13f4f19 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.springframework.boot.gradle.tasks.bundling.BootJar @@ -72,7 +74,20 @@ subprojects { } } + // gradle test logging tasks.withType { useJUnitPlatform() + + testLogging { + events( + TestLogEvent.FAILED, + TestLogEvent.STANDARD_ERROR, + ) + + exceptionFormat = TestExceptionFormat.FULL + showExceptions = true + showCauses = true + showStackTraces = true + } } } \ No newline at end of file diff --git a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt index 42d3315..9ae071d 100644 --- a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt +++ b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt @@ -87,15 +87,16 @@ internal class CafeServiceTest { fun update_cafe_test() { // given val (name, address, phoneNumber, description, cafeMenuList) = CafeTestUtils.createCafeRegisterRequest() - val cafe = Cafe.createCafe( - name = name!!, - address = address!!, - phoneNumber = phoneNumber!!, - description = description!!, - cafeMenuRequestList = cafeMenuList - ) +// val cafe = Cafe.createCafe( +// name = name!!, +// address = address!!, +// phoneNumber = phoneNumber!!, +// description = description!!, +// cafeMenuRequestList = cafeMenuList +// ) val cafeId = 50L + throw RuntimeException() // TODO 'findByIdOrNull'은 kotlin test 라이브러리 필요한 듯 val mockCafe = mock(Cafe::class.java) `when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.of(mockCafe)) From 826badd6380f053632c4ad6304cbb58d2a8eba3c Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 22:36:43 +0900 Subject: [PATCH 06/13] merge --- .../beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt index 9ae071d..b07b694 100644 --- a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt +++ b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt @@ -96,7 +96,6 @@ internal class CafeServiceTest { // ) val cafeId = 50L - throw RuntimeException() // TODO 'findByIdOrNull'은 kotlin test 라이브러리 필요한 듯 val mockCafe = mock(Cafe::class.java) `when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.of(mockCafe)) From 35d951a92df3d0e917a121935e4d5ed3d488f8c7 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 23:25:31 +0900 Subject: [PATCH 07/13] =?UTF-8?q?[#31]=20feat:=20test=20logging=20format?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 2 +- build.gradle.kts | 64 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c929b61..2d7fa46 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,7 +10,7 @@ pipeline { stage('Test') { steps { - sh './gradlew :dongne-service-api:test' + sh './gradlew clean :dongne-service-api:test --stacktrace' } } diff --git a/build.gradle.kts b/build.gradle.kts index 13f4f19..9f3b711 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -67,7 +67,6 @@ subprojects { } tasks.withType { - println("### Configuring $name in project ${project.name} ###") kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") jvmTarget = JavaVersion.VERSION_17.toString() @@ -79,15 +78,68 @@ subprojects { useJUnitPlatform() testLogging { - events( - TestLogEvent.FAILED, - TestLogEvent.STANDARD_ERROR, - ) - exceptionFormat = TestExceptionFormat.FULL + events = setOf(TestLogEvent.FAILED, TestLogEvent.STANDARD_ERROR) + showExceptions = true showCauses = true showStackTraces = true } + + ignoreFailures = true + + addTestListener(object : TestListener { + override fun beforeSuite(suite: TestDescriptor?) {} + override fun afterSuite(desc: TestDescriptor, result: TestResult) { + if (desc.parent != null) return + + val summary = TestOutcome().apply { + add("${project.name}:${name} Test result: ${result.resultType}") + add("Test summary: ${result.testCount} tests, ${result.successfulTestCount} succeeded, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped") + add("report file: ${reports.html.entryPoint}") + } + + if (result.resultType == TestResult.ResultType.SUCCESS) { + testResults.add(0, summary) + } else { + testResults.add(summary) + } + } + + override fun beforeTest(testDescriptor: TestDescriptor?) {} + override fun afterTest(testDescriptor: TestDescriptor?, result: TestResult?) {} + }) + } +} + +gradle.buildFinished { + if (testResults.isNotEmpty()) { + printResults(testResults) + } +} + +fun printResults(allResults:List) { + val maxLength = allResults.maxOfOrNull { it.maxWidth() } ?: 0 + + println("┌${"─".repeat(maxLength)}┐") + + println(allResults.joinToString("├${"─".repeat(maxLength)}┤\n") { testOutcome -> + testOutcome.lines.joinToString("│\n│", "│", "│") { + it + " ".repeat(maxLength - it.length) + } + }) + + println("└${"─".repeat(maxLength)}┘") +} + +val testResults by extra(mutableListOf()) // Container for tests summaries + +data class TestOutcome(val lines: MutableList = mutableListOf()) { + fun add(line: String) { + lines.add(line) + } + + fun maxWidth(): Int { + return lines.maxBy { it.length }?.length ?: 0 } } \ No newline at end of file From 83239c39ecbd26858b17d39e47b33d22091e9050 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Mon, 23 Jan 2023 23:34:58 +0900 Subject: [PATCH 08/13] [#31] feat: add test log event level --- build.gradle.kts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9f3b711..ae2ed0f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -78,15 +78,20 @@ subprojects { useJUnitPlatform() testLogging { - exceptionFormat = TestExceptionFormat.FULL - events = setOf(TestLogEvent.FAILED, TestLogEvent.STANDARD_ERROR) + events = setOf( + TestLogEvent.FAILED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_OUT, + TestLogEvent.STANDARD_ERROR + ) + exceptionFormat = TestExceptionFormat.FULL showExceptions = true showCauses = true showStackTraces = true } - ignoreFailures = true +// ignoreFailures = true addTestListener(object : TestListener { override fun beforeSuite(suite: TestDescriptor?) {} From b814a782b8615e049bc94d83b3dea70022bde5b3 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Tue, 24 Jan 2023 00:04:16 +0900 Subject: [PATCH 09/13] update --- Jenkinsfile | 8 +++++++- dongne-service-api/src/test/resources/application.yml | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 2d7fa46..d28fbb0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,13 @@ pipeline { agent any stages { - stage('github clone') { + stage('Init') { + steps { + sh 'printenv' + } + } + + stage('Github clone') { steps { git branch: '${BUILD_BRANCH}', url: 'https://github.com/beaniejoy/dongne-cafe-api.git' } diff --git a/dongne-service-api/src/test/resources/application.yml b/dongne-service-api/src/test/resources/application.yml index 9619c20..2e28b94 100644 --- a/dongne-service-api/src/test/resources/application.yml +++ b/dongne-service-api/src/test/resources/application.yml @@ -1,6 +1,4 @@ spring: - flyway: - enabled: false jpa: properties: hibernate: From 15744f1a9a158f1dde29aa3a435cd396dd654f0e Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Tue, 24 Jan 2023 00:29:39 +0900 Subject: [PATCH 10/13] =?UTF-8?q?jdk=20tool=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index d28fbb0..238e7b2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,8 @@ pipeline { agent any + tools { + jdk("openjdk-17") + } stages { stage('Init') { From f4951990cdaca94b92245d0e4480ba235adfad70 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Tue, 24 Jan 2023 02:23:05 +0900 Subject: [PATCH 11/13] =?UTF-8?q?[#31]=20feat:=20BuildService=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20gradle=20lifecycle=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - test finished 경우에 result logging 출력을 위한 gradle lifecycle 테스트 진행중 - 전반적인 리팩토링 --- .gitignore | 1 + Jenkinsfile => Jenkinsfile-service | 0 build.gradle.kts | 89 ++++++++++--------- .../kotlin/plugin/BuildLifecyclePlugin.kt | 19 ++++ .../kotlin/plugin/BuildOperationService.kt | 22 +++++ .../src/main/kotlin/plugin/TestSummary.kt | 25 ++++++ 6 files changed, 115 insertions(+), 41 deletions(-) rename Jenkinsfile => Jenkinsfile-service (100%) create mode 100644 buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt create mode 100644 buildSrc/src/main/kotlin/plugin/BuildOperationService.kt create mode 100644 buildSrc/src/main/kotlin/plugin/TestSummary.kt diff --git a/.gitignore b/.gitignore index c426c32..679caf1 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ bin/ out/ !**/src/main/**/out/ !**/src/test/**/out/ +lib/ ### NetBeans ### /nbproject/private/ diff --git a/Jenkinsfile b/Jenkinsfile-service similarity index 100% rename from Jenkinsfile rename to Jenkinsfile-service diff --git a/build.gradle.kts b/build.gradle.kts index ae2ed0f..742326a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,8 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.springframework.boot.gradle.tasks.bundling.BootJar +import plugin.BuildLifecyclePlugin +import plugin.TestSummary plugins { id(Plugins.Spring.boot).version(Version.Spring.boot) @@ -34,7 +36,10 @@ subprojects { plugin(Plugins.Kotlin.kotlinJpa) } - java.sourceCompatibility = JavaVersion.VERSION_17 + java.apply { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } dependencies { // Spring Boot Project @@ -81,7 +86,6 @@ subprojects { events = setOf( TestLogEvent.FAILED, TestLogEvent.SKIPPED, - TestLogEvent.STANDARD_OUT, TestLogEvent.STANDARD_ERROR ) @@ -98,53 +102,56 @@ subprojects { override fun afterSuite(desc: TestDescriptor, result: TestResult) { if (desc.parent != null) return - val summary = TestOutcome().apply { - add("${project.name}:${name} Test result: ${result.resultType}") - add("Test summary: ${result.testCount} tests, ${result.successfulTestCount} succeeded, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped") - add("report file: ${reports.html.entryPoint}") - } + val summary = TestSummary( + projectName = project.name, + taskName = name, + result = result + ) - if (result.resultType == TestResult.ResultType.SUCCESS) { - testResults.add(0, summary) - } else { - testResults.add(summary) - } +// if (result.resultType == TestResult.ResultType.SUCCESS) { +// testResults.add(0, summary) +// } else { +// testResults.add(summary) +// } } override fun beforeTest(testDescriptor: TestDescriptor?) {} override fun afterTest(testDescriptor: TestDescriptor?, result: TestResult?) {} }) } + + // for logging when build finished + apply() } -gradle.buildFinished { - if (testResults.isNotEmpty()) { - printResults(testResults) - } -} +//gradle.buildFinished { +// if (testResults.isNotEmpty()) { +// printResults(testResults) +// } +//} -fun printResults(allResults:List) { - val maxLength = allResults.maxOfOrNull { it.maxWidth() } ?: 0 +//fun printResults(allResults:List) { +// val maxLength = allResults.maxOfOrNull { it.maxWidth() } ?: 0 +// +// println("┌${"─".repeat(maxLength)}┐") +// +// println(allResults.joinToString("├${"─".repeat(maxLength)}┤\n") { testOutcome -> +// testOutcome.lines.joinToString("│\n│", "│", "│") { +// it + " ".repeat(maxLength - it.length) +// } +// }) +// +// println("└${"─".repeat(maxLength)}┘") +//} +// +//val testResults by extra(mutableListOf()) // Container for tests summaries - println("┌${"─".repeat(maxLength)}┐") - - println(allResults.joinToString("├${"─".repeat(maxLength)}┤\n") { testOutcome -> - testOutcome.lines.joinToString("│\n│", "│", "│") { - it + " ".repeat(maxLength - it.length) - } - }) - - println("└${"─".repeat(maxLength)}┘") -} - -val testResults by extra(mutableListOf()) // Container for tests summaries - -data class TestOutcome(val lines: MutableList = mutableListOf()) { - fun add(line: String) { - lines.add(line) - } - - fun maxWidth(): Int { - return lines.maxBy { it.length }?.length ?: 0 - } -} \ No newline at end of file +//data class TestOutcome(val lines: MutableList = mutableListOf()) { +// fun add(line: String) { +// lines.add(line) +// } +// +// fun maxWidth(): Int { +// return lines.maxByOrNull { it.length }?.length ?: 0 +// } +//} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt b/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt new file mode 100644 index 0000000..a606ab9 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt @@ -0,0 +1,19 @@ +package plugin + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.internal.build.event.BuildEventListenerRegistryInternal +import org.gradle.invocation.DefaultGradle + +class BuildLifecyclePlugin : Plugin { + override fun apply(project: Project) { + val gradle = project.gradle + + val services = (gradle as DefaultGradle).services + val registry = services[BuildEventListenerRegistryInternal::class.java] + + val operationService = gradle.sharedServices.registerIfAbsent("operationService", BuildOperationService::class.java) {} + + registry.subscribe(operationService) + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt b/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt new file mode 100644 index 0000000..cab7b36 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt @@ -0,0 +1,22 @@ +package plugin + +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.tooling.events.FinishEvent +import org.gradle.tooling.events.OperationCompletionListener +import org.gradle.tooling.events.task.TaskFinishEvent + +abstract class BuildOperationService : BuildService, OperationCompletionListener { + private val targetProjects = listOf("dongne-account-api", "dongne-service-api") + private val targetTask = "test" + + override fun onFinish(event: FinishEvent?) { + if (event == null || event !is TaskFinishEvent) { + return + } + + if (event.descriptor.taskPath in targetProjects.map { ":$it:$targetTask" }) { + println("####### onFinish 222 ${event}") + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/plugin/TestSummary.kt b/buildSrc/src/main/kotlin/plugin/TestSummary.kt new file mode 100644 index 0000000..e96b402 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugin/TestSummary.kt @@ -0,0 +1,25 @@ +package plugin + +import org.gradle.api.tasks.testing.TestResult + +data class TestSummary( + val projectName: String? = null, + val taskName: String? = null, + val result: TestResult, + val lines: MutableList = mutableListOf() +) { + fun add(line: String) { + lines.add(line) + } + + fun maxWidth(): Int { + return lines.maxByOrNull { it.length }?.length ?: 0 + } + + fun toLogList(): List { + return listOf( + "${projectName}:${taskName} Test result: ${result.resultType}", + "Test summary: ${result.testCount} tests, ${result.successfulTestCount} succeeded, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped" + ) + } +} \ No newline at end of file From 5445a5433588d7212426b7e60b33bbac1b35a3ac Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Wed, 25 Jan 2023 01:21:14 +0900 Subject: [PATCH 12/13] =?UTF-8?q?[#31]=20feat:=20test=20logging=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20Gradle=20Custom=20Plugin=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Custom Gradle Plugin 적용(OperationCompletionListener) - buildSrc 상수명 변경 - TestListener afterTest 적용(각 테스트 결과 로깅) --- build.gradle.kts | 97 +++++++------------ buildSrc/build.gradle.kts | 2 +- buildSrc/src/main/kotlin/Plugins.kt | 14 +-- buildSrc/src/main/kotlin/Version.kt | 14 ++- .../kotlin/plugin/BuildLifecyclePlugin.kt | 6 +- .../kotlin/plugin/BuildOperationService.kt | 11 ++- .../src/main/kotlin/plugin/TestContainer.kt | 55 +++++++++++ .../src/main/kotlin/plugin/TestSummary.kt | 9 +- .../src/test/resources/application.yml | 2 +- 9 files changed, 119 insertions(+), 91 deletions(-) create mode 100644 buildSrc/src/main/kotlin/plugin/TestContainer.kt diff --git a/build.gradle.kts b/build.gradle.kts index 742326a..7fe50cd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,22 +3,23 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.springframework.boot.gradle.tasks.bundling.BootJar import plugin.BuildLifecyclePlugin +import plugin.TestContainer import plugin.TestSummary -plugins { - id(Plugins.Spring.boot).version(Version.Spring.boot) - id(Plugins.Spring.dependencyManagement).version(Version.Spring.dependencyManagement).apply(false) - kotlin(Plugins.Kotlin.jvm).version(Version.kotlin) - kotlin(Plugins.Kotlin.pluginSpring).version(Version.kotlin).apply(false) - kotlin(Plugins.Kotlin.pluginJpa).version(Version.kotlin).apply(false) -} - val bootJar: BootJar by tasks bootJar.enabled = false +plugins { + id(Plugins.Spring.BOOT).version(Version.Spring.BOOT) + id(Plugins.Spring.DEPENDENCY_MANAGEMENT).version(Version.Spring.DEPENDENCY_MANAGEMENT).apply(false) + kotlin(Plugins.Kotlin.JVM).version(Version.KOTLIN) + kotlin(Plugins.Kotlin.PLUGIN_SPRING).version(Version.KOTLIN).apply(false) + kotlin(Plugins.Kotlin.PLUGIN_JPA).version(Version.KOTLIN).apply(false) +} + allprojects { group = "io.beaniejoy.dongecafe" - version = Version.projectVersion + version = Version.PROJECT_VERSION repositories { mavenCentral() @@ -28,17 +29,17 @@ allprojects { subprojects { apply { plugin(Plugins.java) - plugin(Plugins.Spring.dependencyManagement) - plugin(Plugins.Spring.boot) + plugin(Plugins.Spring.DEPENDENCY_MANAGEMENT) + plugin(Plugins.Spring.BOOT) plugin(Plugins.Kotlin.KOTLIN) - plugin(Plugins.Kotlin.kotlinSpring) - plugin(Plugins.Kotlin.kotlinJpa) + plugin(Plugins.Kotlin.KOTLIN_SPRING) + plugin(Plugins.Kotlin.KOTLIN_JPA) } java.apply { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = Version.JAVA + targetCompatibility = Version.JAVA } dependencies { @@ -59,9 +60,9 @@ subprojects { runtimeOnly("com.h2database:h2") // H2 // JWT - implementation("io.jsonwebtoken:jjwt-api:${Version.Deps.Jwt}") - runtimeOnly("io.jsonwebtoken:jjwt-impl:${Version.Deps.Jwt}") - runtimeOnly("io.jsonwebtoken:jjwt-jackson:${Version.Deps.Jwt}") + implementation("io.jsonwebtoken:jjwt-api:${Version.Deps.JWT}") + runtimeOnly("io.jsonwebtoken:jjwt-impl:${Version.Deps.JWT}") + runtimeOnly("io.jsonwebtoken:jjwt-jackson:${Version.Deps.JWT}") // Logging implementation("io.github.microutils:kotlin-logging:${Version.Deps.KOTLIN_LOGGING}") @@ -74,10 +75,13 @@ subprojects { tasks.withType { kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") - jvmTarget = JavaVersion.VERSION_17.toString() + jvmTarget = Version.JAVA.toString() } } + // for logging when build finished + apply() + // gradle test logging tasks.withType { useJUnitPlatform() @@ -95,10 +99,11 @@ subprojects { showStackTraces = true } -// ignoreFailures = true + ignoreFailures = true addTestListener(object : TestListener { - override fun beforeSuite(suite: TestDescriptor?) {} + override fun beforeSuite(desc: TestDescriptor) {} + // handling after all test finished override fun afterSuite(desc: TestDescriptor, result: TestResult) { if (desc.parent != null) return @@ -108,50 +113,14 @@ subprojects { result = result ) -// if (result.resultType == TestResult.ResultType.SUCCESS) { -// testResults.add(0, summary) -// } else { -// testResults.add(summary) -// } + TestContainer.testResults = summary } - override fun beforeTest(testDescriptor: TestDescriptor?) {} - override fun afterTest(testDescriptor: TestDescriptor?, result: TestResult?) {} + override fun beforeTest(desc: TestDescriptor) {} + // handling after each test finished + override fun afterTest(desc: TestDescriptor, result: TestResult) { + TestContainer.printEachResult(desc, result) + } }) } - - // for logging when build finished - apply() -} - -//gradle.buildFinished { -// if (testResults.isNotEmpty()) { -// printResults(testResults) -// } -//} - -//fun printResults(allResults:List) { -// val maxLength = allResults.maxOfOrNull { it.maxWidth() } ?: 0 -// -// println("┌${"─".repeat(maxLength)}┐") -// -// println(allResults.joinToString("├${"─".repeat(maxLength)}┤\n") { testOutcome -> -// testOutcome.lines.joinToString("│\n│", "│", "│") { -// it + " ".repeat(maxLength - it.length) -// } -// }) -// -// println("└${"─".repeat(maxLength)}┘") -//} -// -//val testResults by extra(mutableListOf()) // Container for tests summaries - -//data class TestOutcome(val lines: MutableList = mutableListOf()) { -// fun add(line: String) { -// lines.add(line) -// } -// -// fun maxWidth(): Int { -// return lines.maxByOrNull { it.length }?.length ?: 0 -// } -//} \ No newline at end of file +} \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 876c922..b22ed73 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -4,4 +4,4 @@ plugins { repositories { mavenCentral() -} +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Plugins.kt b/buildSrc/src/main/kotlin/Plugins.kt index 3af7358..fc50b9f 100644 --- a/buildSrc/src/main/kotlin/Plugins.kt +++ b/buildSrc/src/main/kotlin/Plugins.kt @@ -2,18 +2,18 @@ object Plugins { const val java = "java" object Spring { - const val boot = "org.springframework.boot" - const val dependencyManagement = "io.spring.dependency-management" + const val BOOT = "org.springframework.boot" + const val DEPENDENCY_MANAGEMENT = "io.spring.dependency-management" } object Kotlin { const val KOTLIN = "kotlin" - const val kotlinSpring = "kotlin-spring" - const val kotlinJpa = "kotlin-jpa" + const val KOTLIN_SPRING = "kotlin-spring" + const val KOTLIN_JPA = "kotlin-jpa" - const val jvm = "jvm" - const val pluginSpring = "plugin.spring" - const val pluginJpa = "plugin.jpa" + const val JVM = "jvm" + const val PLUGIN_SPRING = "plugin.spring" + const val PLUGIN_JPA = "plugin.jpa" } object FlywayDB { diff --git a/buildSrc/src/main/kotlin/Version.kt b/buildSrc/src/main/kotlin/Version.kt index c94d8cf..7dec8b7 100644 --- a/buildSrc/src/main/kotlin/Version.kt +++ b/buildSrc/src/main/kotlin/Version.kt @@ -1,15 +1,19 @@ +import org.gradle.api.JavaVersion + object Version { - const val projectVersion = "0.0.1-SNAPSHOT" - const val kotlin = "1.6.21" + const val PROJECT_VERSION = "0.0.1-SNAPSHOT" + const val KOTLIN = "1.6.21" + + val JAVA = JavaVersion.VERSION_17 object Spring { - const val boot = "2.7.0" - const val dependencyManagement = "1.0.11.RELEASE" + const val BOOT = "2.7.0" + const val DEPENDENCY_MANAGEMENT = "1.0.11.RELEASE" } object Deps { const val KOTLIN_LOGGING = "3.0.4" - const val Jwt = "0.11.5" + const val JWT = "0.11.5" } object FlywayDB { diff --git a/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt b/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt index a606ab9..6b1da7f 100644 --- a/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt +++ b/buildSrc/src/main/kotlin/plugin/BuildLifecyclePlugin.kt @@ -12,7 +12,11 @@ class BuildLifecyclePlugin : Plugin { val services = (gradle as DefaultGradle).services val registry = services[BuildEventListenerRegistryInternal::class.java] - val operationService = gradle.sharedServices.registerIfAbsent("operationService", BuildOperationService::class.java) {} + val operationService = gradle.sharedServices.registerIfAbsent("operationService", BuildOperationService::class.java) { + gradle.taskGraph.whenReady { + parameters.lastTaskPath = this.allTasks.last().path + } + } registry.subscribe(operationService) } diff --git a/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt b/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt index cab7b36..027409f 100644 --- a/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt +++ b/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt @@ -6,17 +6,18 @@ import org.gradle.tooling.events.FinishEvent import org.gradle.tooling.events.OperationCompletionListener import org.gradle.tooling.events.task.TaskFinishEvent -abstract class BuildOperationService : BuildService, OperationCompletionListener { - private val targetProjects = listOf("dongne-account-api", "dongne-service-api") - private val targetTask = "test" +abstract class BuildOperationService : BuildService, OperationCompletionListener { + interface Params : BuildServiceParameters { + var lastTaskPath: String + } override fun onFinish(event: FinishEvent?) { if (event == null || event !is TaskFinishEvent) { return } - if (event.descriptor.taskPath in targetProjects.map { ":$it:$targetTask" }) { - println("####### onFinish 222 ${event}") + if (event.descriptor.taskPath == parameters.lastTaskPath) { + TestContainer.printTotalResult(TestContainer.testResults) } } } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/plugin/TestContainer.kt b/buildSrc/src/main/kotlin/plugin/TestContainer.kt new file mode 100644 index 0000000..93cd0f1 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugin/TestContainer.kt @@ -0,0 +1,55 @@ +package plugin + +import org.gradle.api.tasks.testing.TestDescriptor +import org.gradle.api.tasks.testing.TestResult +import org.gradle.api.tasks.testing.TestResult.* + +class TestContainer { + companion object { + var testResults: TestSummary? = null + + const val ANSI_RESET = "\u001B[0m" + const val ANSI_GREEN = "\u001B[32m" + const val ANSI_RED = "\u001B[31m" + + fun printTotalResult(summary: TestSummary?) { + if (summary == null) return + + val maxLength = summary.maxWidth() + + println( + """ + |┌${"─".repeat(maxLength)}┐ + |${ + summary.toLogList().joinToString("│\n│", "│", "│") { + val coloredResult = colorResultType(summary.result.resultType) + val str = "$it${" ".repeat(maxLength - it.length)}" + .replace( + oldValue = coloredResult.first.toString(), + newValue = coloredResult.second + ) + str + } + } + |└${"─".repeat(maxLength)}┘ + """.trimMargin() + ) + } + + fun printEachResult(desc: TestDescriptor, result: TestResult) { + println("[${desc.className}] ${desc.displayName} result: ${colorResultType(result.resultType).second}") + } + + fun colorResultType(resultType: ResultType): Pair { + val color = when (resultType) { + ResultType.SUCCESS -> ANSI_GREEN + ResultType.FAILURE -> ANSI_RED + else -> "" + } + + return resultType to if (color.isNotEmpty()) { + "${color}${resultType}${ANSI_RESET}" + } else "${resultType}" + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/plugin/TestSummary.kt b/buildSrc/src/main/kotlin/plugin/TestSummary.kt index e96b402..8efab7c 100644 --- a/buildSrc/src/main/kotlin/plugin/TestSummary.kt +++ b/buildSrc/src/main/kotlin/plugin/TestSummary.kt @@ -5,15 +5,10 @@ import org.gradle.api.tasks.testing.TestResult data class TestSummary( val projectName: String? = null, val taskName: String? = null, - val result: TestResult, - val lines: MutableList = mutableListOf() + val result: TestResult ) { - fun add(line: String) { - lines.add(line) - } - fun maxWidth(): Int { - return lines.maxByOrNull { it.length }?.length ?: 0 + return toLogList().maxByOrNull { it.length }?.length ?: 0 } fun toLogList(): List { diff --git a/dongne-service-api/src/test/resources/application.yml b/dongne-service-api/src/test/resources/application.yml index 2e28b94..7f31e3b 100644 --- a/dongne-service-api/src/test/resources/application.yml +++ b/dongne-service-api/src/test/resources/application.yml @@ -7,7 +7,7 @@ spring: logging: level: - org.hibernate.SQL: debug + org.hibernate.SQL: info # ionShutdownHook logging issue (in 'DEBUG' level) org.hibernate.type: trace # 실제 sql 쿼리의 parameter 값을 확인하고자 함 jwt: From 8bae2da14ab03e91659fa9383b4fbd89e8817cc1 Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Wed, 25 Jan 2023 02:02:58 +0900 Subject: [PATCH 13/13] =?UTF-8?q?[#31]=20feat:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B2=B0=EA=B3=BC=20colorMode=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - buildSrc plugin 내용 클래스 패키지 분리 - colorMode 적용(추후 profile에 따라 처리 필요) --- Jenkinsfile-service | 2 +- build.gradle.kts | 9 +++---- .../kotlin/plugin/BuildOperationService.kt | 5 +++- .../main/kotlin/task/test/TestContainer.kt | 8 +++++++ .../test/TestLoggingUtils.kt} | 24 +++++++++---------- .../{plugin => task/test}/TestSummary.kt | 2 +- 6 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 buildSrc/src/main/kotlin/task/test/TestContainer.kt rename buildSrc/src/main/kotlin/{plugin/TestContainer.kt => task/test/TestLoggingUtils.kt} (68%) rename buildSrc/src/main/kotlin/{plugin => task/test}/TestSummary.kt (97%) diff --git a/Jenkinsfile-service b/Jenkinsfile-service index 238e7b2..2797aad 100644 --- a/Jenkinsfile-service +++ b/Jenkinsfile-service @@ -19,7 +19,7 @@ pipeline { stage('Test') { steps { - sh './gradlew clean :dongne-service-api:test --stacktrace' + sh './gradlew clean :dongne-service-api:test' } } diff --git a/build.gradle.kts b/build.gradle.kts index 7fe50cd..64fb392 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,8 +3,9 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.springframework.boot.gradle.tasks.bundling.BootJar import plugin.BuildLifecyclePlugin -import plugin.TestContainer -import plugin.TestSummary +import task.test.TestContainer +import task.test.TestLoggingUtils +import task.test.TestSummary val bootJar: BootJar by tasks bootJar.enabled = false @@ -99,7 +100,7 @@ subprojects { showStackTraces = true } - ignoreFailures = true +// ignoreFailures = true addTestListener(object : TestListener { override fun beforeSuite(desc: TestDescriptor) {} @@ -119,7 +120,7 @@ subprojects { override fun beforeTest(desc: TestDescriptor) {} // handling after each test finished override fun afterTest(desc: TestDescriptor, result: TestResult) { - TestContainer.printEachResult(desc, result) + TestLoggingUtils.printEachResult(desc, result) } }) } diff --git a/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt b/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt index 027409f..7c4edb4 100644 --- a/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt +++ b/buildSrc/src/main/kotlin/plugin/BuildOperationService.kt @@ -5,6 +5,8 @@ import org.gradle.api.services.BuildServiceParameters import org.gradle.tooling.events.FinishEvent import org.gradle.tooling.events.OperationCompletionListener import org.gradle.tooling.events.task.TaskFinishEvent +import task.test.TestContainer +import task.test.TestLoggingUtils abstract class BuildOperationService : BuildService, OperationCompletionListener { interface Params : BuildServiceParameters { @@ -17,7 +19,8 @@ abstract class BuildOperationService : BuildService> result: ${colorResultType(result.resultType).second}") } - fun colorResultType(resultType: ResultType): Pair { + fun colorResultType(resultType: TestResult.ResultType): Pair { + if (TestContainer.colorMode.not()) { + return resultType to "${resultType}" + } + val color = when (resultType) { - ResultType.SUCCESS -> ANSI_GREEN - ResultType.FAILURE -> ANSI_RED + TestResult.ResultType.SUCCESS -> ANSI_GREEN + TestResult.ResultType.FAILURE -> ANSI_RED else -> "" } return resultType to if (color.isNotEmpty()) { - "${color}${resultType}${ANSI_RESET}" + "${color}${resultType}$ANSI_RESET" } else "${resultType}" } } diff --git a/buildSrc/src/main/kotlin/plugin/TestSummary.kt b/buildSrc/src/main/kotlin/task/test/TestSummary.kt similarity index 97% rename from buildSrc/src/main/kotlin/plugin/TestSummary.kt rename to buildSrc/src/main/kotlin/task/test/TestSummary.kt index 8efab7c..9db03a0 100644 --- a/buildSrc/src/main/kotlin/plugin/TestSummary.kt +++ b/buildSrc/src/main/kotlin/task/test/TestSummary.kt @@ -1,4 +1,4 @@ -package plugin +package task.test import org.gradle.api.tasks.testing.TestResult