feat(workflows): [无需更新] GitHub 添加自动回复和标签功能

This commit is contained in:
zhiyu1998 2025-08-04 13:36:53 +08:00
parent 40f059bcc9
commit 2ded2f90f9
5 changed files with 616 additions and 0 deletions

159
.github/GITHUB-BOT-SETUP.md vendored Normal file
View File

@ -0,0 +1,159 @@
# GitHub Bot 自动回复设置指南
本项目已集成GitHub Actions驱动的自动回复机器人可以自动处理Issues和Pull Requests。
## 🚀 功能特性
### ✅ 已实现功能
- **Issue自动回复**: 根据标题关键词智能回复
- **PR自动回复**: 欢迎新贡献者并提供审核清单
- **智能标签**: 根据内容自动添加相关标签
- **定期状态更新**: 每周检查并更新长期无响应的issue
- **生成周报**: 统计项目活动数据
### 🤖 自动回复类型
#### Issue回复模板
- 🐛 **Bug报告**: 引导用户提供复现步骤和环境信息
- 🚀 **功能建议**: 说明评估流程和时间安排
- 📖 **文档问题**: 承诺改进文档质量
- 👋 **通用回复**: 感谢反馈并说明处理流程
#### PR回复模板
- 🎉 **欢迎贡献者**: 感谢贡献并说明审核流程
- 📋 **审核清单**: 提醒代码规范、测试、文档等要求
- 📊 **PR统计**: 显示修改文件数和PR类型
- 🏷️ **自动标签**: 根据内容和规模自动分类
## 📋 设置步骤
### 1. 创建所需标签
在仓库的 **Issues****Labels** 页面创建以下标签:
#### 基础标签
```
bug - 🐛 - #d73a49 - Bug报告
enhancement - ✨ - #a2eeef - 功能增强
documentation - 📖 - #0075ca - 文档相关
question - ❓ - #d876e3 - 问题咨询
performance - ⚡ - #fbca04 - 性能优化
security - 🔒 - #b60205 - 安全相关
```
#### 优先级标签
```
priority/high - 🔴 - #b60205 - 高优先级
priority/medium - 🟡 - #fbca04 - 中优先级
priority/low - 🟢 - #0e8a16 - 低优先级
```
#### PR大小标签
```
size/small - S - #28a745 - 小型PR (≤3文件)
size/medium - M - #ffc107 - 中型PR (4-10文件)
size/large - L - #dc3545 - 大型PR (>10文件)
```
#### 平台标签
```
platform/windows - 🪟 - #0078d4 - Windows平台
platform/linux - 🐧 - #f89820 - Linux平台
platform/mac - 🍎 - #999999 - macOS平台
```
#### 组件标签
```
component/bilibili - 📺 - #00a1d6 - B站相关
component/tiktok - 🎵 - #ff0050 - 抖音相关
component/youtube - ▶️ - #ff0000 - YouTube相关
component/music - 🎵 - #1db954 - 音乐功能
```
#### 状态标签
```
stale - ⏰ - #795548 - 长期无响应
needs-response - 💬 - #8e44ad - 需要回复
refactor - ♻️ - #00d4aa - 重构相关
test - 🧪 - #17becf - 测试相关
```
### 2. 启用GitHub Actions
1. 进入仓库 **Settings****Actions** → **General**
2. 选择 **Allow all actions and reusable workflows**
3. 在 **Workflow permissions** 部分选择 **Read and write permissions**
4. 勾选 **Allow GitHub Actions to create and approve pull requests**
### 3. 创建里程碑(可选)
为bug自动分配功能创建里程碑
1. 进入 **Issues** → **Milestones**
2. 创建如 `v1.1.0``v1.2.0` 等版本里程碑
3. bot会自动将bug分配到最近的开放里程碑
### 4. 测试设置
创建一个测试issue验证
1. 标题包含 "bug" 或 "功能" 关键词
2. 查看是否收到自动回复
3. 检查是否自动添加了相关标签
## 🔧 自定义配置
### 修改回复模板
编辑 `.github/workflows/` 目录下的workflow文件
- `auto-reply-issues.yml` - Issue回复模板
- `auto-reply-prs.yml` - PR回复模板
- `auto-label.yml` - 标签规则
- `status-update.yml` - 定期更新规则
### 调整触发条件
修改workflow文件中的 `on` 部分:
```yaml
on:
issues:
types: [opened, labeled] # 添加labeled触发
pull_request:
types: [opened, edited] # 添加edited触发
```
### 修改定时任务
`status-update.yml` 中调整cron表达式
```yaml
on:
schedule:
- cron: '0 2 * * *' # 每天凌晨2点运行
```
## 📈 监控和维护
### 查看运行日志
1. 进入 **Actions** 页面
2. 点击具体的workflow运行记录
3. 查看详细日志和错误信息
### 常见问题排查
- **权限错误**: 检查Actions权限设置
- **标签不存在**: 确保创建了所有必需的标签
- **API限制**: GitHub API有频率限制大量操作时可能触发
### 性能优化建议
- 限制单次处理的issue数量当前设置为50
- 合理设置触发条件避免重复运行
- 定期清理过时的workflow运行记录
## 🎯 最佳实践
1. **渐进式部署**: 先在测试仓库验证功能
2. **定期审查**: 每月检查自动回复效果和用户反馈
3. **模板优化**: 根据项目特点调整回复内容
4. **标签管理**: 保持标签体系简洁清晰
5. **用户反馈**: 收集用户对自动回复的意见
---
📝 **注意**: 此bot完全基于GitHub Actions无需外部服务器维护成本极低。所有配置都通过workflow文件管理便于版本控制和团队协作。

132
.github/workflows/auto-label.yml vendored Normal file
View File

@ -0,0 +1,132 @@
name: Auto Label Issues
on:
issues:
types: [opened]
jobs:
auto-label:
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
steps:
- name: Add Labels Based on Content
uses: actions/github-script@v7
with:
script: |
const title = context.payload.issue.title.toLowerCase();
const body = context.payload.issue.body?.toLowerCase() || '';
const labels = [];
// 根据关键词自动添加标签
if (title.includes('bug') || title.includes('错误') || title.includes('问题') ||
body.includes('bug') || body.includes('错误') || body.includes('异常')) {
labels.push('bug');
}
if (title.includes('feature') || title.includes('功能') || title.includes('建议') ||
title.includes('enhancement') || body.includes('功能') || body.includes('建议')) {
labels.push('enhancement');
}
if (title.includes('doc') || title.includes('文档') || title.includes('说明') ||
body.includes('文档') || body.includes('说明') || body.includes('document')) {
labels.push('documentation');
}
if (title.includes('help') || title.includes('求助') || title.includes('question') ||
title.includes('如何') || title.includes('怎么') || body.includes('求助')) {
labels.push('question');
}
if (title.includes('性能') || title.includes('performance') || title.includes('优化') ||
body.includes('性能') || body.includes('慢') || body.includes('优化')) {
labels.push('performance');
}
if (title.includes('安全') || title.includes('security') ||
body.includes('安全') || body.includes('漏洞')) {
labels.push('security');
}
// 根据关键词添加优先级标签
if (title.includes('紧急') || title.includes('urgent') || title.includes('critical') ||
body.includes('紧急') || body.includes('严重')) {
labels.push('priority/high');
} else if (title.includes('minor') || title.includes('小') || body.includes('小问题')) {
labels.push('priority/low');
} else {
labels.push('priority/medium');
}
// 根据平台关键词添加标签
if (title.includes('windows') || body.includes('windows')) {
labels.push('platform/windows');
}
if (title.includes('linux') || body.includes('linux')) {
labels.push('platform/linux');
}
if (title.includes('mac') || title.includes('darwin') || body.includes('mac')) {
labels.push('platform/mac');
}
// 根据组件关键词添加标签
if (title.includes('bilibili') || title.includes('bili') || body.includes('bilibili')) {
labels.push('component/bilibili');
}
if (title.includes('tiktok') || title.includes('抖音') || body.includes('tiktok')) {
labels.push('component/tiktok');
}
if (title.includes('youtube') || body.includes('youtube')) {
labels.push('component/youtube');
}
if (title.includes('music') || title.includes('音乐') || body.includes('音乐')) {
labels.push('component/music');
}
if (labels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labels
});
}
console.log(`Added labels: ${labels.join(', ')}`);
- name: Add Milestone for Bugs
uses: actions/github-script@v7
with:
script: |
const labels = context.payload.issue.labels.map(label => label.name);
const title = context.payload.issue.title.toLowerCase();
// 为bug类issue自动分配到下个版本里程碑
if (labels.includes('bug') || title.includes('bug') || title.includes('错误')) {
try {
// 获取所有开放的里程碑
const { data: milestones } = await github.rest.issues.listMilestones({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
sort: 'due_on',
direction: 'asc'
});
if (milestones.length > 0) {
// 分配到最近的里程碑
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
milestone: milestones[0].number
});
console.log(`Assigned to milestone: ${milestones[0].title}`);
}
} catch (error) {
console.log('No milestones found or error assigning milestone');
}
}

81
.github/workflows/auto-reply-issues.yml vendored Normal file
View File

@ -0,0 +1,81 @@
name: Auto Reply to Issues
on:
issues:
types: [opened]
jobs:
auto-reply:
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
steps:
- name: Reply to Issue
uses: actions/github-script@v7
with:
script: |
const issueNumber = context.issue.number;
const issueTitle = context.payload.issue.title;
const issueAuthor = context.payload.issue.user.login;
// 根据标题关键词判断类型
let replyMessage = '';
let emoji = '👋';
if (issueTitle.toLowerCase().includes('bug') || issueTitle.toLowerCase().includes('错误') || issueTitle.toLowerCase().includes('问题')) {
emoji = '🐛';
replyMessage = `${emoji} Hi @${issueAuthor}!
感谢您报告这个bug我们已经收到您的反馈会尽快调查并修复。
为了更好地帮助您解决问题,请确保提供:
- [ ] 详细的问题描述
- [ ] 复现步骤
- [ ] 运行环境信息
- [ ] 相关的错误日志
我们会尽快回复您!`;
} else if (issueTitle.toLowerCase().includes('feature') || issueTitle.toLowerCase().includes('功能') || issueTitle.toLowerCase().includes('建议')) {
emoji = '🚀';
replyMessage = `${emoji} Hi @${issueAuthor}!
感谢您的功能建议!我们很高兴收到新的想法和建议。
我们会仔细评估您的建议:
- [ ] 评估技术可行性
- [ ] 分析对现有功能的影响
- [ ] 确定开发优先级
如果您有更多细节或使用场景,欢迎补充!`;
} else if (issueTitle.toLowerCase().includes('doc') || issueTitle.toLowerCase().includes('文档') || issueTitle.toLowerCase().includes('说明')) {
emoji = '📖';
replyMessage = `${emoji} Hi @${issueAuthor}!
感谢您关注文档改进!清晰的文档对项目非常重要。
我们会:
- [ ] 审查当前文档内容
- [ ] 补充缺失的说明
- [ ] 优化文档结构
您的反馈很有价值!`;
} else {
replyMessage = `${emoji} Hi @${issueAuthor}!
感谢您提交issue我们已经收到您的反馈。
我们会尽快处理您的请求:
- [ ] 分析问题内容
- [ ] 确定处理方案
- [ ] 及时反馈进展
如有任何疑问,随时与我们联系!`;
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: replyMessage
});

94
.github/workflows/auto-reply-prs.yml vendored Normal file
View File

@ -0,0 +1,94 @@
name: Auto Reply to Pull Requests
on:
pull_request:
types: [opened]
jobs:
auto-reply:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- name: Reply to PR
uses: actions/github-script@v7
with:
script: |
const prNumber = context.issue.number;
const prTitle = context.payload.pull_request.title;
const prAuthor = context.payload.pull_request.user.login;
const prFiles = context.payload.pull_request.changed_files;
let replyMessage = `🎉 Hi @${prAuthor}!
感谢您的贡献您的Pull Request已经提交我们会尽快进行代码审核。
## 📋 审核清单
期间请确保以下项目已完成:
- [ ] 代码符合项目规范和风格
- [ ] 已测试新功能或修复
- [ ] 更新了相关文档(如有需要)
- [ ] 提交信息清晰明确
## 📊 PR 统计
- 📁 修改文件数:${prFiles}
- 🏷️ PR类型${prTitle.toLowerCase().includes('fix') ? '🐛 Bug修复' :
prTitle.toLowerCase().includes('feat') ? '✨ 新功能' :
prTitle.toLowerCase().includes('doc') ? '📖 文档更新' :
prTitle.toLowerCase().includes('refactor') ? '♻️ 重构' : '🔧 其他改进'}
## 🔄 下一步
我们会在1-3个工作日内完成初步审核。如有问题会及时与您沟通。
再次感谢您对项目的贡献! 🙏`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: replyMessage
});
- name: Add PR Labels
uses: actions/github-script@v7
with:
script: |
const prTitle = context.payload.pull_request.title.toLowerCase();
const labels = [];
// 根据PR标题自动添加标签
if (prTitle.includes('fix') || prTitle.includes('修复')) {
labels.push('bug');
}
if (prTitle.includes('feat') || prTitle.includes('功能') || prTitle.includes('add')) {
labels.push('enhancement');
}
if (prTitle.includes('doc') || prTitle.includes('文档')) {
labels.push('documentation');
}
if (prTitle.includes('refactor') || prTitle.includes('重构')) {
labels.push('refactor');
}
if (prTitle.includes('test') || prTitle.includes('测试')) {
labels.push('test');
}
// 根据文件数量添加大小标签
const fileCount = context.payload.pull_request.changed_files;
if (fileCount <= 3) {
labels.push('size/small');
} else if (fileCount <= 10) {
labels.push('size/medium');
} else {
labels.push('size/large');
}
if (labels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labels
});
}

150
.github/workflows/status-update.yml vendored Normal file
View File

@ -0,0 +1,150 @@
name: Weekly Status Update
on:
schedule:
- cron: '0 10 * * 1' # 每周一上午10点UTC时间
workflow_dispatch: # 允许手动触发
jobs:
status-update:
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
steps:
- name: Update Stale Issues
uses: actions/github-script@v7
with:
script: |
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
sort: 'updated',
direction: 'asc',
per_page: 50
});
const now = new Date();
let updatedCount = 0;
for (const issue of issues) {
// 跳过PR
if (issue.pull_request) continue;
const lastUpdated = new Date(issue.updated_at);
const daysSinceUpdate = Math.floor((now - lastUpdated) / (1000 * 60 * 60 * 24));
const daysSinceCreated = Math.floor((now - new Date(issue.created_at)) / (1000 * 60 * 60 * 24));
const hasStaleLabel = issue.labels.some(label => label.name === 'stale');
const hasNeedsResponseLabel = issue.labels.some(label => label.name === 'needs-response');
const isPriorityHigh = issue.labels.some(label => label.name === 'priority/high');
// 7天无更新且不是高优先级的issue
if (daysSinceUpdate >= 7 && !hasStaleLabel && !isPriorityHigh) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `👋 这个issue已经一周没有更新了。
如果问题仍然存在,请提供更多信息:
- 是否还能复现?
- 有没有新的错误信息?
- 是否尝试了其他解决方案?
如果问题已解决欢迎关闭此issue。如果30天内没有响应此issue将被自动关闭。`
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['stale']
});
updatedCount++;
}
// 30天无更新的stale issue自动关闭
else if (daysSinceUpdate >= 30 && hasStaleLabel) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `🤖 此issue因长期无响应被自动关闭。
如果问题仍然存在请创建新的issue并提供详细信息。感谢您的理解`
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
state_reason: 'not_planned'
});
updatedCount++;
}
// 需要回复的issue提醒
else if (daysSinceUpdate >= 3 && hasNeedsResponseLabel) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `⏰ 提醒此issue等待回复已超过3天。
我们会尽快处理,感谢您的耐心等待!`
});
updatedCount++;
}
}
console.log(`Updated ${updatedCount} issues`);
- name: Generate Weekly Report
uses: actions/github-script@v7
with:
script: |
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
// 获取本周的issues
const { data: newIssues } = await github.rest.search.issuesAndPullRequests({
q: `repo:${context.repo.owner}/${context.repo.repo} is:issue created:>=${oneWeekAgo.toISOString().split('T')[0]}`,
sort: 'created',
order: 'desc'
});
// 获取本周的PRs
const { data: newPRs } = await github.rest.search.issuesAndPullRequests({
q: `repo:${context.repo.owner}/${context.repo.repo} is:pr created:>=${oneWeekAgo.toISOString().split('T')[0]}`,
sort: 'created',
order: 'desc'
});
// 获取本周关闭的issues
const { data: closedIssues } = await github.rest.search.issuesAndPullRequests({
q: `repo:${context.repo.owner}/${context.repo.repo} is:issue closed:>=${oneWeekAgo.toISOString().split('T')[0]}`,
sort: 'updated',
order: 'desc'
});
const report = `📊 **本周活动报告** (${oneWeekAgo.toISOString().split('T')[0]} ~ ${new Date().toISOString().split('T')[0]})
## 📈 统计数据
- 🎯 新增 Issues: ${newIssues.total_count}
- 🔀 新增 PRs: ${newPRs.total_count}
- ✅ 关闭 Issues: ${closedIssues.total_count}
## 🏷️ Issue 分类
${newIssues.items.length > 0 ? newIssues.items.slice(0, 5).map(issue =>
`- [${issue.title}](${issue.html_url}) - ${issue.labels.map(l => l.name).join(', ') || '未分类'}`
).join('\n') : '本周暂无新issue'}
感谢所有贡献者的参与! 🙏`;
console.log(report);