0974d8dfa2
build / build (push) Successful in 57s
按已确认的契约实现(口径见 docs/VERSION_HISTORY.md):
- **版本号口径(只给有证据的)**:注释 tag + tag 指向该提交 + 该提交内 CHANGELOG 顶部三者一致 ⇒ 正式版本;
tag 之后的提交按 `<主>.<次>.<自该 tag 的提交数>` 显示开发号(与 scripts/version.py **同规则**);
证据不足 ⇒ 「历史提交 · 短SHA」+ 原因码,**不补造版本号**。完整 SHA 是唯一身份、版本号不是唯一键
(tag 之后两条并行分支各自的第 1 个提交都算 0.1.1 ⇒ 两条都保留,用短 SHA 区分)。
- **迁移 000046**:version_history_commits(提交记录,主键 repo_key+commit_sha)+ version_history_sync_runs
(同步状态)。快照 = 一次同步:抓完并与 X-Total-Count 对账通过才切换;失败不切换快照、不清空历史、
last_success_at 不动(页面显示"上次同步失败(原因)· 仍展示上次成功数据");「同步成功」≠「历史完整」。
- **只读客户端(匿名,不使用任何凭据)**:白名单 origin + 固定仓库、拒绝任意 URL 与跨主机重定向、
响应上限 5MB / 超时 15s、仅 5xx/429 退避重试(最多 3 次);逐页抓到短页为止;每次全量扫 tag
⇒ 旧提交后补的 tag 会更新既有记录(不新增第二行)。
- **接口**(三个都登记进 api/openapi.yaml):GET /api/v1/build-info(viewer)、
GET /api/v1/version-history(viewer;游标绑定快照,过期返回 409 cursor_expired;不返回伪造 total)、
POST /api/v1/version-history/sync(admin;并发同步复用同一作业,靠 IdempotencyKey)。
- **「当前运行」只认精确匹配**:产物注入的完整 SHA 命中某条记录才标该条;开发构建显式标注"开发构建";
没有可用标识 ⇒ "当前运行版本未知";**不拿最新 main / 最新 tag 顶替**,CI 成功不等于已部署。
- **前端**:一级菜单第 5 项(版本记录)+ 时间线页面(全部/正式/开发/历史四段筛选、正文展开、
加载更多、760px 单列无横向溢出、提交正文与变更记录按纯文本渲染);无打 tag / 发布 / 部署入口。
新增配置(留空即未接线,页面降级):VERSION_HISTORY_GITEA_BASE_URL / _REPO / _ALLOWED_ORIGINS /
_HTTP_TIMEOUT / _MAX_PAGES。
验证:`make verify` 15/15 success(tests-go 578 通过 / 0 失败;tests-web 209 通过 / 0 失败);
新增 Go 用例 30(版本口径与图遍历 12、客户端守卫 6、同步编排 5、接口 7);前端新增 18(组件 10 + 客户端 8);
真实仓库匿名快照拉取(`VERSION_HISTORY_LIVE_BASE_URL=… go test -run TestLiveSyncAgainstRealRepository`):
抓到 113 条与 X-Total-Count 一致、v0.1.0 是注释 tag 且目标与 `git rev-parse v0.1.0^{commit}` 一致、
开发号逐个等于 `git rev-list --count v0.1.0..<sha>`(正式 1 / 开发 22 / 历史 90)。
36 lines
1.3 KiB
Go
36 lines
1.3 KiB
Go
package version
|
|
|
|
// 构建身份(「版本记录」页的"当前运行"判据)。**只回身份字段**:不含主机、配置或任何凭据。
|
|
//
|
|
// 关键点:只有注入进来的 **完整 40 位 SHA** 才算可用身份 —— 页面据此做精确匹配;
|
|
// 拿不到就明确返回 identity_available=false,由页面显示"当前运行版本未知",**绝不猜**。
|
|
type BuildInfo struct {
|
|
ReleaseVersion string `json:"release_version"`
|
|
BuildKind string `json:"build_kind"`
|
|
CommitSHA *string `json:"commit_sha"`
|
|
DisplayVersion string `json:"display_version"`
|
|
BuiltAt string `json:"built_at"`
|
|
IdentityAvailable bool `json:"identity_available"`
|
|
}
|
|
|
|
// Snapshot 读当前运行产物的构建身份。
|
|
func Snapshot() BuildInfo {
|
|
info := BuildInfo{ReleaseVersion: ReleaseVersion, BuildKind: BuildKind, BuiltAt: BuildTime}
|
|
if IsRelease() {
|
|
info.BuildKind = "release"
|
|
} else {
|
|
info.BuildKind = "development"
|
|
}
|
|
if fullSHA.MatchString(CommitSHA) {
|
|
sha := CommitSHA
|
|
info.CommitSHA = &sha
|
|
info.DisplayVersion = DisplayVersion()
|
|
info.IdentityAvailable = true
|
|
return info
|
|
}
|
|
// 身份不可用:明确说"未知",不回上一正式版本号,也不假装是某个提交
|
|
info.DisplayVersion = "dev"
|
|
info.IdentityAvailable = false
|
|
return info
|
|
}
|