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

jamesfredley pushed a commit to branch kapa-ai-csp-prep
in repository https://gitbox.apache.org/repos/asf/grails-static-website.git

commit 09059d5e8f2a056c90c7a122db6c929b20fdc624
Author: James Fredley <[email protected]>
AuthorDate: Wed Oct 1 09:59:49 2025 -0400

    Add HtaccessTask to generate .htaccess for dist output
    
    Introduces a new Gradle task, HtaccessTask, to generate a .htaccess file in 
the dist folder for Apache web server configuration. The task is registered in 
GrailsWebsitePlugin and is finalized by the main buildWebsite task to ensure 
the .htaccess file is created as part of the website build process.
---
 .../org/grails/gradle/GrailsWebsitePlugin.groovy   | 13 +++++
 .../groovy/org/grails/gradle/HtaccessTask.groovy   | 66 ++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git 
a/buildSrc/src/main/groovy/org/grails/gradle/GrailsWebsitePlugin.groovy 
b/buildSrc/src/main/groovy/org/grails/gradle/GrailsWebsitePlugin.groovy
index ac22d8f7962..57c38fc87d9 100644
--- a/buildSrc/src/main/groovy/org/grails/gradle/GrailsWebsitePlugin.groovy
+++ b/buildSrc/src/main/groovy/org/grails/gradle/GrailsWebsitePlugin.groovy
@@ -43,6 +43,7 @@ class GrailsWebsitePlugin implements Plugin<Project> {
     public static final String GROUP_GRAILS = 'grails'
     public static final String TASK_RENDER_BLOG = 'renderBlog'
     public static final String TASK_RENDER_MINUTES = 'renderMinutes'
+    public static final String TASK_GEN_HTACCESS = "genHtaccess"
 
 
     @Override
@@ -180,6 +181,17 @@ class GrailsWebsitePlugin implements Plugin<Project> {
             task.setGroup(GROUP_GRAILS)
         })
 
+        project.tasks.register(TASK_GEN_HTACCESS, HtaccessTask, { task ->
+            Object extension = 
project.getExtensions().findByName(EXTENSION_NAME)
+            if (extension instanceof SiteExtension) {
+                SiteExtension siteExtension = ((SiteExtension) extension)
+                task.setProperty("output", siteExtension.output)
+                task.setProperty("url", siteExtension.url)
+            }
+            task.setDescription('Generates .htaccess file in the dist folder 
for Apache web server configuration')
+            task.setGroup(GROUP_GRAILS)
+        })
+
         project.tasks.register(BUILD_GUIDES, BuildGuidesTask, { task ->
             task.dependsOn(TASK_COPY_ASSETS)
             task.dependsOn(TASK_GEN_GUIDES)
@@ -211,6 +223,7 @@ class GrailsWebsitePlugin implements Plugin<Project> {
             task.finalizedBy(TASK_GEN_PLUGINS)
             task.finalizedBy(TASK_RENDER_MINUTES)
             task.finalizedBy(TASK_GEN_SITEMAP)
+            task.finalizedBy(TASK_GEN_HTACCESS)
             task.setDescription('Build Grails website - generates pages with 
HTML entries in pages and build/temp, renders blog and RSS feed, copies assets 
and generates a sitemap')
 
         })
diff --git a/buildSrc/src/main/groovy/org/grails/gradle/HtaccessTask.groovy 
b/buildSrc/src/main/groovy/org/grails/gradle/HtaccessTask.groovy
new file mode 100644
index 00000000000..a61e015b569
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/grails/gradle/HtaccessTask.groovy
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.gradle
+
+import groovy.transform.CompileStatic
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.TaskAction
+
+@CompileStatic
+class HtaccessTask extends DefaultTask {
+
+    @Input
+    final Property<File> output = project.objects.property(File)
+
+    @Input
+    final Property<String> url = project.objects.property(String)
+
+    @OutputFile
+    final RegularFileProperty htaccessFile = project.objects.fileProperty()
+
+    HtaccessTask() {
+        
htaccessFile.convention(project.layout.buildDirectory.file("dist/.htaccess"))
+    }
+
+    @TaskAction
+    void generateHtaccess() {
+        File outputDir = new File(output.get(), "dist")
+        if (!outputDir.exists()) {
+            outputDir.mkdirs()
+        }
+
+        File htaccess = new File(outputDir, ".htaccess")
+
+        String htaccessContent = generateHtaccessContent()
+
+        htaccess.text = htaccessContent
+        logger.lifecycle("Generated .htaccess file at: 
${htaccess.absolutePath}")
+    }
+
+    private String generateHtaccessContent() {
+        return '''# CSP permissions for grails.apache.org - 
https://issues.apache.org/jira/browse/INFRA-27297
+# Ref https://docs.kapa.ai/integrations/understanding-csp-cors
+SetEnv CSP_PROJECT_DOMAINS "https://*.kapa.ai/ 
https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app 
https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 
https://hcaptcha.com https://*.hcaptcha.com";
+'''
+    }
+}

Reply via email to