Skip to content

feat: improve release workflow with test gate, changelog script and smart summary #125

feat: improve release workflow with test gate, changelog script and smart summary

feat: improve release workflow with test gate, changelog script and smart summary #125

Workflow file for this run

name: PR Check
# PR 检查工作流:每次 PR 创建或更新时自动运行
# 确保代码质量、运行测试、验证构建
on:
pull_request:
branches: [ main ]
# 触发事件类型:
# - opened: PR 首次创建
# - synchronize: PR 分支有新 commit(关键!)
# - reopened: PR 重新打开
types: [opened, synchronize, reopened]
# 并发控制:同一 PR 的多次 push 只运行最新的一次
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ========================================
# Job 1: 后端检查 (Go)
# ========================================
backend-check:
name: Backend Check (Go)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
cache-dependency-path: './backend/go.sum'
# Go 代码格式检查
- name: Go Fmt
run: |
cd backend
echo "检查代码格式..."
if [ -n "$(gofmt -l .)" ]; then
echo "❌ 代码格式不符合规范,请运行 'gofmt -w .'"
gofmt -d .
exit 1
fi
echo "✅ 代码格式检查通过"
# Go 静态分析
- name: Go Vet
run: |
cd backend
echo "运行静态分析..."
go vet ./...
# Go 依赖检查
- name: Go Mod Verify
run: |
cd backend
echo "验证依赖完整性..."
go mod verify
# Go 单元测试
- name: Go Test
run: |
cd backend
echo "运行单元测试..."
go test ./... -v -race -coverprofile=coverage.out
# 上传测试覆盖率
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: ./backend/coverage.out
flags: backend
fail_ci_if_error: false
continue-on-error: true
# ========================================
# Job 2: 前端检查 (React + TypeScript)
# ========================================
frontend-check:
name: Frontend Check (React)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: './desktop/package-lock.json'
# 安装依赖
- name: Install dependencies
run: |
cd desktop
npm ci
# ESLint 代码检查
- name: Lint
continue-on-error: true
run: |
cd desktop
echo "运行 ESLint 检查..."
npm run lint
# TypeScript 类型检查
- name: Type Check
run: |
cd desktop
echo "运行 TypeScript 类型检查..."
npm run type-check || echo "⚠️ type-check 脚本未配置,跳过"
continue-on-error: true
# 构建检查
- name: Build
run: |
cd desktop
echo "验证构建..."
npm run build
# ========================================
# Job 3: 烟雾测试(可选)
# ========================================
smoke-test:
name: Smoke Test
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [backend-check, frontend-check]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
# 启动后端并验证健康检查
- name: Start backend and health check
run: |
cd backend
# 复制配置文件(如果需要)
if [ -f ".env.example" ]; then
cp .env.example .env
fi
# 启动后端(后台运行)
echo "启动后端服务..."
go run cmd/server/main.go &
SERVER_PID=$!
# 等待后端启动(最多30秒)
echo "等待后端启动..."
MAX_WAIT=30
for i in $(seq 1 $MAX_WAIT); do
# 检查进程是否存活
if ! kill -0 $SERVER_PID 2>/dev/null; then
echo "❌ 后端进程意外退出"
exit 1
fi
# 检查健康检查接口(假设有 /health 或 /api/health)
if curl -sf http://localhost:8080/health > /dev/null 2>&1 || \
curl -sf http://localhost:8080/api/health > /dev/null 2>&1; then
echo "✅ 后端启动成功(${i}秒)"
# 测试其他关键接口(可选)
# curl -sf http://localhost:8080/api/status
# 停止后端
kill $SERVER_PID
exit 0
fi
sleep 1
done
# 超时
echo "❌ 后端启动超时(${MAX_WAIT}秒)"
kill $SERVER_PID 2>/dev/null || true
exit 1
continue-on-error: true
# ========================================
# Job 4: PR 总结(可选)
# ========================================
pr-summary:
name: PR Summary
runs-on: ubuntu-latest
needs: [backend-check, frontend-check]
if: always()
steps:
- name: Create PR summary
uses: actions/github-script@v7
with:
script: |
const backend = '${{ needs.backend-check.result }}';
const frontend = '${{ needs.frontend-check.result }}';
const smoke = '${{ needs.smoke-test.result }}';
const statusEmoji = {
'success': '✅',
'failure': '❌',
'cancelled': '⚠️',
'skipped': '⏭️'
};
const summary = `## 🔍 PR 检查结果
| 检查项 | 状态 |
|--------|------|
| **后端检查** (Go) | ${statusEmoji[backend] || '❓'} ${backend} |
| **前端检查** (React) | ${statusEmoji[frontend] || '❓'} ${frontend} |
| **烟雾测试** | ${statusEmoji[smoke] || '❓'} ${smoke} |
${backend === 'success' && frontend === 'success' ? '### ✅ 所有检查通过,可以合并!' : '### ⚠️ 请修复上述问题后再合并'}
---
*由 GitHub Actions 自动生成*
`;
// 如果 PR 有更新,创建或更新评论
if (context.issue.number) {
try {
// 查找现有的总结评论
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('🔍 PR 检查结果')
);
if (botComment) {
// 更新现有评论
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: summary
});
} else {
// 创建新评论
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: summary
});
}
} catch (error) {
console.log('无法创建 PR 评论:', error);
}
}
core.summary.addRaw(summary).write();