Skip to content

Commit 4cf8137

Browse files
lazer-devntwigg
authored andcommitted
git pre push hook windows fix
1 parent 94da761 commit 4cf8137

File tree

4 files changed

+187
-35
lines changed

4 files changed

+187
-35
lines changed

lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstaller.java

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,12 @@ private void uninstall(File gitHookFile) throws Exception {
192192
* @param commandApply The command to apply corrections.
193193
* @return A string template representing the Spotless Git pre-push hook content.
194194
*/
195-
protected String preHookTemplate(String executor, String commandCheck, String commandApply) {
195+
protected String preHookTemplate(Executor executor, String commandCheck, String commandApply) {
196196
var spotlessHook = "";
197197

198198
spotlessHook += "\n";
199199
spotlessHook += "\n" + HOOK_HEADER;
200-
spotlessHook += "\nSPOTLESS_EXECUTOR=" + executor;
200+
spotlessHook += "\nSPOTLESS_EXECUTOR=" + executorPath(executor);
201201
spotlessHook += "\nif ! $SPOTLESS_EXECUTOR " + commandCheck + " ; then";
202202
spotlessHook += "\n echo 1>&2 \"spotless found problems, running " + commandApply + "; commit the result and re-push\"";
203203
spotlessHook += "\n $SPOTLESS_EXECUTOR " + commandApply;
@@ -209,6 +209,58 @@ protected String preHookTemplate(String executor, String commandCheck, String co
209209
return spotlessHook;
210210
}
211211

212+
/**
213+
* Determines the path to the build tool executor (Maven or Gradle).
214+
* This method first checks for the existence of a wrapper script in the project root.
215+
* If the wrapper exists, returns a relative path to it, otherwise returns the global command.
216+
*
217+
* @param executor The build tool executor (GRADLE or MAVEN)
218+
* @return The path to the executor - either the wrapper script path (e.g., "./gradlew")
219+
* or the global command (e.g., "gradle")
220+
*/
221+
private String executorPath(Executor executor) {
222+
final var wrapper = executorWrapperFile(executor);
223+
if (wrapper.exists()) {
224+
return "./" + wrapper.getName();
225+
}
226+
227+
logger.info("Local %s wrapper (%s) not found, falling back to global command '%s'",
228+
executor.name().toLowerCase(), executor.wrapper, executor.global);
229+
230+
return executor.global;
231+
}
232+
233+
/**
234+
* Resolves the wrapper script file for the specified build tool executor.
235+
* On Windows systems, checks for both .bat and .cmd extensions.
236+
* On non-Windows systems, uses the wrapper name without extension.
237+
*
238+
* @param executor The build tool executor (GRADLE or MAVEN)
239+
* @return The File object representing the wrapper script
240+
*/
241+
private File executorWrapperFile(Executor executor) {
242+
if (isWindows()) {
243+
final var bat = root.toPath().resolve(executor.wrapper + ".bat").toFile();
244+
if (bat.exists()) {
245+
return bat;
246+
}
247+
248+
return root.toPath().resolve(executor.wrapper + ".cmd").toFile();
249+
}
250+
251+
return root.toPath().resolve(executor.wrapper).toFile();
252+
}
253+
254+
/**
255+
* Checks if the current operating system is Windows.
256+
* This is determined by checking if the "os.name" system property contains "win".
257+
*
258+
* @return true if the current OS is Windows, false otherwise
259+
*/
260+
private boolean isWindows() {
261+
return System.getProperty("os.name").toLowerCase().startsWith("win");
262+
}
263+
212264
/**
213265
* Checks if Git is installed by validating the existence of `.git/config` in the repository root.
214266
*
@@ -243,6 +295,19 @@ private void writeFile(File file, String content, boolean append) throws IOExcep
243295
}
244296
}
245297

298+
public enum Executor {
299+
GRADLE("gradlew", "gradle"),
300+
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

lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerGradle.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package com.diffplug.spotless;
1717

18+
import static com.diffplug.spotless.GitPrePushHookInstaller.Executor.GRADLE;
19+
1820
import java.io.File;
1921

2022
/**
@@ -23,30 +25,15 @@
2325
*/
2426
public class GitPrePushHookInstallerGradle extends GitPrePushHookInstaller {
2527

26-
/**
27-
* The Gradle wrapper file (`gradlew`) located in the root directory of the project.
28-
*/
29-
private final File gradlew;
30-
3128
public GitPrePushHookInstallerGradle(GitPreHookLogger logger, File root) {
3229
super(logger, root);
33-
this.gradlew = root.toPath().resolve("gradlew").toFile();
3430
}
3531

3632
/**
3733
* {@inheritDoc}
3834
*/
3935
@Override
4036
protected String preHookContent() {
41-
return preHookTemplate(executorPath(), "spotlessCheck", "spotlessApply");
42-
}
43-
44-
private String executorPath() {
45-
if (gradlew.exists()) {
46-
return gradlew.getAbsolutePath();
47-
}
48-
49-
logger.info("Gradle wrapper is not installed, using global gradle");
50-
return "gradle";
37+
return preHookTemplate(GRADLE, "spotlessCheck", "spotlessApply");
5138
}
5239
}

lib/src/main/java/com/diffplug/spotless/GitPrePushHookInstallerMaven.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package com.diffplug.spotless;
1717

18+
import static com.diffplug.spotless.GitPrePushHookInstaller.Executor.MAVEN;
19+
1820
import java.io.File;
1921

2022
/**
@@ -23,27 +25,15 @@
2325
*/
2426
public class GitPrePushHookInstallerMaven extends GitPrePushHookInstaller {
2527

26-
private final File mvnw;
27-
2828
public GitPrePushHookInstallerMaven(GitPreHookLogger logger, File root) {
2929
super(logger, root);
30-
this.mvnw = root.toPath().resolve("mvnw").toFile();
3130
}
3231

3332
/**
3433
* {@inheritDoc}
3534
*/
3635
@Override
3736
protected String preHookContent() {
38-
return preHookTemplate(executorPath(), "spotless:check", "spotless:apply");
39-
}
40-
41-
private String executorPath() {
42-
if (mvnw.exists()) {
43-
return mvnw.getAbsolutePath();
44-
}
45-
46-
logger.info("Maven wrapper is not installed, using global maven");
47-
return "mvn";
37+
return preHookTemplate(MAVEN, "spotless:check", "spotless:apply");
4838
}
4939
}

testlib/src/test/java/com/diffplug/spotless/GitPrePushHookInstallerTest.java

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,22 @@
1515
*/
1616
package com.diffplug.spotless;
1717

18+
import static com.diffplug.spotless.GitPrePushHookInstaller.Executor.GRADLE;
19+
import static com.diffplug.spotless.GitPrePushHookInstaller.Executor.MAVEN;
1820
import static org.assertj.core.api.Assertions.assertThat;
1921

2022
import java.util.ArrayList;
2123
import java.util.List;
2224

25+
import org.junit.jupiter.api.AfterEach;
26+
import org.junit.jupiter.api.BeforeEach;
2327
import org.junit.jupiter.api.Test;
2428

2529
import com.diffplug.spotless.GitPrePushHookInstaller.GitPreHookLogger;
2630

2731
class GitPrePushHookInstallerTest extends ResourceHarness {
32+
private final static String OS = System.getProperty("os.name");
33+
2834
private final List<String> logs = new ArrayList<>();
2935
private final GitPreHookLogger logger = new GitPreHookLogger() {
3036
@Override
@@ -43,6 +49,16 @@ public void error(String format, Object... arguments) {
4349
}
4450
};
4551

52+
@BeforeEach
53+
public void beforeEach() {
54+
System.setProperty("os.name", "linux");
55+
}
56+
57+
@AfterEach
58+
public void afterEach() {
59+
System.setProperty("os.name", OS);
60+
}
61+
4662
@Test
4763
public void should_not_create_pre_hook_file_when_git_is_not_installed() throws Exception {
4864
// given
@@ -71,7 +87,7 @@ public void should_use_global_gradle_when_gradlew_is_not_installed() throws Exce
7187
assertThat(logs).hasSize(4);
7288
assertThat(logs).element(0).isEqualTo("Installing git pre-push hook");
7389
assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it");
74-
assertThat(logs).element(2).isEqualTo("Gradle wrapper is not installed, using global gradle");
90+
assertThat(logs).element(2).isEqualTo("Local gradle wrapper (gradlew) not found, falling back to global command 'gradle'");
7591
assertThat(logs).element(3).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath());
7692

7793
final var content = gradleHookContent("git_pre_hook/pre-push.created-tpl", ExecutorType.GLOBAL);
@@ -217,23 +233,117 @@ public void should_use_global_maven_when_maven_wrapper_is_not_installed() throws
217233
assertThat(logs).hasSize(4);
218234
assertThat(logs).element(0).isEqualTo("Installing git pre-push hook");
219235
assertThat(logs).element(1).isEqualTo("Git pre-push hook not found, creating it");
220-
assertThat(logs).element(2).isEqualTo("Maven wrapper is not installed, using global maven");
236+
assertThat(logs).element(2).isEqualTo("Local maven wrapper (mvnw) not found, falling back to global command 'mvn'");
221237
assertThat(logs).element(3).isEqualTo("Git pre-push hook installed successfully to the file " + newFile(".git/hooks/pre-push").getAbsolutePath());
222238

223239
final var content = mavenHookContent("git_pre_hook/pre-push.created-tpl", ExecutorType.GLOBAL);
224240
assertFile(".git/hooks/pre-push").hasContent(content);
225241
}
226242

243+
@Test
244+
public void should_use_maven_bat_wrapper_when_exists_for_windows() {
245+
// given
246+
System.setProperty("os.name", "Windows 10");
247+
setFile("mvnw.bat").toContent("");
248+
setFile("mvnw.cmd").toContent("");
249+
250+
final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder());
251+
252+
// when
253+
final var hook = gradle.preHookTemplate(MAVEN, "spotless:check", "spotless:apply");
254+
255+
// then
256+
assertThat(hook).contains("SPOTLESS_EXECUTOR=./mvnw.bat");
257+
}
258+
259+
@Test
260+
public void should_use_maven_cmd_wrapper_when_exists_for_windows() {
261+
// given
262+
System.setProperty("os.name", "Windows 10");
263+
setFile("mvnw.cmd").toContent("");
264+
265+
final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder());
266+
267+
// when
268+
final var hook = gradle.preHookTemplate(MAVEN, "spotless:check", "spotless:apply");
269+
270+
// then
271+
assertThat(hook).contains("SPOTLESS_EXECUTOR=./mvnw.cmd");
272+
}
273+
274+
@Test
275+
public void should_use_maven_global_when_bat_and_cmd_files_not_exists_for_windows() {
276+
// given
277+
System.setProperty("os.name", "Windows 10");
278+
setFile("mvnw").toContent("");
279+
280+
final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder());
281+
282+
// when
283+
final var hook = gradle.preHookTemplate(MAVEN, "spotless:check", "spotless:apply");
284+
285+
// then
286+
assertThat(hook).contains("SPOTLESS_EXECUTOR=mvn");
287+
}
288+
289+
@Test
290+
public void should_use_gradle_bat_wrapper_when_exists_for_windows() {
291+
// given
292+
System.setProperty("os.name", "Windows 10");
293+
setFile("gradlew.bat").toContent("");
294+
setFile("gradlew.cmd").toContent("");
295+
setFile("gradlew").toContent("");
296+
297+
final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder());
298+
299+
// when
300+
final var hook = gradle.preHookTemplate(GRADLE, "spotlessCheck", "spotlessApply");
301+
302+
// then
303+
assertThat(hook).contains("SPOTLESS_EXECUTOR=./gradlew.bat");
304+
}
305+
306+
@Test
307+
public void should_use_gradle_cmd_wrapper_when_exists_for_windows() {
308+
// given
309+
System.setProperty("os.name", "Windows 10");
310+
setFile("gradlew.cmd").toContent("");
311+
setFile("gradlew").toContent("");
312+
313+
final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder());
314+
315+
// when
316+
final var hook = gradle.preHookTemplate(GRADLE, "spotlessCheck", "spotlessApply");
317+
318+
// then
319+
assertThat(hook).contains("SPOTLESS_EXECUTOR=./gradlew.cmd");
320+
}
321+
322+
@Test
323+
public void should_use_gradle_global_when_bat_and_cmd_files_not_exists_for_windows() {
324+
// given
325+
System.setProperty("os.name", "Windows 10");
326+
setFile("gradlew").toContent("");
327+
328+
final var gradle = new GitPrePushHookInstallerMaven(logger, rootFolder());
329+
330+
// when
331+
final var hook = gradle.preHookTemplate(GRADLE, "spotlessCheck", "spotlessApply");
332+
333+
// then
334+
assertThat(hook).contains("SPOTLESS_EXECUTOR=gradle");
335+
}
336+
227337
private String gradleHookContent(String resourcePath, ExecutorType executorType) {
228338
return getTestResource(resourcePath)
229-
.replace("${executor}", executorType == ExecutorType.WRAPPER ? newFile("gradlew").getAbsolutePath() : "gradle")
339+
.replace("${executor}", executorType == ExecutorType.WRAPPER ? "./" + newFile("gradlew").getName() : "gradle")
230340
.replace("${checkCommand}", "spotlessCheck")
231341
.replace("${applyCommand}", "spotlessApply");
232342
}
233343

234344
private String mavenHookContent(String resourcePath, ExecutorType executorType) {
235345
return getTestResource(resourcePath)
236-
.replace("${executor}", executorType == ExecutorType.WRAPPER ? newFile("mvnw").getAbsolutePath() : "mvn")
346+
.replace("${executor}", executorType == ExecutorType.WRAPPER ? "./" + newFile("mvnw").getName() : "mvn")
237347
.replace("${checkCommand}", "spotless:check")
238348
.replace("${applyCommand}", "spotless:apply");
239349
}

0 commit comments

Comments
 (0)