mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-06 05:55:28 +08:00
feat(ci): add prepare-release skill for automated release workflow (#12958)
<!-- Template from https://github.com/kubevirt/kubevirt/blob/main/.github/PULL_REQUEST_TEMPLATE.md?--> <!-- Thanks for sending a pull request! Here are some tips for you: 1. Consider creating this PR as draft: https://github.com/CherryHQ/cherry-studio/blob/main/CONTRIBUTING.md --> <!-- ⚠️ Important: Redux/IndexedDB Data-Changing Feature PRs Temporarily On Hold ⚠️ Please note: For our current development cycle, we are not accepting feature Pull Requests that introduce changes to Redux data models or IndexedDB schemas. While we value your contributions, PRs of this nature will be blocked without merge. We welcome all other contributions (bug fixes, perf enhancements, docs, etc.). Thank you! Once version 2.0.0 is released, we will resume reviewing feature PRs. --> ### What this PR does Before this PR: Releases had to be prepared manually — collecting commits, writing bilingual release notes, updating version files, creating branches and PRs by hand. After this PR: A new `prepare-release` skill automates the entire release workflow: commit collection, bilingual release note generation, version file updates, and release branch/PR creation. It can be invoked interactively via `/prepare-release` or automatically via a `workflow_dispatch` GitHub Actions workflow. <!-- (optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: --> Fixes # N/A ### Why we need it and why it was done in this way The following tradeoffs were made: The skill is duplicated in both `.agents/skills/` and `.claude/skills/` to support both project-level and user-level skill discovery. The GitHub Actions workflow uses `claude-code-action` to run the skill in CI, skipping the interactive confirmation step since the user explicitly triggers it via `workflow_dispatch`. The following alternatives were considered: A shell script was considered but would lack the flexibility of AI-driven commit categorization and bilingual release note generation. Links to places where the discussion took place: N/A ### Breaking changes <!-- optional --> None. ### Special notes for your reviewer <!-- optional --> - The skill delegates PR creation to the `gh-create-pr` skill (or its SKILL.md fallback) per CLAUDE.md requirements. - The `workflow_dispatch` trigger already requires repository write access, so no additional permission restrictions were added. - The two SKILL.md files (`.agents/skills/` and `.claude/skills/`) should be kept in sync. ### Checklist This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR. Approvers are expected to review this list. - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: [Write code that humans can understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans) and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle) - [x] Refactor: You have [left the code cleaner than you found it (Boy Scout Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html) - [ ] Upgrade: Impact of this change on upgrade flows was considered and addressed if required - [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com) was considered and is present (link) or not required. You want a user-guide update if it's a user facing feature. ### Release note <!-- Write your release note: 1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, include the string "action required". 2. If no release note is required, just write "NONE". --> ```release-note NONE ``` --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2
.agents/skills/.gitignore
vendored
2
.agents/skills/.gitignore
vendored
@@ -6,3 +6,5 @@
|
||||
!public-skills.txt
|
||||
!gh-create-pr/
|
||||
!gh-create-pr/**
|
||||
!prepare-release/
|
||||
!prepare-release/**
|
||||
|
||||
151
.agents/skills/prepare-release/SKILL.md
Normal file
151
.agents/skills/prepare-release/SKILL.md
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
name: prepare-release
|
||||
description: Prepare a new release by collecting commits, generating bilingual release notes, updating version files, and creating a release branch with PR. Use when asked to prepare/create a release, bump version, or run `/prepare-release`.
|
||||
---
|
||||
|
||||
# Prepare Release
|
||||
|
||||
Automate the Cherry Studio release workflow: collect changes → generate bilingual release notes → update files → create release branch + PR → trigger CI/CD.
|
||||
|
||||
## Arguments
|
||||
|
||||
Parse the version intent from the user's message. Accept any of these forms:
|
||||
- Bump type keyword: `patch`, `minor`, `major`
|
||||
- Exact version: `x.y.z` or `x.y.z-pre.N` (e.g. `1.8.0`, `1.8.0-beta.1`, `1.8.0-rc.1`)
|
||||
- Natural language: "prepare a beta release", "bump to 1.8.0-rc.2", etc.
|
||||
|
||||
Defaults to `patch` if no version is specified. Always echo the resolved target version back to the user before proceeding with any file edits.
|
||||
|
||||
- `--dry-run`: Preview only, do not create branch or PR.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Determine Version
|
||||
|
||||
1. Get the latest tag:
|
||||
```bash
|
||||
git describe --tags --abbrev=0
|
||||
```
|
||||
2. Read current version from `package.json`.
|
||||
3. Compute the new version based on the argument:
|
||||
- `patch` / `minor` / `major`: bump from the current tag version.
|
||||
- `x.y.z` or `x.y.z-pre.N`: use as-is after validating it is valid semver.
|
||||
|
||||
### Step 2: Collect Commits
|
||||
|
||||
1. List all commits since the last tag:
|
||||
```bash
|
||||
git log <last-tag>..HEAD --format="%H %s" --no-merges
|
||||
```
|
||||
2. For each commit, get the full body:
|
||||
```bash
|
||||
git log <hash> -1 --format="%B"
|
||||
```
|
||||
3. Extract the content inside `` ```release-note `` code blocks from each commit body.
|
||||
4. Extract the conventional commit type from the title (`feat`, `fix`, `refactor`, `perf`, `docs`, etc.).
|
||||
5. **Skip** these commits:
|
||||
- Titles starting with `🤖 Daily Auto I18N`
|
||||
- Titles starting with `Merge`
|
||||
- Titles starting with `chore(deps)`
|
||||
- Titles starting with `chore: release`
|
||||
- Commits where the release-note block says `NONE`
|
||||
|
||||
### Step 3: Generate Bilingual Release Notes
|
||||
|
||||
Using the collected commit information, generate release notes in **both English and Chinese**.
|
||||
|
||||
**Format** (must match exactly):
|
||||
|
||||
```
|
||||
<!--LANG:en-->
|
||||
Cherry Studio {version} - {Brief English Title}
|
||||
|
||||
✨ New Features
|
||||
- [Component] Description
|
||||
|
||||
🐛 Bug Fixes
|
||||
- [Component] Description
|
||||
|
||||
💄 Improvements
|
||||
- [Component] Description
|
||||
|
||||
⚡ Performance
|
||||
- [Component] Description
|
||||
|
||||
<!--LANG:zh-CN-->
|
||||
Cherry Studio {version} - {简短中文标题}
|
||||
|
||||
✨ 新功能
|
||||
- [组件] 描述
|
||||
|
||||
🐛 问题修复
|
||||
- [组件] 描述
|
||||
|
||||
💄 改进
|
||||
- [组件] 描述
|
||||
|
||||
⚡ 性能优化
|
||||
- [组件] 描述
|
||||
<!--LANG:END-->
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
- Only include categories that have entries (omit empty categories).
|
||||
- Each commit appears as exactly ONE line item in the appropriate category.
|
||||
- Use the `release-note` field if present; otherwise summarize from the commit title.
|
||||
- Component tags should be short: `[Chat]`, `[Models]`, `[Agent]`, `[MCP]`, `[Settings]`, `[Data]`, `[Build]`, etc.
|
||||
- Chinese translations should be natural, not machine-literal.
|
||||
- Do NOT include commit hashes or PR numbers.
|
||||
- Omit purely internal commits (refactor, CI, docs) with no user-facing impact.
|
||||
- Read the **existing** release notes in `electron-builder.yml` as a style reference before writing.
|
||||
|
||||
### Step 4: Update Files
|
||||
|
||||
1. **`package.json`**: Update the `"version"` field to the new version.
|
||||
2. **`electron-builder.yml`**: Replace the content under `releaseInfo.releaseNotes: |` with the generated notes. Preserve the 4-space YAML indentation for the block scalar content.
|
||||
|
||||
### Step 5: Present for Review
|
||||
|
||||
Show the user:
|
||||
- The new version number.
|
||||
- The full generated release notes.
|
||||
- A summary of which files were modified.
|
||||
|
||||
If `--dry-run` was specified, stop here.
|
||||
|
||||
Otherwise, ask the user to confirm before proceeding to Step 6.
|
||||
|
||||
### Step 6: Create Branch and PR
|
||||
|
||||
1. Create and push the release branch:
|
||||
```bash
|
||||
git checkout -b release/v{version}
|
||||
git add package.json electron-builder.yml
|
||||
git commit -m "chore: release v{version}"
|
||||
git push -u origin release/v{version}
|
||||
```
|
||||
2. Create the PR using the `gh-create-pr` skill. If the skill tool is unavailable, read `.agents/skills/gh-create-pr/SKILL.md` and follow it manually. In CI (non-interactive) mode, skip interactive confirmation steps and create the PR directly after filling the template.
|
||||
- Use title: `chore: release v{version}`
|
||||
- Use base branch: `main`
|
||||
- When filling the PR template, incorporate:
|
||||
- The generated release notes (English section only, for readability).
|
||||
- A list of included commits.
|
||||
- A review checklist:
|
||||
- [ ] Review generated release notes in `electron-builder.yml`
|
||||
- [ ] Verify version bump in `package.json`
|
||||
- [ ] CI passes
|
||||
- [ ] Merge to trigger release build
|
||||
3. Report the PR URL and next steps.
|
||||
|
||||
## CI Trigger Chain
|
||||
|
||||
Creating a PR from `release/v*` to `main` automatically triggers:
|
||||
- **`release.yml`**: Builds on macOS, Windows, Linux and creates a draft GitHub Release.
|
||||
- **`ci.yml`**: Runs lint, typecheck, and tests.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Always read `electron-builder.yml` before modifying it to understand the current format.
|
||||
- Never modify files other than `package.json` and `electron-builder.yml`.
|
||||
- Never push directly to `main`.
|
||||
- Always show the generated release notes to the user before creating the branch/PR (unless running in CI with no interactive user).
|
||||
@@ -1,3 +1,4 @@
|
||||
# Public skills tracked by skills:sync and skills:check.
|
||||
# One skill name per line.
|
||||
gh-create-pr
|
||||
prepare-release
|
||||
|
||||
2
.claude/skills/.gitignore
vendored
2
.claude/skills/.gitignore
vendored
@@ -5,3 +5,5 @@
|
||||
!README*.md
|
||||
!gh-create-pr/
|
||||
!gh-create-pr/**
|
||||
!prepare-release/
|
||||
!prepare-release/**
|
||||
|
||||
151
.claude/skills/prepare-release/SKILL.md
Normal file
151
.claude/skills/prepare-release/SKILL.md
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
name: prepare-release
|
||||
description: Prepare a new release by collecting commits, generating bilingual release notes, updating version files, and creating a release branch with PR. Use when asked to prepare/create a release, bump version, or run `/prepare-release`.
|
||||
---
|
||||
|
||||
# Prepare Release
|
||||
|
||||
Automate the Cherry Studio release workflow: collect changes → generate bilingual release notes → update files → create release branch + PR → trigger CI/CD.
|
||||
|
||||
## Arguments
|
||||
|
||||
Parse the version intent from the user's message. Accept any of these forms:
|
||||
- Bump type keyword: `patch`, `minor`, `major`
|
||||
- Exact version: `x.y.z` or `x.y.z-pre.N` (e.g. `1.8.0`, `1.8.0-beta.1`, `1.8.0-rc.1`)
|
||||
- Natural language: "prepare a beta release", "bump to 1.8.0-rc.2", etc.
|
||||
|
||||
Defaults to `patch` if no version is specified. Always echo the resolved target version back to the user before proceeding with any file edits.
|
||||
|
||||
- `--dry-run`: Preview only, do not create branch or PR.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Determine Version
|
||||
|
||||
1. Get the latest tag:
|
||||
```bash
|
||||
git describe --tags --abbrev=0
|
||||
```
|
||||
2. Read current version from `package.json`.
|
||||
3. Compute the new version based on the argument:
|
||||
- `patch` / `minor` / `major`: bump from the current tag version.
|
||||
- `x.y.z` or `x.y.z-pre.N`: use as-is after validating it is valid semver.
|
||||
|
||||
### Step 2: Collect Commits
|
||||
|
||||
1. List all commits since the last tag:
|
||||
```bash
|
||||
git log <last-tag>..HEAD --format="%H %s" --no-merges
|
||||
```
|
||||
2. For each commit, get the full body:
|
||||
```bash
|
||||
git log <hash> -1 --format="%B"
|
||||
```
|
||||
3. Extract the content inside `` ```release-note `` code blocks from each commit body.
|
||||
4. Extract the conventional commit type from the title (`feat`, `fix`, `refactor`, `perf`, `docs`, etc.).
|
||||
5. **Skip** these commits:
|
||||
- Titles starting with `🤖 Daily Auto I18N`
|
||||
- Titles starting with `Merge`
|
||||
- Titles starting with `chore(deps)`
|
||||
- Titles starting with `chore: release`
|
||||
- Commits where the release-note block says `NONE`
|
||||
|
||||
### Step 3: Generate Bilingual Release Notes
|
||||
|
||||
Using the collected commit information, generate release notes in **both English and Chinese**.
|
||||
|
||||
**Format** (must match exactly):
|
||||
|
||||
```
|
||||
<!--LANG:en-->
|
||||
Cherry Studio {version} - {Brief English Title}
|
||||
|
||||
✨ New Features
|
||||
- [Component] Description
|
||||
|
||||
🐛 Bug Fixes
|
||||
- [Component] Description
|
||||
|
||||
💄 Improvements
|
||||
- [Component] Description
|
||||
|
||||
⚡ Performance
|
||||
- [Component] Description
|
||||
|
||||
<!--LANG:zh-CN-->
|
||||
Cherry Studio {version} - {简短中文标题}
|
||||
|
||||
✨ 新功能
|
||||
- [组件] 描述
|
||||
|
||||
🐛 问题修复
|
||||
- [组件] 描述
|
||||
|
||||
💄 改进
|
||||
- [组件] 描述
|
||||
|
||||
⚡ 性能优化
|
||||
- [组件] 描述
|
||||
<!--LANG:END-->
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
- Only include categories that have entries (omit empty categories).
|
||||
- Each commit appears as exactly ONE line item in the appropriate category.
|
||||
- Use the `release-note` field if present; otherwise summarize from the commit title.
|
||||
- Component tags should be short: `[Chat]`, `[Models]`, `[Agent]`, `[MCP]`, `[Settings]`, `[Data]`, `[Build]`, etc.
|
||||
- Chinese translations should be natural, not machine-literal.
|
||||
- Do NOT include commit hashes or PR numbers.
|
||||
- Omit purely internal commits (refactor, CI, docs) with no user-facing impact.
|
||||
- Read the **existing** release notes in `electron-builder.yml` as a style reference before writing.
|
||||
|
||||
### Step 4: Update Files
|
||||
|
||||
1. **`package.json`**: Update the `"version"` field to the new version.
|
||||
2. **`electron-builder.yml`**: Replace the content under `releaseInfo.releaseNotes: |` with the generated notes. Preserve the 4-space YAML indentation for the block scalar content.
|
||||
|
||||
### Step 5: Present for Review
|
||||
|
||||
Show the user:
|
||||
- The new version number.
|
||||
- The full generated release notes.
|
||||
- A summary of which files were modified.
|
||||
|
||||
If `--dry-run` was specified, stop here.
|
||||
|
||||
Otherwise, ask the user to confirm before proceeding to Step 6.
|
||||
|
||||
### Step 6: Create Branch and PR
|
||||
|
||||
1. Create and push the release branch:
|
||||
```bash
|
||||
git checkout -b release/v{version}
|
||||
git add package.json electron-builder.yml
|
||||
git commit -m "chore: release v{version}"
|
||||
git push -u origin release/v{version}
|
||||
```
|
||||
2. Create the PR using the `gh-create-pr` skill. If the skill tool is unavailable, read `.agents/skills/gh-create-pr/SKILL.md` and follow it manually. In CI (non-interactive) mode, skip interactive confirmation steps and create the PR directly after filling the template.
|
||||
- Use title: `chore: release v{version}`
|
||||
- Use base branch: `main`
|
||||
- When filling the PR template, incorporate:
|
||||
- The generated release notes (English section only, for readability).
|
||||
- A list of included commits.
|
||||
- A review checklist:
|
||||
- [ ] Review generated release notes in `electron-builder.yml`
|
||||
- [ ] Verify version bump in `package.json`
|
||||
- [ ] CI passes
|
||||
- [ ] Merge to trigger release build
|
||||
3. Report the PR URL and next steps.
|
||||
|
||||
## CI Trigger Chain
|
||||
|
||||
Creating a PR from `release/v*` to `main` automatically triggers:
|
||||
- **`release.yml`**: Builds on macOS, Windows, Linux and creates a draft GitHub Release.
|
||||
- **`ci.yml`**: Runs lint, typecheck, and tests.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Always read `electron-builder.yml` before modifying it to understand the current format.
|
||||
- Never modify files other than `package.json` and `electron-builder.yml`.
|
||||
- Never push directly to `main`.
|
||||
- Always show the generated release notes to the user before creating the branch/PR (unless running in CI with no interactive user).
|
||||
48
.github/workflows/prepare-release.yml
vendored
Normal file
48
.github/workflows/prepare-release.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Prepare Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version bump type or exact version (patch / minor / major / x.y.z / x.y.z-beta.N)"
|
||||
required: true
|
||||
default: "patch"
|
||||
type: string
|
||||
|
||||
# Ensure this workflow only runs from the default branch
|
||||
# (workflow_dispatch already restricts to branches with write access,
|
||||
# but we guard the job to main to prevent accidental runs from feature branches)
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Prepare Release via Claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.CLAUDE_TRANSLATOR_APIKEY }}
|
||||
github_token: ${{ secrets.TOKEN_GITHUB_WRITE }}
|
||||
claude_args: '--allowed-tools Bash(git:*),Bash(gh pr create:*),Bash(gh pr view:*),Bash(cat:*),Edit,Read,Write,Glob,Grep'
|
||||
prompt: |
|
||||
Run the prepare-release skill with version argument: ${{ github.event.inputs.version }}
|
||||
|
||||
Read the skill instructions from .agents/skills/prepare-release/SKILL.md and follow them exactly.
|
||||
|
||||
Since this is running in CI (non-interactive), skip all interactive confirmation steps. For PR creation, do NOT use the gh-create-pr skill; instead read .github/pull_request_template.md, fill every section, and run gh pr create --body-file directly.
|
||||
|
||||
Configure git before making commits:
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
env:
|
||||
ANTHROPIC_BASE_URL: ${{ secrets.CLAUDE_TRANSLATOR_BASEURL }}
|
||||
Reference in New Issue
Block a user