дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +02:00
fix(run): keep temporary run configurations following the toolchain settings (#1167)
Temporary run configurations were kept with what settings derived when they were made (absolute mvn, -s / -Dmaven.repo.local, JAVA_HOME), and never went through the backend again, so after a Maven home / settings file / JDK change they and gutter test runs narrowed from them still ran the old ones. They are now kept without derived values (run_without_derived) and get the current settings applied when the run list loads (run_apply_settings). Maven's settings file and local repository apply to every Maven configuration unless it sets them itself. Earlier stored entries are dropped once. Refs #822
Цей коміт міститься в:
1 джерело
59567f1af0
коміт
d3b9a39831
10 files changed
+269
-33
No files matched your search
@@ -391,7 +391,7 @@ describe("temporary configurations", () => {
|
||||
expect(s.temporary).not.toContain(apps[0]!.id);
|
||||
expect(s.selectedId).toBe(apps[apps.length - 1]!.id);
|
||||
expect(s.configs.filter((c) => c.kind === "application")).toHaveLength(MAX_TEMPORARY);
|
||||
expect(JSON.parse(localStorage.getItem("openidea.run.temporary:/p")!)).toHaveLength(MAX_TEMPORARY);
|
||||
expect(JSON.parse(localStorage.getItem("openidea.run.temporary.v2:/p")!)).toHaveLength(MAX_TEMPORARY);
|
||||
// Reusing an existing temporary moves it last instead of duplicating it.
|
||||
adoptTemporary(apps[3]!);
|
||||
expect(useRun.getState().temporary.at(-1)).toBe(apps[3]!.id);
|
||||
|
||||
@@ -198,7 +198,10 @@ export async function loadConfigs(): Promise<void> {
|
||||
const saved = await call(commands.runConfigs());
|
||||
if (useProject.getState().project?.root !== root) return;
|
||||
// Temporary configs survive reloads (and restarts) until saved or evicted; a saved one wins.
|
||||
const temps = readTemporary(root).filter((t) => !saved.some((c) => c.id === t.id));
|
||||
// They are kept without what settings derived: today's toolchains apply to them, as to the others.
|
||||
const kept = readTemporary(root).filter((t) => !saved.some((c) => c.id === t.id));
|
||||
const temps = kept.length ? await call(commands.runApplySettings(kept)).catch(() => kept) : kept;
|
||||
if (useProject.getState().project?.root !== root) return;
|
||||
const configs = [...saved, ...temps];
|
||||
const stored = useRun.getState().selectedId ?? readSelected(root);
|
||||
const selectedId =
|
||||
@@ -312,7 +315,8 @@ export function selectedConfig(): RunConfig | undefined {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Temporary configurations (IDEA: created by gutter / context runs, at most 5)
|
||||
|
||||
const TEMPORARY_KEY = "openidea.run.temporary:";
|
||||
// v2: kept without settings-derived values (earlier entries froze the toolchain they were made with).
|
||||
const TEMPORARY_KEY = "openidea.run.temporary.v2:";
|
||||
export const MAX_TEMPORARY = 5;
|
||||
|
||||
function readTemporary(root: string): RunConfig[] {
|
||||
@@ -335,14 +339,23 @@ function writeTemporary(root: string, configs: RunConfig[]) {
|
||||
}
|
||||
}
|
||||
|
||||
let persisting = 0;
|
||||
|
||||
function persistTemporary() {
|
||||
const root = useProject.getState().project?.root;
|
||||
if (!root) return;
|
||||
const { configs, temporary } = useRun.getState();
|
||||
writeTemporary(
|
||||
root,
|
||||
temporary.map((id) => configs.find((c) => c.id === id)).filter((c): c is RunConfig => !!c),
|
||||
);
|
||||
const list = temporary.map((id) => configs.find((c) => c.id === id)).filter((c): c is RunConfig => !!c);
|
||||
writeTemporary(root, list);
|
||||
if (!list.length || !isTauri()) return;
|
||||
// Then rewritten without what settings derived (the project's Maven, JDK, interpreter…), so a
|
||||
// later settings change reaches them as it does detected and saved configurations.
|
||||
const generation = ++persisting;
|
||||
void call(commands.runWithoutDerived(list))
|
||||
.then((kept) => {
|
||||
if (generation === persisting && useProject.getState().project?.root === root) writeTemporary(root, kept);
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
/** IDEA's `isConfigurationFromContext` for an Application: the same main class of the same module. */
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { afterEach, beforeEach, expect, it, vi } from "vitest";
|
||||
|
||||
const ipc = vi.hoisted(() => ({
|
||||
runConfigs: vi.fn(),
|
||||
runWithoutDerived: vi.fn(),
|
||||
runApplySettings: vi.fn(),
|
||||
}));
|
||||
vi.mock("@/platform/ipc", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("@/platform/ipc")>()),
|
||||
isTauri: () => true,
|
||||
commands: ipc,
|
||||
}));
|
||||
|
||||
import type { RunConfig } from "@/platform/ipc";
|
||||
import { useProject } from "@/platform/project";
|
||||
import { adoptTemporary, loadConfigs, resetRuns, useRun } from "./store";
|
||||
|
||||
const KEY = "openidea.run.temporary.v2:/p";
|
||||
const ok = <T>(data: T) => Promise.resolve({ status: "ok" as const, data });
|
||||
|
||||
/** A Maven test run made from the tool window, with the settings of the day baked in. */
|
||||
const goal: RunConfig = {
|
||||
id: "maven:goal:pom.xml:test",
|
||||
name: "app [test]",
|
||||
kind: "maven",
|
||||
command: "/old/maven/bin/mvn",
|
||||
args: ["-s", "/old/settings.xml", "test"],
|
||||
cwd: null,
|
||||
env: { JAVA_HOME: "/old/jdk" },
|
||||
detected: false,
|
||||
isTest: true,
|
||||
debugAdapter: null,
|
||||
};
|
||||
|
||||
let mavenHome = "/new/maven";
|
||||
beforeEach(() => {
|
||||
resetRuns();
|
||||
localStorage.clear();
|
||||
useProject.setState({ project: { root: "/p" } as never });
|
||||
ipc.runConfigs.mockImplementation(() => ok([]));
|
||||
// The backend drops what settings derived, and applies the current settings again.
|
||||
ipc.runWithoutDerived.mockImplementation((configs: RunConfig[]) =>
|
||||
ok(
|
||||
configs.map((c) => ({
|
||||
...c,
|
||||
command: "mvn",
|
||||
args: c.args.filter((a, i, all) => a !== "-s" && all[i - 1] !== "-s"),
|
||||
env: {},
|
||||
})),
|
||||
),
|
||||
);
|
||||
ipc.runApplySettings.mockImplementation((configs: RunConfig[]) =>
|
||||
ok(
|
||||
configs.map((c) => ({
|
||||
...c,
|
||||
command: `${mavenHome}/bin/mvn`,
|
||||
args: ["-s", `${mavenHome}/conf/settings.xml`, ...c.args],
|
||||
env: { JAVA_HOME: "/new/jdk" },
|
||||
})),
|
||||
),
|
||||
);
|
||||
});
|
||||
afterEach(() => useProject.setState({ project: null }));
|
||||
|
||||
it("keeps temporary configurations without settings-derived values and applies today's settings on load", async () => {
|
||||
adoptTemporary(goal);
|
||||
await vi.waitFor(() => expect(JSON.parse(localStorage.getItem(KEY)!)[0].command).toBe("mvn"));
|
||||
const kept = JSON.parse(localStorage.getItem(KEY)!)[0] as RunConfig;
|
||||
expect(kept.args).toEqual(["test"]);
|
||||
expect(kept.env).toEqual({});
|
||||
|
||||
// Settings › Maven changed: the reload after it brings the temporary configuration along.
|
||||
mavenHome = "/moved/maven";
|
||||
await loadConfigs();
|
||||
const loaded = useRun.getState().configs.find((c) => c.id === goal.id)!;
|
||||
expect(useRun.getState().temporary).toEqual([goal.id]);
|
||||
expect(loaded.command).toBe("/moved/maven/bin/mvn");
|
||||
expect(loaded.args).toEqual(["-s", "/moved/maven/conf/settings.xml", "test"]);
|
||||
expect(loaded.env).toEqual({ JAVA_HOME: "/new/jdk" });
|
||||
});
|
||||
Reference in new issue
Заблокувати користувача