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" +''' + } +}
