diff --git a/build.gradle.kts b/build.gradle.kts index 4020069..3367772 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,9 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.TaskAction +import org.gradle.process.ExecOperations +import javax.inject.Inject +import java.io.ByteArrayOutputStream + plugins { kotlin("jvm") version "1.9.25" apply false kotlin("plugin.spring") version "1.9.25" apply false @@ -24,3 +30,101 @@ subprojects { useJUnitPlatform() } } + +abstract class FindBuildModuleTask @Inject constructor( + private val execOps: ExecOperations +) : DefaultTask() { + + @TaskAction + fun run() { + val allowedBuildModules = listOf( + "exporter", + "ai", + "cli" + ) + + fun execAndCapture(vararg cmd: String): String { + val output = ByteArrayOutputStream() + execOps.exec { + commandLine(*cmd) + standardOutput = output + errorOutput = ByteArrayOutputStream() + isIgnoreExitValue = true + } + return output.toString().trim() + } + + val currentBranch = execAndCapture("git", "rev-parse", "--abbrev-ref", "HEAD") + println("๐Ÿ” ํ˜„์žฌ ๋ธŒ๋žœ์น˜: $currentBranch") + + execOps.exec { + commandLine("git", "fetch", "origin", "master") + isIgnoreExitValue = true + } + + val mergeBaseOutput = ByteArrayOutputStream() + execOps.exec { + commandLine("git", "merge-base", "HEAD", "origin/master") + standardOutput = mergeBaseOutput + isIgnoreExitValue = true + } + val mergeBase = mergeBaseOutput.toString().trim() + + if (mergeBase.isBlank()) { + println("โš ๏ธ merge-base๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ธŒ๋žœ์น˜ ๋™๊ธฐํ™” ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.") + return + } + + val diffOutput = ByteArrayOutputStream() + execOps.exec { + commandLine( + "bash", "-c", """ + git diff --name-only $mergeBase..HEAD + git diff --cached --name-only + git diff --name-only + """.trimIndent() + ) + standardOutput = diffOutput + isIgnoreExitValue = true + } + + val changedFiles = diffOutput.toString().trim().lines().filter { it.isNotBlank() } + + if (changedFiles.isEmpty()) { + println("โœ… ๋ณ€๊ฒฝ๋œ ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.") + return + } + + val changedModules = mutableSetOf() + val rootPath = project.rootDir.absolutePath + + project.rootProject.subprojects.forEach { sub -> + val relPath = sub.projectDir.absolutePath + .replace(rootPath + File.separator, "") + .replace("\\", "/") + + changedFiles.forEach { file -> + if (file.startsWith("$relPath/") && allowedBuildModules.contains(sub.name)) { + changedModules += sub.name + } + } + } + + println() + println("๐ŸŸจ ๊ฐ์ง€๋œ ๋นŒ๋“œ ๋Œ€์ƒ ๋ชจ๋“ˆ (exporter, ai, cli ํ•œ์ •)") + if (changedModules.isEmpty()) { + println(" (์—†์Œ)") + } else { + changedModules.forEach { println(" - $it") } + } + + println() + println("[์ฐธ๊ณ ] master์™€ diff ๊ธฐ์ค€์œผ๋กœ ๊ฐ์ง€๋˜๋ฏ€๋กœ, ๋ธŒ๋žœ์น˜๊ฐ€ ์˜ค๋ž˜๋˜๋ฉด ๊ฒฐ๊ณผ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.") + } +} + +tasks.register("findBuildModule") { + group = "build analysis" + description = "Detect changed modules among exporter, ai, cli only" +} +