Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 38 additions & 56 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,44 @@ permissions:
contents: write

jobs:
test:
name: 发布前检查
runs-on: ubuntu-latest
steps:
- name: 拉取源代码
uses: actions/checkout@v4

- name: 安装 Go 环境
uses: actions/setup-go@v5
with:
go-version: '1.21'
cache-dependency-path: './backend/go.sum'

- name: 后端代码检查
run: go vet ./...
working-directory: ./backend

- name: 后端编译检查
run: go build ./...
working-directory: ./backend

- name: 安装 Node.js 环境
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
cache-dependency-path: './desktop/package-lock.json'

- name: 安装前端依赖
run: npm ci
working-directory: ./desktop

- name: 前端构建检查
run: npm run build
working-directory: ./desktop

build-and-release:
needs: test
name: 构建并发布 - ${{ matrix.name }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -88,59 +125,7 @@ jobs:
- name: 生成 Release Notes
id: release_notes
shell: bash
run: |
# 获取上一个 tag,如果不存在则获取第一个 commit
PREV_TAG=$(git describe --tags --abbrev=0 ${{ github.ref_name }}^ 2>/dev/null || git rev-list --max-parents=0 HEAD)
echo "Previous tag: $PREV_TAG"

# 提取 commit 记录(不包括 merge commit)
# --no-merges: 只显示实际代码变更的 commit,过滤掉 PR merge 产生的合并提交
LOGS=$(git log $PREV_TAG..${{ github.ref_name }} --pretty=format:"%s" --no-merges)

# 初始化分类内容
FEATS=""
FIXES=""
DOCS=""
OTHERS=""

# 按前缀归类
while IFS= read -r line; do
[ -z "$line" ] && continue

# 清理可能导致 Markdown 渲染问题的特殊字符(如反斜杠、反引号等)
# 这里简单处理,保证基础展示正常
clean_line=$(echo "$line" | sed 's/\\/\\\\/g; s/`/\\`/g')

if [[ $line =~ ^feat ]]; then
FEATS="$FEATS\n- ${clean_line#feat: }"
elif [[ $line =~ ^fix ]]; then
FIXES="$FIXES\n- ${clean_line#fix: }"
elif [[ $line =~ ^docs ]]; then
DOCS="$DOCS\n- ${clean_line#docs: }"
elif [[ $line =~ ^refactor ]] || [[ $line =~ ^perf ]]; then
FIXES="$FIXES\n- ${clean_line}"
elif [[ $line =~ ^bump ]]; then
OTHERS="$OTHERS\n- ${clean_line}"
else
OTHERS="$OTHERS\n- ${clean_line}"
fi
done <<< "$LOGS"

# 组合最终正文
BODY=""
[ -n "$FEATS" ] && BODY="$BODY\n### 🚀 新功能 (Features)$FEATS\n"
[ -n "$FIXES" ] && BODY="$BODY\n### 🔧 修复与优化 (Bug Fixes & Refactor)$FIXES\n"
[ -n "$DOCS" ] && BODY="$BODY\n### 📝 文档更新 (Documentation)$DOCS\n"
[ -n "$OTHERS" ] && BODY="$BODY\n### 📦 其他改动 (Others)$OTHERS\n"

[ -z "$BODY" ] && BODY="本次发布包含内部优化与稳定性提升。"

# 处理换行符并存入环境变量(使用多行模式)
{
echo "body<<EOF"
echo -e "$BODY"
echo "EOF"
} >> "$GITHUB_OUTPUT"
run: bash scripts/generate-changelog.sh "${{ github.ref_name }}" "https://github.com/${{ github.repository }}" >> "$GITHUB_OUTPUT"

- name: 准备 Go 边车程序
shell: bash
Expand Down Expand Up @@ -218,7 +203,6 @@ jobs:
releaseBody: |
## 🎨 大香蕉 AI - 创作从未如此简单

### 🚀 本次更新
${{ steps.release_notes.outputs.body }}

### 📦 包含组件
Expand All @@ -245,7 +229,6 @@ jobs:
releaseBody: |
## 🎨 大香蕉 AI - 创作从未如此简单

### 🚀 本次更新
${{ steps.release_notes.outputs.body }}

### 📦 包含组件
Expand Down Expand Up @@ -341,7 +324,6 @@ jobs:
releaseBody: |
## 🎨 大香蕉 AI - 创作从未如此简单

### 🚀 本次更新
${{ steps.release_notes.outputs.body }}

### 📦 包含组件
Expand Down
146 changes: 146 additions & 0 deletions scripts/generate-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env bash
# 用法: ./scripts/generate-changelog.sh <current_tag> [repo_url]
# 输出 GITHUB_OUTPUT 多行格式: body<<EOF ... EOF
set -euo pipefail
Comment on lines +1 to +4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

根据项目代码审查规范第 89 条和第 90 条,复杂逻辑应有中文注释,且函数应有文档注释。虽然脚本整体逻辑清晰,但建议在脚本开头添加功能描述,并为 touches 函数及后续的 Commit 分类循环、GitHub Output 格式输出等关键逻辑块添加简要的中文说明,以提高代码的可维护性。

References
  1. 复杂逻辑必须有中文注释说明;公共函数必须有文档注释 (link)


CURRENT_TAG="${1:?Usage: $0 <current_tag> [repo_url]}"
REPO_URL="${2:-}"

PREV_TAG=$(git describe --tags --abbrev=0 "$CURRENT_TAG^" 2>/dev/null || git rev-list --max-parents=0 HEAD)
echo "Previous tag: $PREV_TAG" >&2

CHANGED_FILES=$(git diff --name-only "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null || true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: git diff/git log failures are explicitly swallowed with || true, which makes the workflow continue and publish fallback text even when tags/history are invalid or unavailable. This hides real release-note generation failures and can produce incorrect release content; remove the silent fallback and fail the step when git range queries fail. [logic error]

Severity Level: Major ⚠️
- ⚠️ Local changelog runs hide git history resolution failures.
- ⚠️ Release workflows may publish generic notes after git errors.
Steps of Reproduction ✅
1. From any non-git directory (for example `/tmp`), copy `scripts/generate-changelog.sh`
from this repo and run `bash generate-changelog.sh v0.1.0 https://github.com/org/repo` as
suggested by the usage comment at `scripts/generate-changelog.sh:2-3`.

2. Because the current working directory is not a git repository, the `git diff
--name-only "$PREV_TAG".."$CURRENT_TAG"` command at `scripts/generate-changelog.sh:12`
fails with "fatal: not a git repository"; however, the `2>/dev/null || true` suffix forces
the entire command substitution to succeed and silently assigns an empty string to
`CHANGED_FILES`.

3. Later, the `git log "$PREV_TAG".."$CURRENT_TAG"` call at
`scripts/generate-changelog.sh:74` also fails in the non-git directory, but again
`2>/dev/null || true` suppresses the error and leaves `LOGS` empty, so the loop at
`scripts/generate-changelog.sh:81-106` never populates `FEATS`, `FIXES`, `DOCS`, or
`OTHERS`.

4. With both `CHANGED_FILES` and `LOGS` empty, the script falls back to the generic
message at `scripts/generate-changelog.sh:134` and still prints a `body<<EOF ... EOF`
block at `scripts/generate-changelog.sh:142-145` with exit status 0, so callers (including
workflows like `.github/workflows/release.yml:125-129`) cannot detect that git history
resolution failed and receive misleading "successful" release notes.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** scripts/generate-changelog.sh
**Line:** 12:12
**Comment:**
	*Logic Error: `git diff`/`git log` failures are explicitly swallowed with `|| true`, which makes the workflow continue and publish fallback text even when tags/history are invalid or unavailable. This hides real release-note generation failures and can produce incorrect release content; remove the silent fallback and fail the step when git range queries fail.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎


SUMMARY=""
# 检测变更文件是否匹配指定路径模式
touches() {
printf "%s\n" "$CHANGED_FILES" | grep -qE "$1"
}
Comment on lines +16 to +18

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在处理可能包含特殊字符(如以 - 开头)的变量时,使用 printf 比 echo 更健壮。此外,grep -q 已经静默输出,通常不需要重定向 2>/dev/null。

Suggested change
touches() {
echo "$CHANGED_FILES" | grep -qE "$1" 2>/dev/null
}
touches() {
printf "%s\n" "$CHANGED_FILES" | grep -qE "$1"
}


if touches "backend/internal/provider/"; then
SUMMARY="${SUMMARY}
- AI 提供商接口适配与模型支持更新"
fi
if touches "backend/internal/worker/"; then
SUMMARY="${SUMMARY}
- 任务并发处理引擎优化"
fi
if touches "backend/internal/templates/"; then
SUMMARY="${SUMMARY}
- 模板市场资源更新"
fi
if touches "backend/internal/promptopt/"; then
SUMMARY="${SUMMARY}
- 提示词智能优化引擎改进"
fi
if touches "backend/internal/(storage|config|folder)/"; then
SUMMARY="${SUMMARY}
- 本地存储与配置管理优化"
fi
if touches "backend/internal/api/"; then
SUMMARY="${SUMMARY}
- 后端 API 接口调整"
fi
if touches "desktop/src/components/"; then
SUMMARY="${SUMMARY}
- 前端界面交互与组件体验升级"
fi
if touches "desktop/src/store/"; then
SUMMARY="${SUMMARY}
- 前端状态管理逻辑更新"
fi
if touches "desktop/src/services/"; then
SUMMARY="${SUMMARY}
- 前端 API 服务层调整"
fi
if touches "desktop/src-tauri/"; then
SUMMARY="${SUMMARY}
- 桌面端 Tauri 容器与权限配置更新"
fi
if touches "desktop/src/i18n/"; then
SUMMARY="${SUMMARY}
- 多语言国际化翻译更新"
fi
if touches "docker|Dockerfile|docker-compose|\.env\.example"; then
SUMMARY="${SUMMARY}
- Docker 部署方案优化"
fi
if touches "\.github/"; then
SUMMARY="${SUMMARY}
- CI/CD 构建与发布流程改进"
fi

NOISE_REGEX='^(chore|ci|release|bump|test|ignore)(\(|:|!|:)'
LOGS=$(git log "$PREV_TAG".."$CURRENT_TAG" --pretty=format:"%s" --no-merges 2>/dev/null || true)

FEATS=""
FIXES=""
DOCS=""
OTHERS=""

while IFS= read -r line; do
[ -z "$line" ] && continue
[[ $line =~ $NOISE_REGEX ]] && continue

clean_line=$(printf "%s" "$line" | sed 's/`/\\`/g')

# 剥离 conventional commit 前缀: feat: / feat(scope): / feat(scope)!: / fix!: 等
stripped_line=$(printf "%s" "$clean_line" | sed -E 's/^[a-z]+(\([^)]*\))?!?:[[:space:]]*//')

if [[ $line =~ ^feat ]]; then
FEATS="$FEATS
- ${stripped_line}"
elif [[ $line =~ ^fix ]]; then
FIXES="$FIXES
- ${stripped_line}"
elif [[ $line =~ ^docs ]]; then
DOCS="$DOCS
- ${stripped_line}"
elif [[ $line =~ ^refactor ]] || [[ $line =~ ^perf ]]; then
FIXES="$FIXES
- ${clean_line}"
else
OTHERS="$OTHERS
- ${clean_line}"
fi
done <<< "$LOGS"

BODY=""
if [ -n "$SUMMARY" ]; then
BODY="${BODY}
### 📋 更新概要

本次发布主要涉及以下模块:${SUMMARY}
"
fi

[ -n "$FEATS" ] && BODY="${BODY}

### 🚀 新功能 (Features)${FEATS}
"
[ -n "$FIXES" ] && BODY="${BODY}

### 🔧 修复与优化 (Bug Fixes & Refactor)${FIXES}
"
[ -n "$DOCS" ] && BODY="${BODY}

### 📝 文档更新 (Documentation)${DOCS}
"
[ -n "$OTHERS" ] && BODY="${BODY}

### 📦 其他改动 (Others)${OTHERS}
"

[ -z "$BODY" ] && BODY="本次发布包含内部优化与稳定性提升。"

if [ -n "$REPO_URL" ] && [ "$PREV_TAG" != "$CURRENT_TAG" ]; then
BODY="${BODY}

**Full Changelog**: ${REPO_URL}/compare/${PREV_TAG}...${CURRENT_TAG}"
fi

{
printf "%s\n" "body<<EOF"
printf "%s\n" "$BODY"
printf "%s\n" "EOF"
}
Loading