feat: 添加支持暂存插件源码更新的功能
This commit is contained in:
@@ -74,6 +74,7 @@ KEY FEATURES / 关键特性:
|
|||||||
✅ Only updates content field (不仅更新内容字段)
|
✅ Only updates content field (不仅更新内容字段)
|
||||||
✅ Skips files without openwebui_id (跳过没有 openwebui_id 的文件)
|
✅ Skips files without openwebui_id (跳过没有 openwebui_id 的文件)
|
||||||
✅ Automatically matches CN/EN plugin files (自动匹配中英文插件文件)
|
✅ Automatically matches CN/EN plugin files (自动匹配中英文插件文件)
|
||||||
|
✅ Supports staged plugin source code updates (支持暂存插件源码更新)
|
||||||
✅ Safe: Won't modify version or media fields (安全:不会修改版本或媒体字段)
|
✅ Safe: Won't modify version or media fields (安全:不会修改版本或媒体字段)
|
||||||
|
|
||||||
NOTES / 注意事项:
|
NOTES / 注意事项:
|
||||||
@@ -150,6 +151,38 @@ def _get_staged_readmes(repo_root: Path) -> List[Path]:
|
|||||||
return paths
|
return paths
|
||||||
|
|
||||||
|
|
||||||
|
def _get_staged_plugin_files(repo_root: Path) -> List[Path]:
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(
|
||||||
|
[
|
||||||
|
"git",
|
||||||
|
"-C",
|
||||||
|
str(repo_root),
|
||||||
|
"diff",
|
||||||
|
"--cached",
|
||||||
|
"--name-only",
|
||||||
|
"--",
|
||||||
|
"*.py",
|
||||||
|
],
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
print(f"Failed to read staged files: {exc}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
paths = []
|
||||||
|
for line in output.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
if "/plugins/" not in line:
|
||||||
|
continue
|
||||||
|
if line.endswith("__init__.py") or os.path.basename(line).startswith("test_"):
|
||||||
|
continue
|
||||||
|
paths.append(repo_root / line)
|
||||||
|
return paths
|
||||||
|
|
||||||
|
|
||||||
def _parse_frontmatter(content: str) -> Dict[str, str]:
|
def _parse_frontmatter(content: str) -> Dict[str, str]:
|
||||||
match = re.search(r'^\s*"""\n(.*?)\n"""', content, re.DOTALL)
|
match = re.search(r'^\s*"""\n(.*?)\n"""', content, re.DOTALL)
|
||||||
if not match:
|
if not match:
|
||||||
@@ -202,6 +235,25 @@ def _get_post_id(plugin_file: Path) -> Optional[str]:
|
|||||||
return meta.get("openwebui_id") or meta.get("post_id")
|
return meta.get("openwebui_id") or meta.get("post_id")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_plugin_metadata(plugin_file: Path) -> Dict[str, str]:
|
||||||
|
try:
|
||||||
|
content = plugin_file.read_text(encoding="utf-8")
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
return _parse_frontmatter(content)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_readme_for_plugin(plugin_file: Path) -> Optional[str]:
|
||||||
|
plugin_dir = plugin_file.parent
|
||||||
|
is_cn = plugin_file.stem.endswith("_cn")
|
||||||
|
readme_candidates = ["README_CN.md", "README.md"] if is_cn else ["README.md", "README_CN.md"]
|
||||||
|
for name in readme_candidates:
|
||||||
|
readme_path = plugin_dir / name
|
||||||
|
if readme_path.exists():
|
||||||
|
return readme_path.read_text(encoding="utf-8")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
repo_root = _get_repo_root()
|
repo_root = _get_repo_root()
|
||||||
_load_dotenv(repo_root)
|
_load_dotenv(repo_root)
|
||||||
@@ -223,11 +275,47 @@ def main() -> int:
|
|||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
client = module.get_client(api_key)
|
client = module.get_client(api_key)
|
||||||
|
|
||||||
|
staged_plugins = _get_staged_plugin_files(repo_root)
|
||||||
staged_readmes = _get_staged_readmes(repo_root)
|
staged_readmes = _get_staged_readmes(repo_root)
|
||||||
if not staged_readmes:
|
if not staged_plugins and not staged_readmes:
|
||||||
print("No staged README files found.")
|
print("No staged README or plugin files found.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
updated_post_ids: set[str] = set()
|
||||||
|
|
||||||
|
for plugin_file in staged_plugins:
|
||||||
|
if not plugin_file.exists():
|
||||||
|
print(f"Skipped (missing): {plugin_file}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
post_id = _get_post_id(plugin_file)
|
||||||
|
if not post_id:
|
||||||
|
print(f"Skipped (no openwebui_id): {plugin_file}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
post_data = client.get_post(post_id)
|
||||||
|
if not post_data:
|
||||||
|
print(f"Skipped (post not found): {plugin_file}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
source_code = plugin_file.read_text(encoding="utf-8")
|
||||||
|
metadata = _get_plugin_metadata(plugin_file)
|
||||||
|
readme_content = _find_readme_for_plugin(plugin_file)
|
||||||
|
|
||||||
|
ok = client.update_plugin(
|
||||||
|
post_id=post_id,
|
||||||
|
source_code=source_code,
|
||||||
|
readme_content=readme_content or metadata.get("description", ""),
|
||||||
|
metadata=metadata,
|
||||||
|
media_urls=None,
|
||||||
|
)
|
||||||
|
if ok:
|
||||||
|
updated_post_ids.add(post_id)
|
||||||
|
print(f"Updated plugin -> {plugin_file} (post_id: {post_id})")
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"Failed: {plugin_file} ({exc})")
|
||||||
|
|
||||||
for readme_path in staged_readmes:
|
for readme_path in staged_readmes:
|
||||||
if not readme_path.exists():
|
if not readme_path.exists():
|
||||||
print(f"Skipped (missing): {readme_path}")
|
print(f"Skipped (missing): {readme_path}")
|
||||||
@@ -244,6 +332,10 @@ def main() -> int:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if post_id in updated_post_ids:
|
||||||
|
print(f"Skipped (already updated via plugin): {readme_path}")
|
||||||
|
continue
|
||||||
|
|
||||||
post_data = client.get_post(post_id)
|
post_data = client.get_post(post_id)
|
||||||
if not post_data:
|
if not post_data:
|
||||||
print(f"Skipped (post not found): {readme_path}")
|
print(f"Skipped (post not found): {readme_path}")
|
||||||
|
|||||||
Reference in New Issue
Block a user