mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-30 20:54:32 +08:00
fix(plugin): preserve market package generation
This commit is contained in:
@@ -86,6 +86,7 @@ class PluginMetadataMapper:
|
||||
plugin.history = info.get("history") or {}
|
||||
plugin.release = bool(info.get("release"))
|
||||
plugin.repo_url = market
|
||||
plugin.package_version = package_version
|
||||
plugin.is_local = False
|
||||
plugin.add_time = add_time
|
||||
return plugin
|
||||
|
||||
+14
-2
@@ -1,7 +1,7 @@
|
||||
from enum import Enum as _Enum
|
||||
from typing import Literal, Optional, List, Dict, Union
|
||||
from typing import Dict, List, Literal, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field, RootModel, field_validator
|
||||
from pydantic import BaseModel, Field, PrivateAttr, RootModel, field_validator
|
||||
|
||||
from app.schemas.common import JsonData
|
||||
|
||||
@@ -62,6 +62,8 @@ class Plugin(BaseModel):
|
||||
"""
|
||||
插件信息
|
||||
"""
|
||||
_package_version: Optional[str] = PrivateAttr(default=None)
|
||||
|
||||
id: str = None
|
||||
# 插件名称
|
||||
plugin_name: Optional[str] = None
|
||||
@@ -124,6 +126,16 @@ class Plugin(BaseModel):
|
||||
# 实例实现模式;存量物理分身为空
|
||||
instance_mode: Optional[str] = None
|
||||
|
||||
@property
|
||||
def package_version(self) -> Optional[str]:
|
||||
"""读取仅供宿主内部候选选择使用的插件包代际。"""
|
||||
return self._package_version
|
||||
|
||||
@package_version.setter
|
||||
def package_version(self, value: Optional[str]) -> None:
|
||||
"""保存插件包代际,但不把它暴露到 API 响应模型。"""
|
||||
self._package_version = value
|
||||
|
||||
|
||||
class PluginRuntimeSummary(BaseModel):
|
||||
"""插件后台收敛状态和前端刷新代次。"""
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import asyncio
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
from packaging.version import Version
|
||||
|
||||
from app.application.plugin.catalog import PluginCatalogService
|
||||
from app.runtime.extensions.plugin.metadata import PluginMetadataMapper
|
||||
from app.schemas.plugin import Plugin
|
||||
|
||||
|
||||
def _plugin(
|
||||
@@ -13,14 +14,15 @@ def _plugin(
|
||||
version: str,
|
||||
repo_url: str,
|
||||
package_version: str | None = "v3",
|
||||
):
|
||||
) -> Plugin:
|
||||
"""构造目录合并测试使用的最小插件 DTO。"""
|
||||
return SimpleNamespace(
|
||||
plugin = Plugin(
|
||||
id=plugin_id,
|
||||
plugin_version=version,
|
||||
repo_url=repo_url,
|
||||
package_version=package_version,
|
||||
)
|
||||
plugin.package_version = package_version
|
||||
return plugin
|
||||
|
||||
|
||||
def _service(**overrides) -> PluginCatalogService:
|
||||
@@ -132,6 +134,33 @@ def test_load_maps_market_entries_with_installed_snapshot():
|
||||
assert mapper.call_args_list[1].args[3:] == (["Installed"], 1, "v3")
|
||||
|
||||
|
||||
def test_metadata_mapper_preserves_package_generation_without_serializing_it():
|
||||
"""市场映射必须保留候选代际,同时不能扩张插件 API 响应。"""
|
||||
mapper = PluginMetadataMapper(
|
||||
plugin_instance=lambda _plugin_id: None,
|
||||
plugin_class=lambda _plugin_id: None,
|
||||
annotate_system_version=lambda info: info,
|
||||
is_package_compatible=lambda _info, _version: True,
|
||||
auth_checker=lambda _plugin, _source: True,
|
||||
version_compare=lambda _left, _operator, _right: False,
|
||||
log=Mock(),
|
||||
)
|
||||
|
||||
plugin = mapper.map(
|
||||
plugin_id="Demo",
|
||||
plugin_info={"name": "Demo", "version": "3.0.0"},
|
||||
market="https://market-a",
|
||||
installed_plugins=[],
|
||||
add_time=1,
|
||||
package_version="v3",
|
||||
)
|
||||
|
||||
assert plugin is not None
|
||||
assert plugin.package_version == "v3"
|
||||
assert "package_version" not in plugin.model_dump()
|
||||
assert "package_version" not in Plugin.model_json_schema()["properties"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_collect_isolates_failure_and_completes_progress():
|
||||
"""异步市场单任务失败时保留成功结果,并把进度推进到完成态。"""
|
||||
|
||||
Reference in New Issue
Block a user