Files
halo/application/build.gradle
John Niang 71c621b9b1 Refactor Thymeleaf dependencies to resolve potential memory leak (#7914)
#### What type of PR is this?

/kind bug
/area core
/milestone 2.22.x

#### What this PR does / why we need it:

Supersedes <https://github.com/halo-dev/halo/pull/7678>.

See https://github.com/halo-dev/thymeleaf/pull/4 for more.

#### Does this PR introduce a user-facing change?

```release-note
修复潜在的内存泄漏问题
```
2025-11-06 13:42:29 +00:00

257 lines
8.7 KiB
Groovy

import de.undercouch.gradle.tasks.download.Download
import org.gradle.crypto.checksum.Checksum
import org.springframework.boot.gradle.tasks.bundling.BootBuildImage
import org.springframework.boot.gradle.tasks.bundling.BootJar
import org.springframework.util.StringUtils
plugins {
id 'checkstyle'
id 'java'
id 'idea'
id 'jacoco'
alias(libs.plugins.spring.boot)
alias(libs.plugins.spring.dependency.management)
alias(libs.plugins.git.properties)
alias(libs.plugins.undercouch.download)
alias(libs.plugins.lombok)
alias(libs.plugins.checksum)
alias(libs.plugins.springdoc.openapi)
alias(libs.plugins.versions)
}
group = 'run.halo.app'
tasks.withType(JavaCompile).configureEach {
options.release = 21
options.encoding = 'UTF-8'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
idea {
module {
resourceDirs += file("../ui/build/dist/")
}
}
checkstyle {
toolVersion = libs.versions.checkstyle.get()
showViolations = false
ignoreFailures = false
}
repositories {
mavenCentral()
maven { url = 'https://repo.spring.io/milestone' }
maven { url = 'https://s01.oss.sonatype.org/content/repositories/snapshots' }
flatDir {
dir layout.projectDirectory.dir('libs')
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
springBoot {
buildInfo {
properties {
artifact = 'halo'
name = 'halo'
}
}
}
bootJar {
archiveBaseName = 'halo'
manifest {
attributes 'Implementation-Title': 'Halo Application',
'Implementation-Vendor': 'Halo OSS Team'
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
gitProperties {
dotGitDirectory = layout.settingsDirectory.dir('.git')
}
tasks.named('jar') {
enabled = false
}
dependencies {
implementation project(':api')
// Fix https://github.com/halo-dev/halo/issues/7289
// Build from https://github.com/halo-dev/thymeleaf/commit/d23498ea297059deff04ba8c3578de59c73ccf03
runtimeOnly ':thymeleaf:3.1.3.RELEASE'
runtimeOnly ':thymeleaf-spring6:3.1.3.RELEASE'
annotationProcessor platform(project(':platform:application'))
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
annotationProcessor "org.springframework:spring-context-indexer"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'io.projectreactor:reactor-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe'
// webjars
runtimeOnly 'org.webjars.npm:jsencrypt:3.3.2'
runtimeOnly 'org.webjars.npm:normalize.css:8.0.1'
}
tasks.register('createChecksums', Checksum) {
dependsOn tasks.named('bootJar')
inputFiles.setFrom(layout.buildDirectory.files('libs'))
outputDirectory = layout.buildDirectory.dir("libs")
checksumAlgorithm = Checksum.Algorithm.SHA256
}
tasks.register('copyUiDist', Copy) {
from project(':ui').layout.buildDirectory.dir('dist')
into layout.buildDirectory.dir('resources/main')
mustRunAfter ':ui:doBuild'
}
tasks.named('processResources', ProcessResources) {
dependsOn tasks.named('copyUiDist')
}
tasks.named('build') {
dependsOn tasks.named('createChecksums')
}
tasks.named('test', Test) {
useJUnitPlatform()
maxHeapSize = '1G'
finalizedBy jacocoTestReport
}
tasks.named('jacocoTestReport', JacocoReport) {
reports {
xml.required = true
html.required = false
}
}
tasks.register('downloadPluginPresets', Download) {
def presetPluginUrls = [
'https://github.com/halo-dev/plugin-comment-widget/releases/download/v3.0.0/plugin-comment-widget-3.0.0.jar' : 'plugin-comment-widget.jar',
'https://github.com/halo-dev/plugin-search-widget/releases/download/v1.7.0/plugin-search-widget-1.7.0.jar' : 'plugin-search-widget.jar',
'https://github.com/halo-dev/plugin-sitemap/releases/download/v1.1.2/plugin-sitemap-1.1.2.jar' : 'plugin-sitemap.jar',
'https://github.com/halo-dev/plugin-feed/releases/download/v1.5.0/plugin-feed-1.5.0.jar' : 'plugin-feed.jar',
'https://github.com/halo-sigs/plugin-shiki/releases/download/v1.0.1/plugin-shiki-1.0.1.jar' : 'plugin-shiki.jar',
'https://github.com/halo-sigs/plugin-editor-hyperlink-card/releases/download/v1.5.2/plugin-editor-hyperlink-card-1.5.2.jar': 'plugin-editor-hyperlink-card.jar',
// Currently, plugin-app-store is not open source, so we need to download it from the official website.
// Please see https://github.com/halo-dev/plugin-app-store/issues/55
// https://www.halo.run/store/apps/app-VYJbF
'https://www.halo.run/store/apps/app-VYJbF/releases/download/app-release-uadbam6p/assets/app-release-uadbam6p-kwbir0ge' : 'appstore.jar',
]
src presetPluginUrls.keySet()
dest layout.buildDirectory.dir('resources/main/presets/plugins')
eachFile { f ->
f.name = presetPluginUrls[f.sourceURL.toString()]
}
}
openApi {
outputDir = file("$rootDir/api-docs/openapi/v3_0")
groupedApiMappings = [
'http://localhost:8091/v3/api-docs/apis_aggregated.api_v1alpha1': 'aggregated.json',
'http://localhost:8091/v3/api-docs/apis_public.api_v1alpha1' : 'apis_public.api_v1alpha1.json',
'http://localhost:8091/v3/api-docs/apis_console.api_v1alpha1' : 'apis_console.api_v1alpha1.json',
'http://localhost:8091/v3/api-docs/apis_uc.api_v1alpha1' : 'apis_uc.api_v1alpha1.json',
'http://localhost:8091/v3/api-docs/apis_extension.api_v1alpha1' : 'apis_extension.api_v1alpha1.json',
]
customBootRun {
args = ['--server.port=8091',
'--spring.profiles.active=doc',
"--halo.work-dir=${layout.buildDirectory.get()}/tmp/workdir-for-generating-apidocs"]
}
}
tasks.named('forkedSpringBootRun') {
dependsOn ':api:jar'
}
tasks.named('generateOpenApiDocs') {
outputs.upToDateWhen {
false
}
}
def branchProvider = providers.exec { commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD' }
.standardOutput
.asText
.map { it.trim().replaceAll("/", "-") }
def abbreviatedIdProvider = providers.exec { commandLine 'git', 'rev-parse', '--short', 'HEAD' }
.standardOutput
.asText
.map { it.trim() }
def isRelease = project.hasProperty('release') && Boolean.parseBoolean(project.property('release').toString())
def repoProvider = providers.provider { isRelease ? 'halo' : 'halo-dev' }
def tagProvider = providers.provider {
isRelease ? "${project.version}-cnb" : abbreviatedIdProvider.map { "sha-${it}-cnb" }.get()
}
def branchTagProvider = branchProvider.map { "${it}-cnb" }
def archiveFileProvider = tasks.named('bootJar', BootJar).<RegularFile> flatMap { it.archiveFile }
tasks.register('publishToGhcr', BootBuildImage) {
def ghcrUserProvider = providers.environmentVariable('GHCR_USERNAME')
def ghcrTokenProvider = providers.environmentVariable('GHCR_TOKEN')
group = 'publishing'
description = 'Build and publish the Docker image to GitHub Container Registry.'
imageName = "ghcr.io/halo-dev/${repoProvider.get()}:${tagProvider.get()}"
publish = ghcrTokenProvider.map { StringUtils.hasText(it) }.orElse(false)
if (!isRelease) {
tags.add("ghcr.io/halo-dev/${repoProvider.get()}:${branchTagProvider.get()}")
}
docker {
publishRegistry {
username = ghcrUserProvider
password = ghcrTokenProvider
}
}
archiveFile.set(archiveFileProvider)
}
tasks.register('publishToDockerHub', BootBuildImage) {
def dockerUserProvider = providers.environmentVariable('DOCKER_USERNAME')
def dockerTokenProvider = providers.environmentVariable('DOCKER_TOKEN')
group = 'publishing'
description = 'Build and publish the Docker image to Docker Hub.'
imageName = "halohub/${repoProvider.get()}:${tagProvider.get()}"
publish = dockerTokenProvider.map { StringUtils.hasText(it) }.orElse(false)
if (!isRelease) {
tags.add("halohub/${repoProvider.get()}:${branchTagProvider.get()}")
}
docker {
publishRegistry {
username = dockerUserProvider
password = dockerTokenProvider
}
}
archiveFile.set(archiveFileProvider)
}
tasks.register('publishToAllRegistries') {
group = 'publishing'
description = 'Build and publish the Docker image to all configured registries.'
dependsOn tasks.named('publishToGhcr'), tasks.named('publishToDockerHub')
}