mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 08:07:49 +00: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 <84506708+gudcks0305@users.noreply.github.com>
121 lines
5.4 KiB
TypeScript
121 lines
5.4 KiB
TypeScript
/** Linked Gradle builds use isolated native stubs; no real builds or files are touched. */
|
|
import type { GradleModel, RunConfig } from "../src/platform/ipc";
|
|
import { expect, ipcCalls, stubDesktop, test } from "./fixtures";
|
|
|
|
const build = (dir: string): GradleModel => ({
|
|
dir,
|
|
command: `/dev/acme-api/${dir}/gradlew`,
|
|
env: { JAVA_HOME: `/${dir}/jdk` },
|
|
javaVersion: 21,
|
|
syncedAt: 1,
|
|
stale: false,
|
|
syncError: null,
|
|
projects: [
|
|
{ path: ":", name: dir, dir, buildFile: `${dir}/build.gradle`, tasks: [] },
|
|
{
|
|
path: ":app",
|
|
name: "app",
|
|
dir: `${dir}/app`,
|
|
buildFile: `${dir}/app/build.gradle`,
|
|
tasks: [{ name: "assemble", group: "build", description: "Assembles this project" }],
|
|
},
|
|
],
|
|
});
|
|
|
|
test("links independent Gradle roots, runs identical task paths in their own builds and unlinks without deletion", async ({
|
|
workbench: page,
|
|
}, info) => {
|
|
await stubDesktop(page);
|
|
await page.evaluate(
|
|
async ({ first, second }) => {
|
|
let linked = [first];
|
|
let runId = 0;
|
|
const model = () => ({ maven: null, gradle: linked });
|
|
const h = window.__ipc.handlers;
|
|
h.build_model = model;
|
|
h.build_sync = model;
|
|
h.run_configs = () => [];
|
|
h.run_apply_settings = (args) => args.configs;
|
|
h.gradle_link_projects = () => {
|
|
if (!linked.some((g) => g.dir === second.dir)) linked = [...linked, second];
|
|
return model();
|
|
};
|
|
h.gradle_unlink_projects = (args) => {
|
|
linked = linked.filter((g) => !(args.paths as string[]).includes(g.dir));
|
|
return model();
|
|
};
|
|
h["plugin:dialog|open"] = () => ["/dev/acme-api/second/settings.gradle"];
|
|
h.run_start = (args) => {
|
|
const config = args.config as RunConfig;
|
|
const id = ++runId;
|
|
setTimeout(() => window.__ipc.emit({ type: "runExited", run: id, code: 0 }), 50);
|
|
return { id, configId: config.id, name: config.name, pid: 4242 + id, running: true, pty: false };
|
|
};
|
|
const storeModule = "/src/features/build-tools/store.ts";
|
|
const { loadModel } = await import(/* @vite-ignore */ storeModule);
|
|
await loadModel();
|
|
const contributionsModule = "/src/workbench/contributions.ts";
|
|
const { toolWindowService } = await import(/* @vite-ignore */ contributionsModule);
|
|
toolWindowService().show("gradle", true);
|
|
},
|
|
{ first: build("first"), second: build("second") },
|
|
);
|
|
|
|
const tree = page.getByRole("tree", { name: "Gradle projects" });
|
|
await expect(tree.getByRole("treeitem", { name: "first", exact: true })).toBeVisible();
|
|
await expect(tree.getByRole("treeitem", { name: "second", exact: true })).toHaveCount(0);
|
|
await page.screenshot({ path: info.outputPath("gradle-one-root.png"), animations: "disabled" });
|
|
|
|
await page.getByRole("button", { name: "Link Gradle Projects", exact: true }).click();
|
|
await expect
|
|
.poll(() => ipcCalls(page, "gradle_link_projects"))
|
|
.toEqual([{ paths: ["/dev/acme-api/second/settings.gradle"] }]);
|
|
await expect(tree.getByRole("treeitem", { name: "second", exact: true })).toBeVisible();
|
|
// Reloading the model reads the persisted linkage again.
|
|
await page.evaluate(async () => {
|
|
const storeModule = "/src/features/build-tools/store.ts";
|
|
const { loadModel } = await import(/* @vite-ignore */ storeModule);
|
|
await loadModel();
|
|
const actionModule = "/src/platform/actions.ts";
|
|
const { executeAction } = await import(/* @vite-ignore */ actionModule);
|
|
await executeAction("gradle.expandAll");
|
|
await executeAction("gradle.toggleOffline");
|
|
});
|
|
const tasks = tree.getByRole("treeitem", { name: /^assemble\b/ });
|
|
await expect(tasks).toHaveCount(2);
|
|
await page.screenshot({ path: info.outputPath("gradle-two-roots.png"), animations: "disabled" });
|
|
|
|
await tasks.nth(0).dblclick();
|
|
await expect.poll(async () => (await ipcCalls(page, "run_start")).length).toBe(1);
|
|
await tasks.nth(1).dblclick();
|
|
await expect.poll(async () => (await ipcCalls(page, "run_start")).length).toBe(2);
|
|
const runs = (await ipcCalls(page, "run_start")).map((args) => args.config as RunConfig);
|
|
expect(runs[0]!.id).not.toBe(runs[1]!.id);
|
|
for (const [index, dir] of ["first", "second"].entries()) {
|
|
expect(runs[index]).toMatchObject({
|
|
command: `/dev/acme-api/${dir}/gradlew`,
|
|
cwd: dir,
|
|
args: [":app:assemble", "--offline"],
|
|
env: { JAVA_HOME: `/${dir}/jdk` },
|
|
});
|
|
}
|
|
|
|
for (const dir of ["second", "first"]) {
|
|
await tree.getByRole("treeitem", { name: dir, exact: true }).click({ button: "right" });
|
|
await page.getByRole("menuitem", { name: "Unlink Gradle Project", exact: true }).click();
|
|
const dialog = page.getByRole("dialog", { name: "Unlink Gradle project?" });
|
|
await expect(dialog).toContainText("Files will remain");
|
|
await dialog.getByRole("button", { name: "Unlink", exact: true }).click();
|
|
await expect(tree.getByRole("treeitem", { name: dir, exact: true })).toHaveCount(0);
|
|
}
|
|
await expect
|
|
.poll(() => ipcCalls(page, "gradle_unlink_projects"))
|
|
.toEqual([{ paths: ["second"] }, { paths: ["first"] }]);
|
|
await expect(page.getByText("No Gradle projects", { exact: true })).toBeVisible();
|
|
await expect(page.getByRole("button", { name: "Link Gradle Projects", exact: true })).toBeVisible();
|
|
expect(
|
|
await page.evaluate(() => window.__ipc.calls.filter((c) => /^fs_(?:delete|remove|trash)/.test(c.cmd))),
|
|
).toEqual([]);
|
|
await page.screenshot({ path: info.outputPath("gradle-unlinked.png"), animations: "disabled" });
|
|
});
|