Show version-locked plugins in menu

This commit is contained in:
pleb
2026-07-05 15:01:58 -07:00
parent 1858f76766
commit 53ad6e2c0d
10 changed files with 212 additions and 83 deletions
+103 -4
View File
@@ -547,7 +547,7 @@ state_dir = ".state"
check_health.assert_not_called()
run_bootstrap.assert_not_called()
def test_enable_disabled_plugin_bootstraps_before_plan(self) -> None:
def test_enable_disabled_plugin_plans_before_bootstrap(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
work = Path(tmp)
instance = work / "instances" / "1.44.1"
@@ -628,7 +628,55 @@ install_strategy = "dll-to-plugins"
lockfile=str(lock_path),
repo=work,
)
self.assertEqual(call_order, ["ensure", "plan", "apply"])
self.assertEqual(call_order, ["plan", "ensure", "apply"])
def test_enable_locked_plugin_missing_asset_does_not_bootstrap(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
work = Path(tmp)
instance = work / "instances" / "1.44.1"
state = work / "state"
instance.mkdir(parents=True)
(instance / "Beat Saber_Data").mkdir()
(instance / "Plugins").mkdir()
(work / "locks").mkdir()
(work / "registry").mkdir()
lock_path = work / "locks" / "1.44.1.lock.toml"
lock_path.write_text(
"""
beat_saber_version = "1.44.1"
instance = "1.44.1"
[[plugins]]
id = "example"
tag = "v1.0.0"
asset = "Missing.dll"
""".lstrip(),
encoding="utf-8",
)
registry_path = work / "registry" / "plugins.toml"
registry_path.write_text(
"""
[[plugins]]
id = "example"
name = "Example"
install_strategy = "dll-to-plugins"
""".lstrip(),
encoding="utf-8",
)
with patch("plugin_helper.operations.ensure_healthy_bootstrap") as ensure:
with self.assertRaisesRegex(FileNotFoundError, "asset not found"):
enable_disabled_plugin(
instance="1.44.1",
instance_path=instance,
state_root=state,
plugin_id="example",
registry=str(registry_path),
lockfile=str(lock_path),
repo=work,
)
ensure.assert_not_called()
def test_plan_apply_and_uninstall_dll(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
@@ -1399,6 +1447,33 @@ sha256 = "{sha256_file(asset)}"
self.assertEqual(report["plugins"][0]["asset"], "Example.dll")
self.assertEqual(report["plugins"][0]["fileCount"], 1)
def test_installed_plugins_report_starts_from_version_lock(self) -> None:
registry = Registry(
{
"alpha": RegistryPlugin(id="alpha", name="Alpha", repo="owner/alpha"),
"beta": RegistryPlugin(id="beta", name="Beta", repo="owner/beta"),
}
)
lockfile = Lockfile(
beat_saber_version="1.40.8",
instance="1.40.8",
plugins=(
LockedPlugin(id="alpha", repo="owner/alpha", tag="v1.0.0", asset="Alpha.dll", sha256="a"),
LockedPlugin(id="beta", repo="owner/beta", tag="v2.0.0", asset="Beta.dll", sha256="b"),
),
)
report = installed_plugins_report(
installed_state={"instance": "1.40.8", "plugins": {}},
registry=registry,
lockfile=lockfile,
)
self.assertEqual([plugin["id"] for plugin in report["plugins"]], ["alpha", "beta"])
self.assertEqual([plugin["status"] for plugin in report["plugins"]], ["disabled", "disabled"])
self.assertEqual([plugin["fileCount"] for plugin in report["plugins"]], [0, 0])
self.assertEqual(report["plugins"][1]["version"], "v2.0.0")
def test_update_check_reports_current_matching_asset(self) -> None:
registry = Registry(
{
@@ -1535,7 +1610,13 @@ sha256 = "{sha256_file(asset)}"
self.assertEqual(result["plugins"][0]["latestAssetSha256"], "new")
def _make_tui_fixture(root: Path, *, disabled: bool = False, hash_mismatch: bool = False) -> tuple[PluginHelperTui, Path, Path]:
def _make_tui_fixture(
root: Path,
*,
disabled: bool = False,
hash_mismatch: bool = False,
recorded: bool = True,
) -> tuple[PluginHelperTui, Path, Path]:
repo = root / "repo"
instance_root = root / "instances"
instance = instance_root / "1.40.8"
@@ -1574,7 +1655,10 @@ sha256 = "{sha256_file(asset)}"
)
target = instance / "Plugins" / "Example.dll"
if disabled:
if not recorded:
plugins = {}
disabled_plugins = {}
elif disabled:
plugins = {}
disabled_plugins = {
"example": {
@@ -1762,6 +1846,21 @@ class PluginHelperTuiTests(unittest.IsolatedAsyncioTestCase):
self.assertIn("example", updated["plugins"])
self.assertNotIn("example", updated["disabledPlugins"])
async def test_space_enables_locked_unrecorded_plugin_from_asset(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
app, instance, state = _make_tui_fixture(Path(tmp), recorded=False)
async with app.run_test() as pilot:
self.assertEqual(app.mode, "plugins")
self.assertEqual(app.plugin_rows[0]["status"], "disabled")
await pilot.press("space")
await pilot.pause()
self.assertEqual((instance / "Plugins" / "Example.dll").read_bytes(), b"managed dll")
updated = load_installed_state(state, "1.40.8")
self.assertIn("example", updated["plugins"])
self.assertNotIn("example", updated.get("disabledPlugins", {}))
async def test_disable_all_disables_enabled_plugins(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
app, instance, state = _make_tui_fixture(Path(tmp))