fix(ci): 版本校验在浅克隆下必然误报
- fix(ci): checkout 改成 fetch-depth: 0——没有标签、提交数恒为 1 时, version.mjs --check 算出来的版本一定是 0.0.0+1,于是每次推送都红 - fix(version): CHANGELOG 按标签区间重算全部历史,不再只渲染当前版本, 否则每次发布都会把上一版那一段覆盖掉 - fix(build): 固件包文件名用算出来的版本,不再用 BUILD-INFO.json 里那套旧编号
This commit is contained in:
@@ -174,7 +174,11 @@ jobs:
|
||||
runs-on: ${{ vars.RUNNER_LINUX || 'ubuntu-latest' }}
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
# 版本号从标签算(git describe / rev-list --count)。默认的浅克隆没有标签、
|
||||
# 提交数恒为 1,version.mjs --check 会误报「版本已过期」——必须先取全历史。
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# runner 镜像里多半没有 rustup,而 dtolnay/rust-toolchain 靠它装工具链。
|
||||
# 这里只装一个最小的 rustup 本身,工具链交给下面那个 action —— 这样自建
|
||||
@@ -260,7 +264,11 @@ jobs:
|
||||
TARGET: x86_64-unknown-linux-gnu
|
||||
CARGO_BUILD_TARGET: x86_64-unknown-linux-gnu
|
||||
steps:
|
||||
# 版本号从标签算(git describe / rev-list --count)。默认的浅克隆没有标签、
|
||||
# 提交数恒为 1,version.mjs --check 会误报「版本已过期」——必须先取全历史。
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 确保有 rustup
|
||||
run: |
|
||||
@@ -377,7 +385,11 @@ jobs:
|
||||
npm_config_cache: C:\Users\admin\runner\windows\cache\ci-npm
|
||||
RUNNER_TOOL_CACHE: C:\Users\admin\runner\windows\cache\ci-toolcache
|
||||
steps:
|
||||
# 版本号从标签算(git describe / rev-list --count)。默认的浅克隆没有标签、
|
||||
# 提交数恒为 1,version.mjs --check 会误报「版本已过期」——必须先取全历史。
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 宿主模式的 Windows runner 上,PATH 里的 `bash` 是 C:\Windows\System32\bash.exe
|
||||
# —— WSL 的启动器,而 WSL 在 runner 账户下起不来,报 E_ACCESSDENIED(日志里是
|
||||
@@ -512,7 +524,11 @@ jobs:
|
||||
# cargo 步骤,所有目标都由 tauri build 的 --target 交代。
|
||||
TARGET: universal-apple-darwin
|
||||
steps:
|
||||
# 版本号从标签算(git describe / rev-list --count)。默认的浅克隆没有标签、
|
||||
# 提交数恒为 1,version.mjs --check 会误报「版本已过期」——必须先取全历史。
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 通用包要两个架构的 std 都在。
|
||||
- name: 装 Rust(stable + 两个 mac 目标)
|
||||
|
||||
+15
-101
@@ -1,119 +1,33 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"major": 0,
|
||||
"minor": 2,
|
||||
"patch": 0,
|
||||
"build": 34,
|
||||
"patch": 1,
|
||||
"build": 35,
|
||||
"protocol": 1,
|
||||
"date": "2026-10-19",
|
||||
"baseline": "v0.1.0",
|
||||
"baseline": "v0.2.0",
|
||||
"commits": 1,
|
||||
"groups": {
|
||||
"feat": [
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "RMIC::2026 界面重做、可计算的版本机制与固件版本联动",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "界面换成墨黑蓝底 + 单支红的矩形语言,切角全部去掉,仅装甲条保留平行四边形",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "自托管 HarmonyOS Sans SC 与 JetBrains Mono,中文与拉丁数字逐字回退",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "新增启动序列、首启门、用户端 HUD、裁判端控制台、设置抽屉与固件维护页",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "裁判端中缝与下方控制台可拖,鼠标落在哪一路下方就看哪一路",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "设置抽屉常驻实时预览,与画面共用同一份准星绘制代码",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "动效改用 Material 3 的缓动曲线与时长,逐条替换掉自造的贝塞尔",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "version",
|
||||
"text": "版本号与 CHANGELOG 由 scripts/version.mjs 从 git 历史算出,不再手写",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "firmware",
|
||||
"text": "Hello 报文携带语义化版本、构建号与自报协议号,负载向后兼容",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "固件版本显示在绑定列表与裁判端每一格;协议不匹配时给出具体原因",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "firmware",
|
||||
"text": "固件包版本与客户端同源,都从 version.json 读",
|
||||
"breaking": false
|
||||
}
|
||||
],
|
||||
"fix": [
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "getCurrentWindow() 在没有 Tauri 注入时同步抛异常,浏览器预览整棵树被卸载",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "启动序列的淡出 effect 清掉了自己刚设的 setTimeout,界面永远停在启动页",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "设置抽屉左侧导航的锚点没挂到 section 上,且用错了坐标系",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "protocol",
|
||||
"text": "Hello 改用宽松帧头解析,让协议不匹配的板子能被解释而不是静默消失",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "build",
|
||||
"text": "Windows 上 bindgen 加载不了 libclang 的同目录依赖,构建脚本补上搜索路径",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "build",
|
||||
"text": "esp-idf-sys 在长路径下拒绝构建,固件构建改用短的目标目录",
|
||||
"breaking": false
|
||||
}
|
||||
],
|
||||
"build": [
|
||||
{
|
||||
"scope": "client",
|
||||
"text": "队标图标,含光学尺寸分级与手工拼的多尺寸 ICO",
|
||||
"scope": "ci",
|
||||
"text": "版本校验在浅克隆下必然误报",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "ci",
|
||||
"text": "守门 job 增加版本一致性检查,产物名改为 rmic-2026-*",
|
||||
"text": "checkout 改成 fetch-depth: 0——没有标签、提交数恒为 1 时,",
|
||||
"breaking": false
|
||||
}
|
||||
],
|
||||
"docs": [
|
||||
},
|
||||
{
|
||||
"scope": null,
|
||||
"text": "补充界面语言、版本机制与协议通告布局的说明",
|
||||
"scope": "version",
|
||||
"text": "CHANGELOG 按标签区间重算全部历史,不再只渲染当前版本,",
|
||||
"breaking": false
|
||||
},
|
||||
{
|
||||
"scope": "build",
|
||||
"text": "固件包文件名用算出来的版本,不再用 BUILD-INFO.json 里那套旧编号",
|
||||
"breaking": false
|
||||
}
|
||||
]
|
||||
|
||||
+58
-1
@@ -4,9 +4,20 @@
|
||||
> 提交信息遵循 Conventional Commits,一条一个条目;要求见该脚本的文件头。
|
||||
> 建立这套机制之前的人工整理记录保存在 [`docs/CHANGELOG-legacy.md`](docs/CHANGELOG-legacy.md)。
|
||||
|
||||
## v0.2.1 — 2026-10-19
|
||||
|
||||
构建号 **35** · 线路协议 **1** · 1 个提交(v0.2.0 → v0.2.1)
|
||||
|
||||
### 修复
|
||||
|
||||
- **ci** · 版本校验在浅克隆下必然误报
|
||||
- **ci** · checkout 改成 fetch-depth: 0——没有标签、提交数恒为 1 时,
|
||||
- **version** · CHANGELOG 按标签区间重算全部历史,不再只渲染当前版本,
|
||||
- **build** · 固件包文件名用算出来的版本,不再用 BUILD-INFO.json 里那套旧编号
|
||||
|
||||
## v0.2.0 — 2026-10-19
|
||||
|
||||
构建号 **34** · 线路协议 **1** · 1 个提交(v0.1.0 → v0.2.0)
|
||||
1 个提交
|
||||
|
||||
### 新增
|
||||
|
||||
@@ -39,3 +50,49 @@
|
||||
### 文档
|
||||
|
||||
- 补充界面语言、版本机制与协议通告布局的说明
|
||||
|
||||
## v0.1.0 — 2026-10-19
|
||||
|
||||
33 个提交
|
||||
|
||||
### 新增
|
||||
|
||||
- 链路控制、延迟校准与长测工具,补全文档
|
||||
|
||||
### CI
|
||||
|
||||
- npm 装 pnpm 前先清掉残留影子文件(EEXIST),并去掉 npm 不认的 store-dir
|
||||
- Windows 改用 npm 装的 JS 版 pnpm(standalone 二进制在低完整性沙箱里必崩)
|
||||
- Windows 的 pnpm install 加 corepack 退路(standalone 在低完整性沙箱里栈溢出)
|
||||
- Windows 的 pnpm 安装目录改成每次运行都干净的路径
|
||||
- 删掉两段临时诊断(Windows 的坑已经查清并写进文件头第 5 条)
|
||||
- Windows 的 pnpm 那步写死 shell: pwsh(免得 actionlint 拿 bash 规则挑反斜杠路径)
|
||||
- Windows job 给 pnpm install 明确指定 store 与导入方式
|
||||
- Windows job 加 USERPROFILE 重定向 —— pnpm 的操作锁按它算路径
|
||||
- **diag** · 再探一次 —— pnpm 眼里的目录到底是哪个
|
||||
- Windows job 再加 LOCALAPPDATA/APPDATA 重定向(pnpm 的 store 锁挂在这里)
|
||||
- Windows job 低完整性适配 —— 把 CI 的"家目录"挪到 runner 自己的工作目录
|
||||
- **diag** · 在 Windows job 里加一段临时诊断(查完删)
|
||||
- 修 Windows job 第二个坑 —— TEMP/TMP 为空,Git Bash 的 mktemp 写不进 <Git>\tmp
|
||||
- 修 Windows job 0 秒失败 —— 宿主 runner 上的 bash 是 WSL,不是 Git Bash
|
||||
- Windows 产物默认就编(平台开关从 vars 换成 inputs)
|
||||
- 修两处 Gitea 上跑不了的东西(upload-artifact v4 → v3、去掉缓存)
|
||||
- 构建客户端 workflow(Windows / Linux / macOS)
|
||||
|
||||
### 其它
|
||||
|
||||
- 双方血条(角上平行四边形)、归零即击败、去掉受击抖动、裁判端可改队名
|
||||
- 早先那版 C 写的装甲板固件(ESP-IDF 工程)
|
||||
- ESP32-C3 装甲板固件(一主三从)+ 烧录脚本,之前一直没提交
|
||||
- 修两处小问题(预览模式的命中节奏、设置面板里漏出来的 **)
|
||||
- 用户端与裁判端两套页面(Tauri v2 + React),删掉 Slint 客户端
|
||||
- Tauri v2 后端 + 共享网络层(用户端/裁判端双身份)
|
||||
- 文档:写防作弊、缩放布局、槽位语义
|
||||
- 槽位对应队伍,不再按 id 顺序对号入座
|
||||
- 修裁判端两格不等宽,加滚轮缩放与拖动平移,启动即最大化
|
||||
- 队伍端 release 只接收绑定的那一块板子
|
||||
- 文档:按 UDP 多端架构重写根 README 与 client README
|
||||
- 修 udp_probe.py 的重组与 fps 两处测量错误
|
||||
- 更正上一个提交的归因——坏帧不在这里
|
||||
- 修复重复分片能凑出一张坏帧
|
||||
- ESP32-S3 摄像头图传:固件 + Slint 客户端 + 共享协议
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "rmic-2026",
|
||||
"private": true,
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"type": "module",
|
||||
"description": "RMIC::2026 —— ESP32 图传与装甲板系统的桌面端:用户端(装甲条 + 瞄准器)与裁判端(双路 + 装甲板 + 录制)",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "RMIC-2026",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"identifier": "com.simbarobotics.rmic2026",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
*/
|
||||
|
||||
export const BUILD = {
|
||||
version: "0.2.0",
|
||||
version: "0.2.1",
|
||||
major: 0,
|
||||
minor: 2,
|
||||
patch: 0,
|
||||
patch: 1,
|
||||
/** git 提交数,单调递增。 */
|
||||
build: 34,
|
||||
build: 35,
|
||||
/** 线路协议版本。与固件自报的那个数直接比对。 */
|
||||
protocol: 1,
|
||||
/** 生成时的提交日期(`YYYY-MM-DD`)。 */
|
||||
|
||||
+97
-23
@@ -74,6 +74,56 @@ function git(args, { allowFail = false } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 所有 `v*` 标签,按版本号从旧到新。 */
|
||||
function allTags() {
|
||||
const raw = git(["tag", "--list", "v*", "--sort=version:refname"], { allowFail: true });
|
||||
if (!raw) return [];
|
||||
return raw.split("\n").map((line) => line.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
/** `from..to` 之间的提交;`from` 为 null 表示从头开始。 */
|
||||
function commitsBetween(from, to) {
|
||||
const range = from ? `${from}..${to}` : to;
|
||||
const raw = git(["log", range, "--no-merges", "--pretty=format:%H%x1f%s%x1f%b%x1e"], {
|
||||
allowFail: true,
|
||||
});
|
||||
if (!raw) return [];
|
||||
return raw
|
||||
.split("\x1e")
|
||||
.map((chunk) => chunk.trim())
|
||||
.filter(Boolean)
|
||||
.map((chunk) => {
|
||||
const [hash, subject, body] = chunk.split("\x1f");
|
||||
return { hash, subject: subject ?? "", body: body ?? "" };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 逐个标签还原历史发布。
|
||||
*
|
||||
* 改动日志必须是**可重复计算**的:同一次 `--write` 无论跑多少遍,输出都要一样。
|
||||
* 所以旧版本不从文件里读回来,而是按标签区间重新算一遍——文件只是它的投影。
|
||||
*/
|
||||
function history() {
|
||||
const tags = allTags();
|
||||
const releases = [];
|
||||
let previous = null;
|
||||
|
||||
for (const tag of tags) {
|
||||
const commits = commitsBetween(previous, tag);
|
||||
releases.push({
|
||||
tag,
|
||||
title: tag,
|
||||
date: git(["log", "-1", "--pretty=format:%cs", tag], { allowFail: true }),
|
||||
commits,
|
||||
entries: commits.flatMap(entriesOf),
|
||||
});
|
||||
previous = tag;
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
|
||||
/** 最近的一个 `v*` 标签;没有标签时返回 null(第一次发布)。 */
|
||||
function lastTag() {
|
||||
const tag = git(["describe", "--tags", "--abbrev=0", "--match", "v[0-9]*"], {
|
||||
@@ -178,6 +228,8 @@ function compute() {
|
||||
base,
|
||||
commits,
|
||||
entries,
|
||||
// 历史发布按标签区间重新算,渲染时用。
|
||||
releases: history(),
|
||||
version,
|
||||
build,
|
||||
dirty: git(["status", "--porcelain"]).length > 0,
|
||||
@@ -222,36 +274,24 @@ function groupEntries(entries) {
|
||||
.sort((a, b) => TYPE_ORDER.indexOf(a[0]) - TYPE_ORDER.indexOf(b[0]));
|
||||
}
|
||||
|
||||
function renderChangelog(meta, result) {
|
||||
/** 一节的正文:标题、统计行、按类型分组。 */
|
||||
function renderSection(title, date, meta, commits, entries, span) {
|
||||
const lines = [];
|
||||
lines.push("# 改动记录");
|
||||
lines.push("");
|
||||
lines.push(
|
||||
"> 本文件由 `scripts/version.mjs` 依据 git 历史生成,**请勿手改**。",
|
||||
);
|
||||
lines.push("> 提交信息遵循 Conventional Commits,一条一个条目;要求见该脚本的文件头。");
|
||||
lines.push("> 建立这套机制之前的人工整理记录保存在 [`docs/CHANGELOG-legacy.md`](docs/CHANGELOG-legacy.md)。");
|
||||
lines.push(`## ${title} — ${date}`);
|
||||
lines.push("");
|
||||
|
||||
if (result.entries.length === 0) {
|
||||
lines.push(`## v${meta.version} — ${meta.date}`);
|
||||
if (entries.length === 0) {
|
||||
lines.push("(这一版没有面向使用者的改动。)");
|
||||
lines.push("");
|
||||
lines.push("(自上一个发布以来没有面向使用者的改动。)");
|
||||
lines.push("");
|
||||
return lines.join("\n");
|
||||
return lines;
|
||||
}
|
||||
|
||||
const span = result.tag ? `${result.tag} → v${meta.version}` : `初始 → v${meta.version}`;
|
||||
lines.push(`## v${meta.version} — ${meta.date}`);
|
||||
lines.push("");
|
||||
lines.push(
|
||||
`构建号 **${meta.build}** · 线路协议 **${meta.protocol}** · ` +
|
||||
`${result.commits.length} 个提交(${span})`,
|
||||
);
|
||||
const stat = [`${commits.length} 个提交${span ? `(${span})` : ""}`];
|
||||
if (meta) stat.unshift(`构建号 **${meta.build}**`, `线路协议 **${meta.protocol}**`);
|
||||
lines.push(stat.join(" · "));
|
||||
lines.push("");
|
||||
|
||||
|
||||
for (const [type, list] of groupEntries(result.entries)) {
|
||||
for (const [type, list] of groupEntries(entries)) {
|
||||
const heading = GROUPS.find(([key]) => key === type)?.[1] ?? "其它";
|
||||
lines.push(`### ${heading}`);
|
||||
lines.push("");
|
||||
@@ -263,6 +303,40 @@ function renderChangelog(meta, result) {
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* 整份改动日志:当前这次要发布的 + 所有历史标签。
|
||||
*
|
||||
* 历史部分是从标签区间**重新算**出来的,不是把上一版的文件内容搬过来。这样跑多少遍
|
||||
* `--write` 结果都一样,也不会因为某次忘了提交生成物就把历史吃掉。
|
||||
*/
|
||||
function renderChangelog(meta, result, releases) {
|
||||
const lines = [];
|
||||
lines.push("# 改动记录");
|
||||
lines.push("");
|
||||
lines.push("> 本文件由 `scripts/version.mjs` 依据 git 历史生成,**请勿手改**。");
|
||||
lines.push("> 提交信息遵循 Conventional Commits,一条一个条目;要求见该脚本的文件头。");
|
||||
lines.push(
|
||||
"> 建立这套机制之前的人工整理记录保存在 [`docs/CHANGELOG-legacy.md`](docs/CHANGELOG-legacy.md)。",
|
||||
);
|
||||
lines.push("");
|
||||
|
||||
// HEAD 正好在最新标签上时(刚发布完),当前这一节没有内容,而同一个版本会在下面的
|
||||
// 历史里出现一次。跳过它,免得同一版出现两个标题。
|
||||
const hasCurrent = result.entries.length > 0 || releases.length === 0;
|
||||
if (hasCurrent) {
|
||||
const span = result.tag ? `${result.tag} → v${meta.version}` : `初始 → v${meta.version}`;
|
||||
lines.push(
|
||||
...renderSection(`v${meta.version}`, meta.date, meta, result.commits, result.entries, span),
|
||||
);
|
||||
}
|
||||
|
||||
for (const release of [...releases].reverse()) {
|
||||
lines.push(...renderSection(release.title, release.date, null, release.commits, release.entries, ""));
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
@@ -358,7 +432,7 @@ function write(meta, result) {
|
||||
2,
|
||||
) + "\n",
|
||||
);
|
||||
put("CHANGELOG.md", renderChangelog(meta, result));
|
||||
put('CHANGELOG.md', renderChangelog(meta, result, result.releases));
|
||||
put("CHANGELOG.json", renderJson(meta, result));
|
||||
put("desktop/src/lib/version.ts", renderTs(meta));
|
||||
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"major": 0,
|
||||
"minor": 2,
|
||||
"patch": 0,
|
||||
"build": 34,
|
||||
"patch": 1,
|
||||
"build": 35,
|
||||
"protocol": 1,
|
||||
"date": "2026-10-19",
|
||||
"baseline": "v0.1.0",
|
||||
"baseline": "v0.2.0",
|
||||
"note": "由 scripts/version.mjs 从 git 历史算出,请勿手改。"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user