Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/scripts/select_plugin_release_dir.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail

package_file="${1:?package file is required}"
plugin_id="${2:?lowercase plugin id is required}"

case "$(basename "$package_file")" in
package.json)
plugin_dir="plugins/${plugin_id}"
;;
package.v2.json)
plugin_dir="plugins.v2/${plugin_id}"
;;
*)
echo "Unsupported package file: ${package_file}" >&2
exit 2
;;
esac

test -d "$plugin_dir"
printf '%s\n' "$plugin_dir"
16 changes: 7 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,7 @@ jobs:
plugin_version="${entry##*|}"
plugin_id_lc="$(echo "$plugin_id" | tr '[:upper:]' '[:lower:]')"

dir1="plugins/${plugin_id_lc}"
dir2="plugins.v2/${plugin_id_lc}"
plugin_dir=""
if [ -d "$dir1" ]; then plugin_dir="$dir1"; fi
if [ -d "$dir2" ]; then plugin_dir="$dir2"; fi

if [ -z "$plugin_dir" ]; then
if ! plugin_dir="$(bash .github/scripts/select_plugin_release_dir.sh "$pkg_file" "$plugin_id_lc")"; then
echo "WARN: directory for $plugin_id not found under plugins/ or plugins.v2/, skip."
continue
fi
Expand All @@ -80,8 +74,12 @@ jobs:
continue
fi

# Existing per-plugin tags make unchanged directories a no-op.
prev_tag="$(git tag --list "${plugin_id}_v*" --sort=-version:refname | head -n 1 || true)"
# 同名插件可能跨代维护独立版本线;已有当前版本 tag 时用它判断该代目录是否变化。
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
prev_tag="$tag"
else
prev_tag="$(git tag --list "${plugin_id}_v*" --sort=-version:refname | head -n 1 || true)"
fi

changed=1
if [ -n "$prev_tag" ]; then
Expand Down
3 changes: 2 additions & 1 deletion package.v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,12 @@
"name": "PlexMatch",
"description": "实现入库时添加 .plexmatch 文件,提高识别准确率。",
"labels": "Plex,刮削",
"version": "1.2",
"version": "1.3",
"icon": "https://raw.githubusercontent.com/InfinityPacer/MoviePilot-Plugins/main/icons/plexmatch.png",
"author": "InfinityPacer",
"level": 1,
"history": {
"v1.3": "修复 PostgreSQL 下历史记录查询错误,并保持 SQLite 兼容",
"v1.2": "MoviePilot V2 版本PlexMatch插件"
},
"release": true
Expand Down
7 changes: 4 additions & 3 deletions plugins.v2/plexmatch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class PlexMatch(_PluginBase):
# 插件图标
plugin_icon = "https://raw.githubusercontent.com/InfinityPacer/MoviePilot-Plugins/main/icons/plexmatch.png"
# 插件版本
plugin_version = "1.2"
plugin_version = "1.3"
# 插件作者
plugin_author = "InfinityPacer"
# 作者主页
Expand Down Expand Up @@ -398,9 +398,10 @@ def __check_external_interrupt(self, service: str) -> bool:
@staticmethod
@db_query
def __list_transfer_histories(db: Optional[Session]) -> list[Type[TransferHistory]]:
"""获取TMDBID 不为 0 并成功的历史记录列表"""
"""获取具有有效 TMDB ID 且整理成功的历史记录。"""
result = db.query(TransferHistory).filter(and_(
TransferHistory.tmdbid.is_not(0),
TransferHistory.tmdbid.is_not(None),
TransferHistory.tmdbid != 0,
TransferHistory.status)
).all()
return result
50 changes: 50 additions & 0 deletions tests/ci/test_plugin_release_directory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from pathlib import Path
import subprocess


REPO_ROOT = Path(__file__).resolve().parents[2]
SELECTOR = REPO_ROOT / ".github/scripts/select_plugin_release_dir.sh"
WORKFLOW = REPO_ROOT / ".github/workflows/release.yml"


def _select(tmp_path: Path, package_file: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["bash", str(SELECTOR), package_file, "example"],
cwd=tmp_path,
capture_output=True,
text=True,
check=False,
)


def test_release_directory_keeps_v1_and_v2_assets_separate(tmp_path: Path) -> None:
(tmp_path / "plugins/example").mkdir(parents=True)
(tmp_path / "plugins.v2/example").mkdir(parents=True)

assert _select(tmp_path, "package.json").stdout.strip() == "plugins/example"
assert _select(tmp_path, "package.v2.json").stdout.strip() == "plugins.v2/example"


def test_v2_release_directory_does_not_fall_back_to_v1_source(tmp_path: Path) -> None:
(tmp_path / "plugins/example").mkdir(parents=True)

result = _select(tmp_path, "package.v2.json")

assert result.returncode != 0
assert result.stdout == ""


def test_release_directory_rejects_unknown_package_file(tmp_path: Path) -> None:
result = _select(tmp_path, "package.beta.json")

assert result.returncode == 2
assert "Unsupported package file" in result.stderr


def test_release_workflow_uses_generation_aware_directory_selector() -> None:
workflow = WORKFLOW.read_text(encoding="utf-8")

assert 'select_plugin_release_dir.sh "$pkg_file" "$plugin_id_lc"' in workflow
assert 'git rev-parse -q --verify "refs/tags/$tag"' in workflow
assert 'prev_tag="$tag"' in workflow
assert 'if [ -d "$dir2" ]; then plugin_dir="$dir2"; fi' not in workflow
72 changes: 72 additions & 0 deletions tests/v2/plexmatch/test_transfer_history_query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from sqlalchemy import Boolean, Integer, column, table
from sqlalchemy.dialects import postgresql, sqlite
from sqlalchemy.orm import Session

import plexmatch


_TRANSFER_HISTORY = table(
"transferhistory",
column("tmdbid", Integer),
column("status", Boolean),
)


class _V2153TransferHistory:
"""保留 MoviePilot v2.15.3 中查询依赖的整理记录字段契约。"""

tmdbid = _TRANSFER_HISTORY.c.tmdbid
status = _TRANSFER_HISTORY.c.status


class _RecordingQuery:
"""记录插件提交给 ORM 的筛选条件,不访问真实数据库。"""

def __init__(self) -> None:
self.criterion = None

def filter(self, criterion):
self.criterion = criterion
return self

def all(self) -> list:
return []


class _RecordingSession(Session):
"""提供满足 db_query 契约的 Session,并暴露生成的查询条件。"""

def __init__(self) -> None:
super().__init__()
self.recorded_query = _RecordingQuery()

def query(self, *entities, **kwargs):
return self.recorded_query


def _compile_history_filter(monkeypatch, dialect) -> str:
monkeypatch.setattr(plexmatch, "TransferHistory", _V2153TransferHistory)
session = _RecordingSession()
try:
plexmatch.PlexMatch._PlexMatch__list_transfer_histories(db=session)
criterion = session.recorded_query.criterion
assert criterion is not None
return str(criterion.compile(dialect=dialect, compile_kwargs={"literal_binds": True}))
finally:
session.close()


def test_history_filter_uses_numeric_comparison_on_postgresql(monkeypatch) -> None:
sql = _compile_history_filter(monkeypatch, postgresql.dialect())

assert "tmdbid IS NOT NULL" in sql
assert "tmdbid != 0" in sql
assert "tmdbid IS NOT 0" not in sql


def test_history_filter_keeps_sqlite_compatibility(monkeypatch) -> None:
sql = _compile_history_filter(monkeypatch, sqlite.dialect())

assert "tmdbid IS NOT NULL" in sql
assert "tmdbid != 0" in sql
assert "tmdbid IS NOT 0" not in sql