Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build-logic/plugins/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ gradlePlugin {
id = 'org.apache.grails.gradle.grails-code-style'
implementationClass = 'org.apache.grails.buildsrc.GrailsCodeStylePlugin'
}
register('grailsFormat') {
id = 'org.apache.grails.gradle.grails-format'
implementationClass = 'org.apache.grails.buildsrc.GrailsFormatPlugin'
}
register('groovydocEnhancer') {
id = 'org.apache.grails.buildsrc.groovydoc-enhancer'
implementationClass = 'org.apache.grails.buildsrc.GroovydocEnhancerPlugin'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import groovy.transform.CompileStatic

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.plugins.quality.Checkstyle
import org.gradle.api.plugins.quality.CheckstyleExtension
import org.gradle.api.plugins.quality.CheckstylePlugin
Expand All @@ -49,17 +48,11 @@ class GrailsCodeStylePlugin implements Plugin<Project> {
void apply(Project project) {
initExtension(project)
configureCodeStyle(project)
doNotApplyStylingToTests(project)
}

private static void initExtension(Project project) {
def gce = project.extensions.create('grailsCodeStyle', GrailsCodeStyleExtension)

// Unfortunately, the codenarc plugin is still using a non-lazy property.
// Rather than rewrite the plugin to use afterEvaluate,
// this plugin uses properties to override the configuration location by default


gce.checkstyleDirectory.set(project.provider {
def directory = project.hasProperty(CHECKSTYLE_DIR_PROPERTY) ?
project.rootProject.layout.projectDirectory.dir(project.property(CHECKSTYLE_DIR_PROPERTY) as String) :
Expand Down Expand Up @@ -107,23 +100,6 @@ class GrailsCodeStylePlugin implements Plugin<Project> {
}
}

private static void doNotApplyStylingToTests(Project project) {
project.tasks.named('checkstyleTest') {
it.enabled = false // Do not check test sources at this time
}

project.afterEvaluate {
// Do not check test sources at this time
['codenarcIntegrationTest', 'codenarcTest'].each { testTaskName ->
if (project.tasks.names.contains(testTaskName)) {
project.tasks.named(testTaskName) {
it.enabled = false
}
}
}
}
}

private static void configureCodeStyle(Project project) {
configureCheckstyle(project)
configureCodenarc(project)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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
*
* https://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.apache.grails.buildsrc

import groovy.transform.CompileStatic
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Copy
import org.gradle.process.ExecSpec
import org.gradle.process.ExecOperations
import javax.inject.Inject
import org.apache.tools.ant.taskdefs.condition.Os

@CompileStatic
class GrailsFormatPlugin implements Plugin<Project> {

@Override
void apply(Project project) {
registerFormattingTasks(project)
}

private static void registerFormattingTasks(Project project) {
if (project == project.rootProject) {
project.tasks.register('installGitHooks', Copy) {
it.group = 'verification'
it.description = 'Installs the git pre-commit hook for automatic code formatting'
it.from(project.rootProject.layout.projectDirectory.file('etc/hooks/pre-commit'))
it.into(project.rootProject.layout.projectDirectory.dir('.git/hooks'))
it.fileMode = 0755
}
}

ExecOperationsSupport execSupport = project.objects.newInstance(ExecOperationsSupport)
def ideaExecProvider = project.providers.gradleProperty('idea.exec')
.orElse(Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'idea')
def formatFilesProvider = project.providers.gradleProperty('formatFiles')
def rootProjectDir = project.rootProject.projectDir
def projectDir = project.projectDir

project.tasks.register('formatCode') { task ->
task.group = 'verification'
task.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'

task.doLast {
String ideaExec = ideaExecProvider.get()
def filesToFormat = formatFilesProvider.getOrNull()
def settingsFile = new File(rootProjectDir, '.idea/codeStyles/Project.xml')

if (!settingsFile.exists()) {
throw new RuntimeException("IntelliJ code style settings not found at ${settingsFile.absolutePath}")
}

try {
execSupport.execOperations.exec { ExecSpec exec ->
exec.commandLine ideaExec
if (ideaExec == 'idea') {
exec.args 'format'
}
exec.args '-s', settingsFile.absolutePath
exec.args '-mask', '*.java,*.groovy'
exec.args '-r'
if (filesToFormat) {
exec.args((filesToFormat.toString()).split(','))
} else {
exec.args projectDir.absolutePath
}
}
} catch (Exception e) {
task.logger.error("IntelliJ formatter failed to execute.")
task.logger.error("Please ensure IntelliJ command line tools are installed and available on your PATH.")
task.logger.error("See: https://www.jetbrains.com/help/idea/working-with-the-ide-features-from-command-line.html")
throw new RuntimeException("IntelliJ formatter failed. See logs for details.", e)
}
}
}
}
}

interface ExecOperationsSupport {
@Inject
ExecOperations getExecOperations()
}
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
* limitations under the License.
*/

plugins {
id 'org.apache.grails.gradle.grails-format'
}

import java.time.Instant
import java.time.LocalDate
import java.time.ZoneOffset
Expand All @@ -27,7 +31,6 @@ import org.apache.tools.ant.taskdefs.condition.Os
ext {
isReproducibleBuild = System.getenv("SOURCE_DATE_EPOCH") != null
buildInstant = java.util.Optional.ofNullable(System.getenv("SOURCE_DATE_EPOCH"))
.filter(s -> !s.isEmpty())
.map(Long::parseLong)
.map(Instant::ofEpochSecond)
.orElseGet(Instant::now)
Expand Down
41 changes: 41 additions & 0 deletions etc/hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
#
# 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
#
# https://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.
#

set -e

# Get staged files that are Groovy or Java
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.(groovy|java)$' || true)

if [ -n "$STAGED_FILES" ]; then
echo "Formatting staged Groovy/Java files using IntelliJ formatter..."

# Convert newline-separated list to comma-separated for Gradle property
FILES_COMMAS=$(echo "$STAGED_FILES" | tr '\n' ',' | sed 's/,$//')

# Run the Gradle formatting task
./gradlew :formatCode -PformatFiles="$FILES_COMMAS"

# Re-stage the files in case they were modified by the formatter
for FILE in $STAGED_FILES; do
if [ -f "$FILE" ]; then
git add "$FILE"
fi
done
fi