Skip to content

Commit 50cb0e3

Browse files
committed
fix(plugin-gradle): Try to locate the git system config without executing any processes
While it's not possible to match cgit's behavior exactly, this attempts to read the system gitconfig correcting a regression from 6.21.0 to 6.22.0. Fixes #2404
1 parent 2cc8c04 commit 50cb0e3

File tree

2 files changed

+83
-11
lines changed

2 files changed

+83
-11
lines changed

plugin-gradle/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`).
44

55
## [Unreleased]
6+
### Fixed
7+
* Respect system gitconfig when performing git operations ([#2404](https://github.com/diffplug/spotless/issues/2404))
68

79
## [7.0.4] - 2025-05-27
810
### Fixed

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GitRatchetGradle.java

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2023 DiffPlug
2+
* Copyright 2020-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,14 @@
1616
package com.diffplug.gradle.spotless;
1717

1818
import java.io.File;
19+
import java.io.IOException;
20+
import java.util.concurrent.atomic.AtomicReference;
1921

2022
import javax.annotation.Nullable;
2123

24+
import org.eclipse.jgit.errors.ConfigInvalidException;
2225
import org.eclipse.jgit.lib.Config;
26+
import org.eclipse.jgit.lib.StoredConfig;
2327
import org.eclipse.jgit.storage.file.FileBasedConfig;
2428
import org.eclipse.jgit.util.FS;
2529
import org.eclipse.jgit.util.SystemReader;
@@ -28,20 +32,86 @@
2832

2933
/** Gradle implementation of GitRatchet. */
3034
public class GitRatchetGradle extends GitRatchet<File> {
35+
private static final String[] GIT_EXEC_CANDIDATES = {"git", "git.exe", "git.cmd"};
36+
3137
static {
32-
preventJGitFromCallingExecutables();
38+
GitRatchetGradle.redirectJGitExecutions();
3339
}
3440

35-
static void preventJGitFromCallingExecutables() {
36-
SystemReader reader = SystemReader.getInstance();
37-
SystemReader.setInstance(new DelegatingSystemReader(reader) {
41+
static void redirectJGitExecutions() {
42+
SystemReader existing = SystemReader.getInstance();
43+
SystemReader.setInstance(new DelegatingSystemReader(existing) {
44+
private AtomicReference<FileBasedConfig> systemConfig = new AtomicReference<>();
45+
46+
@Override
47+
public StoredConfig getSystemConfig() throws ConfigInvalidException, IOException {
48+
FileBasedConfig c = systemConfig.get();
49+
if (c == null) {
50+
systemConfig.compareAndSet(null,
51+
this.openSystemConfig(this.getJGitConfig(), FS.DETECTED));
52+
c = systemConfig.get();
53+
}
54+
updateAll(c);
55+
return c;
56+
}
57+
58+
// lifted from SystemReader since it's private
59+
private void updateAll(Config config) throws ConfigInvalidException, IOException {
60+
if (config == null) {
61+
return;
62+
}
63+
64+
updateAll(config.getBaseConfig());
65+
if (config instanceof FileBasedConfig) {
66+
FileBasedConfig cfg = (FileBasedConfig) config;
67+
if (cfg.isOutdated()) {
68+
cfg.load();
69+
}
70+
}
71+
}
72+
3873
@Override
39-
public String getenv(String variable) {
40-
if ("PATH".equals(variable)) {
41-
return "";
42-
} else {
43-
return super.getenv(variable);
74+
public FileBasedConfig openSystemConfig(final Config parent, final FS fs) {
75+
// cgit logic: https://git.kernel.org/pub/scm/git/git.git/tree/config.c#n1973 - in git_system_config()
76+
// They check the GIT_CONFIG_SYSTEM env var first, then follow up with logic based on compile-time parameters
77+
// We can't replicate this exactly so we'll do the closest approximation that Gradle will allow.
78+
final String systemPath = this.getenv("GIT_CONFIG_SYSTEM");
79+
if (systemPath != null) {
80+
fs.setGitSystemConfig(new File(systemPath).getAbsoluteFile());
81+
return super.openSystemConfig(parent, fs);
82+
}
83+
84+
// match FS.searchPath
85+
File gitExec = null;
86+
final String path = this.getenv("PATH");
87+
if (path != null) {
88+
outer: for (final String p : path.split(File.pathSeparator)) {
89+
for (final String name : GIT_EXEC_CANDIDATES) {
90+
final File candidate = new File(p, name);
91+
if (candidate.isFile() && candidate.canExecute()) {
92+
gitExec = candidate.getAbsoluteFile();
93+
break outer;
94+
}
95+
}
96+
}
97+
}
98+
99+
// Guess at common locations
100+
if (gitExec != null) {
101+
// If git exec is at <prefix>/bin/git, this returns <prefix>
102+
File prefix = gitExec.getParentFile().getParentFile();
103+
104+
// Then we try to resolve a config
105+
final File systemConfig = new File(prefix, "etc/gitconfig");
106+
if (systemConfig.exists()) {
107+
fs.setGitSystemConfig(systemConfig);
108+
return super.openSystemConfig(parent, fs);
109+
}
44110
}
111+
112+
// Fallback to the non-prefixed path (this is not the logic that cgit uses, but oh well)
113+
fs.setGitSystemConfig(new File("/etc/gitconfig"));
114+
return super.openSystemConfig(parent, fs);
45115
}
46116
});
47117
}
@@ -70,7 +140,7 @@ public String getHostname() {
70140

71141
@Override
72142
public String getenv(String variable) {
73-
return reader.getProperty(variable);
143+
return reader.getenv(variable);
74144
}
75145

76146
@Override

0 commit comments

Comments
 (0)