feat: discover default AI test toolchain
This commit is contained in:
@@ -19,6 +19,7 @@ import java.util.Properties;
|
||||
public class AiTestSettingsService {
|
||||
|
||||
private final Path settingsFile;
|
||||
private final ToolchainSettingsDetector detector;
|
||||
|
||||
@Autowired
|
||||
public AiTestSettingsService(WorkUtilsProperties properties) {
|
||||
@@ -29,20 +30,31 @@ public class AiTestSettingsService {
|
||||
this(paths.resolve("data", "ai-test"));
|
||||
}
|
||||
|
||||
AiTestSettingsService(ApplicationPaths paths, ToolchainSettingsDetector detector) {
|
||||
this(paths.resolve("data", "ai-test"), detector);
|
||||
}
|
||||
|
||||
private AiTestSettingsService(Path aiTestDataDirectory) {
|
||||
this(aiTestDataDirectory, ToolchainSettingsDetector.system());
|
||||
}
|
||||
|
||||
AiTestSettingsService(Path aiTestDataDirectory, ToolchainSettingsDetector detector) {
|
||||
this.settingsFile = aiTestDataDirectory.resolve("settings.properties");
|
||||
this.detector = detector;
|
||||
}
|
||||
|
||||
public AiTestSettings load() throws IOException {
|
||||
if (Files.notExists(settingsFile)) {
|
||||
return AiTestSettings.defaults();
|
||||
AiTestSettings detected = detector.complete(AiTestSettings.defaults());
|
||||
save(detected);
|
||||
return detected;
|
||||
}
|
||||
Properties values = new Properties();
|
||||
try (InputStream input = Files.newInputStream(settingsFile)) {
|
||||
values.load(input);
|
||||
}
|
||||
AiTestSettings defaults = AiTestSettings.defaults();
|
||||
return new AiTestSettings(
|
||||
AiTestSettings loaded = new AiTestSettings(
|
||||
Path.of(values.getProperty("jdk8.home", defaults.jdk8Home().toString())),
|
||||
Path.of(values.getProperty("maven.home", defaults.mavenHome().toString())),
|
||||
values.getProperty("codefree.command", defaults.codeFreeCommand()),
|
||||
@@ -52,6 +64,11 @@ public class AiTestSettingsService {
|
||||
Math.toIntExact(defaults.codeFreeTimeout().toSeconds()))),
|
||||
Duration.ofSeconds(integer(values, "maven.timeout.seconds",
|
||||
Math.toIntExact(defaults.mavenTimeout().toSeconds()))));
|
||||
AiTestSettings completed = detector.complete(loaded);
|
||||
if (!completed.equals(loaded)) {
|
||||
save(completed);
|
||||
}
|
||||
return completed;
|
||||
}
|
||||
|
||||
public void save(AiTestSettings settings) throws IOException {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.example.workutils.biz.aitest.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class ToolchainSettingsDetector {
|
||||
private static final Path WINDOWS_JDK8 = Path.of("C:/Program Files/Java/jdk-1.8");
|
||||
private static final Path WINDOWS_MAVEN = Path.of("D:/bestpay-maven/apache-maven-3.8.6");
|
||||
|
||||
private final Map<String, String> environment;
|
||||
private final Map<String, String> properties;
|
||||
private final Supplier<String> mavenVersion;
|
||||
private final Predicate<Path> directoryExists;
|
||||
private final String osName;
|
||||
|
||||
public ToolchainSettingsDetector(Map<String, String> environment, Map<String, String> properties,
|
||||
Supplier<String> mavenVersion, Predicate<Path> directoryExists,
|
||||
String osName) {
|
||||
this.environment = environment;
|
||||
this.properties = properties;
|
||||
this.mavenVersion = mavenVersion;
|
||||
this.directoryExists = directoryExists;
|
||||
this.osName = osName;
|
||||
}
|
||||
|
||||
public static ToolchainSettingsDetector system() {
|
||||
return new ToolchainSettingsDetector(System.getenv(),
|
||||
Map.of("java.home", System.getProperty("java.home", "")),
|
||||
ToolchainSettingsDetector::readMavenVersion, Files::isDirectory,
|
||||
System.getProperty("os.name", ""));
|
||||
}
|
||||
|
||||
public AiTestSettings complete(AiTestSettings saved) {
|
||||
Path jdk = specified(saved.jdk8Home()) ? saved.jdk8Home() : detectJdk8();
|
||||
Path maven = specified(saved.mavenHome()) ? saved.mavenHome() : detectMaven();
|
||||
return new AiTestSettings(jdk, maven, saved.codeFreeCommand(), saved.coverageTarget(),
|
||||
saved.maxRepairRounds(), saved.codeFreeTimeout(), saved.mavenTimeout());
|
||||
}
|
||||
|
||||
private Path detectJdk8() {
|
||||
Path environmentHome = path(environment.get("JAVA_HOME"));
|
||||
if (usable(environmentHome)) return normalizeJdk(environmentHome);
|
||||
Path runtimeHome = normalizeJdk(path(properties.get("java.home")));
|
||||
if (usable(runtimeHome)) return runtimeHome;
|
||||
return windows() && usable(WINDOWS_JDK8) ? WINDOWS_JDK8 : Path.of("");
|
||||
}
|
||||
|
||||
private Path detectMaven() {
|
||||
for (String key : new String[]{"MAVEN_HOME", "M2_HOME"}) {
|
||||
Path candidate = path(environment.get(key));
|
||||
if (usable(candidate)) return candidate;
|
||||
}
|
||||
Path parsed = parseMavenHome(mavenVersion.get());
|
||||
if (usable(parsed)) return parsed;
|
||||
return windows() && usable(WINDOWS_MAVEN) ? WINDOWS_MAVEN : Path.of("");
|
||||
}
|
||||
|
||||
static Path parseMavenHome(String output) {
|
||||
if (output != null) {
|
||||
for (String line : output.split("\\R")) {
|
||||
if (line.regionMatches(true, 0, "Maven home:", 0, "Maven home:".length())) {
|
||||
return path(line.substring("Maven home:".length()).trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Path.of("");
|
||||
}
|
||||
|
||||
private Path normalizeJdk(Path value) {
|
||||
if (value != null && value.getFileName() != null
|
||||
&& "jre".equalsIgnoreCase(value.getFileName().toString())) {
|
||||
return value.getParent();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean usable(Path path) {
|
||||
return path != null && !path.toString().isBlank() && directoryExists.test(path);
|
||||
}
|
||||
|
||||
private static boolean specified(Path path) {
|
||||
return path != null && !path.toString().isBlank();
|
||||
}
|
||||
|
||||
private boolean windows() {
|
||||
return osName.toLowerCase().contains("win");
|
||||
}
|
||||
|
||||
private static Path path(String value) {
|
||||
return value == null || value.isBlank() ? Path.of("") : Path.of(value.trim());
|
||||
}
|
||||
|
||||
private static String readMavenVersion() {
|
||||
try {
|
||||
Process process = new ProcessBuilder("mvn", "-version").redirectErrorStream(true).start();
|
||||
if (!process.waitFor(5, TimeUnit.SECONDS)) {
|
||||
process.destroyForcibly();
|
||||
return "";
|
||||
}
|
||||
return new String(process.getInputStream().readAllBytes(), Charset.defaultCharset());
|
||||
} catch (IOException | InterruptedException ignored) {
|
||||
if (ignored instanceof InterruptedException) Thread.currentThread().interrupt();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -6,6 +6,7 @@ import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@@ -26,11 +27,18 @@ class AiTestSettingsServiceTest {
|
||||
|
||||
@Test
|
||||
void returnsSafeDefaultsWhenNoSettingsExist(@TempDir Path home) throws Exception {
|
||||
AiTestSettings settings = new AiTestSettingsService(ApplicationPaths.of(home)).load();
|
||||
ToolchainSettingsDetector detector = new ToolchainSettingsDetector(
|
||||
Map.of("JAVA_HOME", "C:/jdk8", "MAVEN_HOME", "C:/maven"), Map.of(),
|
||||
() -> "", ignored -> true, "Windows 11");
|
||||
AiTestSettingsService service = new AiTestSettingsService(ApplicationPaths.of(home), detector);
|
||||
|
||||
AiTestSettings settings = service.load();
|
||||
|
||||
assertEquals(85, settings.coverageTarget());
|
||||
assertEquals(3, settings.maxRepairRounds());
|
||||
assertEquals("codefree", settings.codeFreeCommand());
|
||||
assertTrue(settings.jdk8Home().toString().isEmpty());
|
||||
assertEquals(Path.of("C:/jdk8"), settings.jdk8Home());
|
||||
assertEquals(Path.of("C:/maven"), settings.mavenHome());
|
||||
assertTrue(java.nio.file.Files.exists(service.settingsFile()));
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.example.workutils.biz.aitest.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class ToolchainSettingsDetectorTest {
|
||||
|
||||
@Test
|
||||
void discoversJdkRootFromJavaHomeJreAndParsesMavenHome() {
|
||||
ToolchainSettingsDetector detector = new ToolchainSettingsDetector(Map.of(),
|
||||
Map.of("java.home", "C:/Program Files/Java/jdk-1.8/jre"),
|
||||
() -> "Apache Maven 3.8.6\nMaven home: D:/bestpay-maven/apache-maven-3.8.6",
|
||||
ignored -> true, "Windows 11");
|
||||
|
||||
AiTestSettings result = detector.complete(AiTestSettings.defaults());
|
||||
|
||||
assertEquals(Path.of("C:/Program Files/Java/jdk-1.8"), result.jdk8Home());
|
||||
assertEquals(Path.of("D:/bestpay-maven/apache-maven-3.8.6"), result.mavenHome());
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsUsableSavedPathsAheadOfDiscoveredValues() {
|
||||
ToolchainSettingsDetector detector = new ToolchainSettingsDetector(
|
||||
Map.of("JAVA_HOME", "C:/auto-jdk", "MAVEN_HOME", "C:/auto-maven"),
|
||||
Map.of(), () -> "", ignored -> true, "Windows 11");
|
||||
AiTestSettings saved = new AiTestSettings(Path.of("C:/saved-jdk"), Path.of("C:/saved-maven"),
|
||||
"codefree", 85, 3, java.time.Duration.ofMinutes(5), java.time.Duration.ofMinutes(15));
|
||||
|
||||
AiTestSettings result = detector.complete(saved);
|
||||
|
||||
assertEquals(saved.jdk8Home(), result.jdk8Home());
|
||||
assertEquals(saved.mavenHome(), result.mavenHome());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user