[#31] feat: test logging 출력 기능을 위한 Gradle Custom Plugin 구성
- Custom Gradle Plugin 적용(OperationCompletionListener) - buildSrc 상수명 변경 - TestListener afterTest 적용(각 테스트 결과 로깅)
This commit is contained in:
@@ -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<KotlinCompile> {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = listOf("-Xjsr305=strict")
|
||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||
jvmTarget = Version.JAVA.toString()
|
||||
}
|
||||
}
|
||||
|
||||
// for logging when build finished
|
||||
apply<BuildLifecyclePlugin>()
|
||||
|
||||
// gradle test logging
|
||||
tasks.withType<Test> {
|
||||
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<BuildLifecyclePlugin>()
|
||||
}
|
||||
|
||||
//gradle.buildFinished {
|
||||
// if (testResults.isNotEmpty()) {
|
||||
// printResults(testResults)
|
||||
// }
|
||||
//}
|
||||
|
||||
//fun printResults(allResults:List<TestOutcome>) {
|
||||
// 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<TestOutcome>()) // Container for tests summaries
|
||||
|
||||
//data class TestOutcome(val lines: MutableList<String> = mutableListOf()) {
|
||||
// fun add(line: String) {
|
||||
// lines.add(line)
|
||||
// }
|
||||
//
|
||||
// fun maxWidth(): Int {
|
||||
// return lines.maxByOrNull { it.length }?.length ?: 0
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -4,4 +4,4 @@ plugins {
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -12,7 +12,11 @@ class BuildLifecyclePlugin : Plugin<Project> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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<BuildServiceParameters.None>, OperationCompletionListener {
|
||||
private val targetProjects = listOf("dongne-account-api", "dongne-service-api")
|
||||
private val targetTask = "test"
|
||||
abstract class BuildOperationService : BuildService<BuildOperationService.Params>, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
55
buildSrc/src/main/kotlin/plugin/TestContainer.kt
Normal file
55
buildSrc/src/main/kotlin/plugin/TestContainer.kt
Normal file
@@ -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<ResultType, String> {
|
||||
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}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String> = 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<String> {
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user