⚠️ 两条最容易被忘记的规则
- CHANGELOG.md 默认整体重写,不是追加。 它是“这次发布”的说明书,不是历史累积日志——默认清空旧内容,只写本次区间的变更。仅当用户在本次对话中明确要求“这次用追加”时才允许追加,且只对本次生效,下次执行不参考上次的选择,仍然默认重写。
- 每条日志写的是功能现在的最终样子,不是这次做了哪些操作。 同一功能/bug 在区间内被改了不止一次,只写一条,描述改完之后的最终效果,不按 commit 顺序拆开写。
流程
- 读取
app/build.gradle.kts中的versionCode和versionName - 检查是否存在未提交内容;如果有,先根据其更改内容执行格式化、校验并提交,提交必须只包含这些业务改动,不得把版本号与 changelog 混入同一个提交
- 执行
./gradlew versionCatalogUpdate,更新gradle/libs.versions.toml中可升级的版本与插件声明 - 检查
gradle/libs.versions.toml是否仍保留构建脚本依赖的自定义版本别名;若versionCatalogUpdate删除了android-compileSdk、android-targetSdk、android-minSdk、android-jvm这类项目自定义键,必须立即补回,保证构建脚本访问器不失效 - 确定新版本号:
- 默认:patch +1(如 1.0.3 → 1.0.4),
versionCode+1 - 用户指定了具体版本号时,使用用户指定的版本
- 默认:patch +1(如 1.0.3 → 1.0.4),
- 通过
git log查找上一次版本号提升的 commit,收集此后所有变更 - 归纳为面向用户的功能描述,忽略纯重构、CI 修复、GitHub Action、发布脚本、代码风格、调试指令等不影响普通用户体验的改动。同一功能被多次改动时合并为一条最终效果描述,不要按 commit 拆开写
- 识别本次版本涉及的 GitHub issue:
- 用
gh读取相关 issue 原文 - 逐条核对本次改动是否完整满足 issue 要求
- 只有在 issue 要求被本次改动完整满足时,提交信息才允许追加
close #xxxx - 若只是部分满足,或无法证明已完整满足,则不要追加
close #xxxx
- 用
- 修改
app/build.gradle.kts的versionCode和versionName - 更新
.github/CHANGELOG.md:- 默认整体重写:清空旧内容,只保留上一次版本号提升 commit 之后到当前版本的变更
- 仅当用户本次明确要求追加时,保留旧内容并把本次变更追加进去;没有明确要求就一律重写,不要因为上次是追加就顺着延续
- 执行自动格式化与校验指令,至少运行
./gradlew ktlintFormat ktlintCheck - 版本号与 changelog 更新后必须及时提交,提交信息基础格式:
chore: bump version to {version} and update changelog- 仅当第 8 步确认完整满足某个 issue 时,才在提交信息末尾追加
close #xxxx
- 仅当第 8 步确认完整满足某个 issue 时,才在提交信息末尾追加
- 提交前自检:
- 本次是重写还是追加?没有用户明确要求追加的话必须是整体重写,文件里不能有本次区间之外的旧版本条目
- 每条日志是否是最终效果,而不是按 commit 罗列的过程?重复/互相修正的条目合并成一条
- 中英文条目一一对应、数量一致
-
close #xxxx都基于gh读到的 issue 原文核实过,不是凭印象加的 - 任一项不通过,回到对应步骤重做
更新日志格式
- English change 1
- English change 2
---
- 中文改动描述 1
- 中文改动描述 2
规则:
- 英文在上,中文在下,中间用单独一行
---分隔 - 不写版本号标题、日期和分类小节,发布标题已有体现
- 条目平铺,不折叠,不用 emoji,条目末尾不加标点
- 更新日志禁止黑话,要求用自然拟人的语气来写
- 中英文一一对应
- 每条以动词开头,简洁描述用户可感知的变化;同一改动只写最终效果,不写过程,净效果为零则不写
- 禁止写入 GitHub Action、发布脚本、构建产物命名、CI 调整、调试指令变更等非用户可感知变化
- 末尾无空行
- issue 校验必须基于
gh返回的原文,不允许凭印象追加close #xxxx - 版本号更新只处理本地改动与本地提交,push 阶段交给用户自己执行