дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +02:00
Opening a folder of independent Gradle builds selected only the first build. Link Gradle Projects… (pick a build's settings or build file) and Unlink on a build's root let an ordinary project window manage several independent builds without changing their scripts. The build model holds a list of Gradle builds; each keeps its own wrapper, working directory, environment, task routing and sync cache, keyed by the owning build directory. The links persist in the project's Gradle settings (linkedProjects); unlinking leaves files and saved run configurations alone. Existing includeBuild support is unchanged, and an explicitly linked build takes precedence over a composite that also includes it. Workspace windows keep Link/Unlink disabled. Co-authored-by: gudcks0305 <[email protected]>
138 рядки
4.8 KiB
TypeScript
138 рядки
4.8 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"]);
|
|
});
|
|
});
|
|
|
|
it("namespaces module group identities by independently linked build", () => {
|
|
const projects = [
|
|
{ path: ":", dir: "/w/first" },
|
|
{ path: ":app", dir: "/w/shared" },
|
|
];
|
|
const first = gradleModuleGroups(projects, "same", "/w/project", "first");
|
|
const second = gradleModuleGroups(projects, "same", "/w/project", "second");
|
|
expect(first.length).toBeGreaterThan(0);
|
|
expect(first[0]!.id).not.toBe(second[0]!.id);
|
|
expect(first.map(shape)).toEqual(second.map(shape));
|
|
});
|