This is an automated email from the ASF dual-hosted git repository.

matrei pushed a commit to branch refactor-and-plugins
in repository https://gitbox.apache.org/repos/asf/grails-static-website.git

commit 0a344a3f8d4ed8e536515a4bfae96a94134784dd
Author: Mattias Reichel <[email protected]>
AuthorDate: Thu Feb 5 15:18:38 2026 +0100

    Adapt to Gradle 9 and Groovy 4
---
 buildSrc/build.gradle                              | 27 +++-------
 .../website/gradle/GrailsWebsitePlugin.groovy      |  3 +-
 .../groovy/website/gradle/tasks/AssetsTask.groovy  | 15 ++----
 .../groovy/website/gradle/tasks/BlogTask.groovy    | 58 +++++++++-------------
 .../website/gradle/tasks/DocumentationTask.groovy  | 31 +++++-------
 .../website/gradle/tasks/DownloadTask.groovy       | 22 +++-----
 .../website/gradle/tasks/GrailsWebsiteTask.groovy  |  3 ++
 .../groovy/website/gradle/tasks/GuidesTask.groovy  | 34 +++++--------
 .../website/gradle/tasks/HtaccessTask.groovy       | 14 +-----
 .../groovy/website/gradle/tasks/MinutesTask.groovy | 49 ++++++++----------
 .../groovy/website/gradle/tasks/PluginsTask.groovy | 29 ++++-------
 .../website/gradle/tasks/ProfilesTask.groovy       | 28 ++++-------
 .../website/gradle/tasks/QuestionsTask.groovy      | 22 +++-----
 .../website/gradle/tasks/RenderSiteTask.groovy     | 52 +++++++++----------
 .../groovy/website/gradle/tasks/SitemapTask.groovy | 21 +++-----
 .../groovy/website/model/MinutesMetadata.groovy    |  3 +-
 .../model/documentation/DocumentationPage.groovy   |  1 +
 .../model/documentation/ProfilesPage.groovy        |  1 +
 .../website/model/documentation/SiteMap.groovy     |  2 +-
 .../website/model/documentation/Snapshot.groovy    |  4 +-
 .../model/documentation/SoftwareVersion.groovy     |  8 +--
 .../main/groovy/website/model/events/Event.groovy  |  4 +-
 .../website/model/questions/QuestionsPage.groovy   |  2 +-
 .../src/main/groovy/website/utils/DateUtils.groovy |  4 +-
 24 files changed, 162 insertions(+), 275 deletions(-)

diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 51d7639aedf..b70f0c9de7f 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -3,8 +3,8 @@ plugins {
 }
 
 ext {
-    micronautVersion = '4.10.4'
     flexmarkVersion = '0.64.8'
+    micronautVersion = '4.10.4'
 }
 
 repositories {
@@ -13,31 +13,18 @@ repositories {
 
 dependencies {
 
-    annotationProcessor 
platform("io.micronaut.platform:micronaut-platform:$micronautVersion")
     implementation 
platform("io.micronaut.platform:micronaut-platform:$micronautVersion")
-    testAnnotationProcessor 
platform("io.micronaut.platform:micronaut-platform:$micronautVersion")
-    testImplementation 
platform("io.micronaut.platform:micronaut-platform:$micronautVersion")
 
-    annotationProcessor 'io.micronaut:micronaut-inject-java'
-    annotationProcessor 
'io.micronaut.validation:micronaut-validation-processor'
-
-    implementation 'io.micronaut.validation:micronaut-validation'
-    implementation 'io.micronaut:micronaut-http-client'
-    implementation 'io.micronaut:micronaut-http'
-    implementation 'io.micronaut:micronaut-inject'
-
-    implementation 'org.yaml:snakeyaml'
-    implementation 'jakarta.annotation:jakarta.annotation-api'
-    implementation 'jakarta.validation:jakarta.validation-api'
-    implementation 'io.micronaut.rss:micronaut-rss-core'
     implementation "com.vladsch.flexmark:flexmark:$flexmarkVersion"
     implementation "com.vladsch.flexmark:flexmark-ext-tables:$flexmarkVersion"
+    implementation 'io.micronaut.rss:micronaut-rss-core'
+    implementation 'io.micronaut.validation:micronaut-validation'
+    implementation 'jakarta.annotation:jakarta.annotation-api'
+    implementation 'org.yaml:snakeyaml'
 
-    testImplementation 'org.spockframework:spock-core:2.4-groovy-3.0'
-}
+    testImplementation 'org.spockframework:spock-core'
 
-tasks.withType(Jar).configureEach {
-    it.duplicatesStrategy = DuplicatesStrategy.INCLUDE
+    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
 }
 
 gradlePlugin {
diff --git a/buildSrc/src/main/groovy/website/gradle/GrailsWebsitePlugin.groovy 
b/buildSrc/src/main/groovy/website/gradle/GrailsWebsitePlugin.groovy
index 94d3439d5f2..8d39010052a 100644
--- a/buildSrc/src/main/groovy/website/gradle/GrailsWebsitePlugin.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/GrailsWebsitePlugin.groovy
@@ -23,9 +23,8 @@ import groovy.transform.CompileStatic
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 
-import website.gradle.tasks.BlogTask
-
 import website.gradle.tasks.AssetsTask
+import website.gradle.tasks.BlogTask
 import website.gradle.tasks.DocumentationTask
 import website.gradle.tasks.DownloadTask
 import website.gradle.tasks.GrailsWebsiteTask
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/AssetsTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/AssetsTask.groovy
index 9b0a3910d19..079c4c00675 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/AssetsTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/AssetsTask.groovy
@@ -26,7 +26,6 @@ import org.gradle.api.Project
 import org.gradle.api.file.CopySpec
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.FileSystemOperations
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.InputDirectory
 import org.gradle.api.tasks.Internal
@@ -40,7 +39,7 @@ import website.gradle.GrailsWebsiteExtension
 
 @CompileStatic
 @CacheableTask
-class AssetsTask extends GrailsWebsiteTask {
+abstract class AssetsTask extends GrailsWebsiteTask {
 
     @Internal
     final String description =
@@ -57,21 +56,15 @@ class AssetsTask extends GrailsWebsiteTask {
             'stylesheets': ['*.css'],
     ]
 
-    private final ObjectFactory objects
-    private final FileSystemOperations fileSystemOperations
-
     @Inject
-    AssetsTask(ObjectFactory objects, FileSystemOperations 
fileSystemOperations) {
-        this.objects = objects
-        this.fileSystemOperations = fileSystemOperations
-    }
+    abstract FileSystemOperations getFileSystemOperations()
 
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty assetsDir = objects.directoryProperty()
+    abstract DirectoryProperty getAssetsDir()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<AssetsTask> register(Project project, 
GrailsWebsiteExtension siteExt) {
         project.tasks.register(NAME, AssetsTask) {
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy
index 87e4113ee8f..c0365a18807 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/BlogTask.groovy
@@ -23,12 +23,12 @@ import java.time.ZoneId
 import java.time.ZonedDateTime
 import java.util.regex.Pattern
 
-import jakarta.annotation.Nonnull
 import javax.inject.Inject
 
 import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
-import groovy.xml.MarkupBuilder
+
+import jakarta.annotation.Nonnull
 
 import io.micronaut.rss.DefaultRssFeedRenderer
 import io.micronaut.rss.RssChannel
@@ -39,7 +39,6 @@ import org.gradle.api.file.Directory
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.FileSystemOperations
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.Property
 import org.gradle.api.provider.Provider
@@ -54,17 +53,19 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
+import website.gradle.GrailsWebsiteExtension
 import website.model.HtmlPost
 import website.model.MarkdownPost
 import website.model.PostMetadataAdapter
 import website.model.documentation.SiteMap
-import website.gradle.GrailsWebsiteExtension
 import website.utils.DateUtils
 import website.utils.MarkdownUtils
 
+import static website.utils.RenderUtils.renderHtml
+
 @CompileStatic
 @CacheableTask
-class BlogTask extends GrailsWebsiteTask {
+abstract class BlogTask extends GrailsWebsiteTask {
 
     @Internal
     final String description =
@@ -88,48 +89,42 @@ class BlogTask extends GrailsWebsiteTask {
     private static final int MAX_RELATED_POSTS = 3
     private static final int MAX_TITLE_LENGTH = 45
 
-    private final ObjectFactory objects
-    private final FileSystemOperations fileSystemOperations
-
     @Inject
-    BlogTask(ObjectFactory objects, FileSystemOperations fileSystemOperations) 
{
-        this.objects = objects
-        this.fileSystemOperations = fileSystemOperations
-    }
+    abstract FileSystemOperations getFileSystemOperations()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty document = objects.fileProperty()
+    abstract RegularFileProperty getDocument()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty releases = objects.fileProperty()
+    abstract RegularFileProperty getReleases()
 
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty assetsDir = objects.directoryProperty()
+    abstract DirectoryProperty getAssetsDir()
 
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty postsDir = objects.directoryProperty()
+    abstract DirectoryProperty getPostsDir()
 
     @Input
-    final Property<String> about = objects.property(String)
+    abstract Property<String> getAbout()
 
     @Input
-    final ListProperty<String> keywords = objects.listProperty(String)
+    abstract ListProperty<String> getKeywords()
 
     @Input
-    final Property<String> robots = objects.property(String)
+    abstract Property<String> getRobots()
 
     @Input
-    final Property<String> title = objects.property(String)
+    abstract Property<String> getTitle()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<BlogTask> register(Project project, 
GrailsWebsiteExtension siteExt) {
         project.tasks.register(NAME, BlogTask) {
@@ -217,8 +212,7 @@ class BlogTask extends GrailsWebsiteTask {
 
     @CompileDynamic
     static String renderPostHtml(HtmlPost htmlPost, String templateText, 
List<HtmlPost> posts) {
-        def writer = new StringWriter()
-        new MarkupBuilder(writer).with {
+        def html = renderHtml {
             div(class: 'header-bar chalices-bg') {
                 div(class: 'content') {
                     h1 {
@@ -244,7 +238,7 @@ class BlogTask extends GrailsWebsiteTask {
         }
 
         def metadata = htmlPost.metadata.toMap()
-        def html = 
RenderSiteTask.renderHtmlWithTemplateContent(writer.toString(), metadata, 
templateText)
+        html = RenderSiteTask.renderHtmlWithTemplateContent(html, metadata, 
templateText)
         html = RenderSiteTask.highlightMenu(html, metadata, htmlPost.path)
 
         def bodyClass = metadata.body
@@ -382,29 +376,25 @@ class BlogTask extends GrailsWebsiteTask {
         def style = imageUrl ? "background-image: url('$imageUrl')" : null
         def title = RenderSiteTask.replaceLineWithMetadata(meta.title, 
meta.toMap())
         title = title.size() > MAX_TITLE_LENGTH ? 
"${title.take(MAX_TITLE_LENGTH)}..." : title
-        def writer = new StringWriter()
-        new MarkupBuilder(writer).with {
+        renderHtml {
             omitNullAttributes = true
             article(class: 'blog-card', style: style) {
-                a(href: postLink(htmlPost)) {
+                a(href: BlogTask.postLink(htmlPost)) {
                     h3 { mkp.yield(RenderSiteTask.formatDate(meta.date)) }
                     h2 { mkp.yield(title) }
                 }
             }
         }
-        writer.toString()
     }
 
     @CompileDynamic
     private static String renderTagTitle(String tag) {
-        def writer = new StringWriter()
-        new MarkupBuilder(writer).with {
+        renderHtml {
             h1 {
                 span('Tag:')
                 b(tag)
             }
         }
-        writer.toString()
     }
 
     @CompileDynamic
@@ -442,8 +432,7 @@ class BlogTask extends GrailsWebsiteTask {
 
     @CompileDynamic
     static String cardsHtml(List<String> cards, String title = null) {
-        def writer = new StringWriter()
-        new MarkupBuilder(writer).tap {
+        renderHtml {
             div(class: 'header-bar chalices-bg') {
                 div(class: 'content') {
                     if (title) {
@@ -467,7 +456,6 @@ class BlogTask extends GrailsWebsiteTask {
                 }
             }
         }
-        writer.toString()
     }
 
     private static void renderRss(
diff --git 
a/buildSrc/src/main/groovy/website/gradle/tasks/DocumentationTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/DocumentationTask.groovy
index a5bb653b3c0..1a6ebf33284 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/DocumentationTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/DocumentationTask.groovy
@@ -18,14 +18,11 @@
  */
 package website.gradle.tasks
 
-import javax.inject.Inject
-
 import groovy.transform.CompileStatic
 
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.Input
@@ -37,12 +34,12 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
-import website.model.documentation.DocumentationPage
 import website.gradle.GrailsWebsiteExtension
+import website.model.documentation.DocumentationPage
 
 @CompileStatic
 @CacheableTask
-class DocumentationTask extends GrailsWebsiteTask {
+abstract class DocumentationTask extends GrailsWebsiteTask {
 
     @Internal
     final String description =
@@ -50,28 +47,25 @@ class DocumentationTask extends GrailsWebsiteTask {
 
     public static final String NAME = 'genDocsPage'
 
-    private final ObjectFactory objects
-
-    @Inject
-    DocumentationTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty modules = objects.fileProperty()
+    abstract RegularFileProperty getModules()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty releases = objects.fileProperty()
+    abstract RegularFileProperty getReleases()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
-    static TaskProvider<DocumentationTask> register(Project project, 
GrailsWebsiteExtension siteExt, String name = NAME) {
+    static TaskProvider<DocumentationTask> register(
+            Project project,
+            GrailsWebsiteExtension siteExt,
+            String name = NAME)
+    {
         project.tasks.register(name, DocumentationTask) {
             it.modules.set(siteExt.modules)
             it.url.set(siteExt.url)
@@ -82,8 +76,7 @@ class DocumentationTask extends GrailsWebsiteTask {
 
     @TaskAction
     void renderDocsPage() {
-        def buildDir = outputDir.get().asFile
-        def tempDir = new File(buildDir, 'temp').tap {mkdirs() }
+        def tempDir = outputDir.dir('temp').get().asFile.tap {mkdirs() }
         def outputFile = new File(tempDir, 'documentation.html')
         outputFile.setText(
                 'title: Documentation | Grails Framework\n' +
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/DownloadTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/DownloadTask.groovy
index d0c2791bca1..414d0c0cf1d 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/DownloadTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/DownloadTask.groovy
@@ -18,14 +18,11 @@
  */
 package website.gradle.tasks
 
-import javax.inject.Inject
-
 import groovy.transform.CompileStatic
 
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.Input
@@ -37,34 +34,27 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
-import website.model.documentation.DownloadPage
 import website.gradle.GrailsWebsiteExtension
+import website.model.documentation.DownloadPage
 
 @CompileStatic
 @CacheableTask
-class DownloadTask extends GrailsWebsiteTask {
+abstract class DownloadTask extends GrailsWebsiteTask {
 
     @Internal
     final String description = 'Generates download HTML page -> 
build/temp/download.html'
 
     public static final String NAME = 'genDownloads'
 
-    private final ObjectFactory objects
-
-    @Inject
-    DownloadTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty releases = objects.fileProperty()
+    abstract RegularFileProperty getReleases()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<DownloadTask> register(
             Project project,
@@ -80,7 +70,7 @@ class DownloadTask extends GrailsWebsiteTask {
 
     @TaskAction
     void renderDocsPage() {
-        def tempDir = new File(outputDir.get().asFile, 'temp').tap { 
it.mkdirs() }
+        def tempDir = outputDir.dir('temp').get().asFile.tap { it.mkdirs() }
         def outputFile = new File(tempDir, 'download.html')
         outputFile.setText(
                 'title: Downloads | Apache Grails&reg;\n' +
diff --git 
a/buildSrc/src/main/groovy/website/gradle/tasks/GrailsWebsiteTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/GrailsWebsiteTask.groovy
index 49dbdf0e3c5..97cc783b12f 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/GrailsWebsiteTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/GrailsWebsiteTask.groovy
@@ -18,8 +18,11 @@
  */
 package website.gradle.tasks
 
+import groovy.transform.CompileStatic
+
 import org.gradle.api.DefaultTask
 
+@CompileStatic
 abstract class GrailsWebsiteTask extends DefaultTask {
 
     public static String GROUP = 'grails website'
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/GuidesTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/GuidesTask.groovy
index 49fe3eb1b48..f4b1b818851 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/GuidesTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/GuidesTask.groovy
@@ -18,14 +18,11 @@
  */
 package website.gradle.tasks
 
-import javax.inject.Inject
-
 import groovy.transform.CompileStatic
 
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
@@ -38,16 +35,16 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
+import website.gradle.GrailsWebsiteExtension
 import website.model.Page
 import website.model.documentation.SiteMap
-import website.gradle.GrailsWebsiteExtension
 import website.model.guides.GuidesFetcher
 import website.model.guides.GuidesPage
 import website.model.guides.TagUtils
 
 @CompileStatic
 @CacheableTask
-class GuidesTask extends GrailsWebsiteTask {
+abstract class GuidesTask extends GrailsWebsiteTask {
 
     @Internal
     final String description =
@@ -57,38 +54,31 @@ class GuidesTask extends GrailsWebsiteTask {
 
     private static final String PAGE_NAME_GUIDES = 'guides.html'
     
-    private ObjectFactory objects
-
-    @Inject
-    GuidesTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-    
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty document = objects.fileProperty()
+    abstract RegularFileProperty getDocument()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty releases = objects.fileProperty()
+    abstract RegularFileProperty getReleases()
 
     @Input
-    final Property<String> about = objects.property(String)
+    abstract Property<String> getAbout()
 
     @Input
-    final ListProperty<String> keywords = objects.listProperty(String)
+    abstract ListProperty<String> getKeywords()
 
     @Input
-    final Property<String> robots = objects.property(String)
+    abstract Property<String> getRobots()
 
     @Input
-    final Property<String> title = objects.property(String)
+    abstract Property<String> getTitle()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<GuidesTask> register(
             Project project,
@@ -109,12 +99,12 @@ class GuidesTask extends GrailsWebsiteTask {
 
     @TaskAction
     void renderGuides() {
-        def tempDir = new File(outputDir.get().asFile, 'temp').tap { 
it.mkdirs() }
+        def tempDir = outputDir.dir('temp').get().asFile.tap { it.mkdirs() }
         generateGuidesPages(tempDir, url.get())
 
         def template = document.get().asFile
         def templateText = template.text
-        def distDir = new File(outputDir.get().asFile, 'dist').tap { 
it.mkdirs() }
+        def distDir = outputDir.dir('dist').get().asFile.tap { it.mkdirs() }
 
         def releasesFile = releases.get().asFile
         def latest = SiteMap.latestVersion(releasesFile)
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/HtaccessTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/HtaccessTask.groovy
index 383da218e1b..4a1684cc843 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/HtaccessTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/HtaccessTask.groovy
@@ -18,13 +18,10 @@
  */
 package website.gradle.tasks
 
-import javax.inject.Inject
-
 import groovy.transform.CompileStatic
 
 import org.gradle.api.Project
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.Internal
 import org.gradle.api.tasks.OutputFile
@@ -35,7 +32,7 @@ import website.gradle.GrailsWebsiteExtension
 
 @CompileStatic
 @CacheableTask
-class HtaccessTask extends GrailsWebsiteTask {
+abstract class HtaccessTask extends GrailsWebsiteTask {
 
     @Internal
     final String description = 'Generates the .htaccess file'
@@ -59,15 +56,8 @@ class HtaccessTask extends GrailsWebsiteTask {
             '# Ref https://docs.kapa.ai/integrations/understanding-csp-cors\n' 
+
             'SetEnv CSP_PROJECT_DOMAINS "' + DOMAINS.join(' ') + '"'
 
-    private final ObjectFactory objects
-
-    @Inject
-    HtaccessTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @OutputFile
-    final RegularFileProperty htaccess = objects.fileProperty()
+    abstract RegularFileProperty getHtaccess()
 
     static TaskProvider<HtaccessTask> register(
             Project project,
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy
index 10684a0b3df..cb06ad96092 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/MinutesTask.groovy
@@ -36,7 +36,6 @@ import org.gradle.api.file.CopySpec
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.FileSystemOperations
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
@@ -50,17 +49,19 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
-import website.utils.DateUtils
+import website.gradle.GrailsWebsiteExtension
 import website.model.HtmlMinutes
 import website.model.MarkdownMinutes
 import website.model.MinutesMetadataAdaptor
 import website.model.documentation.SiteMap
-import website.gradle.GrailsWebsiteExtension
+import website.utils.DateUtils
 import website.utils.MarkdownUtils
 
+import static website.utils.RenderUtils.renderHtml
+
 @CompileStatic
 @CacheableTask
-class MinutesTask extends GrailsWebsiteTask {
+abstract class MinutesTask extends GrailsWebsiteTask {
 
     @Internal
     final String description =
@@ -76,48 +77,42 @@ class MinutesTask extends GrailsWebsiteTask {
     private static final String MINUTES = 'foundation/minutes'
     private static final String INDEX = 'index.html'
 
-    private final ObjectFactory objects
-    private final FileSystemOperations fileSystemOperations
-
     @Inject
-    MinutesTask(ObjectFactory objects, FileSystemOperations 
fileSystemOperations) {
-        this.objects = objects
-        this.fileSystemOperations = fileSystemOperations
-    }
+    abstract FileSystemOperations getFileSystemOperations()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty document = objects.fileProperty()
+    abstract RegularFileProperty getDocument()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty releases = objects.fileProperty()
+    abstract RegularFileProperty getReleases()
 
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty assetsDir = objects.directoryProperty()
+    abstract DirectoryProperty getAssetsDir()
 
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty minutesDir = objects.directoryProperty()
+    abstract DirectoryProperty getMinutesDir()
 
     @Input
-    final Property<String> about = objects.property(String)
+    abstract Property<String> getAbout()
 
     @Input
-    final ListProperty<String> keywords = objects.listProperty(String)
+    abstract ListProperty<String> getKeywords()
 
     @Input
-    final Property<String> robots = objects.property(String)
+    abstract Property<String> getRobots()
 
     @Input
-    final Property<String> title = objects.property(String)
+    abstract Property<String> getTitle()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<MinutesTask> register(
             Project project,
@@ -266,7 +261,7 @@ class MinutesTask extends GrailsWebsiteTask {
         for (def htmlMinutes : listOfMinutes) {
             minuteCards.add(minutesCard(htmlMinutes))
             new File(outputDir, htmlMinutes.path).tap {
-                it.setText(renderMinutesHtml(htmlMinutes, templateText, 
listOfMinutes), 'UTF-8')
+                it.text = renderMinutesHtml(htmlMinutes, templateText, 
listOfMinutes)
             }
             rssItems.add(
                     BlogTask.rssItemWithPage(
@@ -297,8 +292,7 @@ class MinutesTask extends GrailsWebsiteTask {
 
     @CompileDynamic
     private static String minutesCard(HtmlMinutes htmlMinutes) {
-        def writer = new StringWriter()
-        new MarkupBuilder(writer).with {
+        renderHtml {
             article(class: 'blog-card', style: "margin-bottom: 0; 
background-image: url($htmlMinutes.metadata.url/$IMAGES/$MINUTES_BG)") {
                 a(href: minutesLink(htmlMinutes)) {
                     h3 {
@@ -314,7 +308,6 @@ class MinutesTask extends GrailsWebsiteTask {
                 }
             }
         }
-        writer.toString()
     }
 
     private static void renderArchive(
@@ -329,13 +322,12 @@ class MinutesTask extends GrailsWebsiteTask {
         }
         html = RenderSiteTask.renderHtmlWithTemplateContent(html, 
resolvedMetadata, templateText)
         html = RenderSiteTask.highlightMenu(html, resolvedMetadata, 
"/$MINUTES/$INDEX")
-        f.setText(html, 'UTF-8')
+        f.text = html
     }
 
     @CompileDynamic
     static String cardsHtml(List<String> cards, String title = null) {
-        def writer = new StringWriter()
-        new MarkupBuilder(writer).with {
+        renderHtml {
             div(class: 'header-bar chalices-bg') {
                 div(class: 'content') {
                     if (title) {
@@ -370,7 +362,6 @@ class MinutesTask extends GrailsWebsiteTask {
                 }
             }
         }
-        writer.toString()
     }
 
     private static void renderRss(
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy
index 96b0cf19984..d55e7f40bf3 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/PluginsTask.groovy
@@ -24,8 +24,6 @@ import java.net.http.HttpResponse
 import java.time.LocalDateTime
 import java.time.format.DateTimeFormatter
 
-import javax.inject.Inject
-
 import groovy.json.JsonSlurper
 import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
@@ -36,7 +34,6 @@ import jakarta.annotation.Nullable
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
@@ -48,6 +45,7 @@ import org.gradle.api.tasks.PathSensitive
 import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
+
 import website.gradle.GrailsWebsiteExtension
 import website.model.plugin.Owner
 import website.model.plugin.Plugin
@@ -57,7 +55,7 @@ import website.model.plugin.PluginsPage
 @Slf4j
 @CompileStatic
 @CacheableTask
-class PluginsTask extends GrailsWebsiteTask {
+abstract class PluginsTask extends GrailsWebsiteTask {
 
     @Internal
     final String description = 'Generates an HTML Page listing the Grails 
plugins'
@@ -67,25 +65,18 @@ class PluginsTask extends GrailsWebsiteTask {
     private static final String GRAILS_PLUGINS_JSON =
             
'https://raw.githubusercontent.com/grails/grails-plugins-metadata/main/grails-plugins-index.json'
 
-    private final ObjectFactory objects
-
-    @Inject
-    PluginsTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty document = objects.fileProperty()
+    abstract RegularFileProperty getDocument()
 
     @Input
-    final ListProperty<String> keywords = objects.listProperty(String)
+    abstract ListProperty<String> getKeywords()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<PluginsTask> register(
             Project project,
@@ -121,10 +112,10 @@ class PluginsTask extends GrailsWebsiteTask {
     void renderHtml(List<Plugin> plugins, String templateText, Map<String, 
String> metadata, String fileName) {
         def siteUrl = url.get()
 
-        def distDir          = new File(outputDir.get().asFile, 'dist').tap { 
mkdirs() }
-        def pluginsDir       = new File(distDir, 'plugins').tap { mkdirs() }
-        def pluginsTagsDir   = new File(pluginsDir, 'tags').tap { mkdirs() }
-        def pluginsOwnersDir = new File(pluginsDir, 'owners').tap { mkdirs() }
+        def distDir          = outputDir.dir('dist').get().asFile
+        def pluginsDir       = outputDir.dir('dist/plugins').get().asFile
+        def pluginsTagsDir   = 
outputDir.dir('dist/plugins/tags').get().asFile.tap { mkdirs() }
+        def pluginsOwnersDir = 
outputDir.dir('dist/plugins/owners').get().asFile.tap { mkdirs() }
 
         def wrap = { String html -> 
RenderSiteTask.renderHtmlWithTemplateContent(html, metadata, templateText) }
 
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/ProfilesTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/ProfilesTask.groovy
index 92a1102a1de..11e393e6fca 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/ProfilesTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/ProfilesTask.groovy
@@ -18,14 +18,11 @@
  */
 package website.gradle.tasks
 
-import javax.inject.Inject
-
 import groovy.transform.CompileStatic
 
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.Internal
@@ -35,34 +32,31 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
-import website.model.documentation.ProfilesPage
 import website.gradle.GrailsWebsiteExtension
+import website.model.documentation.ProfilesPage
 
 @CompileStatic
 @CacheableTask
-class ProfilesTask extends GrailsWebsiteTask {
+abstract class ProfilesTask extends GrailsWebsiteTask {
 
     @Internal
     final String description = 'Generates the Profiles HTML Page -> 
build/temp/profiles.html'
 
     public static final String NAME = 'genProfilesPage'
 
-    private final ObjectFactory objects
-
-    @Inject
-    ProfilesTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty profiles = objects.fileProperty()
+    abstract RegularFileProperty getProfiles()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
-    static TaskProvider<ProfilesTask> register(Project project, 
GrailsWebsiteExtension siteExt) {
-        project.tasks.register(NAME, ProfilesTask) {
+    static TaskProvider<ProfilesTask> register(
+            Project project,
+            GrailsWebsiteExtension siteExt,
+            String name = NAME
+    ) {
+        project.tasks.register(name, ProfilesTask) {
             it.profiles.set(siteExt.profiles)
             it.outputDir.set(siteExt.outputDir)
         }
@@ -70,7 +64,7 @@ class ProfilesTask extends GrailsWebsiteTask {
 
     @TaskAction
     void renderProfilesPage() {
-        def tempDir = new File(outputDir.get().asFile, 'temp').tap { mkdirs() }
+        def tempDir = outputDir.dir('temp').get().asFile.tap { mkdirs() }
         def output = new File(tempDir, 'profiles.html')
         output.setText(
                 'title: Profiles | Grails Framework\n' +
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/QuestionsTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/QuestionsTask.groovy
index 8ac574545ac..80dfa14de91 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/QuestionsTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/QuestionsTask.groovy
@@ -18,14 +18,11 @@
  */
 package website.gradle.tasks
 
-import javax.inject.Inject
-
 import groovy.transform.CompileStatic
 
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.Internal
@@ -40,7 +37,7 @@ import website.model.questions.QuestionsPage
 
 @CompileStatic
 @CacheableTask
-class QuestionsTask extends GrailsWebsiteTask {
+abstract class QuestionsTask extends GrailsWebsiteTask {
 
     @Internal
     final String description = 'Generates FAQ HTML - build/temp/faq.html'
@@ -49,19 +46,12 @@ class QuestionsTask extends GrailsWebsiteTask {
 
     private static final String PAGE_NAME_QUESTIONS = 'faq.html'
 
-    private final ObjectFactory objects
-
-    @Inject
-    QuestionsTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty questions = objects.fileProperty()
+    abstract RegularFileProperty getQuestions()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<QuestionsTask> register(
             Project project,
@@ -76,11 +66,11 @@ class QuestionsTask extends GrailsWebsiteTask {
 
     @TaskAction
     void renderQuestionsPage() {
-        def buildDir = outputDir.get().asFile
-        def temp = new File(buildDir, 'temp').tap { it.mkdirs() }
+        def temp = outputDir.dir('temp').get().asFile.tap { it.mkdirs() }
         def output = new File(temp, PAGE_NAME_QUESTIONS)
         output.setText(
-                "title: FAQ | Apache Grails&reg;\nbody: faq\n---\n" + 
QuestionsPage.mainContent(questions.get().asFile),
+                "title: FAQ | Apache Grails&reg;\nbody: faq\n---\n" +
+                        QuestionsPage.mainContent(questions.get().asFile),
                 'UTF-8'
         )
     }
diff --git 
a/buildSrc/src/main/groovy/website/gradle/tasks/RenderSiteTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/RenderSiteTask.groovy
index 531991febe9..e58943d5353 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/RenderSiteTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/RenderSiteTask.groovy
@@ -18,19 +18,17 @@
  */
 package website.gradle.tasks
 
-import jakarta.annotation.Nonnull
-import javax.inject.Inject
-import jakarta.validation.constraints.NotNull
-
 import groovy.time.TimeCategory
 import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
 
+import jakarta.annotation.Nonnull
 import jakarta.annotation.Nullable
+import jakarta.validation.constraints.NotNull
+
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
@@ -44,17 +42,17 @@ import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.TaskProvider
 
+import website.gradle.GrailsWebsiteExtension
 import website.model.ContentAndMetadata
-import website.utils.DateUtils
 import website.model.Page
 import website.model.documentation.SiteMap
-import website.gradle.GrailsWebsiteExtension
+import website.utils.DateUtils
 
 import static groovy.io.FileType.FILES
 
 @CompileStatic
 @CacheableTask
-class RenderSiteTask extends GrailsWebsiteTask {
+abstract class RenderSiteTask extends GrailsWebsiteTask {
 
     @Internal
     final String description =
@@ -69,42 +67,35 @@ class RenderSiteTask extends GrailsWebsiteTask {
     private static final int TWITTER_CARD_PLAYER_WIDTH = 560
     private static final int TWITTER_CARD_PLAYER_HEIGHT = 315
 
-    private final ObjectFactory objects
-
-    @Inject
-    RenderSiteTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-    
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty document = objects.fileProperty()
+    abstract RegularFileProperty getDocument()
 
     @InputFile
     @PathSensitive(PathSensitivity.RELATIVE)
-    final RegularFileProperty releases = objects.fileProperty()
+    abstract RegularFileProperty getReleases()
 
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty pagesDir = objects.directoryProperty()
+    abstract DirectoryProperty getPagesDir()
 
     @Input
-    final Property<String> title = objects.property(String)
+    abstract Property<String> getTitle()
 
     @Input
-    final Property<String> about = objects.property(String)
+    abstract Property<String> getAbout()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @Input
-    final ListProperty<String> keywords = objects.listProperty(String)
+    abstract ListProperty<String> getKeywords()
 
     @Input
-    final Property<String> robots = objects.property(String)
+    abstract Property<String> getRobots()
 
     @OutputDirectory
-    final DirectoryProperty outputDir = objects.directoryProperty()
+    abstract DirectoryProperty getOutputDir()
 
     static TaskProvider<RenderSiteTask> register(
             Project project,
@@ -126,14 +117,13 @@ class RenderSiteTask extends GrailsWebsiteTask {
 
     @TaskAction
     void renderSite() {
-        def o = outputDir.get().asFile
         def releasesFile = releases.get().asFile
         def latest = SiteMap.latestVersion(releasesFile)
         def versions = SiteMap.olderVersions(releasesFile)
                 .reverse()
                 .collect { "<option>${it}</option>" }
                 .join(' ')
-        def m = website.gradle.tasks.RenderSiteTask.siteMeta(
+        def metaData = siteMeta(
                 title.get(),
                 about.get(),
                 url.get(),
@@ -144,11 +134,15 @@ class RenderSiteTask extends GrailsWebsiteTask {
         def listOfPages = parsePages(pagesDir.get().asFile)
         listOfPages.addAll(
                 parsePages(
-                        new File(o, 'temp')
+                        outputDir.dir('temp').get().asFile
                 )
         )
-        File dist = new File(o, 'dist')
-        renderPages(m, listOfPages, dist, document.get().asFile.text)
+        renderPages(
+                metaData,
+                listOfPages,
+                outputDir.dir('dist').get().asFile,
+                document.get().asFile.text
+        )
     }
 
     static Map<String, String> siteMeta(
diff --git a/buildSrc/src/main/groovy/website/gradle/tasks/SitemapTask.groovy 
b/buildSrc/src/main/groovy/website/gradle/tasks/SitemapTask.groovy
index 5cb8d978b7a..47a47895d97 100644
--- a/buildSrc/src/main/groovy/website/gradle/tasks/SitemapTask.groovy
+++ b/buildSrc/src/main/groovy/website/gradle/tasks/SitemapTask.groovy
@@ -22,12 +22,9 @@ import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
 import groovy.xml.MarkupBuilder
 
-import javax.inject.Inject
-
 import org.gradle.api.Project
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
 import org.gradle.api.provider.Property
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.Input
@@ -45,29 +42,22 @@ import static groovy.io.FileType.FILES
 
 @CompileStatic
 @CacheableTask
-class SitemapTask extends GrailsWebsiteTask {
+abstract class SitemapTask extends GrailsWebsiteTask {
 
     @Internal
     final String description = 'Generates build/dist/sitemap.xml with every 
page in the site'
 
     public static final String NAME = 'genSitemap'
 
-    private final ObjectFactory objects
-
-    @Inject
-    SitemapTask(ObjectFactory objects) {
-        this.objects = objects
-    }
-
     @InputDirectory
     @PathSensitive(PathSensitivity.RELATIVE)
-    final DirectoryProperty inputDir = objects.directoryProperty()
+    abstract DirectoryProperty getInputDir()
 
     @Input
-    final Property<String> url = objects.property(String)
+    abstract Property<String> getUrl()
 
     @OutputFile
-    final RegularFileProperty outputFile = objects.fileProperty()
+    abstract RegularFileProperty getOutputFile()
 
     static TaskProvider<SitemapTask> register(
             Project project,
@@ -100,7 +90,8 @@ class SitemapTask extends GrailsWebsiteTask {
     @CompileDynamic
     static String sitemapContent(List<String> urls) {
         def writer = new StringWriter()
-        def xml = new MarkupBuilder(writer)
+        def printer = new IndentPrinter(new PrintWriter(writer), '', false)
+        def xml = new MarkupBuilder(printer)
         xml.urlset(xmlns: 'https://www.sitemaps.org/schemas/sitemap/0.9') {
             for (def urlStr : urls) {
                 url {
diff --git a/buildSrc/src/main/groovy/website/model/MinutesMetadata.groovy 
b/buildSrc/src/main/groovy/website/model/MinutesMetadata.groovy
index dd0547f8ef5..03849f3f216 100644
--- a/buildSrc/src/main/groovy/website/model/MinutesMetadata.groovy
+++ b/buildSrc/src/main/groovy/website/model/MinutesMetadata.groovy
@@ -18,9 +18,10 @@
  */
 package website.model
 
-import jakarta.annotation.Nullable
 import groovy.transform.CompileStatic
 
+import jakarta.annotation.Nullable
+
 @CompileStatic
 interface MinutesMetadata {
 
diff --git 
a/buildSrc/src/main/groovy/website/model/documentation/DocumentationPage.groovy 
b/buildSrc/src/main/groovy/website/model/documentation/DocumentationPage.groovy
index 33fa011bfca..58c82eb5bf1 100644
--- 
a/buildSrc/src/main/groovy/website/model/documentation/DocumentationPage.groovy
+++ 
b/buildSrc/src/main/groovy/website/model/documentation/DocumentationPage.groovy
@@ -20,6 +20,7 @@ package website.model.documentation
 
 import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
+
 import org.yaml.snakeyaml.Yaml
 
 import static website.utils.RenderUtils.renderHtml
diff --git 
a/buildSrc/src/main/groovy/website/model/documentation/ProfilesPage.groovy 
b/buildSrc/src/main/groovy/website/model/documentation/ProfilesPage.groovy
index f013ebf4f0f..d9a5bce6540 100644
--- a/buildSrc/src/main/groovy/website/model/documentation/ProfilesPage.groovy
+++ b/buildSrc/src/main/groovy/website/model/documentation/ProfilesPage.groovy
@@ -22,6 +22,7 @@ import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
 
 import org.yaml.snakeyaml.Yaml
+
 import website.utils.MarkdownUtils
 
 import static website.utils.RenderUtils.renderHtml
diff --git 
a/buildSrc/src/main/groovy/website/model/documentation/SiteMap.groovy 
b/buildSrc/src/main/groovy/website/model/documentation/SiteMap.groovy
index f29727071ed..8b96946559c 100644
--- a/buildSrc/src/main/groovy/website/model/documentation/SiteMap.groovy
+++ b/buildSrc/src/main/groovy/website/model/documentation/SiteMap.groovy
@@ -45,7 +45,7 @@ class SiteMap {
 
     static List<SoftwareVersion> stableVersions(File releases) {
         versions(releases)
-                .findAll { !it.isSnapshot() }
+                .findAll { !it.getIsSnapshot() }
                 .toSorted { a, b -> b <=> a }
     }
 
diff --git 
a/buildSrc/src/main/groovy/website/model/documentation/Snapshot.groovy 
b/buildSrc/src/main/groovy/website/model/documentation/Snapshot.groovy
index 99d5914b8df..2225b5ae2d8 100644
--- a/buildSrc/src/main/groovy/website/model/documentation/Snapshot.groovy
+++ b/buildSrc/src/main/groovy/website/model/documentation/Snapshot.groovy
@@ -18,9 +18,9 @@
  */
 package website.model.documentation
 
-import groovy.transform.CompileStatic
+//import groovy.transform.CompileStatic
 
-@CompileStatic
+//@CompileStatic Does not compile statically with Groovy 4
 class Snapshot implements Comparable<Snapshot> {
 
     final String text
diff --git 
a/buildSrc/src/main/groovy/website/model/documentation/SoftwareVersion.groovy 
b/buildSrc/src/main/groovy/website/model/documentation/SoftwareVersion.groovy
index b12d78c5056..182d296adc6 100644
--- 
a/buildSrc/src/main/groovy/website/model/documentation/SoftwareVersion.groovy
+++ 
b/buildSrc/src/main/groovy/website/model/documentation/SoftwareVersion.groovy
@@ -76,7 +76,7 @@ class SoftwareVersion implements Comparable<SoftwareVersion> {
         version.toLowerCase().contains('snapshot')
     }
 
-    boolean isSnapshot() {
+    boolean getIsSnapshot() {
         snapshot != null
     }
 
@@ -97,11 +97,11 @@ class SoftwareVersion implements 
Comparable<SoftwareVersion> {
             return patchCompare
         }
 
-        if (this.isSnapshot() && !o.isSnapshot()) {
+        if (this.getIsSnapshot() && !o.getIsSnapshot()) {
             return -1
-        } else if (!this.isSnapshot() && o.isSnapshot()) {
+        } else if (!this.getIsSnapshot() && o.getIsSnapshot()) {
             return 1
-        } else if (this.isSnapshot() && o.isSnapshot()) {
+        } else if (this.getIsSnapshot() && o.getIsSnapshot()) {
             return this.getSnapshot() <=> o.getSnapshot()
         } else {
             return 0
diff --git a/buildSrc/src/main/groovy/website/model/events/Event.groovy 
b/buildSrc/src/main/groovy/website/model/events/Event.groovy
index f17ba67f039..ef3ac30af33 100644
--- a/buildSrc/src/main/groovy/website/model/events/Event.groovy
+++ b/buildSrc/src/main/groovy/website/model/events/Event.groovy
@@ -19,11 +19,11 @@
 
 package website.model.events
 
+import java.time.LocalDate
+
 import groovy.transform.CompileStatic
 import groovy.transform.ToString
 
-import java.time.LocalDate
-
 import jakarta.annotation.Nullable
 
 @ToString
diff --git 
a/buildSrc/src/main/groovy/website/model/questions/QuestionsPage.groovy 
b/buildSrc/src/main/groovy/website/model/questions/QuestionsPage.groovy
index fdb09353b09..670db810d8a 100644
--- a/buildSrc/src/main/groovy/website/model/questions/QuestionsPage.groovy
+++ b/buildSrc/src/main/groovy/website/model/questions/QuestionsPage.groovy
@@ -18,8 +18,8 @@
  */
 package website.model.questions
 
-
 import org.yaml.snakeyaml.Yaml
+
 import website.utils.MarkdownUtils
 
 import static website.utils.RenderUtils.renderHtml
diff --git a/buildSrc/src/main/groovy/website/utils/DateUtils.groovy 
b/buildSrc/src/main/groovy/website/utils/DateUtils.groovy
index cd9b6e1afc7..791fb89f2d4 100644
--- a/buildSrc/src/main/groovy/website/utils/DateUtils.groovy
+++ b/buildSrc/src/main/groovy/website/utils/DateUtils.groovy
@@ -18,14 +18,14 @@
  */
 package website.utils
 
-import groovy.transform.CompileStatic
-
 import java.time.LocalDate
 import java.time.LocalDateTime
 import java.time.ZoneId
 import java.time.format.DateTimeFormatter
 import java.time.format.DateTimeParseException
 
+import groovy.transform.CompileStatic
+
 import org.gradle.api.GradleException
 
 @CompileStatic

Reply via email to