Файли
openidea/src/features/run/application.ts
T
l0ng-ai ee5d912157 fix(java): run Application and Spring Boot configs from the project root (#1475)
Configurations created for a main class, and the Spring Boot applications
detected in a module, set their working directory to the module directory.
A relative path in the VM options (such as --module-path=app/server/target/dependency)
then resolved against the module and the JVM failed to start. They now leave the
working directory empty, so the process starts in the project root, which is what
an empty working directory means elsewhere. The module is still stored separately
and keeps supplying the classpath and the debugger's sources.

Fixes #1197
2026-11-05 13:55:34 +08:00

80 рядки
2.9 KiB
TypeScript

/**
* IDEA-style "Application" run configurations for Java / Kotlin main classes
* (Spring Boot applications get their own kind), the module a source file
* belongs to, and test configurations scoped to one class or method.
*/
import type { RunConfig } from "@/platform/ipc";
import { CLASSPATH, TEST_CLASSPATH, jvmModuleDir } from "@/platform/javaLaunch";
import { isTestPath, rootFor } from "@/platform/languageSettings";
import { currentRoots } from "@/platform/projectRoots";
import { simpleClassName } from "./jvmTargets";
export { jvmModuleDir } from "@/platform/javaLaunch";
/**
* In a test source root, as IDEA's `getClasspathType` decides: the root holding the file
* (synced from Gradle, detected or marked in Project Structure) wins; `src/test` only
* while no root is known for the file.
*/
const isTestSource = (relPath: string) => {
const roots = currentRoots();
return rootFor(roots, relPath) ? isTestPath(roots, relPath) : /(^|\/)src\/test\//.test(relPath);
};
/** Temporary "Application" configuration that runs `className` (a binary name). */
export function applicationConfig(
target: { className: string; spring?: boolean },
relPath: string,
configs: readonly RunConfig[] = [],
): RunConfig {
const module = jvmModuleDir(relPath, configs);
return {
id: `application:${module ? `${module}:` : ""}${target.className}`,
name: simpleClassName(target.className),
kind: target.spring ? "spring-boot" : "application",
command: "java",
args: ["-cp", isTestSource(relPath) ? TEST_CLASSPATH : CLASSPATH, target.className],
cwd: null,
module,
env: {},
detected: true,
isTest: false,
debugAdapter: relPath.endsWith(".kt") ? "kotlin-debug-adapter" : "java-debug",
};
}
/**
* Narrows a Maven / Gradle test configuration to a class (`method` unset) or
* one method: Surefire `-Dtest=Class#method`, Gradle `--tests Class.method`.
* `fileConfig` is the file-level configuration whose last argument is the file filter.
*/
export function jvmTestConfig(fileConfig: RunConfig, className: string, method: string | undefined): RunConfig | null {
const args = fileConfig.args.slice(0, -1);
const simple = simpleClassName(className);
const name = method ? `${simple}.${method}` : simple;
const id = `context:target:${fileConfig.id}:${className}${method ? `#${method}` : ""}`;
switch (fileConfig.kind) {
case "maven":
return {
...fileConfig,
id,
name,
env: { ...fileConfig.env },
args: [...args, `-Dtest=${className}${method ? `#${method}` : ""}`, "-Dsurefire.failIfNoSpecifiedTests=false"],
};
case "gradle":
return {
...fileConfig,
id,
name,
env: { ...fileConfig.env },
args: [
...(args[args.length - 1] === "--tests" ? args.slice(0, -1) : args),
"--tests",
method ? `${className}.${method}` : className,
],
};
}
return null;
}