You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@grails.apache.org by "sanjana2505006 (via GitHub)" <gi...@apache.org> on 2026/04/04 19:05:39 UTC

[PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

sanjana2505006 opened a new pull request, #15555:
URL: https://github.com/apache/grails-core/pull/15555

   Summary of the changes:
   1. A 'formatCode' Gradle task that invokes the IntelliJ command-line formatter.
   2. An 'installGitHooks' task to easily setup pre-commit hooks for all developers.
   3. A pre-commit hook script in etc/hooks that formats only staged .groovy and .java files.
   4. Robust detection of common IntelliJ installation paths on Mac and Linux.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3126587568


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsFormatPlugin.groovy:
##########
@@ -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) {

Review Comment:
   Done, split it into `registerGitHooks(project)` and `registerFormattingTasks(project)`, and now apply() calls both.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty merged PR #15555:
URL: https://github.com/apache/grails-core/pull/15555


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041302679


##########
build.gradle:
##########
@@ -27,10 +31,10 @@ 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)
+            .filter { s -> !s.isEmpty() }

Review Comment:
   Please revert these changes.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3117534400


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -108,8 +112,10 @@ 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
+        if (project.tasks.names.contains('checkstyleTest')) {

Review Comment:
   While we do need to eventually format our tests, we have agreed to not do so at this time.  We should leave styles and only adjust the styles when working on the tests.  



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3068395510


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -108,8 +112,10 @@ 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
+        if (project.tasks.names.contains('checkstyleTest')) {

Review Comment:
   I originally added this to focus the initial rollout on production source code and avoid overwhelming the PR with style violations from the existing test suite. However, I agree that tests should ideally follow the same standards. Would you prefer that I remove this block and enable styling for tests as well?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3068446812


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {
+                        def commonPaths = [
+                                "/Applications/IntelliJ IDEA.app/Contents/bin/$executable",
+                                "/Applications/IntelliJ IDEA CE.app/Contents/bin/$executable"
+                        ]
+                        for (path in commonPaths) {
+                            File f = new File(path)
+                            if (f.exists()) {
+                                formatExec = f
+                                break
+                            }
+                        }
+                    }
+
+                    if (formatExec == null && !Os.isFamily(Os.FAMILY_WINDOWS)) {
+                        // On Linux/Mac, try to find 'idea' in PATH
+                        try {
+                            def out = new ByteArrayOutputStream()
+                            project.exec { ExecSpec exec ->
+                                exec.commandLine 'which', 'idea'
+                                exec.standardOutput = out
+                                exec.ignoreExitValue = true
+                            }
+                            def path = out.toString().trim()
+                            if (path) {
+                                formatExec = new File(new File(path).parentFile, executable)
+                            }
+                        } catch (Exception ignored) { }
+                    }
+                }
+
+                if (formatExec == null || !formatExec.exists()) {
+                    project.logger.error("IntelliJ formatter executable not found.")
+                    project.logger.error("Please set 'idea.home' property or IDEA_HOME environment variable to your IntelliJ installation directory.")
+                    project.logger.error("Example: ./gradlew formatCode -Pidea.home=/Applications/IntelliJ\\ IDEA.app/Contents")
+                    throw new RuntimeException("IntelliJ formatter executable not found.")
+                }
+
+                def filesToFormat = project.findProperty('formatFiles')

Review Comment:
   I completely agree with the split. I've moved all the formatting logic into a separate `grails-format` plugin.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4845008891

   @matrei hold off. there's a problem - the format.sh / format bat is the correct way to invoke this.  The jetbrains toolbox installs an idea but it assumes it's not running / will only return once the app is closed.  I'm going to rework this.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041318796


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {

Review Comment:
   We should just make it a requirement that `idea` is on the path and reference the version on the path.  IntelliJ has an option to install the command line tools (https://www.jetbrains.com/help/idea/working-with-the-ide-features-from-command-line.html) so let's just reference the help article and not trying to be smart about locating it (anyone using JetBrains toolbox won't be installing it to /Applications or to a specific location)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041313629


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<Project> {
             )
         }
     }
+
+    private static void registerFormattingTasks(Project project) {

Review Comment:
   The code style work is planned to move to it's own repository (eventually).  I'm ok with putting the formatting logic adjacent to this plugin, but I don't think it should be in this plugin since it's effectively a root only plugin - the root project won't ever have sources.  Let's move this to it's own format plugin? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3068388841


##########
build.gradle:
##########
@@ -27,10 +31,10 @@ 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)
+            .filter { s -> !s.isEmpty() }

Review Comment:
   Done. I've reverted the changes to `buildInstant` in `build.gradle` and restored the original method references.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "matrei (via GitHub)" <gi...@apache.org>.
matrei commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3500454471


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsIJFormatterPlugin.groovy:
##########
@@ -0,0 +1,216 @@
+/*
+ *  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.apache.tools.ant.taskdefs.condition.Os
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.file.Directory
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Copy
+import org.gradle.process.ExecResult
+import org.gradle.process.ExecSpec
+import org.gradle.process.ExecOperations
+import javax.inject.Inject
+
+@CompileStatic
+class GrailsIJFormatterPlugin implements Plugin<Project> {
+
+    @Override
+    void apply(Project project) {
+        registerGitHooks(project)
+        registerFormattingTasks(project)
+    }
+
+    private static void registerGitHooks(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

Review Comment:
   ```suggestion
                   it.filePermissions {
                       it.unix('0755')
                   }
   ```



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsIJFormatterPlugin.groovy:
##########
@@ -0,0 +1,216 @@
+/*
+ *  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.apache.tools.ant.taskdefs.condition.Os
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.file.Directory
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Copy
+import org.gradle.process.ExecResult
+import org.gradle.process.ExecSpec
+import org.gradle.process.ExecOperations
+import javax.inject.Inject
+
+@CompileStatic
+class GrailsIJFormatterPlugin implements Plugin<Project> {
+
+    @Override
+    void apply(Project project) {
+        registerGitHooks(project)
+        registerFormattingTasks(project)
+    }
+
+    private static void registerGitHooks(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
+            }
+        }
+    }
+
+    private static void registerFormattingTasks(Project project) {
+        project.tasks.register('formatCode') { task ->
+            task.group = 'verification'

Review Comment:
   ```suggestion
   ```



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsIJFormatterPlugin.groovy:
##########
@@ -0,0 +1,216 @@
+/*
+ *  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.apache.tools.ant.taskdefs.condition.Os
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.file.Directory
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Copy
+import org.gradle.process.ExecResult
+import org.gradle.process.ExecSpec
+import org.gradle.process.ExecOperations
+import javax.inject.Inject
+
+@CompileStatic
+class GrailsIJFormatterPlugin implements Plugin<Project> {
+
+    @Override
+    void apply(Project project) {
+        registerGitHooks(project)
+        registerFormattingTasks(project)
+    }
+
+    private static void registerGitHooks(Project project) {
+        if (project == project.rootProject) {
+            project.tasks.register('installGitHooks', Copy) {
+                it.group = 'verification'

Review Comment:
   ```suggestion
   ```



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsIJFormatterPlugin.groovy:
##########


Review Comment:
   - Use `def` for local variables where the type can be inferred? (Rename variable if it improves readability).
   - Align on using parentheses for method calls?



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsIJFormatterPlugin.groovy:
##########
@@ -0,0 +1,216 @@
+/*
+ *  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.apache.tools.ant.taskdefs.condition.Os
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.file.Directory
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Copy
+import org.gradle.process.ExecResult
+import org.gradle.process.ExecSpec
+import org.gradle.process.ExecOperations
+import javax.inject.Inject
+
+@CompileStatic
+class GrailsIJFormatterPlugin implements Plugin<Project> {
+
+    @Override
+    void apply(Project project) {
+        registerGitHooks(project)
+        registerFormattingTasks(project)
+    }
+
+    private static void registerGitHooks(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
+            }
+        }
+    }
+
+    private static void registerFormattingTasks(Project project) {
+        project.tasks.register('formatCode') { task ->
+            task.group = 'verification'
+            task.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            ExecOperationsSupport execSupport = project.objects.newInstance(ExecOperationsSupport)
+            Provider<String> formatExecProvider = project.providers.gradleProperty('format.exec')
+            Provider<String> formatFilesProvider = project.providers.gradleProperty('formatFiles')
+
+            Directory rootProjectDir = project.rootProject.layout.projectDirectory
+            Directory projectDir = project.layout.projectDirectory
+            File formatterHome = new File(project.gradle.gradleUserHomeDir, 'grails-ij-formatter')
+
+            task.doLast {
+                String formatExec = resolveFormatExecutable(formatExecProvider.getOrNull())
+                String filesToFormat = formatFilesProvider.getOrNull()
+                File settingsFile = rootProjectDir.file('.idea/codeStyles/Project.xml').getAsFile()
+
+                if (!settingsFile.exists()) {
+                    throw new GradleException("IntelliJ code style settings not found at ${settingsFile.absolutePath}")
+                }
+
+                // The formatter is the full IDE in headless mode, and the platform allows only one instance per
+                // config/system directory. Point it at a private set of directories so it can run even while the
+                // developer has IntelliJ IDEA open against the default ones.
+                File ideaProperties = writeIsolatedInstanceProperties(formatterHome)
+
+                ByteArrayOutputStream output = new ByteArrayOutputStream()
+                ExecResult result
+                try {
+                    result = execSupport.execOperations.exec { ExecSpec exec ->
+                        exec.commandLine formatExec
+                        exec.args '-s', settingsFile.absolutePath
+                        exec.args '-mask', '*.java,*.groovy'
+                        exec.args '-r'
+                        if (filesToFormat) {
+                            exec.args(filesToFormat.split(','))
+                        } else {
+                            exec.args projectDir.getAsFile().absolutePath
+                        }
+                        exec.environment 'IDEA_PROPERTIES', ideaProperties.absolutePath
+                        exec.standardOutput = output
+                        exec.errorOutput = output
+                        exec.ignoreExitValue = true
+                    }
+                } catch (Exception e) {
+                    throw new GradleException("Failed to start the IntelliJ formatter '${formatExec}': ${e.message}", e)
+                }
+
+                String formatterOutput = output.toString()
+                task.logger.info(formatterOutput)
+                // With the isolated instance above this should not happen, but fail loudly rather than let a commit
+                // proceed with unformatted code if the formatter still could not acquire its instance.
+                if (formatterOutput.contains('Only one instance')) {
+                    task.logger.error(formatterOutput)
+                    throw new GradleException('The IntelliJ formatter could not start its own instance. ' +
+                            'Close IntelliJ IDEA and try again, or format the files from within the IDE.')
+                }
+                if (result.exitValue != 0) {
+                    task.logger.error(formatterOutput)
+                    throw new GradleException("IntelliJ formatter exited with code ${result.exitValue}. See output above.")
+                }
+            }
+        }
+    }
+
+    private static final List<String> UNIX_LAUNCHERS = ['idea.sh', 'idea'].asImmutable()
+    private static final List<String> WINDOWS_LAUNCHERS = ['idea64.exe', 'idea.exe', 'idea.bat', 'idea.cmd'].asImmutable()
+
+    /**
+     * Resolves the IntelliJ command line formatter ({@code format.sh}/{@code format.bat}).
+     * An explicit {@code -Pformat.exec} override wins; otherwise the script is looked up on the
+     * PATH directly and then as a sibling of an {@code idea} launcher on the PATH, which matches
+     * the standard install layout on Windows, macOS and Linux.
+     */
+    private static String resolveFormatExecutable(String override) {
+        if (override) {
+            return override
+        }
+
+        boolean windows = Os.isFamily(Os.FAMILY_WINDOWS)
+        String formatScript = windows ? 'format.bat' : 'format.sh'
+
+        File onPath = findOnPath(formatScript)
+        if (onPath) {
+            return onPath.absolutePath
+        }
+
+        List<String> launchers = windows ? WINDOWS_LAUNCHERS : UNIX_LAUNCHERS
+        for (String launcher : launchers) {
+            File found = findOnPath(launcher)
+            if (found) {
+                File sibling = new File(found.canonicalFile.parentFile, formatScript)
+                if (sibling.isFile()) {
+                    return sibling.absolutePath
+                }
+            }
+        }
+
+        throw new GradleException("Could not locate the IntelliJ command line formatter (${formatScript}).\n" +
+                "Add the IDE's bin directory to your PATH, or point 'format.exec' at it.\n" +
+                'The format script lives in the IDE bin directory, for example:\n' +
+                '  macOS:   <IDE>.app/Contents/bin/format.sh\n' +
+                '  Linux:   <IDE>/bin/format.sh\n' +
+                '  Windows: <IDE>\\bin\\format.bat\n' +
+                'Set it per invocation with -Pformat.exec=/path/to/' + formatScript + ', or persist it (recommended,\n' +
+                "and required for the git pre-commit hook) by adding 'format.exec=/path/to/${formatScript}' to\n" +
+                '~/.gradle/gradle.properties.\n' +
+                'See: https://www.jetbrains.com/help/idea/command-line-formatter.html')
+    }
+
+    /**
+     * Creates a private set of IntelliJ config/system/plugins/log directories and writes an
+     * {@code idea.properties} file pointing at them. Passing this file via the {@code IDEA_PROPERTIES}
+     * environment variable lets the formatter run as an isolated instance that does not collide with a
+     * running IDE. The directories are reused between runs to avoid re-initialising on every commit.
+     */
+    private static File writeIsolatedInstanceProperties(File home) {
+        File config = new File(home, 'config')
+        File system = new File(home, 'system')
+        File plugins = new File(home, 'plugins')
+        File log = new File(home, 'log')
+        for (File dir : [config, system, plugins, log]) {
+            dir.mkdirs()
+        }
+        Properties props = new Properties()
+        props.setProperty('idea.config.path', config.absolutePath)
+        props.setProperty('idea.system.path', system.absolutePath)
+        props.setProperty('idea.plugins.path', plugins.absolutePath)
+        props.setProperty('idea.log.path', log.absolutePath)
+        File propsFile = new File(home, 'idea.properties')
+        OutputStream out = new FileOutputStream(propsFile)
+        try {
+            props.store(out, 'Isolated IntelliJ instance for command line formatting')
+        } finally {
+            out.close()
+        }
+        return propsFile
+    }

Review Comment:
   ```suggestion
       private static File writeIsolatedInstanceProperties(File home) {
           def props = new Properties()
           ['config', 'system', 'plugins', 'log'].each {
               props.setProperty(
                       "idea.${it}.path",
                       new File(home, it).tap { it.mkdirs() }.absolutePath
               )
           }
           def propsFile = new File(home, 'idea.properties')
           propsFile.withOutputStream {
               props.store(it, 'Isolated IntelliJ instance for command line formatting')
           }
           propsFile
       }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "matrei (via GitHub)" <gi...@apache.org>.
matrei commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3180232384


##########
build-logic/plugins/build.gradle:
##########
@@ -62,6 +62,10 @@ gradlePlugin {
             id = 'org.apache.grails.gradle.grails-code-style'
             implementationClass = 'org.apache.grails.buildsrc.GrailsCodeStylePlugin'
         }
+        register('grailsFormat') {

Review Comment:
   Can we name this: `grailsIJFormatter`



##########
build-logic/plugins/build.gradle:
##########
@@ -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'

Review Comment:
   Can we have id: `org.apache.grails.gradle.grails-ij-formatter`



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsFormatPlugin.groovy:
##########
@@ -0,0 +1,101 @@
+/*
+ *  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) {
+        registerGitHooks(project)
+        registerFormattingTasks(project)
+    }
+
+    private static void registerGitHooks(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
+            }
+        }
+    }
+
+    private static void registerFormattingTasks(Project project) {
+        ExecOperationsSupport execSupport = project.objects.newInstance(ExecOperationsSupport)
+        def ideaExecProvider = project.providers.gradleProperty('idea.exec')
+                .orElse(Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'idea')

Review Comment:
   Is `format.bat` the correct way to call this on windows?
   https://www.jetbrains.com/help/idea/command-line-formatter.html



##########
build-logic/plugins/build.gradle:
##########
@@ -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'

Review Comment:
   Can we have: `org.apache.grails.buildsrc.GrailsIJFormatterPlugin`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4194563093

   <!-- Bito Reply -->
   To revert the changes in build.gradle, remove the added plugin block and revert the lambda expressions in the ext block back to method references.
   
   **build.gradle**
   ```
   /*
    *  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.
    */
   
   import java.time.Instant
   import java.time.LocalDate
   import java.time.ZoneOffset
   import java.time.format.DateTimeFormatter
   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)
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4299528342

   > @sanjana2505006 if you can get the rest of these comments implemented, I'll ping another reviewer and we can get this merged.
   
   Done, please have a look and let me know if there's anything I need to update.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3130733944


##########
build.gradle:
##########
@@ -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())

Review Comment:
   @sanjana2505006 this should not be removed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041321364


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {
+                        def commonPaths = [
+                                "/Applications/IntelliJ IDEA.app/Contents/bin/$executable",
+                                "/Applications/IntelliJ IDEA CE.app/Contents/bin/$executable"
+                        ]
+                        for (path in commonPaths) {
+                            File f = new File(path)
+                            if (f.exists()) {
+                                formatExec = f
+                                break
+                            }
+                        }
+                    }
+
+                    if (formatExec == null && !Os.isFamily(Os.FAMILY_WINDOWS)) {
+                        // On Linux/Mac, try to find 'idea' in PATH
+                        try {
+                            def out = new ByteArrayOutputStream()
+                            project.exec { ExecSpec exec ->
+                                exec.commandLine 'which', 'idea'
+                                exec.standardOutput = out
+                                exec.ignoreExitValue = true
+                            }
+                            def path = out.toString().trim()
+                            if (path) {
+                                formatExec = new File(new File(path).parentFile, executable)
+                            }
+                        } catch (Exception ignored) { }
+                    }
+                }
+
+                if (formatExec == null || !formatExec.exists()) {
+                    project.logger.error("IntelliJ formatter executable not found.")

Review Comment:
   It's deprecated to reference `project` from inside of a task.  `logger` should be available already.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4229938958

   > To revert the changes in build.gradle, remove the added plugin block and revert the lambda expressions in the ext block back to method references.
   > 
   > **build.gradle**
   > 
   > ```
   > /*
   >  *  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.
   >  */
   > 
   > import java.time.Instant
   > import java.time.LocalDate
   > import java.time.ZoneOffset
   > import java.time.format.DateTimeFormatter
   > 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)
   > ```
   
   I have reverted the `buildInstant` calculation to use the original method references and removed the extra filter. I am keeping the plugin application at the root level so that the new formatting tasks remain available for use.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3068445281


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {
+                        def commonPaths = [
+                                "/Applications/IntelliJ IDEA.app/Contents/bin/$executable",
+                                "/Applications/IntelliJ IDEA CE.app/Contents/bin/$executable"
+                        ]
+                        for (path in commonPaths) {
+                            File f = new File(path)
+                            if (f.exists()) {
+                                formatExec = f
+                                break
+                            }
+                        }
+                    }
+
+                    if (formatExec == null && !Os.isFamily(Os.FAMILY_WINDOWS)) {
+                        // On Linux/Mac, try to find 'idea' in PATH
+                        try {
+                            def out = new ByteArrayOutputStream()
+                            project.exec { ExecSpec exec ->
+                                exec.commandLine 'which', 'idea'
+                                exec.standardOutput = out
+                                exec.ignoreExitValue = true
+                            }
+                            def path = out.toString().trim()
+                            if (path) {
+                                formatExec = new File(new File(path).parentFile, executable)
+                            }
+                        } catch (Exception ignored) { }
+                    }
+                }
+
+                if (formatExec == null || !formatExec.exists()) {
+                    project.logger.error("IntelliJ formatter executable not found.")

Review Comment:
   I've refactored the task action to avoid any direct references to `project`, including switching from `project.logger` to the task's own `logger`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3068444196


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {

Review Comment:
   I've simplified the formatter discovery logic to rely on the `idea` command being on the system `PATH`, as suggested. I removed the redundant path-searching code and added a reference to the JetBrains help article in the error message if the command isn't found



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4473886672

   @sanjana2505006 Can you please take a look at @matrei feedback so we can get this merged? 
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041308861


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -108,8 +112,10 @@ 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
+        if (project.tasks.names.contains('checkstyleTest')) {

Review Comment:
   Can you help me understand why this change was necessary? 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3117539949


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -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.

Review Comment:
   This comment needs to stay.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "sanjana2505006 (via GitHub)" <gi...@apache.org>.
sanjana2505006 commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3068424514


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<Project> {
             )
         }
     }
+
+    private static void registerFormattingTasks(Project project) {

Review Comment:
   I've moved the formatting logic into its own dedicated plugin and registered it in the build-logic. I've also updated the root `build.gradle` to only apply this new format plugin.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4296146690

   @sanjana2505006 if you can get the rest of these comments implemented, I'll ping another reviewer and we can get this merged.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4194554349

   @sanjana2505006 we explicitly decided to not auto-install the hook so it would be optional if people wanted it.  


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041329677


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {
+                        def commonPaths = [
+                                "/Applications/IntelliJ IDEA.app/Contents/bin/$executable",
+                                "/Applications/IntelliJ IDEA CE.app/Contents/bin/$executable"
+                        ]
+                        for (path in commonPaths) {
+                            File f = new File(path)
+                            if (f.exists()) {
+                                formatExec = f
+                                break
+                            }
+                        }
+                    }
+
+                    if (formatExec == null && !Os.isFamily(Os.FAMILY_WINDOWS)) {
+                        // On Linux/Mac, try to find 'idea' in PATH
+                        try {
+                            def out = new ByteArrayOutputStream()
+                            project.exec { ExecSpec exec ->
+                                exec.commandLine 'which', 'idea'
+                                exec.standardOutput = out
+                                exec.ignoreExitValue = true
+                            }
+                            def path = out.toString().trim()
+                            if (path) {
+                                formatExec = new File(new File(path).parentFile, executable)
+                            }
+                        } catch (Exception ignored) { }
+                    }
+                }
+
+                if (formatExec == null || !formatExec.exists()) {
+                    project.logger.error("IntelliJ formatter executable not found.")
+                    project.logger.error("Please set 'idea.home' property or IDEA_HOME environment variable to your IntelliJ installation directory.")
+                    project.logger.error("Example: ./gradlew formatCode -Pidea.home=/Applications/IntelliJ\\ IDEA.app/Contents")
+                    throw new RuntimeException("IntelliJ formatter executable not found.")
+                }
+
+                def filesToFormat = project.findProperty('formatFiles')

Review Comment:
   I hadn't considered the useful of having a format task added to the subprojects.  I still think we should split the format tasks out from the code style though - otherwise you're trying to apply styling to the root project which we don't want to do.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4368537546

   ## ✅ All tests passed ✅
   
   🏷️ Commit: 8da88d32ed6614ee2b98787a931dfde69965853e
   ▶️ Tests:  18200 executed
   ⚪️ Checks: 33/33 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4844885640

   @matrei  this feedback is complete, can you please confirm it's ok to merge? 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4845901173

   ## ✅ All tests passed ✅
   
   🏷️ Commit: bb41c258b26cccc358d7e497e936837eb8f955df
   ▶️ Tests:  25131 executed
   ⚪️ Checks: 33/33 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3041333715


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -191,4 +197,88 @@ class GrailsCodeStylePlugin implements Plugin<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
+            }
+        }
+
+        project.tasks.register('formatCode') {
+            it.group = 'verification'
+            it.description = 'Formats Java and Groovy source files using the IntelliJ command line formatter'
+
+            it.doLast {
+                String ideaHome = (project.findProperty('idea.home') ?: System.getenv('IDEA_HOME')) as String
+                String executable = Os.isFamily(Os.FAMILY_WINDOWS) ? 'format.bat' : 'format.sh'
+                File formatExec = null
+
+                if (ideaHome) {
+                    formatExec = new File(ideaHome, "bin/$executable")
+                } else {
+                    // Try common paths on macOS
+                    if (Os.isFamily(Os.FAMILY_MAC)) {
+                        def commonPaths = [
+                                "/Applications/IntelliJ IDEA.app/Contents/bin/$executable",
+                                "/Applications/IntelliJ IDEA CE.app/Contents/bin/$executable"
+                        ]
+                        for (path in commonPaths) {
+                            File f = new File(path)
+                            if (f.exists()) {
+                                formatExec = f
+                                break
+                            }
+                        }
+                    }
+
+                    if (formatExec == null && !Os.isFamily(Os.FAMILY_WINDOWS)) {
+                        // On Linux/Mac, try to find 'idea' in PATH
+                        try {
+                            def out = new ByteArrayOutputStream()
+                            project.exec { ExecSpec exec ->
+                                exec.commandLine 'which', 'idea'
+                                exec.standardOutput = out
+                                exec.ignoreExitValue = true
+                            }
+                            def path = out.toString().trim()
+                            if (path) {
+                                formatExec = new File(new File(path).parentFile, executable)
+                            }
+                        } catch (Exception ignored) { }
+                    }
+                }
+
+                if (formatExec == null || !formatExec.exists()) {
+                    project.logger.error("IntelliJ formatter executable not found.")
+                    project.logger.error("Please set 'idea.home' property or IDEA_HOME environment variable to your IntelliJ installation directory.")
+                    project.logger.error("Example: ./gradlew formatCode -Pidea.home=/Applications/IntelliJ\\ IDEA.app/Contents")
+                    throw new RuntimeException("IntelliJ formatter executable not found.")
+                }
+
+                def filesToFormat = project.findProperty('formatFiles')
+                def settingsFile = project.rootProject.file('.idea/codeStyles/Project.xml')
+
+                if (!settingsFile.exists()) {
+                    throw new RuntimeException("IntelliJ code style settings not found at ${settingsFile.absolutePath}")
+                }
+
+                project.exec { ExecSpec exec ->

Review Comment:
   Take a look at the `publishAllToMavenLocal` task for how to do in this a modern Gradle way without referencing `project` .



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#discussion_r3117541839


##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy:
##########
@@ -107,23 +100,6 @@ class GrailsCodeStylePlugin implements Plugin<Project> {
         }
     }
 
-    private static void doNotApplyStylingToTests(Project project) {

Review Comment:
   This needs to stay.  We decided as a project to not yet do styling changes to the tests.  



##########
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsFormatPlugin.groovy:
##########
@@ -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) {

Review Comment:
   I think self-descriptive method names are great.  However, if you're going to have 1 method that does everything it's less useful.  Let's split this method into 2 and then call those 2 methods from apply?  
   
   registerGitHooks(project)
   registerFormattingTasks(project)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4304701971

   ## ✅ All tests passed ✅
   
   🏷️ Commit: 769f735714ec56198403ab5052e6f07c4ed1e7fa
   ▶️ Tests:  23459 executed
   ⚪️ Checks: 31/31 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4368296180

   @matrei  this looks accepatble to me.  Do you agree?  If so, we can merge.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Gradle tasks and Git hooks for IntelliJ-based code formatting (#15535) [grails-core]

Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on PR #15555:
URL: https://github.com/apache/grails-core/pull/15555#issuecomment-4845460894

   @matrei this should be fixed now.  You should be able to invoke the formatting independently of intellij running.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org