Die Oberfläche ist lokalisiert; Skill-Beschreibungen und -Dokumente werden per KI automatisch in Ihre Sprache übersetzt. Code, Befehle, Pfade und Fachbegriffe bleiben im Original, maßgeblich ist das Dokument des Autors.
Skills entdecken
Entwicklung · SKILL.md

release

release

发布 Usage4Claude 新版本时使用。当用户说“发布新版本 / 发版 / 出新版 / release / 打 tag 发布 / 准备发版材料”等,用本 skill 引导完成从收集变更、编写 CHANGELOG 与 RELEASE_NOTES、更新版本号、编译验证,到发版 commit、CI 自动发布的完整流程。

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill-Dokumentation

GitHub

name: release description: 发布 Usage4Claude 新版本时使用。当用户说“发布新版本 / 发版 / 出新版 / release / 打 tag 发布 / 准备发版材料”等,用本 skill 引导完成从收集变更、编写 CHANGELOG 与 RELEASE_NOTES、更新版本号、编译验证,到发版 commit、CI 自动发布的完整流程。

发布新版本(Release)

Usage4Claude 采用 CI 自动发布:向 main push 一个满足条件的 commit 后, GitHub Actions(.github/workflows/release.yml)自动完成构建、签名、发 Release、 更新 Sparkle 更新源。你(Claude)的职责是准备好发版材料并引导用户完成触发, 不代替用户执行发版 commit 与 push。

若根目录存在 NEXT_RELEASE.md,说明本次发版有一次性特殊情况,先读它再按本流程走。

必须先记住的架构事实

  • 两份发布材料,各司其职(详见下一节分工表):
    • CHANGELOG.md — 完整技术档案 + 版本号权威源,不进 Sparkle。
    • docs/RELEASE_NOTES.md — 面向用户的发布说明,CI 提取当前版本段落后同时注入 Sparkle 弹窗(appcast.xml 的 <description>)和 GitHub Release 正文。
  • 触发条件:commit message 含 [release]/[RELEASE],push 到 main,且本次改动 包含 CHANGELOG.md 或 docs/RELEASE_NOTES.md(发版通常两者都改)。
  • Sparkle 弹窗内容来自 docs/RELEASE_NOTES.md(不是 CHANGELOG)。用户在应用内“检查更新” 看到的就是 RELEASE_NOTES 当前版本段落。
  • docs/RELEASE_NOTES.md 必须有当前版本段落:否则 Sparkle/Release 正文会为空。CI 的 validate 阶段会 grep "^## [X.Y.Z]" fail-fast,但应发版前就写好。
  • Build 号自动跟随:CURRENT_PROJECT_VERSION = $(MARKETING_VERSION),Build 恒等于 Version。只改 Version,绝不手动固定 Build,否则 Sparkle 认不出新版本。
  • appcast.xml 由 CI 维护,绝不手改。
  • 详细背景见 docs/DAILY_RELEASE_WORKFLOW.md、docs/SPARKLE_SETUP.md。

两份材料的分工(关键)

CHANGELOG.mddocs/RELEASE_NOTES.md
定位完整技术档案 + 版本号权威源面向用户的发布说明
收录范围所有改动,含内部重构、CI、安全加固只留用户可感知的现象
措辞可保留技术细节(JWT、actor、base64url 等)口语化,去技术词
致谢不加在相关条目末尾加 (thanks @author, #N)
CI 喂给无(纯档案;validate 从它提版本号)Sparkle 弹窗 + GitHub Release 正文
何时写发版前发版前(不是发布后精修)

规则细节见 docs/CHANGELOG_AND_RELEASE_NOTES_GUIDELINES.md。

流程

1. 收集自上个 tag 以来的变更

git fetch origin                                     # 先核对远程,避免发版已在别处完成
LAST_TAG=$(git describe --tags --abbrev=0)           # 上一个发布 tag,如 v3.3.0
git log "$LAST_TAG"..HEAD --oneline                  # 变更概览
git log "$LAST_TAG"..HEAD --format='=== %h ===%n%B'  # 完整 message(判断影响面必读)
git log "$LAST_TAG"..HEAD --merges --format='%h %s'  # 合并的 PR(用于致谢)

逐条阅读完整 message,区分:用户可感知的现象 vs 纯内部改动。两类都进 CHANGELOG, 但只有前者进 RELEASE_NOTES。

2. 决定版本号

读 CHANGELOG.md 顶部当前版本,按语义化递增:

改动类型递增例
仅 Bug 修复patch3.3.0 → 3.3.1
含新功能minor3.3.0 → 3.4.0
破坏性变更major3.3.0 → 4.0.0

版本号不确定时用 AskUserQuestion 让用户确认。

3. 编写两份发布材料

3a. CHANGELOG.md(完整技术档案)

  • 在文件顶部(# Changelog 与首个 ## [ 之间)插入新版本段落,日期用当天。
  • 收录所有改动,按 Added / Changed / Fixed / Security 分类。
  • 新功能的后续修改/优化/bug 修复并入该功能条目,不在 Fixed 里重复列出。
  • 每个变更点一条,不同变更点只出现一次,简洁不赘述。
  • 更新文件底部版本链接:新增 [X.Y.Z]: https://github.com/f-is-h/Usage4Claude/releases/tag/vX.Y.Z

3b. docs/RELEASE_NOTES.md(面向用户 + 致谢)

  • 在文件顶部插入 ## [X.Y.Z] - 当天日期 段落(结构同 CHANGELOG)。
  • 只保留用户可感知的现象,去技术词、口语化。
  • 收集本版本对应的 已合并 PR 与 已解决 Issue 及作者,条目末尾致谢 (thanks @author, #N):
    gh pr view <n> --repo f-is-h/Usage4Claude --json number,title,author,state
    gh issue view <n> --repo f-is-h/Usage4Claude --json number,title,author,state
    
    只对确已合并的 PR / 确已解决的 Issue 致谢。未合并的 PR、仍 Open 且本次并未真正 修复的 Issue 不致谢,避免误导用户(硬规则)。

两份写入文件的都是英文;同时在对话里给用户中文对照(不写进文件)。写好后用 AskUserQuestion 让用户确认草稿再继续。

4. 更新 Xcode 版本号

两处 MARKETING_VERSION(Debug/Release)都要改:

sed -i '' 's/MARKETING_VERSION = <旧版本>;/MARKETING_VERSION = <新版本>;/g' \
  Usage4Claude.xcodeproj/project.pbxproj
grep -n "MARKETING_VERSION" Usage4Claude.xcodeproj/project.pbxproj  # 确认两处都改了

CHANGELOG 版本与 Xcode 版本必须完全一致,否则 CI 的 verify_version.sh 会失败。 RELEASE_NOTES 也必须有同一版本段落(CI validate 会 fail-fast)。

5. 编译验证

xcodebuild -project Usage4Claude.xcodeproj -scheme Usage4Claude -configuration Release build 2>&1 | tail -5

看到 ** BUILD SUCCEEDED ** 后,核对产物版本号:

APP=$(find ~/Library/Developer/Xcode/DerivedData -name Usage4Claude.app -path '*/Release/*' | head -1)
/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$APP/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$APP/Contents/Info.plist"  # 应与 Version 相同

6. 发版 commit + push(commit 由用户手写)

发版 commit message 不走日常 COMMIT_MESSAGE_GUIDELINES 那套,由用户手工编写。 你只提供草稿供参考,不擅自 commit/push——git add/commit/push 需用户确认后执行。

  • 只写一行标题,不要正文。 CI 只取第一行(去掉 [release] 前缀)作为 GitHub Release 标题;正文不被使用(Release 正文来自 RELEASE_NOTES),写了也是浪费。
  • 格式:
[release] vX.Y.Z - 简短标题
  • 触发前自检:commit 含 [release]、本次改动含 CHANGELOG.md/docs/RELEASE_NOTES.md、目标分支 main。

推送后 CI 触发。

7. 监控 CI

gh run list --workflow=release.yml --limit 3
gh run watch                     # 或看 https://github.com/f-is-h/Usage4Claude/actions

CI 三段:validate(版本校验 + RELEASE_NOTES 段落校验)→ build(构建签名,约 8 分钟)→ release(发 Release + 推 appcast.xml 回 main)。失败常见原因:版本号不一致、RELEASE_NOTES 缺当前版本段落、CHANGELOG 版本已发布过。

8.(可选)发布后装饰 GitHub Release 页面

CI 已用 RELEASE_NOTES 自动发布了面向用户的 Release,且 Sparkle 弹窗同源——通常无需再做。 若想让 GitHub Release 页面更精致(大标题、总览段落、emoji),可发布后手工编辑网页。

  • 这属于 GitHub 页面装饰,不回流 Sparkle(Sparkle 已在发布时拿到 RELEASE_NOTES 段落)。
  • 改的是对外公开页面,先与用户确认再执行。
  • 页面正文结构 = 「RELEASE_NOTES 段落」+ --- + Installation + --- + Full Changelog, 只改第一个 --- 上方那段,下方模板不要动。用 gh release edit 会整体替换正文,需先 gh release view vX.Y.Z --json body -q .body 取回完整正文改上半段后整体回填。

发版前的安全测试(不真正发布)

按影响面从小到大三档,用于在正式发版前验证:

① 本地预览(零风险,什么都不发)

swift test                                                          # 单元测试
xcodebuild -project Usage4Claude.xcodeproj -scheme Usage4Claude \
  -configuration Release build                                      # 能否编译
.github/scripts/verify_version.sh verify CHANGELOG.md Usage4Claude.xcodeproj  # 版本号一致性
.github/scripts/generate_release_notes.sh \
  .github/RELEASE_TEMPLATE.md <版本> /tmp/rn_preview.md docs/RELEASE_NOTES.md      # 预览 Release 正文
./scripts/build.sh --config Release                                # 本地打 DMG,验证打包脚本

generate_release_notes.sh 输出里第一个 --- 上方那段,同时也是 Sparkle 更新弹窗 会显示的内容(都来自 RELEASE_NOTES)——发版前务必看一眼措辞是否面向用户。

② test-release 分支(CI 构建冒烟,不发布)

  • 把改动 push 到 test-release 分支(commit 仍含 [release])。
  • CI 跑 validate + build:在 CI 环境编译、导入证书、Sparkle 签名、打 DMG。
  • 跳过 release job(is_test=true)→ 不打 tag、不发 Release、不碰 appcast、不 push main。
  • 用途:验证 CI 能否构建出签名 DMG(本地过 ≠ CI 过,证书/Sparkle 私钥只在 CI secrets)。 DMG 作为 artifact 可下载。几乎无需清理。

③ workflow_dispatch dry_run(端到端演练,产草稿)

  • 在 Actions 页面对 main 手动运行 workflow,勾选 dry_run。
  • 跑完整三段,但:tag=test-v<版本>、Release 走 --draft(公众不可见)、appcast 只打印不 push。
  • 用途:演练整条发布链路(含 release job 的 tag/release/appcast 逻辑)而不影响用户。
  • 需清理:gh release delete test-v<版本> --yes 且 git push origin :refs/tags/test-v<版本>。
  • 注意:dry_run 必须在 main 触发才有端到端效果;在 test-release 触发会退化成 ②。

选择:只验发布材料 → ①;验 CI 构建 → ②;验整条链路 → ③。

红线清单

  • 发版 commit 与 push 由用户执行,你只准备材料 + 提供草稿。
  • 发版前 CHANGELOG.md 与 docs/RELEASE_NOTES.md 都要有当前版本段落。
  • CHANGELOG 版本号与 Xcode MARKETING_VERSION 必须一致。
  • 只改 Version,不碰 Build 号(自动跟随 MARKETING_VERSION)。
  • 不手改 appcast.xml(CI 维护)。
  • 致谢只给确已合并/解决的 PR/Issue。
  • 已发布版本的 CHANGELOG / RELEASE_NOTES 段落不回改(否则与已发内容、Sparkle 说明不一致)。
  • 冒烟测试若需杀进程,用 kill <PID> 而非 killall(避免误伤用户在跑的正式版实例)。

相关文档

  • docs/DAILY_RELEASE_WORKFLOW.md — 日常发版流程全文
  • docs/CHANGELOG_AND_RELEASE_NOTES_GUIDELINES.md — CHANGELOG 与 RELEASE_NOTES 编写规范
  • docs/COMMIT_MESSAGE_GUIDELINES.md — 日常 commit 规范(发版 commit 不适用)
  • docs/SPARKLE_SETUP.md — Sparkle 自动更新机制
  • .github/workflows/release.yml — CI 发布流水线
  • .github/RELEASE_TEMPLATE.md — Release 正文固定模板(Installation 等)
Gespeicherte Skills