Files
lyxy-document/publish.py
lanyuanxiaoyao a578c0b7ac refactor: 统一构建/发布脚本输出样式,更简约
- 添加 build.sh 调用脚本
- 移除装饰性分隔线和标题
- 移除进度输出,只保留必要的错误提示
- 使用 >>> 前缀标识脚本步骤
2026-03-15 12:54:40 +08:00

245 lines
5.9 KiB
Python

#!/usr/bin/env python3
"""
Skill 发布脚本
使用方式:
uv run python publish.py
"""
import os
import sys
import shutil
import subprocess
import tempfile
TARGET_REPO_URL = "https://github.com/lanyuanxiaoyao/skills.git"
TARGET_PATH = "skills/lyxy-document-reader"
def check_build_dir(build_dir: str) -> None:
"""
检查 build/ 目录是否存在
Args:
build_dir: build 目录路径
Raises:
SystemExit: 目录不存在时退出
"""
if not os.path.exists(build_dir):
print("错误: build/ 目录不存在")
print("请先运行 build.py:")
print(" uv run python build.py")
sys.exit(1)
def check_build_skill_md(build_skill_md_path: str) -> None:
"""
检查 build/SKILL.md 是否存在
Args:
build_skill_md_path: build/SKILL.md 路径
Raises:
SystemExit: 文件不存在时退出
"""
if not os.path.exists(build_skill_md_path):
print("错误: build/SKILL.md 不存在")
print("请先运行 build.py:")
print(" uv run python build.py")
sys.exit(1)
def parse_version_from_skill_md(skill_md_path: str) -> str:
"""
从 SKILL.md 解析出版本号
Args:
skill_md_path: SKILL.md 路径
Returns:
版本号字符串
Raises:
SystemExit: 解析失败时退出
"""
with open(skill_md_path, "r", encoding="utf-8") as f:
content = f.read()
# 简单解析 YAML frontmatter 中的 version
lines = content.split("\n")
in_frontmatter = False
in_metadata = False
for line in lines:
stripped = line.strip()
if stripped == "---":
if not in_frontmatter:
in_frontmatter = True
else:
break
continue
if in_frontmatter:
if stripped == "metadata:":
in_metadata = True
elif in_metadata and stripped.startswith("version:"):
# 提取版本号,去掉引号
version_part = stripped.split(":", 1)[1].strip()
version = version_part.strip('"').strip("'")
return version
elif in_metadata and stripped and not stripped.startswith(" "):
# metadata 块结束
in_metadata = False
print("错误: 无法从 build/SKILL.md 解析版本号")
print("请检查 build/SKILL.md 是否包含 metadata.version 字段")
sys.exit(1)
def run_git_command(repo_dir: str, args: list[str]) -> subprocess.CompletedProcess:
"""
在指定目录运行 git 命令
Args:
repo_dir: 仓库目录
args: git 命令参数列表
Returns:
subprocess.CompletedProcess
Raises:
subprocess.CalledProcessError: 命令失败时
"""
cmd = ["git"] + args
return subprocess.run(
cmd,
cwd=repo_dir,
check=True,
capture_output=True,
text=True
)
def clone_repo(temp_dir: str) -> str:
"""
在临时目录 clone 目标仓库
Args:
temp_dir: 临时目录路径
Returns:
仓库目录路径
Raises:
SystemExit: clone 失败时退出
"""
repo_dir = os.path.join(temp_dir, "skills-repo")
try:
run_git_command(temp_dir, ["clone", "--depth", "1", TARGET_REPO_URL, "skills-repo"])
except subprocess.CalledProcessError as e:
print(f"错误: Clone 仓库失败")
print(f" 返回码: {e.returncode}")
print(f" 标准输出: {e.stdout}")
print(f" 错误输出: {e.stderr}")
sys.exit(1)
return repo_dir
def clear_target_dir(repo_dir: str) -> str:
"""
清空目标路径目录
Args:
repo_dir: 仓库目录
Returns:
目标目录路径
"""
target_dir = os.path.join(repo_dir, TARGET_PATH)
if os.path.exists(target_dir):
shutil.rmtree(target_dir)
os.makedirs(target_dir, exist_ok=True)
return target_dir
def copy_build_contents(build_dir: str, target_dir: str) -> None:
"""
复制 build/ 内容到目标目录
Args:
build_dir: build 源目录
target_dir: 目标目录
"""
for item in os.listdir(build_dir):
src = os.path.join(build_dir, item)
dst = os.path.join(target_dir, item)
if os.path.isdir(src):
shutil.copytree(src, dst)
else:
shutil.copy2(src, dst)
def git_commit_and_push(repo_dir: str, version: str) -> None:
"""
执行 git add / commit / push
Args:
repo_dir: 仓库目录
version: 版本号
Raises:
SystemExit: git 操作失败时退出
"""
commit_message = f"publish: lyxy-document-reader {version}"
try:
run_git_command(repo_dir, ["add", "."])
run_git_command(repo_dir, ["commit", "-m", commit_message])
run_git_command(repo_dir, ["push"])
except subprocess.CalledProcessError as e:
print(f"错误: Git 操作失败")
print(f" 返回码: {e.returncode}")
print(f" 标准输出: {e.stdout}")
print(f" 错误输出: {e.stderr}")
sys.exit(1)
def main() -> None:
"""
主函数:执行完整的发布流程
"""
# 路径配置
project_root = os.path.dirname(os.path.abspath(__file__))
build_dir = os.path.join(project_root, "build")
build_skill_md_path = os.path.join(build_dir, "SKILL.md")
# 检查 build/ 目录
check_build_dir(build_dir)
check_build_skill_md(build_skill_md_path)
# 解析版本号
version = parse_version_from_skill_md(build_skill_md_path)
# 使用临时目录
with tempfile.TemporaryDirectory(prefix="lyxy-publish-") as temp_dir:
# Clone 仓库
repo_dir = clone_repo(temp_dir)
# 清空目标路径
target_dir = clear_target_dir(repo_dir)
# 复制内容
copy_build_contents(build_dir, target_dir)
# Git 提交并推送
git_commit_and_push(repo_dir, version)
if __name__ == "__main__":
main()