Skip to content

ci: LLM bilingual release notes + release pipeline fixes#673

Merged
icebear0828 merged 4 commits into
devfrom
ci/release-notes-revamp
Jun 9, 2026
Merged

ci: LLM bilingual release notes + release pipeline fixes#673
icebear0828 merged 4 commits into
devfrom
ci/release-notes-revamp

Conversation

@icebear0828

Copy link
Copy Markdown
Owner

Summary

CI 盘点后的第一批修复(详见各小节根因)。

P0 — Release notes 质量

  • 删除 400 行逐词替换字典 translate-notes.js(机翻词盐根因:'打包打包冒烟超时''未捕获捕获'、介词全局替换)
  • 新增 summarize-release-notes.mjs:单次 OpenAI-compatible LLM 调用,按 Electron 用户视角输出「✨ 本次更新」中文亮点 + 英文对照 + <details> 完整 commit 清单
  • 输出强校验(JSON 契约 / 必须含 CJK / 条数上限);LLM 不可用或校验失败 → 回退按 type 分组的纯英文列表;脚本永不非零退出,notes 问题不可能阻塞发版
  • secrets 已配置:RELEASE_NOTES_BASE_URL / RELEASE_NOTES_API_KEY / RELEASE_NOTES_MODEL

P0 — release.yml 空 body 窗口

notes 生成从最后一个 job 提前为第一个 job:此前 upload 步骤先 gh release create --notes "",notes job 一挂 release 永久空 body(更新弹窗显示空白)。Node 统一到 22。

P1 — promote soak 饿死

旧规则要求 dev HEAD 本身 ≥24h,活跃周每个 push 重置时钟 → master 长期不晋升。新增 select-promote-candidate.sh:晋升最新的已泡满 24h 的 first-parent commit(新鲜提交留 dev 继续 soak),CI 门禁按候选从新到旧找绿。force_skip_soak 行为不变。

P1 — Docker 版本镜像被覆盖

docker-publish.yml 此前在 master push 时用 max(package.json, latest stable tag) 打版本镜像 → 14:00 promote 后 ghcr.io/...:vX.Y.Z 被晚于 tag 的代码覆盖。现在分支 push 只打 latest + sha-<short>;版本镜像仅由 bump-electron.yml dispatch 带 tag 输入、从 tag 源码构建。

P1 — 发版通知

notify-webhook.sh:release 成功/失败、promote 成功/ff 破坏时 POST 纯文本到 NOTIFY_WEBHOOK_URL secret(ntfy 开箱可用);未配置静默跳过、永不阻塞。该 secret 尚未配置,填上即生效。

P2

notes 过滤规则对齐 bump 的 SKIP_RELEASE_PATTERN(排除 chore/docs/ci/test/refactor/style)。

Test plan

  • tests/unit/ci/summarize-release-notes.test.ts(13 用例:双语渲染 / JSON 契约校验 / CJK 校验 / fence 容错 / fallback 分组 / CLI exit-0)
  • tests/unit/ci/select-promote-candidate.test.ts(6 用例:fixture git repo 控制 commit 时间,覆盖饿死场景 / FORCE / MAX_CANDIDATES)
  • tests/unit/ci/release-notes-script.test.ts 更新(filter 对齐 + fallback 断言)
  • 全量 npm test:2537 passed / 1 skipped
  • E2E:真实 gateway(proxypool.store)连调 3 次全部产出合格双语 notes
  • 全部 workflow YAML 经 js-yaml 解析通过

…grity, notify webhook

- Replace 400-line word-by-word translate-notes.js dictionary with
  summarize-release-notes.mjs: one OpenAI-compatible LLM call produces
  user-facing Chinese highlights + English counterparts + collapsible
  raw commit list; strict JSON/CJK validation with grouped plain-English
  fallback; never exits non-zero so notes can't block a release
- release.yml: notes job moved first (kills the empty-body window left
  by upload steps' 'gh release create --notes ""'); final job replaced
  by webhook notify; Node unified to 22
- promote-dev-to-master.yml: soak now promotes the newest first-parent
  dev commit >= 24h old (select-promote-candidate.sh) instead of
  requiring dev HEAD age — active weeks no longer starve master;
  CI gate walks candidates newest-first
- docker-publish.yml: branch pushes tag latest + sha-<short> only;
  ghcr.io vX.Y.Z images now build exclusively from the tag via
  bump-electron.yml dispatch (no more version-tag clobbering)
- notify-webhook.sh: plain-text POST to NOTIFY_WEBHOOK_URL secret on
  release/promote success/failure; silent no-op when unset
- align notes commit filter with bump SKIP_RELEASE_PATTERN
- select-promote-candidate.sh: filter candidates with merge-base
  --is-ancestor -- first-parent commits below a master->dev sync-back
  merge are not fast-forwards and would reject the promote push;
  validate numeric env; avoid "[ ] &&" errexit footguns
- release.yml notes job: stable releases created --latest=false so an
  asset-less release never becomes /releases/latest during the build
  window (or permanently, when smokes fail); notify job flips --latest
  only after all platforms succeed; edit/create wrapped in a 3-attempt
  retry without discarding stderr
- docker-publish.yml: dispatching an old tag no longer moves "latest"
  backwards (only tagged when HEAD == master tip); tag input validated
  against semver (blocks GITHUB_OUTPUT heredoc injection); interpolation
  moved to env vars
- promote pick loop: gh api failure skips the candidate (api-error)
  instead of aborting the job and firing a misleading ff-failure alarm;
  failure webhook text genericized; notify-ff-failure gets contents:read
  and sends the webhook before issue creation
- summarize-release-notes.mjs: stdin captured once (fatal fallback no
  longer double-reads EOF and prints empty); highlights must be
  single-line <=300 chars (prompt-injection guard); commit lines
  HTML-escaped in details block; feat!: / fix(scope)!: grouped correctly
- generate-release-notes.sh: node crash falls back to raw commit list
  instead of failing the release job (pipefail path)
- tests: +6 covering all of the above (60/60 in tests/unit/ci)
@icebear0828 icebear0828 force-pushed the ci/release-notes-revamp branch from fd4eb70 to 7b24966 Compare June 9, 2026 18:18
- release.yml notify: delete a zero-asset release when all builds fail
  (a published empty release would break beta clients resolving the
  newest prerelease; tag kept so re-dispatch can retry), retry the
  --latest flip 3x, webhook runs if always() and reports flip failures
- release.yml: backstop gh release create in upload steps also passes
  --latest=false for stable tags; notes-job retry uses growing backoff
- docker-publish.yml: tag validation switched to whole-string anchored
  bash regex (grep matched per-line, letting multiline payloads through)
- select-promote-candidate.sh: verify MASTER_REF/DEV_REF exist up front
  (rev-list errors inside process substitution were swallowed and looked
  like a normal soak skip)
- tests: +1 missing-ref loud-failure case (61/61)
@icebear0828 icebear0828 merged commit bc2d134 into dev Jun 9, 2026
2 checks passed
@icebear0828 icebear0828 deleted the ci/release-notes-revamp branch June 9, 2026 18:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant