From 32420abb8db3625a4962ae4a71e6f9d94d0996aa Mon Sep 17 00:00:00 2001 From: liuchunguang <345080091@qq.com> Date: Thu, 12 Mar 2026 13:24:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9versioncode=E7=9A=84=E8=AF=BB?= =?UTF-8?q?=E5=86=99=E6=96=B9=E5=BC=8F=EF=BC=8C=E6=94=B9=E4=B8=BA=E4=BB=8E?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tool/py_tools/version_code_manager.py | 74 ++++++++++++++++++++------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/Tool/py_tools/version_code_manager.py b/Tool/py_tools/version_code_manager.py index 9badeace8ee..627b2f088d8 100644 --- a/Tool/py_tools/version_code_manager.py +++ b/Tool/py_tools/version_code_manager.py @@ -2,11 +2,12 @@ # version_code_manager.py # 用途:管理各渠道的 Android versionCode / iOS buildNumber 自动递增 # -# 逻辑: -# 1. 读取环境变量 NLD_CLIENT_{ChannelName}_VERSION_CODE -# 2. 若环境变量不存在,则从对应渠道的 ChannelSetting.yaml 中读取 BuildCode 作为初始值 -# 3. 将该值 +1 后写回环境变量(通过写出 shell export 语句供调用方 source) -# 4. 将最终使用的 code 打印到 stdout,供调用方捕获 +# 逻辑(优先级从高到低): +# 1. 读取 Jenkins node 状态文件 ~/.nld_build_state/{channel}.json 中保存的上次值 +# 2. 若状态文件不存在,则从 ChannelSetting.yaml 的 BuildCode 字段读取默认初始值 +# 3. 将该值 +1 后: +# a. 写回状态文件(跨构建持久化,因为 Jenkins 每次构建是全新进程,环境变量不保留) +# b. 输出 shell export 语句供调用方 source # # 使用方式(在 build_unity.sh 中): # source <(python3 .../version_code_manager.py ) @@ -25,8 +26,19 @@ import sys import os +import json import yaml +# Jenkins node 上存储各渠道 versionCode 的状态目录 +# 优先使用 JENKINS_HOME 下的固定路径,避免 ~ 在不同用户身份下解析到不同目录 +# 发布历史只保存在 Jenkins node 上,不进入 git 仓库 +_jenkins_home = os.environ.get("JENKINS_HOME") or os.environ.get("HUDSON_HOME") +if _jenkins_home: + STATE_DIR = os.path.join(_jenkins_home, "nld_build_state") +else: + # 本地调试场景回退到 ~/.nld_build_state + STATE_DIR = os.path.expanduser("~/.nld_build_state") + def main(): if len(sys.argv) < 3: @@ -40,32 +52,56 @@ def main(): safe_channel = channel_name.replace("-", "_").replace(" ", "_") env_var_name = f"NLD_CLIENT_{safe_channel}_VERSION_CODE" - # 1. 尝试从环境变量读取当前值 - current_value_str = os.environ.get(env_var_name) + # 1. 优先从状态文件读取(跨构建持久化存储) + current_code = read_state_file(safe_channel) - if current_value_str is not None: - # 环境变量存在,解析为整数 - try: - current_code = int(current_value_str) - print(f"[VersionCode] 从环境变量 {env_var_name} 读取到当前值: {current_code}", file=sys.stderr) - except ValueError: - print(f"[VersionCode] 警告: 环境变量 {env_var_name} 的值 '{current_value_str}' 无法解析为整数,将从 YAML 重新读取", file=sys.stderr) - current_code = read_build_code_from_yaml(yaml_path) + if current_code is not None: + print(f"[VersionCode] 从状态文件读取到 {safe_channel} 上次值: {current_code}", file=sys.stderr) else: - # 环境变量不存在,从 YAML 读取初始值 - print(f"[VersionCode] 环境变量 {env_var_name} 不存在,从 YAML 读取初始值", file=sys.stderr) + # 2. 回退到 YAML 默认值 + print(f"[VersionCode] 状态文件不存在,从 YAML 读取初始值", file=sys.stderr) current_code = read_build_code_from_yaml(yaml_path) # 2. 递增 new_code = current_code + 1 print(f"[VersionCode] 渠道={channel_name}, 旧值={current_code}, 新值={new_code}", file=sys.stderr) - # 3. 输出 export 语句供 shell source(写到 stdout) - # 同时输出 BUILD_CODE 变量供 build_unity.sh 直接使用 + # 3. 写回状态文件(跨构建持久化) + write_state_file(safe_channel, new_code) + + # 4. 输出 export 语句供 shell source(写到 stdout) print(f"export {env_var_name}={new_code}") print(f"export NLD_CURRENT_VERSION_CODE={new_code}") +def read_state_file(safe_channel): + """从 Jenkins node 状态文件读取渠道的上次 versionCode,不存在时返回 None""" + state_file = os.path.join(STATE_DIR, f"{safe_channel}.json") + if not os.path.exists(state_file): + print(f"[VersionCode] 状态文件不存在: {state_file}", file=sys.stderr) + return None + try: + with open(state_file, 'r', encoding='utf-8') as f: + data = json.load(f) + code = int(data.get("version_code", "")) + return code + except Exception as e: + print(f"[VersionCode] 警告: 读取状态文件失败: {e}", file=sys.stderr) + return None + + +def write_state_file(safe_channel, new_code): + """将递增后的 versionCode 写入 Jenkins node 状态文件,实现跨构建持久化""" + try: + os.makedirs(STATE_DIR, exist_ok=True) + state_file = os.path.join(STATE_DIR, f"{safe_channel}.json") + with open(state_file, 'w', encoding='utf-8') as f: + json.dump({"version_code": new_code, "channel": safe_channel}, f) + print(f"[VersionCode] ✅ 已将 {safe_channel} versionCode={new_code} 写入状态文件: {state_file}", file=sys.stderr) + except Exception as e: + print(f"[VersionCode] 警告: 写入状态文件失败: {e},不影响本次构建", file=sys.stderr) + + def read_build_code_from_yaml(yaml_path): """从 ChannelSetting.yaml 读取 BuildCode 字段""" if not os.path.exists(yaml_path):