diff --git a/!src-dist/archive.py b/!src-dist/archive.py new file mode 100644 index 000000000..e9324f193 --- /dev/null +++ b/!src-dist/archive.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# pip3 install semver + +""" +构建打包自动化脚本 + +功能: + 执行构建并生成压缩包,自动切换到打包目录,并触发构建和打包操作。 + +使用方法: + python archive.py +""" + +import plib.environment as env +from plib.publish import run + + +def main() -> None: + """ + 主入口函数,设置工作目录并执行构建打包任务。 + """ + # 切换当前工作目录为打包目录 + env.set_packet_as_cwd() + + # 调用构建命令,执行构建和打包操作 + run("archive") + + +if __name__ == "__main__": + main() diff --git a/!src-dist/build.py b/!src-dist/build.py index 7641392d0..c0b9ba032 100644 --- a/!src-dist/build.py +++ b/!src-dist/build.py @@ -2,13 +2,14 @@ # pip3 install semver """ -新版本打包自动化脚本 +构建自动化脚本 功能: - 一键执行构建打包,自动切换到打包目录,并触发构建操作。 + 一键执行构建,自动切换到打包目录,并触发构建操作。 + 仅构建不打压缩包,如需打包请使用 archive.py。 使用方法: - python script.py + python build.py """ import plib.environment as env @@ -17,13 +18,12 @@ def main() -> None: """ - 主入口函数,解析命令行参数、设置工作目录并执行构建任务。 + 主入口函数,设置工作目录并执行构建任务。 """ - # 切换当前工作目录为打包目录 env.set_packet_as_cwd() - # 调用构建命令,执行打包操作 + # 调用构建命令,仅执行构建操作 run("build") diff --git a/!src-dist/changelog.py b/!src-dist/changelog.py new file mode 100644 index 000000000..d0df20256 --- /dev/null +++ b/!src-dist/changelog.py @@ -0,0 +1,465 @@ +# -*- coding: utf-8 -*- +""" +版本更新与更新日志管理脚本 + +说明: + 本脚本负责更新 Base.lua 中的版本号和打包时间,以及更新 CHANGELOG.md 文件。 + 支持两种使用方式: + 1. 交互式模式:默认模式,供本地终端使用 + 2. 命令行参数模式:供 CI/CD 流水线使用 + +用法: + # 交互式模式(默认) + python changelog.py + + # CI/CD 模式(命令行参数) + python changelog.py --version-type patch --changelog "插件A:修复问题|插件B:新增功能" + + # 仅获取新版本号(不修改文件) + python changelog.py --version-type patch --dry-run +""" + +import argparse +import os +import re +import sys +from datetime import datetime +from typing import Optional, Tuple, List + +# 添加 plib 路径以便导入本地模块 +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import semver # noqa: E402 +from plib.environment import get_packet_path, get_current_packet_id # noqa: E402 + + +def get_base_lua_path() -> str: + """获取 Base.lua 文件路径""" + packet_id = get_current_packet_id() + packet_path = get_packet_path() + return os.path.join(packet_path, f"{packet_id}_!Base", "src", "lib", "Base.lua") + + +def get_changelog_path() -> str: + """获取 CHANGELOG.md 文件路径""" + packet_path = get_packet_path() + return os.path.join(packet_path, "CHANGELOG.md") + + +def read_current_version() -> str: + """ + 从 Base.lua 中读取当前版本号 + + 返回: + 当前版本号字符串(如 "1.2.3") + """ + base_lua_path = get_base_lua_path() + + try: + with open(base_lua_path, "r", encoding="gbk") as f: + content = f.read() + except UnicodeDecodeError: + with open(base_lua_path, "r", encoding="utf-8") as f: + content = f.read() + + # 匹配 _VERSION_ = 'x.y.z' 格式 + match = re.search(r"_VERSION_\s*=\s*'([^']*)'", content) + if not match: + raise ValueError("无法从 Base.lua 中读取版本号") + + version = match.group(1) + + # 验证版本号格式 + if not re.match(r"^\d+\.\d+\.\d+$", version): + raise ValueError(f"版本号格式无效: {version},期望格式: X.Y.Z") + + return version + + +def calculate_new_version(current_version: str, version_type: str) -> str: + """ + 根据版本类型计算新版本号 + + 参数: + current_version: 当前版本号 + version_type: 版本类型(major/minor/patch) + + 返回: + 新版本号字符串 + """ + version_type = version_type.lower() + + if version_type == "patch": + return semver.bump_patch(current_version) + elif version_type == "minor": + return semver.bump_minor(current_version) + elif version_type == "major": + return semver.bump_major(current_version) + else: + raise ValueError(f"无效的版本类型: {version_type},有效值: major/minor/patch") + + +def update_base_lua(new_version: str, build_date: Optional[str] = None) -> None: + """ + 更新 Base.lua 中的版本号和打包时间 + + 参数: + new_version: 新版本号 + build_date: 打包日期(格式 YYYYMMDD),默认为当前日期 + """ + if build_date is None: + build_date = datetime.now().strftime("%Y%m%d") + + base_lua_path = get_base_lua_path() + + try: + with open(base_lua_path, "r", encoding="gbk") as f: + content = f.read() + encoding = "gbk" + except UnicodeDecodeError: + with open(base_lua_path, "r", encoding="utf-8") as f: + content = f.read() + encoding = "utf-8" + + # 更新 _BUILD_ + content = re.sub( + r"(local _BUILD_\s*=\s*)'[^']*'", + rf"\1'{build_date}'", + content, + ) + + # 更新 _VERSION_ + content = re.sub( + r"(local _VERSION_\s*=\s*)'[^']*'", + rf"\1'{new_version}'", + content, + ) + + with open(base_lua_path, "w", encoding=encoding) as f: + f.write(content) + + print(f"✅ Base.lua 已更新: 版本={new_version}, 构建日期={build_date}") + + +def process_changelog_input(changelog_input: str) -> List[str]: + """ + 处理更新日志输入,将其转换为标准格式 + + 支持的输入格式: + 1. "插件A:内容|插件B:内容" (冒号分隔) + 2. "* [插件A] 内容|* [插件B] 内容" (标准格式) + 3. 混合格式 + + 参数: + changelog_input: 原始更新日志输入 + + 返回: + 格式化后的更新日志行列表 + """ + # 首先处理原始格式 * [插件] 内容,在 * 前面添加分隔符 + processed = re.sub(r"([^|])(\*\s*\[)", r"\1|\2", changelog_input) + + # 按 | 分割每一行 + lines = processed.split("|") + result = [] + + for line in lines: + # 去掉首尾空格和引号 + line = line.strip().strip('"').strip('"').strip('"') + + # 跳过空行 + if not line: + continue + + # 检查是否已经是 * [插件] 格式 + if re.match(r"^\*\s*\[", line): + # 已经是正确格式,只需要格式化空格 + match = re.match(r"^\*\s*\[([^\]]*)\]\s*(.*)", line) + if match: + plugin = match.group(1).strip() + content = match.group(2).strip() + result.append(f"* [{plugin}] {content}") + else: + result.append(line) + else: + # 转换 插件:内容 或 插件:内容 格式为 * [插件] 内容 + if re.search(r"[::]", line): + parts = re.split(r"[::]", line, maxsplit=1) + plugin = parts[0].strip().strip('"').strip('"').strip('"') + content = ( + parts[1].strip().strip('"').strip('"').strip('"') + if len(parts) > 1 + else "" + ) + result.append(f"* [{plugin}] {content}") + else: + # 如果没有冒号,假设整行都是内容 + result.append(f"* {line}") + + return result + + +def update_changelog(new_version: str, changelog_lines: List[str]) -> str: + """ + 更新 CHANGELOG.md 文件 + + 参数: + new_version: 新版本号 + changelog_lines: 格式化后的更新日志行列表 + + 返回: + 生成的更新日志内容(用于输出) + """ + changelog_path = get_changelog_path() + packet_id = get_current_packet_id() + + # 读取现有内容 + with open(changelog_path, "r", encoding="utf-8") as f: + existing_content = f.readlines() + + # 构建新的更新日志条目 + new_entry_lines = [ + f"## {packet_id}插件集 v{new_version}\n", + "\n", + ] + for line in changelog_lines: + new_entry_lines.append(f"{line}\n") + new_entry_lines.append("\n") + + # 构建新的文件内容 + # 保留标题(前两行),插入新条目,然后是剩余内容 + new_content = [] + new_content.append("# 更新日志\n") + new_content.append("\n") + new_content.extend(new_entry_lines) + + # 跳过原文件的前两行(标题和空行),添加剩余内容 + if len(existing_content) > 2: + new_content.extend(existing_content[2:]) + + # 写入文件 + with open(changelog_path, "w", encoding="utf-8") as f: + f.writelines(new_content) + + # 返回生成的更新日志内容(不含标题) + generated_changelog = f"## {packet_id}插件集 v{new_version}\n\n" + generated_changelog += "\n".join(changelog_lines) + + print("✅ CHANGELOG.md 已更新") + + return generated_changelog + + +def interactive_mode() -> Tuple[str, str]: + """ + 交互式模式,提示用户输入版本类型和更新日志 + + 返回: + (version_type, changelog) 元组 + """ + print("\n" + "=" * 50) + print("📦 版本更新与更新日志管理工具") + print("=" * 50 + "\n") + + # 显示当前版本 + current_version = read_current_version() + print(f"当前版本: {current_version}\n") + + # 计算三种版本类型的新版本号 + patch_version = calculate_new_version(current_version, "patch") + minor_version = calculate_new_version(current_version, "minor") + major_version = calculate_new_version(current_version, "major") + + # 选择版本类型 + print("请选择版本更新类型:") + print(f" 1. Patch (修订版本) -> {patch_version}") + print(f" 2. Minor (次版本) -> {minor_version}") + print(f" 3. Major (主版本) -> {major_version}") + print() + + while True: + choice = input("请输入选项 (1/2/3): ").strip() + if choice == "1": + version_type = "patch" + break + elif choice == "2": + version_type = "minor" + break + elif choice == "3": + version_type = "major" + break + else: + print("❌ 无效选项,请重新输入") + + new_version = calculate_new_version(current_version, version_type) + print(f"\n新版本号将为: {new_version}\n") + + # 输入更新日志 + print("请输入更新日志内容:") + print(" 格式1: 插件名:更新内容|插件名:更新内容") + print(" 格式2: * [插件名] 更新内容|* [插件名] 更新内容") + print(" 提示: 使用 | 分隔多条更新记录") + print() + + changelog = input("更新日志: ").strip() + + if not changelog: + print("❌ 更新日志不能为空") + sys.exit(1) + + return version_type, changelog + + +def run( + version_type: Optional[str] = None, + changelog: str = "", + dry_run: bool = False, + build_date: Optional[str] = None, + new_version: Optional[str] = None, +) -> dict: + """ + 执行版本更新和更新日志更新 + + 参数: + version_type: 版本类型(major/minor/patch),如果指定了 new_version 则可不传 + changelog: 更新日志内容 + dry_run: 是否只计算不修改文件 + build_date: 打包日期(可选) + new_version: 直接指定目标版本号(供 CI 使用,跳过计算) + + 返回: + 包含版本信息的字典 + """ + # 读取当前版本 + current_version = read_current_version() + + # 计算新版本(如果未直接指定) + if new_version is None: + if version_type is None: + raise ValueError("必须指定 version_type 或 new_version") + new_version = calculate_new_version(current_version, version_type) + + result = { + "current_version": current_version, + "new_version": new_version, + "version_type": version_type or "direct", + } + + if dry_run: + print(f"当前版本: {current_version}") + print(f"版本类型: {version_type}") + print(f"新版本号: {new_version}") + return result + + # 更新 Base.lua + update_base_lua(new_version, build_date) + + # 处理并更新更新日志 + changelog_lines = process_changelog_input(changelog) + generated_changelog = update_changelog(new_version, changelog_lines) + + result["changelog"] = generated_changelog + + print("\n" + "=" * 50) + print("📝 更新日志内容预览:") + print("=" * 50) + print(generated_changelog) + print("=" * 50 + "\n") + + return result + + +def main(): + """脚本入口函数""" + parser = argparse.ArgumentParser( + description="版本更新与更新日志管理工具", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +示例: + # 交互式模式(默认) + python changelog.py + + # CI/CD 模式 + python changelog.py --version-type patch --changelog "插件A:修复问题|插件B:新增功能" + + # 仅计算新版本号(不修改文件) + python changelog.py --version-type patch --dry-run + + # 指定打包日期 + python changelog.py --version-type patch --changelog "更新内容" --build-date 20260127 + """, + ) + + parser.add_argument( + "--version-type", + "-t", + choices=["major", "minor", "patch", "Major", "Minor", "Patch"], + help="版本更新类型: major/minor/patch", + ) + parser.add_argument( + "--changelog", + "-c", + help="更新日志内容,使用 | 分隔多条记录", + ) + parser.add_argument( + "--dry-run", + "-n", + action="store_true", + help="仅计算新版本号,不修改任何文件", + ) + parser.add_argument( + "--build-date", + "-d", + help="打包日期(格式 YYYYMMDD),默认为当前日期", + ) + parser.add_argument( + "--output-version", + "-o", + action="store_true", + help="仅输出新版本号(供脚本使用,不修改文件)", + ) + parser.add_argument( + "--new-version", + "-v", + help="直接指定目标版本号(跳过计算,供 CI 使用)", + ) + + args = parser.parse_args() + + # 切换到项目根目录 + script_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(script_dir) + os.chdir(project_root) + + # 仅输出新版本号模式 + if args.output_version and args.version_type: + current_version = read_current_version() + new_version = calculate_new_version(current_version, args.version_type) + print(new_version) + return + + # 命令行参数模式 + if args.version_type or args.new_version: + if not args.changelog and not args.dry_run: + parser.error("--changelog 参数是必需的(除非使用 --dry-run)") + + run( + version_type=args.version_type, + changelog=args.changelog or "", + dry_run=args.dry_run, + build_date=args.build_date, + new_version=args.new_version, + ) + + if not args.dry_run: + print("✅ 版本更新完成!") + return + + # 如果没有提供任何参数,默认进入交互模式 + version_type, changelog = interactive_mode() + run(version_type, changelog, dry_run=False, build_date=args.build_date) + print("✅ 版本更新完成!") + + +if __name__ == "__main__": + main() diff --git a/!src-dist/plib/git.py b/!src-dist/plib/git.py index 690354b75..7511a9b7f 100644 --- a/!src-dist/plib/git.py +++ b/!src-dist/plib/git.py @@ -2,6 +2,11 @@ """ 本脚本提供 Git 相关的工具函数,包括状态检查、版本信息获取等。 + +注意: + - 本模块函数在 Git 不可用时可能抛出异常或返回空值 + - 上层调用者应先通过 is_available() 检测 Git 可用性 + - 根据业务需求决定是否退出或降级处理 """ import os @@ -15,6 +20,30 @@ from plib.environment import get_current_packet_id +def is_available() -> bool: + """ + 检测当前目录是否是有效的 Git 仓库。 + + 检测条件: + 1. git 命令可用 + 2. 当前目录处于 git 工作区内(存在 .git 目录或父目录中有) + + 返回: + bool: 是有效的 Git 仓库返回 True,否则返回 False + """ + try: + result = subprocess.run( + ["git", "rev-parse", "--is-inside-work-tree"], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + return result.stdout.strip().lower() == "true" + except (subprocess.CalledProcessError, FileNotFoundError, OSError): + return False + + def is_clean() -> bool: """ 判断当前 Git 工作区是否干净,即是否存在未提交的修改。 @@ -50,7 +79,6 @@ def get_current_branch() -> str: str: 当前分支的名称,如果找不到则返回空字符串。 """ try: - # 运行 "git branch" 命令,获取分支列表 result = subprocess.run( ["git", "branch"], check=True, @@ -60,12 +88,10 @@ def get_current_branch() -> str: ) branch_lines: List[str] = result.stdout.strip().splitlines() for line in branch_lines: - # 当前分支的行以 "*" 开头,后面跟着一个空格及分支名称 if line.startswith("*"): return line[2:].strip() return "" - except subprocess.CalledProcessError: - # 若执行命令失败,则返回空字符串 + except (subprocess.CalledProcessError, FileNotFoundError, OSError): return "" @@ -75,10 +101,9 @@ def get_head_time_tag() -> str: 返回: str: 格式为 "YYYYMMDDHHMMSS-commit_hash" 的字符串, - 如果获取失败则返回当前本地时间的字符串标签。 + 如果获取失败则返回当前本地时间的字符串标签(不含 hash)。 """ try: - # 获取当前提交的短哈希 result_hash = subprocess.run( ["git", "rev-parse", "--short", "HEAD"], check=True, @@ -88,7 +113,6 @@ def get_head_time_tag() -> str: ) commit_hash: str = result_hash.stdout.strip() - # 获取当前提交的日期,格式为 YYYYMMDDHHMMSS result_date = subprocess.run( ["git", "log", "-1", "--format=%cd", "--date=format:%Y%m%d%H%M%S"], check=True, @@ -99,8 +123,8 @@ def get_head_time_tag() -> str: commit_date: str = result_date.stdout.strip() return f"{commit_date}-{commit_hash}" - except subprocess.CalledProcessError: - # 如果获取 Git 信息失败,则使用当前本地时间作为标签 + except (subprocess.CalledProcessError, FileNotFoundError, OSError): + # Git 不可用时,仅返回本地时间(不含 hash) return time.strftime("%Y%m%d%H%M%S", time.localtime()) diff --git a/!src-dist/plib/publish.py b/!src-dist/plib/publish.py index fda2ab793..678e2019e 100644 --- a/!src-dist/plib/publish.py +++ b/!src-dist/plib/publish.py @@ -560,11 +560,16 @@ def __prepublish(packet: str, packet_path: str, diff_ver: Optional[str] = None) ) -def __pack(packet: str, packet_path: str, version_info: Dict[str, str]) -> None: +def __pack( + packet: str, + packet_path: str, + version_info: Dict[str, str], +) -> None: """ 打包流程: 根据是否存在上一个版本的提交hash, 分别生成差异包和全量包(分别处理 remake 与 classic 分支)。 + 如果 git 不可用,则自动跳过差异包。 参数: packet: 包标识 @@ -592,8 +597,8 @@ def __pack(packet: str, packet_path: str, version_info: Dict[str, str]) -> None: else: dist_root = os.path.abspath(os.path.join(dist_root, os.pardir, "dist")) - # 如果存在上一个版本,则生成差异包 - if version_info.get("previous_hash"): + # 如果 git 可用且存在上一个版本,则生成差异包 + if git.is_available() and version_info.get("previous_hash"): file_name_fmt: str = os.path.abspath( os.path.join( dist_root, @@ -634,24 +639,53 @@ def __pack(packet: str, packet_path: str, version_info: Dict[str, str]) -> None: __7zip(packet, file_name_fmt % "classic-", "", "", ".7zipignore-classic") -def run(mode: str, diff_ver: Optional[str] = None, is_source: bool = False) -> None: +def run( + mode: str, + diff_ver: Optional[str] = None, + is_source: bool = False, +) -> None: """ 脚本入口函数,根据 mode 确定打包或发布流程。 参数: - mode: 发布模式,取值 "publish" 或其他(仅打包,不发布) + mode: 执行模式 + - "build": 仅构建,不打压缩包 + - "archive": 构建 + 打压缩包(仅完整包) + - "ci": 构建 + lint + 打压缩包(完整包+差异包) + - "publish": 完整发布流程 diff_ver: 指定对比版本(可选) is_source: 是否仅打包源码(目前未使用,可扩展) """ + print("--------------------------------") print("> 对比版本: %s" % (diff_ver or "auto")) - print("> 发布模式: %s" % mode) + print("> 执行模式: %s" % mode) packet: str = get_current_packet_id() packet_path: str = get_packet_path() - version_info: Dict[str, str] = __get_version_info(packet, diff_ver) - if diff_ver and version_info.get("previous_hash") == "": - print("错误:指定的对比提交未找到(release: %s)。" % diff_ver) - exit() + # build/archive 模式不依赖 git,仅需要从 Base.lua 获取版本号 + if mode in ("build", "archive"): + version_info: Dict[str, str] = {"current": "", "current_hash": ""} + base_file: str = f"{packet}_!Base/src/lib/Base.lua" + try: + content = utils.read_file(base_file) + for line in content.splitlines(): + if line.startswith("local _VERSION_ "): + import re + + version_info["current"] = re.sub( + r"(?is)^local _VERSION_\s+=", "", line + ).strip()[1:-1] + break + except Exception as e: + print(f"Warning: Cannot read version from {base_file}: {e}") + if not version_info.get("current"): + version_info["current"] = "0.0.0" + else: + version_info = __get_version_info(packet, diff_ver) + + if diff_ver and version_info.get("previous_hash") == "": + print("错误:指定的对比提交未找到(release: %s)。" % diff_ver) + exit() # 如为发布模式,先执行预发布检查与操作 if mode == "publish": @@ -663,8 +697,10 @@ def run(mode: str, diff_ver: Optional[str] = None, is_source: bool = False) -> N # 执行整体构建打包流程 __build(packet) - if mode == "publish" or mode == "ci": + # 打包流程 + if mode == "publish" or mode == "ci" or mode == "archive": __pack(packet, packet_path, version_info) + # build 模式不打包 if mode == "publish": os.system("git checkout master") diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index df5e845e1..764afd1b5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -56,59 +56,23 @@ jobs: git checkout master git reset --hard origin/master - - name: Calculate new version - id: calculate_version + - name: Update version, changelog and AssertVersion + id: update_changelog run: | VERSION_TYPE="${{ github.event.inputs.version_type }}" - CURRENT_VERSION=$(grep "_VERSION_.*'.*'" MY_!Base/src/lib/Base.lua | sed -E "s/.*'(.*)'.*/\1/") - - # 验证当前版本格式 - if ! echo "$CURRENT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then - echo "::error::Current version format is invalid: $CURRENT_VERSION. Expected format: X.Y.Z" - exit 1 - fi - - # 使用Python计算新版本号 - NEW_VERSION=$(python3 -c " - import semver + CHANGELOG="${{ github.event.inputs.changelog }}" - current = '$CURRENT_VERSION' - version_type = '$VERSION_TYPE'.lower() # 转换为小写 + echo "🔄 开始更新版本信息..." - try: - if version_type == 'patch': - new_version = semver.bump_patch(current) - elif version_type == 'minor': - new_version = semver.bump_minor(current) - elif version_type == 'major': - new_version = semver.bump_major(current) - else: - raise ValueError(f'Invalid version type: {version_type}') + # 使用 changelog.py 脚本更新版本号和更新日志 + python3 \!src-dist/changelog.py --version-type "$VERSION_TYPE" --changelog "$CHANGELOG" - print(new_version) - except Exception as e: - print(f'Error calculating new version: {e}', file=sys.stderr) - exit(1) - ") + # 从 Base.lua 读取更新后的版本号 + NEW_VERSION=$(grep "_VERSION_.*'.*'" MY_!Base/src/lib/Base.lua | sed -E "s/.*'(.*)'.*/\1/") - echo "Current version: $CURRENT_VERSION" - echo "Version type: $VERSION_TYPE" - echo "New version: $NEW_VERSION" + echo "📦 新版本号: $NEW_VERSION" - # 设置输出变量 - echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT - echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT - - - name: Update Base.lua version and build - run: | - DATE=$(date +%Y%m%d) - NEW_VERSION="${{ steps.calculate_version.outputs.new_version }}" - sed -i "s/\(local _BUILD_\)\( *\)\(=\) *'[^']*'/\1\2\3 '${DATE}'/" MY_!Base/src/lib/Base.lua - sed -i "s/\(local _VERSION_\)\( *\)\(=\) *'[^']*'/\1\2\3 '${NEW_VERSION}'/" MY_!Base/src/lib/Base.lua - - - name: Update AssertVersion calls in Lua files - run: | - NEW_VERSION="${{ steps.calculate_version.outputs.new_version }}" + # 更新 AssertVersion 调用 echo "🔍 Updating AssertVersion calls to version: $NEW_VERSION" python3 \!src-dist/update_assert_version.py "$NEW_VERSION" --force-changed @@ -120,69 +84,24 @@ jobs: git diff --name-only fi - - name: Update CHANGELOG.md - id: update_changelog - run: | - NEW_VERSION="${{ steps.calculate_version.outputs.new_version }}" - CHANGELOG="${{ github.event.inputs.changelog }}" - TMPFILE=$(mktemp) - echo "# 更新日志" > $TMPFILE - echo "" >> $TMPFILE - - # 智能处理更新日志内容 - process_changelog() { - local input="$1" - - # 首先处理原始格式 * [插件] 内容,在 * 前面添加分隔符 - input=$(echo "$input" | sed 's/\([^|]\)\(\*[[:space:]]*\[\)/\1|\2/g') - - # 按 | 分割每一行 - echo "$input" | tr '|' '\n' | while IFS= read -r line; do - # 去掉首尾空格 - line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - - # 去掉首尾引号 - line=$(echo "$line" | sed 's/^["""]//;s/["""]$//') - - # 跳过空行 - [ -z "$line" ] && continue - - # 检查是否已经是 * [插件] 格式 - if echo "$line" | grep -q '^\*[[:space:]]*\['; then - # 已经是正确格式,只需要格式化空格 - plugin=$(echo "$line" | sed 's/^\*[[:space:]]*\[\([^]]*\)\].*/\1/' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - content=$(echo "$line" | sed 's/^\*[[:space:]]*\[[^]]*\][[:space:]]*//') - echo "* [$plugin] $content" - else - # 转换 插件:内容 格式为 * [插件] 内容 - if echo "$line" | grep -q '[::]'; then - plugin=$(echo "$line" | sed 's/\([^::]*\)[::].*/\1/' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/^["""]//;s/["""]$//') - content=$(echo "$line" | sed 's/[^::]*[::][[:space:]]*//' | sed 's/^["""]//;s/["""]$//') - echo "* [$plugin] $content" - else - # 如果没有冒号,假设整行都是内容 - echo "* $line" - fi - fi - done - } - - # 处理更新日志并保存到临时变量 - PROCESSED_CHANGELOG="## 茗伊插件集 v${NEW_VERSION}"$'\n\n'"$(process_changelog "$CHANGELOG")" + # 设置输出变量 + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT - # 输出到 TMPFILE - echo "$PROCESSED_CHANGELOG" >> $TMPFILE - echo "" >> $TMPFILE - tail -n +3 CHANGELOG.md >> $TMPFILE - mv $TMPFILE CHANGELOG.md + # 读取生成的更新日志内容(从 CHANGELOG.md 中提取最新条目) + PROCESSED_CHANGELOG=$(sed -n '/^## 茗伊插件集 v'"$NEW_VERSION"'/,/^## 茗伊插件集 v[0-9]/{ /^## 茗伊插件集 v[0-9]/!p; /^## 茗伊插件集 v'"$NEW_VERSION"'/p }' CHANGELOG.md | sed '/^$/d') - # 设置步骤输出(用于后续步骤) + # 设置步骤输出 { echo "changelog<> $GITHUB_OUTPUT + - name: Calculate version for outputs + id: calculate_version + run: | + echo "new_version=${{ steps.update_changelog.outputs.new_version }}" >> $GITHUB_OUTPUT + - name: Write secret to file run: | cat > secret.jx3dat << 'EOF'