lunBackServer/build.gradle.kts
2025-09-24 17:29:33 +09:00

316 lines
12 KiB
Plaintext

import com.github.jk1.license.render.*
import com.github.jk1.license.filter.ExcludeTransitiveDependenciesFilter
import com.github.jk1.license.filter.LicenseBundleNormalizer
import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer
import com.github.jk1.license.render.InventoryMarkdownReportRenderer
import org.jsoup.Jsoup
import org.springframework.boot.gradle.tasks.bundling.BootJar
//import org.gradle.internal.impldep.org.jsoup.Jsoup
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath ("org.jsoup:jsoup:1.18.1")
// 빌드 스크립트에서 commonmark 라이브러리를 사용할 수 있도록 추가합니다.
classpath("org.commonmark:commonmark:0.18.0")
}
}
plugins {
kotlin("jvm") version "1.9.25"
kotlin("plugin.spring") version "1.9.25"
id("org.springframework.boot") version "3.3.4"
id("io.spring.dependency-management") version "1.1.6"
id("com.github.jk1.dependency-license-report") version "2.0"
}
group = "kr.lunaticbum.back"
version = "0.0.7-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
maven { url = uri("https://repo.spring.io/milestone") }
}
dependencies {
// [추가] Kotlin BOM(Bill of Materials)을 사용하여 모든 코틀린 라이브러리 버전을 정렬합니다.
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.9.25"))
// --- 기존 의존성 (정리됨) ---
implementation ("org.slf4j:jcl-over-slf4j")
implementation ("org.springframework.boot:spring-boot-starter-quartz")
implementation ("org.apache.tomcat.embed:tomcat-embed-jasper")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity6")
implementation("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect")
implementation ("org.jsoup:jsoup:1.18.1")
implementation ("org.seleniumhq.selenium:selenium-java:4.10.0")
implementation ("org.commonmark:commonmark:0.18.0")
implementation ("net.coobird:thumbnailator:0.4.14")
implementation("org.sejda.imageio:webp-imageio:0.1.6")
implementation ("com.drewnoakes:metadata-extractor:2.19.0")
implementation("org.springframework.boot:spring-boot-starter-security")
compileOnly("org.projectlombok:lombok")
implementation ("com.google.maps:google-maps-services:2.2.0")
implementation(platform("org.springframework.ai:spring-ai-bom:1.0.0-M6"))
implementation("org.springframework.ai:spring-ai-ollama-spring-boot-starter:1.0.0-M6")
implementation ("org.springframework.ai:spring-ai-qdrant-store-spring-boot-starter")
implementation ("org.slf4j:slf4j-simple:1.7.25")
implementation("io.jsonwebtoken:jjwt-api:0.11.5")
implementation("io.jsonwebtoken:jjwt-impl:0.11.5")
implementation("io.jsonwebtoken:jjwt-jackson:0.11.5")
// [수정] 버전 번호를 제거합니다. (BOM이 버전을 관리해 줍니다)
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-reflect")
// [수정] Gson 라이브러리 중복 제거 (2.11.0 버전만 남김)
implementation ("com.google.code.gson:gson:2.11.0")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
}
}
tasks.withType<org.gradle.jvm.tasks.Jar>() {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude("META-INF/BC1024KE.RSA", "META-INF/BC1024KE.SF", "META-INF/BC1024KE.DSA")
exclude("META-INF/BC2048KE.RSA", "META-INF/BC2048KE.SF", "META-INF/BC2048KE.DSA")
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.jar {
archiveFileName.set("app.jar")
manifest {
attributes["Main-Class"] = "kr.lunaticbum.back.lun.LunApplicationKt"
}
configurations["compileClasspath"].forEach { file: File ->
from(zipTree(file.absoluteFile))
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks.jar {
// Otherwise you'll get a "No main manifest attribute" error
manifest {
attributes["Main-Class"] = "kr.lunaticbum.back.lun.LunApplicationKt"
}
// To avoid the duplicate handling strategy error
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
// To add all of the dependencies otherwise a "NoClassDefFoundError" error
from(sourceSets.main.get().output)
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
}
// ✅ licenseReport는 이전과 동일하게 Markdown을 생성하도록 둡니다.
licenseReport {
outputDir = "$projectDir/build/licenses"
renderers = arrayOf(InventoryMarkdownReportRenderer())
// filters = arrayOf(com.github.jk1.license.filter.LicenseBundleNormalizer(), com.github.jk1.license.filter.ExcludeTransitiveDependenciesFilter())
}
tasks.register("updateLicensePage") {
dependsOn("generateLicenseReport")
doLast {
// file("$projectDir/build/licenses").listFiles().forEach {
// println("${it.absolutePath}: ${it.name}")
// }
// ... 로그 출력 로직은 그대로 유지 ...
println("🚀 'updateLicensePage' 태스크를 시작합니다.")
val licenseMarkdownFile = file("$projectDir/build/licenses/licenses.md")
val targetHtmlFile = file("src/main/resources/templates/content/licenses.html")
println(" - 원본 마크다운 파일: ${licenseMarkdownFile.path}")
println(" - 대상 HTML 파일: ${targetHtmlFile.path}")
if (!licenseMarkdownFile.exists()) {
throw GradleException("❌ 라이선스 마크다운 파일이 생성되지 않았습니다. '${licenseMarkdownFile.path}'")
}
val licenseMarkdown = licenseMarkdownFile.readText()
println(" - 마크다운 파일을 성공적으로 읽었습니다. (내용 길이: ${licenseMarkdown.length})")
val parser = Parser.builder().build()
val renderer = HtmlRenderer.builder().build()
val licenseHtml = renderer.render(parser.parse(licenseMarkdown))
println(" - 마크다운을 HTML로 변환했습니다. (HTML 길이: ${licenseHtml.length})")
// ✅ Jsoup으로 HTML 파일을 파싱합니다.
val doc = Jsoup.parse(targetHtmlFile, "UTF-8")
// ✅ CSS 선택자를 이용해 ID가 'license-content-container'인 태그를 선택하고
// 그 내부 HTML을 생성된 라이선스 내용으로 교체합니다.
doc.selectFirst("#license-content-container")?.html(licenseHtml)
println(" - HTML 파일 내 placeholder div의 내용을 교체했습니다.")
// ✅ 변경된 HTML 내용을 파일에 다시 씁니다.
targetHtmlFile.writeText(doc.outerHtml())
println("✅ 라이선스 정보(HTML)가 '${targetHtmlFile.name}' 파일에 성공적으로 업데이트되었습니다.")
}
}
// 'build' 태스크 실행 시 이 작업이 자동으로 수행되도록 연결
// [수정 전] tasks.build { dependsOn(tasks.getByName("updateLicensePage")) }
tasks.named("build") { // [수정 후] 'build' 태스크를 더 안전하게 참조합니다.
dependsOn(tasks.named("updateLicensePage"))
}
tasks.named("bootJar") { // [수정 후] 'build' 태스크를 더 안전하게 참조합니다.
dependsOn(tasks.named("updateLicensePage"))
}
// 기본 bootJar 태스크의 설정을 가져오기 위한 참조
val bootJar by tasks.getting(BootJar::class)
//
//// 'prod' 프로필이 내장된 JAR를 빌드하는 최종 태스크 정의
//tasks.register<BootJar>("bootJarProd") {
// group = "build"
// description = "Builds a production JAR that defaults to the 'prod' profile."
// archiveClassifier.set("prod")
//
// // --- 필수 설정 복사 ---
// // 1. Main 클래스 설정 복사
// mainClass.set(bootJar.mainClass)
// // 2. Classpath 설정 복사
// classpath = bootJar.classpath
// // 3. Target Java Version 설정 복사 (이번 오류 해결)
// targetJavaVersion.set(bootJar.targetJavaVersion)
//
// manifest {
// attributes["Spring-Profiles-Active"] = "prod"
// }
//}
// "local" 프로파일용 JAR를 빌드하는 작업
tasks.register<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJarLocal") {
group = "build"
description = "로컬 환경용 JAR 파일을 빌드합니다 ('local' 프로파일 적용)."
archiveClassifier.set("local") // 파일 이름에 local 접미사 추가 (e.g., app-local.jar)
// 메인 클래스와 클래스패스는 기본 bootJar 설정을 따라갑니다.
mainClass.set(tasks.bootJar.get().mainClass)
classpath = tasks.bootJar.get().classpath
targetJavaVersion.set(bootJar.targetJavaVersion)
// 'resources' 폴더의 모든 파일을 복사하되...
from("src/main/resources") {
include("**/*")
// prod 설정 파일은 제외합니다.
exclude("application-prod.properties")
// local 설정 파일의 이름을 application.properties로 변경합니다.
rename("application-local.properties", "application.properties")
}
}
// "prod" 프로파일용 JAR를 빌드하는 작업
tasks.register<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJarProd") {
group = "build"
description = "운영 환경용 JAR 파일을 빌드합니다 ('prod' 프로파일 적용)."
archiveClassifier.set("prod") // 파일 이름에 prod 접미사 추가 (e.g., app-prod.jar)
// 메인 클래스와 클래스패스는 기본 bootJar 설정을 따라갑니다.
mainClass.set(tasks.bootJar.get().mainClass)
classpath = tasks.bootJar.get().classpath
targetJavaVersion.set(bootJar.targetJavaVersion)
// 'resources' 폴더의 모든 파일을 복사하되...
from("src/main/resources") {
include("**/*")
// local 설정 파일은 제외합니다.
exclude("application-local.properties")
// prod 설정 파일의 이름을 application.properties로 변경합니다.
rename("application-prod.properties", "application.properties")
}
}
// 🚀 1. 명령어를 실행할 새로운 Exec 태스크 정의
tasks.register<Exec>("runCommandAfterProdJar") {
group = "build"
description = "prod JAR 빌드 후 실행할 명령어를 정의합니다."
// 이 태스크는 bootJarProd가 성공해야만 의미가 있으므로, 의존성을 명시해주는 것이 좋습니다.
dependsOn(tasks.named("bootJarProd"))
// 실행할 OS 명령어와 인자를 설정합니다.
// 예시 1: Docker 이미지 빌드
commandLine("docker", "buildx","buildx","--platform","linux/amd64", "-t", "lunaticbum/testjar:0.025", ".")
// 예시 2: 빌드된 JAR 파일을 특정 서버로 복사
// commandLine("scp", "build/libs/your-app-name-prod.jar", "user@server:/path/to/deploy")
// 예시 3: 간단한 셸 스크립트 실행
// commandLine("./deploy.sh")
// 필요하다면 작업 디렉토리를 설정할 수 있습니다.
// workingDir = rootDir
// doLast {
// println("prod JAR 빌드가 완료되었습니다. 추가 명령어를 실행합니다.")
// exec {
// commandLine("docker", "push", "lunaticbum/testjar:0.025")
// // commandLine("echo", "Hello from doLast!")
// }
// }
}
// 🚀 2. bootJarProd 태스크가 끝나면 위에서 정의한 태스크를 실행하도록 연결
//tasks.named("bootJarProd") {
// finalizedBy(tasks.named("runCommandAfterProdJar"))
//}
//
//// 'build' 태스크 실행 시 이 작업이 자동으로 수행되도록 연결
//tasks.build {
// dependsOn(tasks.getByName("updateLicensePage"))
//}