2222import java .io .FileWriter ;
2323import java .io .IOException ;
2424import java .nio .file .Files ;
25+ import java .util .Locale ;
2526
2627/**
2728 * Abstract class responsible for installing a Git pre-push hook in a repository.
@@ -192,12 +193,12 @@ private void uninstall(File gitHookFile) throws Exception {
192193 * @param commandApply The command to apply corrections.
193194 * @return A string template representing the Spotless Git pre-push hook content.
194195 */
195- protected String preHookTemplate (String executor , String commandCheck , String commandApply ) {
196+ protected String preHookTemplate (Executor executor , String commandCheck , String commandApply ) {
196197 var spotlessHook = "" ;
197198
198199 spotlessHook += "\n " ;
199200 spotlessHook += "\n " + HOOK_HEADER ;
200- spotlessHook += "\n SPOTLESS_EXECUTOR=" + executor ;
201+ spotlessHook += "\n SPOTLESS_EXECUTOR=" + executorPath ( executor ) ;
201202 spotlessHook += "\n if ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then" ;
202203 spotlessHook += "\n echo 1>&2 \" spotless found problems, running " + commandApply + "; commit the result and re-push\" " ;
203204 spotlessHook += "\n $SPOTLESS_EXECUTOR " + commandApply ;
@@ -209,6 +210,58 @@ protected String preHookTemplate(String executor, String commandCheck, String co
209210 return spotlessHook ;
210211 }
211212
213+ /**
214+ * Determines the path to the build tool executor (Maven or Gradle).
215+ * This method first checks for the existence of a wrapper script in the project root.
216+ * If the wrapper exists, returns a relative path to it, otherwise returns the global command.
217+ *
218+ * @param executor The build tool executor (GRADLE or MAVEN)
219+ * @return The path to the executor - either the wrapper script path (e.g., "./gradlew")
220+ * or the global command (e.g., "gradle")
221+ */
222+ private String executorPath (Executor executor ) {
223+ final var wrapper = executorWrapperFile (executor );
224+ if (wrapper .exists ()) {
225+ return "./" + wrapper .getName ();
226+ }
227+
228+ logger .info ("Local %s wrapper (%s) not found, falling back to global command '%s'" ,
229+ executor .name ().toLowerCase (Locale .ROOT ), executor .wrapper , executor .global );
230+
231+ return executor .global ;
232+ }
233+
234+ /**
235+ * Resolves the wrapper script file for the specified build tool executor.
236+ * On Windows systems, checks for both .bat and .cmd extensions.
237+ * On non-Windows systems, uses the wrapper name without extension.
238+ *
239+ * @param executor The build tool executor (GRADLE or MAVEN)
240+ * @return The File object representing the wrapper script
241+ */
242+ private File executorWrapperFile (Executor executor ) {
243+ if (isWindows ()) {
244+ final var bat = root .toPath ().resolve (executor .wrapper + ".bat" ).toFile ();
245+ if (bat .exists ()) {
246+ return bat ;
247+ }
248+
249+ return root .toPath ().resolve (executor .wrapper + ".cmd" ).toFile ();
250+ }
251+
252+ return root .toPath ().resolve (executor .wrapper ).toFile ();
253+ }
254+
255+ /**
256+ * Checks if the current operating system is Windows.
257+ * This is determined by checking if the "os.name" system property contains "win".
258+ *
259+ * @return true if the current OS is Windows, false otherwise
260+ */
261+ private boolean isWindows () {
262+ return System .getProperty ("os.name" ).toLowerCase (Locale .ROOT ).startsWith ("win" );
263+ }
264+
212265 /**
213266 * Checks if Git is installed by validating the existence of `.git/config` in the repository root.
214267 *
@@ -243,6 +296,18 @@ private void writeFile(File file, String content, boolean append) throws IOExcep
243296 }
244297 }
245298
299+ public enum Executor {
300+ GRADLE ("gradlew" , "gradle" ), MAVEN ("mvnw" , "mvn" ),;
301+
302+ public final String wrapper ;
303+ public final String global ;
304+
305+ Executor (String wrapper , String global ) {
306+ this .wrapper = wrapper ;
307+ this .global = global ;
308+ }
309+ }
310+
246311 public interface GitPreHookLogger {
247312 void info (String format , Object ... arguments );
248313
0 commit comments