mcpField
P
prepare-release

prepare-release

github.com/cherryhq开发53.1k57 次安装今天更新
代码仓库

关于 prepare-release

prepare-release 是用于 Cherry Studio 的发布准备技能,可从变更整理双语发布说明、更新版本文件并启动发布分支与 CI/CD 流程。它涵盖版本校验、发布状态检查及后续发布链路约束。

主要功能

  1. 01解析版本类型或指定版本
  2. 02整理提交并生成双语说明
  3. 03更新发布元数据文件
  4. 04创建发布分支并触发 CI/CD
  5. 05校验发布状态与版本顺序

适用场景

  1. 01为 Cherry Studio 准备补丁或次版本
  2. 02生成中英文发布说明
  3. 03在发布分支启动构建与发布流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cherryhq/cherry-studio --skill prepare-release

安装后在 Claude Code 中输入/prepare-release确认已加载。

详细介绍

准备发布

自动化 Cherry Studio 的发布工作流:收集变更 → 生成双语文档发布说明 → 更新文件 → 创建发布分支 → 触发 CI/CD。

参数

从用户的消息中解析版本意图。接受以下任意形式:

  • 版本号递增类型关键字:patch、minor、major
  • 确切版本:严格的 x.y.z 或 x.y.z-<prerelease>,不带构建元数据(例如 1.8.0、1.8.0-beta.1、1.8.0-rc.1)
  • 自然语言:"prepare a beta release"、"bump to 1.8.0-rc.2" 等。

如果未指定版本,则默认为 patch。在进行任何文件编辑之前,始终向用户回显解析出的目标版本。

  • --dry-run:仅预览,不创建发布分支。

工作流

步骤 1:确定版本
  1. 对于交互式本地运行,获取 origin/main 和所有标签,然后验证检出内容是否为干净的 main,且恰好位于 origin/main:
    git fetch origin refs/heads/main:refs/remotes/origin/main --tags
    test "$(git branch --show-current)" = main
    test -z "$(git status --porcelain)"
    test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
    
    如果任何检查失败,则在编辑文件之前停止。这可防止独立运行从任意或过期的检出内容创建发布分支。 在 GitHub Actions 中,使用工作流冻结的 dispatch SHA,并将检出验证交给工作流处理。不要获取或比较之后的 origin/main head。
  2. 从 package.json 读取当前版本。即使该发布后来已被撤回,也用它来进行版本递增;绝不要复用已撤回的版本。
  3. 选择最新的已发布、非草稿的 GitHub Release,其标签为严格的 v<semver>,作为发布说明基线。非 semver 的预览发布和草稿永远不能作为基线:
    gh release list --limit 1000 --json isDraft,publishedAt,tagName --jq '[.[] | select(.isDraft == false and (.tagName | test("^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$")))] | sort_by(.publishedAt) | last | .tagName // empty'
    
    如果不存在已发布的基线,或其 Git 标签缺失(git rev-parse --verify refs/tags/{baseline-tag}),则停止。使用 semver 将其版本与当前 package 版本进行比较:如果 main 落后,则停止并要求合并最新的 Post Release 元数据 PR。如果 main 领先,则允许使用已发布基线生成发布说明,并使用 package 版本进行版本递增。例如,在撤回 2.1.1 后,main 位于 2.1.1,而已发布基线为 2.1.0,则准备 2.1.2 并包含自 2.1.0 以来的变更。 在 GitHub Actions 中,使用工作流提供的基线标签和收集基准,无需重复这些检查。
  4. 根据参数计算新版本:
    • patch / minor / major:从当前版本递增。
    • 确切版本必须匹配 ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ 并通过 semver.valid;不接受诸如 +build.1 这样的构建元数据。
    • 在两种情况下,都要求结果按照 semver 优先级严格大于当前版本。拒绝相同版本和降级。
步骤 2:收集提交
  1. 根据步骤 1 中选定的已发布基线确定 release note 收集基准,而不是根据包版本:
    • 如果基线标签是 HEAD 的祖先,则使用该标签。
    • 否则,使用完整提交信息中包含精确标记 release-metadata-boundary: <baseline-tag> 的最新提交。该机器标记被添加到 Post Release pull request 正文中,并在必需的 squash merge 后保留下来。
    • 对于在机器标记存在之前创建的元数据 pull request,接受主题恰好等于 chore(release): sync <baseline-tag> metadata 的提交,或该主题后仅跟随 GitHub 的 squash 后缀 (#<PR-number>) 的提交。
    • 如果该标签不是祖先且其元数据同步提交缺失,则以错误停止;否则已发布的 hotfix 可能会被再次包含。
  2. 列出该基准以来的所有提交:
    git log <collection-base>..HEAD --format="%H %s" --no-merges
    
  3. 对每个提交,获取完整正文:
    git log <hash> -1 --format="%B"
    
  4. 从每个提交正文中提取 ```release-note 代码块内的内容。
  5. 从标题中提取 conventional commit 类型(feat、fix、refactor、perf、docs 等)。
  6. 将以下提交作为独立 release note 候选项跳过,但在步骤 3 中将候选项与最终代码核对时,仍要检查其影响:
    • 标题以 🤖 Daily Auto I18N 开头的提交
    • 标题以 Merge 开头的提交
    • 标题以 chore(deps) 开头的提交
    • 标题以 chore: release 开头的提交
    • 标题以 chore(release) 开头的提交
    • release-note 块中写有 NONE 的提交
步骤 3:生成双语言 Release Notes

根据相对于已发布基线的最终用户可见变更,生成英文和中文两种语言的 release notes。提交标题和 release-note 块是候选描述,并不证明某项变更一定会发布。

起草前先核对净变更:

  1. 检查 git diff --name-status <baseline-tag> <release-head>,然后在两个端点处阅读相关补丁和代码。<release-head> 是发布准备之前的源 HEAD(CI 中冻结的 dispatch SHA)。比较两个端点树,而不是三点 merge-base diff。收集基准仅用于发现提交;当它与已发布标签不同时,还要检查该提交范围内缺失的用户可见差异。
  2. 按用户可见行为对候选项分组,并按时间顺序追踪相关补丁,包括步骤 2 中排除的提交。从代码中检测显式 revert、手动撤销、替换、部分回退和重新引入;不要仅依赖提交措辞或匹配的哈希值。
  3. 省略在本周期内引入并完全撤销的变更,包括仅针对该临时变更的修复。对于部分回退、替换或重新引入,只描述与已发布基线不同的最终结果,每个不同的用户可见变更描述一次。
  4. 如果回退移除了或改变了已发布基线中已存在的行为,则描述由此产生的用户可见移除或恢复。不要不加区分地丢弃所有 revert 提交。保持相同用户可见行为的实现重写本身并不足以成为 release-note 条目的理由。
  5. 根据端点 diff 和最终代码验证每个提议的条目,并确保英文和中文版本描述相同的结果。如果所声称的效果无法证实,则省略它,并在准备摘要中报告该不确定性,而不是编造 release-note 声明。

推荐格式:


Cherry Studio {version} - {Brief English Title}

✨ New Features
- [Component] Description

🐛 Bug Fixes
- [Component] Description

💄 Improvements
- [Component] Description

⚡ Performance
- [Component] Description


Cherry Studio {version} - {简短中文标题}

✨ 新功能
- [组件] 描述

🐛 问题修复
- [组件] 描述

💄 改进
- [组件] 描述

⚡ 性能优化
- [组件] 描述

语言标记是机器可读的契约:每个标记包含一次,保持其顺序,并提供非空的英文和中文部分。标题和周围的说明文字是呈现方式的选择,不是验证要求。 规则:

  • 只保留有内容的分类(省略空分类)。
  • 每个不同的、用户可见的最终变更在相应分类中只出现一次;合并相关提交,省略已取消或被取代的条目。
  • 优先采用 release-note 字段的措辞,否则采用提交标题,但仅当其与验证后的最终结果一致时。
  • 组件标签应简短:[Chat]、[Models]、[Agent]、[MCP]、[Settings]、[Data]、[Build] 等。
  • 中文翻译应自然,不要机翻。
  • 不要包含提交哈希或 PR 编号。
  • 撰写前先阅读 electron-builder.yml 中现有的发布说明作为风格参考。

重要:仅限面向用户的内容

发布说明面向最终用户,而非开发者。排除用户不关心的内容:

  • 排除内部重构、代码清理或架构变更
  • 排除 CI/CD、构建工具或测试基础设施变更
  • 排除依赖更新(除非它们带来了用户可见的功能)
  • 排除文档更新
  • 排除开发者体验改进
  • 排除无用户可见影响的技术债修复
  • 排除过于技术化的描述(例如“修复 Redux 中间件中的竞态条件”)

仅包含用户会注意到的变更:

  • 他们可以使用的新功能
  • 影响其工作流的缺陷修复
  • 他们能看到的 UI/UX 改进
  • 他们能感受到的性能改进
  • 安全修复(简化描述,不涉及实现细节)

保持描述简单、非技术化:

  • ❌ “修复流式竞态条件导致 Redux 状态中工具响应状态不完整”
  • ✅ “修复中止时工具状态不停止的问题”
  • ❌ “为 OpenAI 兼容提供商自动将 reasoning_effort 转换为 reasoningEffort”
  • ✅ “修复深度思考模式在部分提供商下无法使用的问题”
步骤 4:更新文件
  1. package.json:将 "version" 字段更新为新版本号。
  2. electron-builder.yml:用生成的说明替换 releaseInfo.releaseNotes: | 下的内容。保留块标量内容的 4 空格 YAML 缩进。
  3. resources/cherry-studio/release-history.json:切勿手工编辑;说明必须与 electron-builder.yml 逐字节一致。运行 node scripts/release/sync-release-history.js --target-version {version},它会为稳定版预置(或替换)对应条目,而对预发布版保持文件不变。在 GitHub Actions 中,工作流会在 Claude 步骤之后自行运行此命令。
  4. 校验源元数据:对于交互式本地运行,在生成产品清单之前运行 node scripts/release/validate-prepared-release.js --target-version {version},如果它拒绝了变更路径、版本顺序、双语章节或稳定版历史记录,则停止。在 GitHub Actions 中,将校验交给 Claude 之后运行的工作流步骤处理。
  5. 内置知识库:对于交互式本地运行,在校验后运行 pnpm build:builtin-knowledge。这会用新的包版本刷新 resources/builtin-agents/cherry-assistant/product-manifest.json。切勿手工编辑生成的产品清单。在 GitHub Actions 中,不要运行生成器:工作流会先运行同一个校验器,然后自行运行受信任的生成器。
步骤 5:提交审阅

向用户展示:

  • 新版本号。
  • 生成的完整发布说明。
  • 修改了哪些文件的摘要。

如果指定了 --dry-run,则在此停止。

否则,请用户确认后再继续到步骤 6。

步骤 6:创建发布分支
  1. 对于交互式本地运行,在创建分支之前立即重复步骤 1 的第 1-3 项,从 HEAD:package.json 读取原始包版本。要求已发布的基线仍与用于收集发布说明的基线一致;否则在继续之前重新生成发布说明。由于步骤 4 已特意准备并验证了发布元数据,请用 git status --short 替换步骤 1 的干净工作树断言,并且除非列出的每个路径都是四个允许的发布元数据文件之一,否则停止。然后创建并推送一个签名的、符合 DCO 的发布提交:
    git fetch origin refs/heads/main:refs/remotes/origin/main --tags
    test "$(git branch --show-current)" = main
    test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
    test "$(node -p "require('./package.json').version")" = "{version}"
    CURRENT_VERSION="$(git show HEAD:package.json | jq -r .version)"
    LATEST_PUBLISHED="$(gh release list --limit 1000 --json isDraft,publishedAt,tagName --jq '[.[] | select(.isDraft == false and (.tagName | test("^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$")))] | sort_by(.publishedAt) | last | .tagName // empty')"
    test "$LATEST_PUBLISHED" = "{baseline-tag}"
    git rev-parse --verify "refs/tags/$LATEST_PUBLISHED"
    node -e "const semver = require('semver'); process.exit(semver.gte(process.argv[1], process.argv[2]) ? 0 : 1)" "$CURRENT_VERSION" "${LATEST_PUBLISHED#v}"
    REPO="$(gh repo view --json nameWithOwner --jq .nameWithOwner)"
    gh api --paginate --slurp "repos/$REPO/releases?per_page=100" | TAG="v{version}" node scripts/release/validate-release-state.js prepare
    test -z "$(git ls-remote --heads origin refs/heads/release/v{version})"
    git status --short
    UNEXPECTED_RELEASE_PATHS="$(git status --porcelain | cut -c4- | grep -Ev '^(package\.json|electron-builder\.yml|resources/cherry-studio/release-history\.json|resources/builtin-agents/cherry-assistant/product-manifest\.json)$' || true)"
    test -z "$UNEXPECTED_RELEASE_PATHS"
    git checkout -b release/v{version}
    git add package.json electron-builder.yml resources/cherry-studio/release-history.json resources/builtin-agents/cherry-assistant/product-manifest.json
    git commit -S --signoff -m "chore(release): prepare v{version}"
    git cat-file commit HEAD | grep -q '^gpgsig '
    git log -1 --format=%B | grep -q '^Signed-off-by: '
    git push -u origin release/v{version}
    
  2. 在 GitHub Actions 中,更新 package.json 和 electron-builder.yml 后停止。允许使用临时辅助文件和本地 Git 操作;工作流提取这两个文件变更,恢复冻结的源 SHA,并丢弃其他所有内容。然后它推导发布历史、进行验证、生成产品清单、创建分支,并使用 GitHub 的 API 创建和验证签名的、符合 DCO 的提交。切勿从 Claude 步骤推送。
  3. 报告发布分支和后续步骤。暂时不要创建 PR:必须先从此分支构建并发布版本。

CI 触发链

  • 等待新 release/v{version} 提交上的 CI 推送运行成功。auto-release-build.yml 会重新验证该确切的活动分支头,并以 all 调度 release.yml;它构建 macOS、Windows 和 Linux,并创建或更新草稿 GitHub Release。仅在重试失败的 all-platform 构建或针对未更改的已标记提交重试单个平台时,才手动使用 release.yml。
  • 当单个草稿语义版本发布处于活动状态时,backport-release-fixes.yml 会为来自 main 的第一个已合并的 hotfix: <description> 或 hotfix(<kebab-case-scope>): <description> PR 打开一个 backport PR,应用任何可选的双语发布说明,然后将连续的 hotfix 和源标记追加到同一个打开的主题分支。它管理每个源 PR 的 hotfix 和 backport-status 标签,并在源 PR 上报告失败;切勿将 main 合并到发布分支。
  • 审查 backport PR,等待其 CI,然后合并它。在由此产生的发布分支推送通过 CI 后,确切头的 all-platform 草稿重建会自动开始。
  • 成功的精确头 all-platform 构建会启动 publish-release.yml。在检查草稿后批准 release Environment 部署。然后发布获取 release-state 锁,重新验证已批准的运行、发布分支、标签、草稿、产物、打开的 PR 和待处理的 hotfix,并且仅当它们仍然一致时才发布。草稿正文包含双语 electron-builder.yml 说明,后跟 GitHub 生成的更改。最终获取的 main SHA 是 hotfix 截止点;在该快照之后合并的 hotfix 属于下一个版本。发布触发 post-release.yml,它使用已发布的标签作为其源,仅将发布元数据增量应用于最新的 main,并创建一个 release-sync/v{version} 仅元数据 PR。
  • 元数据 PR 仅同步 package.json、electron-builder.yml、发布历史和生成的产品清单。它触发 ci.yml;仅在 CI 通过后合并它。
  • 在 squash 合并元数据 PR 时,将提交标题设置为恰好 chore(release): sync v{version} metadata,仅带有 GitHub 的可选 PR 编号后缀,并将 release-metadata-boundary: v{version} 保留在 squash 提交正文中的单独一行,以便下一个版本可以可靠地找到边界。

约束

  • 修改 electron-builder.yml 前,始终先阅读它,以了解当前格式。
  • 切勿保留 package.json、electron-builder.yml、resources/cherry-studio/release-history.json 以及生成的 resources/builtin-agents/cherry-assistant/product-manifest.json 之外的更改。
  • 切勿直接推送到 main。
  • 在 GitHub Release 发布之前,切勿创建发布元数据 PR;该步骤由 post-release.yml 负责。
  • 在创建发布分支之前,始终向用户展示生成的发布说明(除非在无交互用户的 CI 中运行)。

评论

支持 Markdown