Repository navigation
ci(release): 使用手动 tag 覆盖七分支发布版本 - #255
Conversation
- 必填无 v 前缀的 tag 并覆盖构建与 Central 部署版本 - 按输入后缀决定发布类型和升版规则,保持 Beta 开发快照 - 校验重跑 tag 一致性,并从锁定开发版本安全创建升版 PR
Gugle2308
left a comment
There was a problem hiding this comment.
结论:核心机制已验证成立——本地实跑 27 项发布测试全通过,-Pmod_version 已覆盖构建与 JReleaser 部署两条路径,且手工 tag 的校验链完整;但 bump() 缺少“版本是否已更新”的判断,存在把分支版本写回旧值的路径,且预检不再校验 mod_version 的可解析性,这一点只有到发布成功后的 bump 才会暴露。
审查范围:base dev/26.1 → head e73df50a,8 文件 +96/−48(patch-diff 与 API 声明逐位一致)、draft=false、mergeable=true、无既有 review。前置 #252 已于 2026-11-10T07:28Z 合并,默认分支上已有 Create Multi-Version Releases 与 release_notes.py。
✅ 一、已验证成立的部分
27 项测试本地实跑通过(抽出 head 的 .github/release/ 后 unittest discover):Ran 27 tests in 0.130s — OK。
| 检查点 | 结论 |
|---|---|
| 手工 tag 作为唯一版本源 | prepare() 用 RELEASE_TAG,plan = {"tag": tag, "version": tag};删除了七线 mod_version 一致性校验,与文档一致 |
| tag 校验时机 | release_type(tag) 在 artifact() 之前;测试断言非法 tag(空、v2.0.0、2.0、2.0.0-beta.1、2.0.0+snapshot.5、含换行、$(example))时 artifact/github 均未被调用 |
v 前缀清除彻底 |
全仓 grep 无残留 "v" + 构造;TAG/PLAN/publish/bump/断言全部改为无前缀;tag_manifest 改 re.fullmatch(VERSION, tag)、manifest["version"] == tag、asset stem 用 tag |
-Pmod_version 双通道 |
release.yml:91 构建传入;central.py 的 jreleaserDeploy 命令行传入(有专门测试断言 -Pmod_version=<version> 在 argv 中) |
| 构件校验用输入版本 | artifacts.py 以 version 校验 POM 坐标、内部依赖 version+scope=compile、主 JAR 内 neoforge.mods.toml 的 version、jarjar 内嵌 artifactVersion、slim JAR 的 mod 描述符 |
| 重跑防篡改 | 已保存计划时 require(plan["tag"] == tag, "Input tag differs…"),测试验证此时不发任何 API |
| bump 的漂移防护 | expected 取自锁定源码、current 取自 base HEAD,不等即报 expected … from the locked source |
| 文档对齐 | RELEASING.md 同步更新了表格标题(输入 tag)、-Pmod_version 说明、状态名去 v(release/2.0.0/26.1/central)、patch 计算口径 |
⚠️ 二、bump() 缺少“已经更新”判断,存在版本写回路径
major, minor, patch = version.split(".")
next_version = f"{major}.{minor}.{int(patch) + 1}"
current = mod_version(props)
if current == next_version: # ← 只挡"恰好相等"
summary(f"{base} is already at {next_version}."); return
expected = mod_version(contents("gradle.properties", plan["targets"][line]["sha"]))
require(current == expected, …) # ← 只挡"分支被人改过"next_version 由 tag 的 core 计算,current 是分支的开发版本,两者没有大小关系检查。若分支已处于更新的序列(例如 2.1.1),而本次补发一个低序列 tag(例如 2.0.5),则 current(2.1.1) != next_version(2.0.6)、且 current == expected 成立 → 会把 gradle.properties 从 2.1.1 改写成 2.0.6(版本回退),并创建一个标题为「将版本推进到 2.0.6」的 PR。
RELEASING.md 写的是「仅当根版本仍等于锁定源码中的开发版本时才修改……其他版本报告冲突」,但此路径既不冲突也不跳过。
建议:解析 core 三元组后比较,current_core >= next_version 时记为“无需修改”并跳过写回(或明确报冲突)。改动很小、测试也容易补一条。
⚠️ 三、预检不再校验 mod_version,失败点被推迟到发布之后
prepare() 现在只读 java_version 与 gradle/scripts/release.gradle,mod_version() 仅剩 bump() 使用:
props = contents("gradle.properties", sha)
java = re.search(rb"(?m)^java_version=(\d+)\s*$", props).group(1).decode()
contents("gradle/scripts/release.gradle", sha) # ← 不再读 mod_version由于构建由 -Pmod_version 供给版本,某条分支的 gradle.properties 即使缺少 mod_version 或出现多行,预检与七个构建都会通过;直到发布已经推到 Central / GitHub 之后,bump() 里的 mod_version() 才抛 Expected one mod_version property,bump job 失败。
建议:预检保留“能解析出唯一 mod_version”的检查(只校验可解析,不比较七线是否一致、不比较是否等于 tag),把失败点前移到 dispatch 的第一分钟。这与本 PR 的设计并不冲突。
💡 四、其余建议
bump()的等值早退在漂移检查之前:if current == next_version: return先于require(current == expected),因此“分支已是目标版本、但锁定源码版本不同”会被当作完成。影响很小,但与文档「其他版本报告冲突」的措辞略偏,可把漂移检查上移。- tag 在部分 GitHub 路径未做 URL 编码:
releases/tags/{tag}、git/ref/tags/{tag}直接拼 tag,而同仓release_notes.py的compare/{quote(tag, safe='')}是编码的。+在路径中按 RFC 3986 属合法字面量、实际大概率可用,但同一代码库两套写法建议统一(mod_sites.release_url()同理,…/releases/tag/{plan['tag']})。这是既有代码,本次 tag 只是去掉了v。 - 迁移期提示:新的
tag_manifest只接受无v的 tag。若切换时存在vX.Y.Z的在途草稿,升级后无法续跑(历史已发布 tag 不受影响——generate_notes只读tag_name,仍可作为previous_tag_name候选)。建议在 RELEASING.md 加一句「切换前的在途发布需先收尾或放弃」。
验证边界
脚本从 head 抽取后在本地 Python 3.11.2 实跑(27 项全过),未执行任何真实发布、未调用 GitHub API;release.yml 仅静态阅读,未跑 actionlint(PR 描述称已通过)。PR 描述中「实际 stageRelease 构建 + artifacts.py 校验 22 组坐标 / 21 个内嵌模块」我无法独立复核,请以作者运行记录为准;gradle.properties 未被改写这一点与代码一致(构建只用 -Pmod_version,prepare 不写文件)。
🌿 Roseau API Breaking Change Report
|
Create Multi-Version Releases 现在要求输入不带 v 前缀的 tag,直接以它作为所有 Minecraft 构建的版本。例如输入
2.0.0+pre-release.13,Git tag、JAR 内版本和 Maven 版本均为该值,不再从分支的gradle.properties读取发布版本,也不要求开发版本一致。-Pmod_version,构件校验使用输入版本。X.Y.Z才创建下一 patch 的 PR,并比较锁定源码中的原始开发版本防止覆盖并发修改。验证:27 项 Python 发布测试通过,release.yml 的 actionlint 和 git diff --check 通过。实际执行
CI_BUILD=false ./gradlew -PanvillibRelease -Pmod_version=2.0.0+pre-release.13 stageRelease --offline --no-configuration-cache成功,artifacts.py 校验通过 22 个 Maven 发布单元和 21 个内嵌模块;gradle.properties 未改写。未执行真实发布。