feat(version): 版本号唯一来源 = CHANGELOG.md(含改了什么/怎么验收的结构约束) #3

Closed
zheromiku wants to merge 1 commits from feat/versioning-and-changelog into main
Owner

范围

分支 feat/versioning-and-changelog(1 个提交,10 个文件)。只加版本化与变更记录机制,不改业务逻辑。

解决了什么

本仓此前没有任何版本/构建元信息 —— 没有 -ldflags 注入、没有产物可读的版本号,
"线上跑的是哪个提交"答不出来;"这次改了什么、怎么验收"也没有载体。

设计:CHANGELOG.md 就是版本的唯一来源

正本 §6.1 要求"版本号只有一个来源"。所以不放 VERSION 文件、也不靠 git tag
(CI 是 git fetch --depth 50,取不到 tag ⇒ git describe 会静默退化,见 docs/agents/traps.md trap-5)。

CHANGELOG.md 顶部已发布版本
  → scripts/version.py 解析
  → 构建时 -ldflags -X …version.Number=<号> 注入
  → CI 断言「注入的号 == CHANGELOG 顶部」

没有 CHANGELOG 条目 ⇒ 解析失败 ⇒ 构建红 —— 所以"忘了记变更"过不去。

你要求的两件事,是怎么被强制的

版本里面要告诉我改了什么、怎么验收

每个已发布版本必须有两节:### 改了什么 与 ### 怎么验收。
scripts/check_changelog.py 逐条检查(两节齐、带日期、版本号不重复且严格递减、小节不为空),
CI 会跑它 —— 缺任一节即红。首次记录 0.1.0 已按这个格式写好,验收步骤是实测出来的
(web 8088->8080;/health /livez /readyz / 全 200;nginx 反代 /health 与 /api/;
api 容器 health=healthy),不是设计意图。

反向自检(都真跑过)

  • make version-contract 注入正确号 → PASS
  • 注入 9.9.9(CHANGELOG 里没有)→ FAIL
  • 删掉真实 CHANGELOG.md 的「怎么验收」小节 → 报红(对真实文件做,不只是夹具)
  • make changelog-check --self-test → 造正/反夹具,断言该红会红、该绿会绿

安全与数据边界

  • 未改任何业务逻辑、未改数据库、未改 compose.yaml
  • Dockerfile 加了 ARG VERSION/COMMIT_SHA/BUILD_TIME + ldflags,未透传时落 dev ——
    故意的:一个显眼的 dev 好过一个看起来正常的假版本号

尚未验证

  • 未跑 make verify 全量(含 go test ./... 与前端)—— CI 是本次测试证据
  • GET /version 端点与 cmd/api -version 开关未做:它们要改
    internal/httpapi/server.go 与 cmd/api/main.go,与在审 PR #2 冲突 ⇒ 待 PR #2 合并后在 main 上补
  • 同样原因,compose.yaml 的 build args 透传未做(当前 compose 构建的镜像会报 dev)

明确声明

未合并、未部署。 合并由人决定;合并与部署是分开的动作。

## 范围 分支 `feat/versioning-and-changelog`(1 个提交,10 个文件)。**只加版本化与变更记录机制,不改业务逻辑。** ## 解决了什么 本仓此前**没有任何版本/构建元信息** —— 没有 `-ldflags` 注入、没有产物可读的版本号, "线上跑的是哪个提交"答不出来;"这次改了什么、怎么验收"也没有载体。 ## 设计:CHANGELOG.md 就是版本的**唯一来源** 正本 §6.1 要求"版本号只有一个来源"。所以**不放** `VERSION` 文件、也**不靠 git tag** (CI 是 `git fetch --depth 50`,取不到 tag ⇒ `git describe` 会静默退化,见 `docs/agents/traps.md` trap-5)。 ``` CHANGELOG.md 顶部已发布版本 → scripts/version.py 解析 → 构建时 -ldflags -X …version.Number=<号> 注入 → CI 断言「注入的号 == CHANGELOG 顶部」 ``` **没有 CHANGELOG 条目 ⇒ 解析失败 ⇒ 构建红** —— 所以"忘了记变更"过不去。 ## 你要求的两件事,是怎么被强制的 > 版本里面要告诉我**改了什么**、**怎么验收** 每个已发布版本必须有两节:`### 改了什么` 与 `### 怎么验收`。 `scripts/check_changelog.py` 逐条检查(两节齐、带日期、版本号不重复且严格递减、小节不为空), CI 会跑它 —— **缺任一节即红**。首次记录 `0.1.0` 已按这个格式写好,验收步骤是**实测出来的** (web `8088->8080`;`/health` `/livez` `/readyz` `/` 全 200;nginx 反代 `/health` 与 `/api/`; api 容器 `health=healthy`),不是设计意图。 ## 反向自检(都真跑过) - `make version-contract` 注入正确号 → **PASS** - 注入 `9.9.9`(CHANGELOG 里没有)→ **FAIL** - 删掉真实 `CHANGELOG.md` 的「怎么验收」小节 → **报红**(对真实文件做,不只是夹具) - `make changelog-check --self-test` → 造正/反夹具,断言该红会红、该绿会绿 ## 安全与数据边界 - 未改任何业务逻辑、未改数据库、未改 `compose.yaml` - `Dockerfile` 加了 `ARG VERSION/COMMIT_SHA/BUILD_TIME` + ldflags,**未透传时落 `dev`** —— 故意的:一个显眼的 `dev` 好过一个看起来正常的假版本号 ## 尚未验证 - 未跑 `make verify` 全量(含 `go test ./...` 与前端)—— CI 是本次测试证据 - **`GET /version` 端点与 `cmd/api -version` 开关未做**:它们要改 `internal/httpapi/server.go` 与 `cmd/api/main.go`,与在审 PR #2 冲突 ⇒ 待 PR #2 合并后在 main 上补 - 同样原因,`compose.yaml` 的 build args 透传未做(当前 compose 构建的镜像会报 `dev`) ## 明确声明 **未合并、未部署。** 合并由人决定;合并与部署是分开的动作。
zheromiku added 1 commit 2026-10-10 17:54:16 +08:00
背景:本仓此前没有任何版本/构建元信息 —— 没有 ldflags 注入、也没有产物可读的
版本号,"线上跑的是哪个提交"答不出来;"这次改了什么、怎么验收"也没有载体。

落地:
- CHANGELOG.md:**版本号的唯一来源**(正本 §6.1:版本号只准有一处)。刻意不放
  VERSION 文件、也不靠 git tag —— CI 是 `git fetch --depth 50`,取不到 tag,
  `git describe` 会静默退化。每个已发布版本必须有两节:### 改了什么 与 ### 怎么验收。
- scripts/version.py:从 CHANGELOG 顶部解析版本号;解析不到即非 0 退出(构建据此失败)。
- scripts/check_changelog.py:结构自检(两节齐、带日期、版本号不重复且严格递减、
  小节不为空),带 --self-test 反向自检。
- internal/version:三个构建期注入变量 + 契约测试(注入的号必须等于 CHANGELOG 顶部)。
- Makefile:build 带 -ldflags 注入;verify 增加 changelog-check 与 version-contract。
- Dockerfile:ARG VERSION/COMMIT_SHA/BUILD_TIME + ldflags(未透传时落 dev —— 故意显眼,
  好过看起来正常的假版本号)。
- CI:新增「版本与变更记录契约」步,并显式断言契约测试真的 PASS(被跳过的断言等于没有断言)。
- docs/提交规范.md(ci_gate.py 的报错文案一直在指它)、docs/agents/traps.md(7 条实测陷阱)。

验证(都真跑过):
- make version → 0.1.0;make changelog-check → 合规
- make version-contract → PASS;注入 9.9.9(CHANGELOG 里没有)→ FAIL(反向自检)
- 删掉真实 CHANGELOG 的「怎么验收」小节 → 报红(对真实文件做,不只是夹具)
- go build ./... 与 go vet ./internal/version/... 通过

未做(会与在审 PR #2 冲突,待其合并后在 main 上补):
- GET /version 端点(internal/httpapi/server.go)与 cmd/api 的 -version 开关
- compose.yaml 透传 build args(当前由 compose 构建的镜像会报 dev)

⚠️ 未跑 make verify 全量(含 go test ./... 与前端),CI 是本次的测试证据。
zheromiku closed this pull request 2026-10-10 18:13:30 +08:00
zheromiku deleted branch feat/versioning-and-changelog 2026-10-10 18:13:30 +08:00
Some checks are pending
build / build (push) Successful in 27s

Pull request closed

Sign in to join this conversation.