diff --git a/.github/prompt/default.md b/.github/prompt/default.md index 058935f9..99c728fa 100644 --- a/.github/prompt/default.md +++ b/.github/prompt/default.md @@ -1,27 +1,18 @@ -# V?.?.? +# {VERSION} [使用文档](https://napneko.github.io/) ## Windows 一键包 -我们为提供了的轻量化一键部署方案 -相对于普通需要安装QQ的方案,下面已内置QQ和Napcat 阅读使用文档参考 +我们提供了轻量化一键部署方案,内置 QQ 和 NapCat,详见使用文档。 -你可以下载 +可下载文件: +- NapCat.Shell.Windows.Node.zip(无头模式) -NapCat.Shell.Windows.OneKey.zip (无头) +## 注意事项 +**推荐 QQ 版本:9.9.23+,最低支持 9.9.22** +**默认 WebUI 密钥为随机密码,请在控制台查看** -启动后可自动化部署一键包,教程参考使用文档安装部分 +## 运行库 +如果 Windows x64 缺少 xxx.dll,请安装 [VC++ 运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe) -## 警告 -**注意QQ版本推荐使用 40768+ 版本 最低可以使用40768版本** -**默认WebUi密钥为随机密码 控制台查看** - -**[9.9.22-40990 X64 Win](https://dldir1v6.qq.com/qqfile/qq/QQNT/2c9d3f6c/QQ9.9.22.40990_x64.exe)** -[LinuxX64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_amd64.deb) -[LinuxX64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_x86_64.rpm) -[LinuxArm64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_arm64.deb) -[LinuxArm64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_aarch64.rpm) -[MAC DMG 40990 ](https://dldir1v6.qq.com/qqfile/qq/QQNT/c6cb0f5d/QQ_v6.9.82.40990.dmg) -## 如果WinX64缺少运行库或者xxx.dll? -[安装运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe) - -## 更新 \ No newline at end of file +## 更新内容 +详见 commit 历史。 \ No newline at end of file diff --git a/.github/prompt/release_note_prompt.txt b/.github/prompt/release_note_prompt.txt index 81c9633a..97989918 100644 --- a/.github/prompt/release_note_prompt.txt +++ b/.github/prompt/release_note_prompt.txt @@ -1,60 +1,94 @@ -注意:输出必须严格使用 NapCat 的发布说明格式,严格保证示例格式,并用简体中文。 +# NapCat Release Note Generator -格式规则: -1. 第一行:# V{TAG} -2. 第二行:[使用文档](https://napneko.github.io/) -3. 空行后,按下面的节顺序输出(存在则输出,不存在则省略该节): +你是 NapCat 项目的发布说明生成器。请根据提供的 commit 列表生成标准格式的发布说明。 -## Windows 一键包 -- 简短一句话介绍一键包用途 -- 列出可下载的文件名(只列文件名,不写下载链接) +## 核心规则 -## 警告 -- 如果有需要特别提醒的兼容/运行库/版本要求,写成加粗警告句 +1. **版本号**:第一行必须是 `# {VERSION}`,使用用户提供的版本号(如 v4.10.2),不要添加额外的 V 前缀 +2. **语言**:全部使用简体中文 +3. **格式**:严格按照下方模板输出,不要添加额外的 markdown 格式 -## 如果WinX64缺少运行库或者xxx.dll? -- 常见运行库建议 +## Commit 分析规则 -## 更新 -按数字序列列出主要变更项,每条尽量一句话 -- 前缀短 commit id,例如:1. 修复 get_essence_msg_list 崩溃 (a1b2c3d) -- 保持 4-18 条要点 +将 commit 分类为以下类型: +- 🐛 **修复**:bug fix、修复、fix 相关 +- ✨ **新增**:新功能、feat、add 相关 +- 🔧 **优化**:优化、重构、refactor、improve、perf 相关 +- 📦 **依赖**:deps、依赖更新(通常可以忽略或合并) +- 🔨 **构建**:ci、build、workflow 相关(通常可以忽略) -## 开发者注意 -- 列出迁移/接口断裂/配置变更;若无则省略 +## 合并和筛选 -额外约束: -- 语言简体中文,面向最终用户 +- **合并相似项**:同一功能的多个 commit 合并为一条 +- **忽略琐碎项**:合并冲突、格式化、typo 等可忽略 +- **控制数量**:最终保持 5-15 条更新要点 +- **保留 commit hash**:每条末尾附上短 hash,格式 `(a1b2c3d)` -下面为真实示例,请完全参考(第一行版本号必须使用用户提供的版本号,例如 v4.9.5) +## 输出模板 -# V4.9.0 +``` +# {VERSION} [使用文档](https://napneko.github.io/) ## Windows 一键包 -我们为提供了的轻量化一键部署方案 -相对于普通需要安装QQ的方案,下面已内置QQ和Napcat 阅读使用文档参考 +我们提供了轻量化一键部署方案,内置 QQ 和 NapCat,详见使用文档。 -你可以下载 +可下载文件: +- NapCat.Shell.Windows.Node.zip(无头模式) -NapCat.Shell.Windows.OneKey.zip (无头) +## 注意事项 +**推荐 QQ 版本:9.9.23+,最低支持 9.9.22** +**默认 WebUI 密钥为随机密码,请在控制台查看** -启动后可自动化部署一键包,教程参考使用文档安装部分 +## 运行库 +如果 Windows x64 缺少 xxx.dll,请安装 [VC++ 运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe) -## 警告 -**注意QQ版本推荐使用 40768+ 版本 最低可以使用40768版本** -**默认WebUi密钥为随机密码 控制台查看** +## 更新内容 -**[9.9.22-40990 X64 Win](https://dldir1v6.qq.com/qqfile/qq/QQNT/2c9d3f6c/QQ9.9.22.40990_x64.exe)** -[LinuxX64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_amd64.deb) -[LinuxX64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_x86_64.rpm) -[LinuxArm64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_arm64.deb) -[LinuxArm64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_aarch64.rpm) -[MAC DMG 40990 ](https://dldir1v6.qq.com/qqfile/qq/QQNT/c6cb0f5d/QQ_v6.9.82.40990.dmg) -## 如果WinX64缺少运行库或者xxx.dll? -[安装运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe) +### 🐛 修复 +1. 修复 xxx 问题 (a1b2c3d) +2. 修复 yyy 崩溃 (b2c3d4e) -## 更新 -1. 修改了XXXXX -2. 新增了XXXX -3. 重构了XXXX \ No newline at end of file +### ✨ 新增 +1. 新增 xxx 功能 (c3d4e5f) +2. 支持 yyy 特性 (d4e5f6g) + +### 🔧 优化 +1. 优化 xxx 性能 (e5f6g7h) +2. 重构 yyy 模块 (f6g7h8i) + +--- + +**完整更新日志**: [{PREV_VERSION}...{VERSION}](https://github.com/NapNeko/NapCatQQ/compare/{PREV_VERSION}...{VERSION}) +``` + +## 重要约束 + +1. 如果某个分类没有内容,则完全省略该分类 +2. 不要编造不存在的更新 +3. 保持简洁,每条更新控制在一行内 +4. 使用用户友好的语言,避免过于技术化的描述 +5. 重大变更(Breaking Changes)需要在注意事项中加粗提示 + +## 文件变化分析 + +用户会提供文件变化统计和具体代码diff,帮助你理解变更内容: + +### 目录含义 +- `packages/napcat-core/` → 核心功能、消息处理、QQ接口 +- `packages/napcat-onebot/` → OneBot 协议实现、API、事件 +- `packages/napcat-webui-backend/` → WebUI 后端接口 +- `packages/napcat-webui-frontend/` → WebUI 前端界面 +- `packages/napcat-shell/` → Shell 启动器 + +### 代码diff阅读指南 +- `+` 开头的行是新增代码 +- `-` 开头的行是删除代码 +- 关注函数名、类名的变化来理解功能变更 +- 关注 `fix`、`bug`、`error` 等关键词识别修复项 +- 关注 `add`、`new`、`feature` 等关键词识别新功能 +- 忽略纯重构(代码移动但功能不变)和格式化变更 + +### 截断说明 +- 如果看到 `[... 已截断 ...]`,表示内容过长被截断 +- 根据已有信息推断完整变更意图即可 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e7a3419..c75cb7f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,8 +4,7 @@ on: workflow_dispatch: push: tags: - - 'v[0-9]*.[0-9]*.[0-9]*' - - 'v[0-9]*.[0-9]*.[0-9]*-*' + - 'v*' permissions: write-all @@ -15,7 +14,38 @@ env: RELEASE_NAME: "NapCat" jobs: + # 验证版本号格式 + validate-version: + runs-on: ubuntu-latest + outputs: + valid: ${{ steps.check.outputs.valid }} + version: ${{ steps.check.outputs.version }} + steps: + - name: Validate semantic version + id: check + run: | + TAG="${GITHUB_REF#refs/tags/}" + echo "Checking tag: $TAG" + + # 语义化版本正则表达式 + # 支持: v1.0.0, v1.0.0-beta, v1.0.0-rc.1, v1.0.0-alpha.1+build.123 + SEMVER_REGEX="^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?$" + + if [[ "$TAG" =~ $SEMVER_REGEX ]]; then + echo "✅ Valid semantic version: $TAG" + echo "valid=true" >> $GITHUB_OUTPUT + echo "version=$TAG" >> $GITHUB_OUTPUT + else + echo "❌ Invalid version format: $TAG" + echo "Expected format: vX.Y.Z or vX.Y.Z-prerelease" + echo "Examples: v1.0.0, v1.2.3-beta, v2.0.0-rc.1" + echo "valid=false" >> $GITHUB_OUTPUT + exit 1 + fi + Build-Framework: + needs: validate-version + if: needs.validate-version.outputs.valid == 'true' runs-on: ubuntu-latest steps: - name: Clone Main Repository @@ -43,6 +73,8 @@ jobs: path: framework-dist Build-Shell: + needs: validate-version + if: needs.validate-version.outputs.valid == 'true' runs-on: ubuntu-latest steps: - name: Clone Main Repository @@ -179,7 +211,7 @@ jobs: OPENAI_KEY: ${{ secrets.OPENAI_KEY }} OPENROUTER_API_URL: ${{ env.OPENROUTER_API_URL }} OPENROUTER_MODEL: ${{ env.OPENROUTER_MODEL }} - GITHUB_OWNER: "NapNeKo" # 替换成你的 repo owner + GITHUB_OWNER: "NapNeko" # 替换成你的 repo owner GITHUB_REPO: "NapCatQQ" # 替换成你的 repo 名 run: | set -euo pipefail @@ -204,34 +236,145 @@ jobs: done if [ -z "$PREV_TAG" ]; then - echo "❌ Could not find previous tag for $CURRENT_TAG, aborting." - exit 1 + echo "⚠️ Could not find previous tag for $CURRENT_TAG, using first commit" + PREV_TAG=$(git rev-list --max-parents=0 HEAD | head -1) fi echo "Previous tag: $PREV_TAG" # 强制拉取上一个 tag 和当前 tag - git fetch origin "refs/tags/$PREV_TAG:refs/tags/$PREV_TAG" --force - git fetch origin "refs/tags/$CURRENT_TAG:refs/tags/$CURRENT_TAG" --force + git fetch origin "refs/tags/$PREV_TAG:refs/tags/$PREV_TAG" --force || true + git fetch origin "refs/tags/$CURRENT_TAG:refs/tags/$CURRENT_TAG" --force || true - # 获取 commit title + body + 作者,保留换行 - COMMITS=$(git log --pretty=format:'%h %B (%an)' "$PREV_TAG".."$CURRENT_TAG" | sed 's/$/\\n/') + # 获取 commit,使用更清晰的格式 + # 格式: : () + COMMITS=$(git log --pretty=format:'- %s (%h)' "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null || git log --pretty=format:'- %s (%h)' -20) echo "Commit list from $PREV_TAG to $CURRENT_TAG:" - echo -e "$COMMITS" + echo "$COMMITS" + + # 获取文件变化统计 + echo "Getting file change statistics..." + FILE_STATS=$(git diff --stat "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null || echo "") + + # 获取总体统计(最后一行) + SUMMARY_LINE=$(echo "$FILE_STATS" | tail -1) + echo "Summary: $SUMMARY_LINE" + + # 获取每个文件的变化(去掉最后一行汇总) + # 截断过长的输出(最多50个文件,每行最多80字符) + FILE_CHANGES=$(echo "$FILE_STATS" | head -n -1 | head -50 | cut -c1-80) + + # 如果文件变化太多,进一步精简:只保留主要目录的变化 + FILE_COUNT=$(echo "$FILE_STATS" | head -n -1 | wc -l) + if [ "$FILE_COUNT" -gt 50 ]; then + echo "Too many files ($FILE_COUNT), grouping by directory..." + # 按目录分组统计 + DIR_STATS=$(git diff --stat "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null | head -n -1 | \ + sed 's/|.*//g' | \ + awk -F'/' '{if(NF>1) print $1"/"$2; else print $1}' | \ + sort | uniq -c | sort -rn | head -20) + FILE_CHANGES="[按目录分组统计 - 共 $FILE_COUNT 个文件变更] + $DIR_STATS" + fi + + echo "File changes:" + echo "$FILE_CHANGES" + + # 获取具体代码变化(关键文件的diff) + echo "Getting code diff for key files..." + + # 定义关键目录(优先展示这些目录的变化) + KEY_DIRS="packages/napcat-core packages/napcat-onebot packages/napcat-webui-backend" + + # 获取变更的关键文件列表(排除测试、配置等) + KEY_FILES=$(git diff --name-only "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null | \ + grep -E "^packages/napcat-(core|onebot|webui-backend|shell)/" | \ + grep -E "\.(ts|js)$" | \ + grep -v -E "(test|spec|\.d\.ts|config)" | \ + head -15) + + CODE_DIFF="" + DIFF_CHAR_LIMIT=6000 # 总diff字符限制 + CURRENT_CHARS=0 + + for file in $KEY_FILES; do + if [ "$CURRENT_CHARS" -ge "$DIFF_CHAR_LIMIT" ]; then + CODE_DIFF="$CODE_DIFF + [... 更多文件变化已截断 ...]" + break + fi + + # 获取单个文件的diff,限制每个文件最多50行 + FILE_DIFF=$(git diff "$PREV_TAG".."$CURRENT_TAG" -- "$file" 2>/dev/null | head -50) + FILE_DIFF_LEN=${#FILE_DIFF} + + # 如果单个文件diff超过1500字符,截断 + if [ "$FILE_DIFF_LEN" -gt 1500 ]; then + FILE_DIFF=$(echo "$FILE_DIFF" | head -c 1500) + FILE_DIFF="$FILE_DIFF + [... 文件 $file 变化已截断 ...]" + fi + + if [ -n "$FILE_DIFF" ]; then + CODE_DIFF="$CODE_DIFF + + ### $file + \`\`\`diff + $FILE_DIFF + \`\`\`" + CURRENT_CHARS=$((CURRENT_CHARS + FILE_DIFF_LEN)) + fi + done + + # 如果没有关键文件变化,获取前5个变更文件的diff + if [ -z "$CODE_DIFF" ]; then + echo "No key files changed, getting top changed files..." + TOP_FILES=$(git diff --name-only "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null | \ + grep -E "\.(ts|js)$" | head -5) + + for file in $TOP_FILES; do + FILE_DIFF=$(git diff "$PREV_TAG".."$CURRENT_TAG" -- "$file" 2>/dev/null | head -30) + if [ -n "$FILE_DIFF" ] && [ ${#FILE_DIFF} -lt 1000 ]; then + CODE_DIFF="$CODE_DIFF + + ### $file + \`\`\`diff + $FILE_DIFF + \`\`\`" + fi + done + fi + + echo "Code diff preview:" + echo "$CODE_DIFF" | head -50 # 读取 prompt PROMPT_FILE=".github/prompt/release_note_prompt.txt" SYSTEM_PROMPT=$(<"$PROMPT_FILE") - # 构建用户内容 - USER_CONTENT="当前真正的版本: $CURRENT_TAG\n提交列表:\n$COMMITS" + # 构建用户内容,传递更多上下文(包含文件变化和代码diff) + USER_CONTENT="当前版本: $CURRENT_TAG + 上一版本: $PREV_TAG + + ## 提交列表 + $COMMITS + + ## 文件变化统计 + $SUMMARY_LINE + + ## 变更文件列表 + $FILE_CHANGES + + ## 关键代码变化 + $CODE_DIFF" - # 构建请求 JSON + # 构建请求 JSON,增加 max_tokens 以获取更完整的输出 BODY=$(jq -n \ --arg system "$SYSTEM_PROMPT" \ --arg user "$USER_CONTENT" \ - '{model: env.OPENROUTER_MODEL, messages:[{role:"system", content:$system},{role:"user", content:$user}], temperature:0.3, max_tokens:800}') + --arg model "$OPENROUTER_MODEL" \ + '{model: $model, messages:[{role:"system", content:$system},{role:"user", content:$user}], temperature:0.2, max_tokens:1500}') echo "=== OpenRouter request body ===" echo "$BODY" | jq . @@ -255,13 +398,18 @@ jobs: if [ -z "$RELEASE_BODY" ]; then echo "❌ OpenRouter failed to generate release note, using default.md" - cp .github/prompt/default.md CHANGELOG.md + # 替换默认模板中的版本占位符 + sed "s/{VERSION}/$CURRENT_TAG/g" .github/prompt/default.md > CHANGELOG.md else + # 后处理:确保版本号正确,并添加比较链接 echo -e "$RELEASE_BODY" > CHANGELOG.md + # 替换可能的占位符 + sed -i "s/{VERSION}/$CURRENT_TAG/g" CHANGELOG.md + sed -i "s/{PREV_VERSION}/$PREV_TAG/g" CHANGELOG.md fi else echo "❌ Curl failed, using default.md" - cp .github/prompt/default.md CHANGELOG.md + sed "s/{VERSION}/$CURRENT_TAG/g" .github/prompt/default.md > CHANGELOG.md fi echo "=== generated release note ===" cat CHANGELOG.md