дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
The Gradle model came from a static parse of settings.gradle, which cannot follow includeFlat, projectDir assignments, computed include lists or included builds, so those modules were missing from the Gradle tool window, the Project view, indexing and run. Sync now runs an init script that prints every evaluated project (identity path, directory, build directory, source sets with test classification, Java version) without resolving dependencies; the static parser stays as the fallback before the first sync. Modules outside the root become content roots, the Project view lists the build's module group above the project folder, an unsynced Gradle build is imported once when opened, and staleness ignores comments and whitespace in build scripts. Application / Spring Boot configurations of a Gradle module run through a JavaExec task on the source set's runtime classpath by default (Settings › Build Tools › Gradle › Build and run using), with the debugger attached to the forked JVM. The build model reaches run and the Project view through a platform store rather than a cross-feature import. Fixes #737 Fixes #861 Co-authored-by: ntbang0901 <[email protected]>
126 рядки
4.3 KiB
TypeScript
126 рядки
4.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { FileEntry } from "@/bindings";
|
|
import { buildModel, DEFAULT_TREE_OPTIONS, type ExtraRoot, withExtraRoots } from "./model";
|
|
import { gradleModuleGroups } from "./moduleGroups";
|
|
|
|
type Shown = { label: string; detail?: string; children?: Shown[] };
|
|
const shape = (e: ExtraRoot): Shown => ({
|
|
label: e.label,
|
|
...(e.detail ? { detail: e.detail } : {}),
|
|
...(e.children ? { children: e.children.map(shape) } : {}),
|
|
});
|
|
|
|
describe("gradleModuleGroups (IDEA's module groups)", () => {
|
|
// `includeFlat` sibling modules, one with layer modules nested in its folder.
|
|
const flat = [
|
|
{ path: ":", dir: "" },
|
|
{ path: ":common", dir: "/w/common" },
|
|
{ path: ":billing", dir: "/w/billing" },
|
|
...["core", "api"].map((l) => ({ path: `:billing:${l}`, dir: `/w/billing/modules/${l}` })),
|
|
];
|
|
|
|
it("lists every module of the group, nested ones flattened, as IntelliJ shows it", () => {
|
|
expect(gradleModuleGroups(flat, "Shop", "/w/shop").map(shape)).toEqual([
|
|
{
|
|
label: "Shop",
|
|
children: [
|
|
{ label: "api", detail: "Shop.billing.api" },
|
|
{ label: "billing", detail: "Shop.billing" },
|
|
{ label: "common", detail: "Shop.common" },
|
|
{ label: "core", detail: "Shop.billing.core" },
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("shows no group while every module lives in the project folder", () => {
|
|
const inside = [
|
|
{ path: ":", dir: "" },
|
|
{ path: ":app", dir: "app" },
|
|
{ path: ":libs:core", dir: "libs/core" },
|
|
];
|
|
expect(gradleModuleGroups(inside, "demo", "/w/demo")).toEqual([]);
|
|
});
|
|
|
|
it("keeps a subgroup that no module is named like", () => {
|
|
const projects = [
|
|
{ path: ":", dir: "" },
|
|
{ path: ":svc", dir: "/w/svc" },
|
|
{ path: ":libs:a", dir: "/w/libs/a" },
|
|
{ path: ":libs:b", dir: "/w/libs/b" },
|
|
];
|
|
expect(gradleModuleGroups(projects, "R", "/w/r").map(shape)).toEqual([
|
|
{
|
|
label: "R",
|
|
children: [
|
|
{
|
|
label: "libs",
|
|
children: [
|
|
{ label: "a", detail: "R.libs.a" },
|
|
{ label: "b", detail: "R.libs.b" },
|
|
],
|
|
},
|
|
{ label: "svc", detail: "R.svc" },
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("names an included build's modules after it and lists it as an ungrouped module", () => {
|
|
const projects = [
|
|
{ path: ":", dir: "" },
|
|
{ path: ":app", dir: "app" },
|
|
{ path: ":buildSrc", dir: "buildSrc", build: ":buildSrc" },
|
|
{ path: ":lib", dir: "/w/lib", build: ":lib" },
|
|
{ path: ":lib:core", dir: "/w/lib/core", build: ":lib" },
|
|
];
|
|
expect(gradleModuleGroups(projects, "Shop", "/w/shop").map(shape)).toEqual([{ label: "lib" }]);
|
|
// Beside includeFlat modules: the group (every `Shop.*` module), then the included build.
|
|
const both = [...projects, { path: ":svc", dir: "/w/svc" }];
|
|
expect(gradleModuleGroups(both, "Shop", "/w/shop").map(shape)).toEqual([
|
|
{
|
|
label: "Shop",
|
|
children: [
|
|
{ label: "app", detail: "Shop.app" },
|
|
{ label: "buildSrc", detail: "Shop.buildSrc" },
|
|
{ label: "svc", detail: "Shop.svc" },
|
|
],
|
|
},
|
|
{ label: "lib" },
|
|
]);
|
|
});
|
|
});
|
|
|
|
const dir = (path: string): FileEntry => ({
|
|
name: path.slice(path.lastIndexOf("/") + 1),
|
|
path,
|
|
kind: "dir",
|
|
size: 0,
|
|
mtimeMs: 1,
|
|
ignored: false,
|
|
excluded: false,
|
|
hidden: false,
|
|
});
|
|
|
|
describe("module group nodes in the tree", () => {
|
|
it("lists the group above the project and keeps a nested module whose parent is expanded", () => {
|
|
const listings = new Map([
|
|
["/w/billing", [dir("/w/billing/modules")]],
|
|
["/w/billing/modules", [dir("/w/billing/modules/core")]],
|
|
]);
|
|
const base = buildModel({ path: "/p", name: "p" }, new Map(), DEFAULT_TREE_OPTIONS);
|
|
const group = {
|
|
label: "Shop",
|
|
icon: "gradle-project",
|
|
beforeProject: true,
|
|
children: [
|
|
{ label: "billing", icon: "gradle-module", path: "/w/billing" },
|
|
{ label: "core", icon: "gradle-module", path: "/w/billing/modules/core" },
|
|
],
|
|
};
|
|
const m = withExtraRoots(base, [group], listings, DEFAULT_TREE_OPTIONS);
|
|
expect(m.roots.map((r) => r.label)).toEqual(["Shop", "p"]);
|
|
expect(m.children.get(m.roots[0]!.key)!.map((n) => n.label)).toEqual(["billing", "core"]);
|
|
});
|
|
});
|