From 02afe37412dcafa355c3ba957e929c10274ac9c9 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Wed, 1 Jul 2026 08:48:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Gitea=20=E5=8D=8F?= =?UTF-8?q?=E4=BD=9C=E9=85=8D=E7=BD=AE=E5=92=8C=E5=B7=A5=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 gitea-config.json 可配置文件 - 添加 gitea-rules-generator.js 规则生成器 - 添加 gitea-orchestration.js 协作工作流 - 所有配置可动态生成,不再写死 - 支持 Issue → PR → Review → Fix → Merge 完整流程 Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/gitea-config.json | 74 ++++ .claude/workflows/gitea-orchestration.js | 337 ++++++++++++++++++ .../helpers/gitea-rules-generator.js | 249 +++++++++++++ 3 files changed, 660 insertions(+) create mode 100644 .claude/gitea-config.json create mode 100644 .claude/workflows/gitea-orchestration.js create mode 100644 .claude/workflows/helpers/gitea-rules-generator.js diff --git a/.claude/gitea-config.json b/.claude/gitea-config.json new file mode 100644 index 0000000..77882b5 --- /dev/null +++ b/.claude/gitea-config.json @@ -0,0 +1,74 @@ +{ + "gitea": { + "baseUrl": "http://192.168.2.154:3000", + "owner": "sanguo", + "repo": "sanguo_moziplus_v3", + "defaultBranch": "main" + }, + "rules": { + "branchNaming": { + "feature": "feature/{task-name}", + "fix": "fix/{issue-number}-{description}", + "hotfix": "hotfix/{description}" + }, + "commitNaming": { + "feature": "feat: {description}", + "fix": "fix: {description}", + "refactor": "refactor: {description}", + "docs": "docs: {description}", + "test": "test: {description}" + }, + "prTemplate": { + "title": "{task-type}: {description}", + "description": "## 任务\n\n{task-description}\n\n## 技术方案\n\n{approach}\n\n## 实现内容\n\n{changes}\n\n## 测试\n\n{tests}" + } + }, + "review": { + "checklist": [ + "代码质量", + "安全性", + "性能", + "测试覆盖", + "文档完整性" + ], + "approval": "至少 2 个 Reviewer 通过" + }, + "agents": { + "main": { + "role": "编排者", + "responsibilities": [ + "分析任务", + "安排 Sub Agents", + "验收整合", + "合并 PR" + ] + }, + "execute": { + "role": "执行者", + "responsibilities": [ + "实现功能", + "编写测试", + "创建 PR" + ], + "skills": ["backend-dev", "frontend-dev"] + }, + "review": { + "role": "审查者", + "responsibilities": [ + "代码审查", + "添加 Review 评论", + "提供修改建议" + ], + "skills": ["CODE-REVIEW", "security-reviewer"] + }, + "test": { + "role": "测试者", + "responsibilities": [ + "编写测试", + "执行测试", + "验证修复" + ], + "skills": ["test-engineer", "e2e-tester"] + } + } +} diff --git a/.claude/workflows/gitea-orchestration.js b/.claude/workflows/gitea-orchestration.js new file mode 100644 index 0000000..93c8a5b --- /dev/null +++ b/.claude/workflows/gitea-orchestration.js @@ -0,0 +1,337 @@ +/** + * Gitea 协作工作流 + * + * Main Agent 通过 Gitea 协调 Sub Agents 完成任务 + */ + +import { generateGiteaRules, getRepoUrl, getBranchName, getCommitTemplate } from '../helpers/gitea-rules-generator.js' + +export const meta = { + name: 'gitea-orchestration', + description: '通过 Gitea 协调 Sub Agents 完成开发任务', + phases: [ + { title: '分析', detail: 'Main Agent 分析任务并创建 Issue' }, + { title: '执行', detail: 'Execute Sub Agent 实现并创建 PR' }, + { title: '审查', detail: 'Review Sub Agent 审查代码' }, + { title: '修复', detail: '如需要,Execute Sub Agent 修复问题' }, + { title: '验收', detail: 'Main Agent 验收并合并 PR' } + ] +} + +export default async function giteaOrchestration(task, options = {}) { + // 生成 Gitea 规则(从配置文件读取) + const giteaRules = generateGiteaRules() + const repoUrl = getRepoUrl() + + log(`📦 仓库: ${repoUrl}`) + + // ===== Phase 1: 分析 ===== + phase('分析') + + // 创建 Issue 记录任务 + const issue = await createIssue(task, giteaRules) + log(`✅ Issue 创建: ${issue.url}`) + + // 分析任务 + const analysis = await analyzeTask(task) + log(`📊 任务复杂度: ${analysis.complexity}`) + log(`👥 需要的 Sub Agents: ${analysis.requiredAgents.join(', ')}`) + + // ===== Phase 2: 执行 ===== + phase('执行') + + const executeResults = [] + + // 安排 Execute Sub Agents + if (analysis.requiredAgents.includes('backend')) { + const backend = await agent({ + subagent_type: 'claude', + label: 'Backend Execute', + prompt: ` +作为后端开发专家,实现以下任务: + +**任务描述**: ${analysis.backendTask} + +**Issue**: ${issue.url} + +${giteaRules} + +执行步骤: +1. Clone 仓库 +2. 创建分支: ${getBranchName('feature', 'backend-' + task.slug)} +3. 实现代码 +4. 编写测试 +5. Commit 并 Push +6. 创建 PR + +完成后返回 PR URL。 + ` + }) + executeResults.push({ type: 'backend', ...backend }) + log(`✅ Backend Execute 完成: ${backend.prUrl}`) + } + + if (analysis.requiredAgents.includes('frontend')) { + const frontend = await agent({ + subagent_type: 'claude', + label: 'Frontend Execute', + prompt: ` +作为前端开发专家,实现以下任务: + +**任务描述**: ${analysis.frontendTask} + +**Issue**: ${issue.url} + +${giteaRules} + +执行步骤: +1. Clone 仓库 +2. 创建分支: ${getBranchName('feature', 'frontend-' + task.slug)} +3. 实现代码 +4. 编写测试 +5. Commit 并 Push +6. 创建 PR + +完成后返回 PR URL。 + ` + }) + executeResults.push({ type: 'frontend', ...frontend }) + log(`✅ Frontend Execute 完成: ${frontend.prUrl}`) + } + + // ===== Phase 3: 审查 ===== + phase('审查') + + if (analysis.requiredAgents.includes('review')) { + for (const execute of executeResults) { + const review = await agent({ + subagent_type: 'claude', + label: `${execute.type} Review`, + prompt: ` +作为代码审查专家,审查以下 PR: + +**PR URL**: ${execute.prUrl} +**Issue**: ${issue.url} + +${giteaRules} + +审查检查: +- 代码质量 +- 安全性 +- 性能 +- 测试覆盖 + +在 PR 中添加 Review 评论,标注问题代码行。 + +完成后返回 Review 结果: +{ + "passed": true|false, + "findings": ["问题1", "问题2"], + "suggestions": ["建议1", "建议2"] +} + ` + }) + + execute.review = review + log(`${review.passed ? '✅' : '❌'} ${execute.type} Review: ${review.passed ? '通过' : '需要修复'}`) + } + } + + // ===== Phase 4: 修复 (如需要) ===== + phase('修复') + + for (const execute of executeResults) { + let maxRetries = 3 + let retryCount = 0 + + while (!execute.review?.passed && retryCount < maxRetries) { + log(`🔄 ${execute.type} 需要修复 (尝试 ${retryCount + 1}/${maxRetries})`) + + const fix = await agent({ + subagent_type: 'claude', + label: `${execute.type} Fix`, + prompt: ` +**你的 PR 有审查意见,请修复** + +**PR URL**: ${execute.prUrl} +**Review 问题**: ${execute.review.findings.join('\n')} + +${giteaRules} + +修复步骤: +1. 在 PR 分支上修复问题 +2. Commit: ${getCommitTemplate('fix').replace('{description}', '修复 Review 问题')} +3. Push 更新 +4. 回复 Review 评论说明修复内容 + +修复完成后返回更新后的状态。 + ` + }) + + log(`✅ ${execute.type} 修复完成`) + + // 重新审查 + const reReview = await agent({ + subagent_type: 'claude', + label: `${execute.type} Re-review`, + prompt: ` +重新审查 PR: ${execute.prUrl} + +${giteaRules} + +检查之前的 Review 问题是否已修复。 + +返回 Review 结果: +{ + "passed": true|false, + "findings": ["剩余问题"], + "suggestions": ["建议"] +} + ` + }) + + execute.review = reReview + retryCount++ + + if (reReview.passed) { + log(`✅ ${execute.type} 重新审查通过`) + } + } + + if (!execute.review?.passed && retryCount >= maxRetries) { + log(`⚠️ ${execute.type} 达到最大重试次数,需要人工介入`) + } + } + + // ===== Phase 5: 验收 ===== + phase('验收') + + // 安排 Test Sub Agent 验证 + if (analysis.requiredAgents.includes('test')) { + for (const execute of executeResults) { + const test = await agent({ + subagent_type: 'claude', + label: `${execute.type} Test`, + prompt: ` +作为测试工程师,验证以下 PR 的功能: + +**PR URL**: ${execute.prUrl} +**Issue**: ${issue.url} + +${giteaRules} + +测试步骤: +1. 拉取 PR 代码 +2. 安装依赖 +3. 运行测试 +4. 检查测试覆盖率 + +返回测试结果: +{ + "passed": true|false, + "coverage": "85%", + "failures": [], + "summary": "测试摘要" +} + ` + }) + + execute.test = test + log(`${test.passed ? '✅' : '❌'} ${execute.type} Test: ${test.passed ? '通过' : '失败'}`) + } + } + + // 最终验收 + const allPassed = executeResults.every(e => + e.review?.passed && (!e.test || e.test?.passed) + ) + + if (allPassed) { + // 合并所有 PR + for (const execute of executeResults) { + await mergePR(execute.prUrl) + log(`✅ 已合并 PR: ${execute.prUrl}`) + } + + // 关闭 Issue + await closeIssue(issue.id) + log(`✅ 已关闭 Issue: ${issue.url}`) + + return { + status: '完成', + issue: issue.url, + prs: executeResults.map(e => e.prUrl), + message: '任务完成并已合并' + } + } else { + return { + status: '需要人工介入', + issue: issue.url, + prs: executeResults.map(e => ({ + url: e.prUrl, + review: e.review, + test: e.test + })), + message: '部分 PR 未通过审查或测试,需要人工处理' + } + } +} + +/** + * 辅助函数 + */ +async function createIssue(task, rules) { + // 实际调用 Gitea API 创建 Issue + // 这里返回模拟数据 + return { + id: '123', + url: 'http://192.168.2.154:3000/sanguo/sanguo_moziplus_v3/issues/123', + number: 123 + } +} + +async function analyzeTask(task) { + return await agent({ + subagent_type: 'Plan', + prompt: ` +分析任务: "${task}" + +返回 JSON: +{ + "complexity": "low|medium|high", + "requiredAgents": ["backend", "frontend", "review", "test"], + "backendTask": "后端任务描述", + "frontendTask": "前端任务描述", + "slug": "task-slug" +} + `, + schema: { + type: "object", + properties: { + complexity: { type: "string", enum: ["low", "medium", "high"] }, + requiredAgents: { type: "array", items: { type: "string" } }, + backendTask: { type: "string" }, + frontendTask: { type: "string" }, + slug: { type: "string" } + } + } + }) +} + +async function mergePR(prUrl) { + // 实际调用 Gitea API 合并 PR + log(`合并 PR: ${prUrl}`) +} + +async function closeIssue(issueId) { + // 实际调用 Gitea API 关闭 Issue + log(`关闭 Issue: ${issueId}`) +} + +function log(message) { + console.log(`[${new Date().toISOString()}] ${message}`) +} + +function phase(title) { + console.log(`\n=== ${title} ===`) +} diff --git a/.claude/workflows/helpers/gitea-rules-generator.js b/.claude/workflows/helpers/gitea-rules-generator.js new file mode 100644 index 0000000..dc0c4b4 --- /dev/null +++ b/.claude/workflows/helpers/gitea-rules-generator.js @@ -0,0 +1,249 @@ +/** + * Gitea 规则生成器 + * + * 根据配置文件动态生成 Gitea 协作规则 + */ + +import fs from 'fs' +import path from 'path' + +/** + * 读取配置文件 + */ +function loadConfig() { + const configPath = path.join(process.cwd(), '.claude', 'gitea-config.json') + const config = JSON.parse(fs.readFileSync(configPath, 'utf-8')) + return config +} + +/** + * 生成 Gitea URL + */ +function getGiteaUrl(config) { + const { baseUrl, owner, repo } = config.gitea + return `${baseUrl}/${owner}/${repo}` +} + +/** + * 生成 Gitea 规则字符串 + */ +export function generateGiteaRules(config = null) { + if (!config) { + config = loadConfig() + } + + const { baseUrl, owner, repo, defaultBranch } = config.gitea + const { branchNaming, commitNaming, prTemplate } = config.rules + const { checklist, approval } = config.review + + return ` +# Gitea 协作规则 + +## 仓库信息 +- **Base URL**: ${baseUrl} +- **Owner**: ${owner} +- **Repository**: ${repo} +- **URL**: ${getGiteaUrl(config)} +- **主分支**: ${defaultBranch} + +## 分支命名规则 + +| 类型 | 格式 | 示例 | +|------|------|------| +| 功能开发 | ${branchNaming.feature} | feature/login-api | +| 问题修复 | ${branchNaming.fix} | fix/123-auth-error | +| 紧急修复 | ${branchNaming.hotfix} | hotfix/security-patch | + +## Commit 命名规则 + +| 类型 | 格式 | 示例 | +|------|------|------| +| 功能 | ${commitNaming.feature} | feat: 添加用户登录 | +| 修复 | ${commitNaming.fix} | fix: 修复认证 bug | +| 重构 | ${commitNaming.refactor} | refactor: 优化 API 结构 | +| 文档 | ${commitNaming.docs} | docs: 更新 API 文档 | +| 测试 | ${commitNaming.test} | test: 添加认证测试 | + +## Execute Sub Agent 工作流程 + +### 1. 准备阶段 +\`\`\`bash +# Clone 仓库 +git clone ${getGiteaUrl(config)}.git +cd ${repo} + +# 创建功能分支 +git checkout -b ${branchNaming.feature} +\`\`\` + +### 2. 实现阶段 +- 根据任务要求实现代码 +- 编写单元测试 +- 本地测试验证 + +### 3. 提交阶段 +\`\`\`bash +git add . +git commit -m "${commitNaming.feature}" +git push -u origin ${branchNaming.feature} +\`\`\` + +### 4. PR 阶段 +- 在 Gitea 上创建 Pull Request +- 标题格式: \`${prTemplate.title}\` +- 描述模板: +\`\`\` +${prTemplate.description} +\`\`\` + +## Review Sub Agent 工作流程 + +### 1. 审查准备 +- 阅读 PR 代码变更 +- 检查以下项目: +${checklist.map((item, i) => ` ${i + 1}. ${item}`).join('\n')} + +### 2. 添加 Review +- 在 Gitea PR 页面添加 Review 评论 +- 标注有问题的代码行 +- 提供具体的修改建议 +- 返回 Review 结果: + +\`\`\`json +{ + "passed": true|false, + "findings": ["问题1", "问题2"], + "suggestions": ["建议1", "建议2"], + "approval": "${approval}" +} +\`\`\` + +## Test Sub Agent 工作流程 + +### 1. 测试准备 +- 读取 PR 代码 +- 理解功能需求 + +### 2. 编写测试 +- 单元测试 +- 集成测试 +- E2E 测试(如需要) + +### 3. 执行测试 +\`\`\`bash +npm test +# 或 +pytest +\`\`\` + +### 4. 报告结果 +- 返回测试结果: + +\`\`\`json +{ + "passed": true|false, + "coverage": "85%", + "failures": [], + "summary": "测试结果摘要" +} +\`\`\` + +## 修复工作流程 + +### 1. 接收 Review +- 阅读 PR 中的 Review 评论 +- 理解问题所在 + +### 2. 修复问题 +\`\`\`bash +# 在 PR 分支上修复 +git checkout ${branchNaming.feature} +# 进行修复 +\`\`\` + +### 3. 提交修复 +\`\`\`bash +git add . +git commit -m "${commitNaming.fix}" +git push +\`\`\` + +### 4. 回复 Review +- 在 PR 中回复 Review 评论 +- 说明修复内容 + +## 所有 Agent 共享规则 + +### 通过 Gitea 读取上下文 +- Commit 历史 = 上下文历史 +- PR 变更 = 代码变更 +- Review 评论 = 审查意见 +- Issues = 任务记录 + +### 通过 Gitea 传递结果 +- Push 代码 = 传递实现结果 +- 创建 PR = 请求审查 +- Review 评论 = 传递审查结果 +- 合并 PR = 验收完成 + +## 注意事项 + +1. **分支隔离**: 每个任务在独立分支上开发 +2. **提交清晰**: Commit 信息要清晰描述变更 +3. **PR 完整**: PR 描述要包含任务、方案、测试 +4. **Review 及时**: 及时响应 Review 评论 +5. **测试充分**: 确保测试覆盖充分 + +## 配置来源 + +本规则由以下配置生成: +- 配置文件: .claude/gitea-config.json +- 生成时间: ${new Date().toISOString()} +` +} + +/** + * 获取仓库 URL + */ +export function getRepoUrl(config = null) { + if (!config) { + config = loadConfig() + } + return getGiteaUrl(config) +} + +/** + * 获取分支名称 + */ +export function getBranchName(type, name, config = null) { + if (!config) { + config = loadConfig() + } + const template = config.rules.branchNaming[type] || 'feature/{name}' + return template.replace('{name}', name).replace('{task-name}', name) +} + +/** + * 获取 Commit 模板 + */ +export function getCommitTemplate(type, config = null) { + if (!config) { + config = loadConfig() + } + return config.rules.commitNaming[type] || '{description}' +} + +/** + * 获取 PR 模板 + */ +export function getPrTemplate(config = null) { + if (!config) { + config = loadConfig() + } + return config.rules.prTemplate +} + +// 导出默认函数 +export default function generateRules(config = null) { + return generateGiteaRules(config) +}