name: github-workflow-automation description: “使用AI辅助自动化GitHub工作流。包括PR代码审查、问题分类、CI/CD集成和Git操作。适用于自动化GitHub工作流、设置PR审查自动化、创建GitHub Actions或问题分类。”
🔧 GitHub工作流自动化
使用AI辅助自动化GitHub工作流的模式,灵感来自Gemini CLI和现代DevOps实践。
何时使用此技能
在以下情况下使用此技能:
- 使用AI自动化PR审查
- 设置问题分类自动化
- 创建GitHub Actions工作流
- 将AI集成到CI/CD管道中
- 自动化Git操作(如变基、挑选提交)
1. 自动化PR审查
1.1 PR审查操作
# .github/workflows/ai-review.yml
name: AI代码审查
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 获取更改的文件
id: changed
run: |
files=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$files" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: 获取差异
id: diff
run: |
diff=$(git diff origin/${{ github.base_ref }}...HEAD)
echo "diff<<EOF" >> $GITHUB_OUTPUT
echo "$diff" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: AI审查
uses: actions/github-script@v7
with:
script: |
const { Anthropic } = require('@anthropic-ai/sdk');
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const response = await client.messages.create({
model: "claude-3-sonnet-20240229",
max_tokens: 4096,
messages: [{
role: "user",
content: `审查此PR差异并提供反馈:
更改的文件: ${{ steps.changed.outputs.files }}
差异:
${{ steps.diff.outputs.diff }}
提供:
1. 更改摘要
2. 潜在问题或错误
3. 改进建议
4. 安全关注点(如有)
格式化为GitHub markdown。`
}]
});
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: response.content[0].text,
event: 'COMMENT'
});
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
1.2 审查评论模式
# AI审查结构
## 📋 摘要
此PR内容的简要描述。
## ✅ 看起来不错的地方
- 结构良好的代码
- 良好的测试覆盖率
- 清晰的命名约定
## ⚠️ 潜在问题
1. **第42行**:可能的空指针异常
```javascript
// 当前
user.profile.name;
// 建议
user?.profile?.name ?? "Unknown";
```
- 第78行:考虑错误处理
// 添加 try-catch 或 .catch()
💡 建议
- 考虑将验证逻辑提取到单独的函数中
- 为公共方法添加JSDoc注释
🔒 安全注意事项
- 未检测到敏感数据暴露
- API密钥处理看起来正确
### 1.3 聚焦审查
```yaml
# 仅审查特定文件类型
- name: 过滤代码文件
run: |
files=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | \
grep -E '\.(ts|tsx|js|jsx|py|go)$' || true)
echo "code_files=$files" >> $GITHUB_OUTPUT
# 带上下文的审查
- name: 带上下文的AI审查
run: |
# 包含相关上下文文件
context=""
for file in ${{ steps.changed.outputs.files }}; do
if [[ -f "$file" ]]; then
context+="=== $file ===
$(cat $file)
"
fi
done
# 发送给AI并附上完整的文件上下文
2. 问题分类自动化
2.1 自动标记问题
# .github/workflows/issue-triage.yml
name: 问题分类
on:
issues:
types: [opened]
jobs:
triage:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: 分析问题
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
// 调用AI进行分析
const analysis = await analyzeIssue(issue.title, issue.body);
// 应用标签
const labels = [];
if (analysis.type === 'bug') {
labels.push('bug');
if (analysis.severity === 'high') labels.push('priority: high');
} else if (analysis.type === 'feature') {
labels.push('enhancement');
} else if (analysis.type === 'question') {
labels.push('question');
}
if (analysis.area) {
labels.push(`area: ${analysis.area}`);
}
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: labels
});
// 添加初始响应
if (analysis.type === 'bug' && !analysis.hasReproSteps) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `感谢报告此问题!
为了帮助我们调查,请提供:
- 重现问题的步骤
- 预期行为
- 实际行为
- 环境(操作系统、版本等)
这将帮助我们更快地解决您的问题。 🙏`
});
}
2.2 问题分析提示
const TRIAGE_PROMPT = `
分析此GitHub问题并分类:
标题:{title}
正文:{body}
返回JSON:
{
"type": "bug" | "feature" | "question" | "docs" | "other",
"severity": "low" | "medium" | "high" | "critical",
"area": "frontend" | "backend" | "api" | "docs" | "ci" | "other",
"summary": "一行摘要",
"hasReproSteps": boolean,
"isFirstContribution": boolean,
"suggestedLabels": ["label1", "label2"],
"suggestedAssignees": ["username"] // 基于领域专业知识
}
`;
2.3 陈旧问题管理
# .github/workflows/stale.yml
name: 管理陈旧问题
on:
schedule:
- cron: "0 0 * * *" # 每天
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: |
此问题已自动标记为陈旧,因为最近没有活动。如果14天内没有进一步活动,将关闭它。
如果此问题仍然相关:
- 添加带有更新的评论
- 移除 `stale` 标签
感谢您的贡献! 🙏
stale-pr-message: |
此PR已自动标记为陈旧。请更新它,否则将在14天内关闭。
days-before-stale: 60
days-before-close: 14
stale-issue-label: "stale"
stale-pr-label: "stale"
exempt-issue-labels: "pinned,security,in-progress"
exempt-pr-labels: "pinned,security"
3. CI/CD集成
3.1 智能测试选择
# .github/workflows/smart-tests.yml
name: 智能测试选择
on:
pull_request:
jobs:
analyze:
runs-on: ubuntu-latest
outputs:
test_suites: ${{ steps.analyze.outputs.suites }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 分析更改
id: analyze
run: |
# 获取更改的文件
changed=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
# 确定要运行的测试套件
suites="[]"
if echo "$changed" | grep -q "^src/api/"; then
suites=$(echo $suites | jq '. + ["api"]')
fi
if echo "$changed" | grep -q "^src/frontend/"; then
suites=$(echo $suites | jq '. + ["frontend"]')
fi
if echo "$changed" | grep -q "^src/database/"; then
suites=$(echo $suites | jq '. + ["database", "api"]')
fi
# 如果没有特定更改,运行所有测试
if [ "$suites" = "[]" ]; then
suites='["all"]'
fi
echo "suites=$suites" >> $GITHUB_OUTPUT
test:
needs: analyze
runs-on: ubuntu-latest
strategy:
matrix:
suite: ${{ fromJson(needs.analyze.outputs.test_suites) }}
steps:
- uses: actions/checkout@v4
- name: 运行测试
run: |
if [ "${{ matrix.suite }}" = "all" ]; then
npm test
else
npm test -- --suite ${{ matrix.suite }}
fi
3.2 使用AI验证的部署
# .github/workflows/deploy.yml
name: 使用AI验证的部署
on:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 获取部署更改
id: changes
run: |
# 获取自上次部署以来的提交
last_deploy=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$last_deploy" ]; then
changes=$(git log --oneline $last_deploy..HEAD)
else
changes=$(git log --oneline -10)
fi
echo "changes<<EOF" >> $GITHUB_OUTPUT
echo "$changes" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: AI风险评估
id: assess
uses: actions/github-script@v7
with:
script: |
// 分析更改以评估部署风险
const prompt = `
分析这些更改以评估部署风险:
${process.env.CHANGES}
返回JSON:
{
"riskLevel": "low" | "medium" | "high",
"concerns": ["concern1", "concern2"],
"recommendations": ["rec1", "rec2"],
"requiresManualApproval": boolean
}
`;
// 调用AI并解析响应
const analysis = await callAI(prompt);
if (analysis.riskLevel === 'high') {
core.setFailed('检测到高风险部署。需要手动审核。');
}
return analysis;
env:
CHANGES: ${{ steps.changes.outputs.changes }}
deploy:
needs: validate
runs-on: ubuntu-latest
environment: production
steps:
- name: 部署
run: |
echo "正在部署到生产环境..."
# 部署命令放在这里
3.3 回滚自动化
# .github/workflows/rollback.yml
name: 自动回滚
on:
workflow_dispatch:
inputs:
reason:
description: "回滚原因"
required: true
jobs:
rollback:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 查找最后一个稳定版本
id: stable
run: |
# 查找最后一个成功部署
stable=$(git tag -l 'v*' --sort=-version:refname | head -1)
echo "version=$stable" >> $GITHUB_OUTPUT
- name: 回滚
run: |
git checkout ${{ steps.stable.outputs.version }}
# 部署稳定版本
npm run deploy
- name: 通知团队
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "🔄 生产已回滚到 ${{ steps.stable.outputs.version }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*已执行回滚*
• 版本:`${{ steps.stable.outputs.version }}`
• 原因:${{ inputs.reason }}
• 触发者:${{ github.actor }}"
}
}
]
}
4. Git操作
4.1 自动化变基
# .github/workflows/auto-rebase.yml
name: 自动变基
on:
issue_comment:
types: [created]
jobs:
rebase:
if: github.event.issue.pull_request && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: 设置Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: 变基PR
run: |
# 获取PR分支
gh pr checkout ${{ github.event.issue.number }}
# 变基到main分支
git fetch origin main
git rebase origin/main
# 强制推送
git push --force-with-lease
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 评论结果
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: '✅ 成功变基到main!'
})
4.2 智能挑选提交
// 处理冲突的AI辅助挑选提交
async function smartCherryPick(commitHash: string, targetBranch: string) {
// 获取提交信息
const commitInfo = await exec(`git show ${commitHash} --stat`);
// 检查潜在冲突
const targetDiff = await exec(
`git diff ${targetBranch}...HEAD -- ${affectedFiles}`
);
// AI分析
const analysis = await ai.analyze(`
我需要将此次提交挑选到 ${targetBranch}:
${commitInfo}
受影响的文件在 ${targetBranch} 上的当前状态:
${targetDiff}
会有冲突吗?如果有,建议解决策略。
`);
if (analysis.willConflict) {
// 创建用于手动解决冲突的分支
await exec(
`git checkout -b cherry-pick-${commitHash.slice(0, 7)} ${targetBranch}`
);
const result = await exec(`git cherry-pick ${commitHash}`, {
allowFail: true,
});
if (result.failed) {
// AI辅助冲突解决
const conflicts = await getConflicts();
for (const conflict of conflicts) {
const resolution = await ai.resolveConflict(conflict);
await applyResolution(conflict.file, resolution);
}
}
} else {
await exec(`git checkout ${targetBranch}`);
await exec(`git cherry-pick ${commitHash}`);
}
}
4.3 分支清理
# .github/workflows/branch-cleanup.yml
name: 分支清理
on:
schedule:
- cron: '0 0 * * 0' # 每周
workflow_dispatch:
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 查找陈旧分支
id: stale
run: |
# 超过30天未更新的分支
stale=$(git for-each-ref --sort=-committerdate refs/remotes/origin \
--format='%(refname:short) %(committerdate:relative)' | \
grep -E '[3-9][0-9]+ days|[0-9]+ months|[0-9]+ years' | \
grep -v 'origin/main\|origin/develop' | \
cut -d' ' -f1 | sed 's|origin/||')
echo "branches<<EOF" >> $GITHUB_OUTPUT
echo "$stale" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: 创建清理PR
if: steps.stale.outputs.branches != ''
uses: actions/github-script@v7
with:
script: |
const branches = `${{ steps.stale.outputs.branches }}`.split('
').filter(Boolean);
const body = `## 🧹 陈旧分支清理
以下分支超过30天未更新:
${branches.map(b => `- \`${b}\``).join('
')}
### 操作:
- [ ] 审核每个分支
- [ ] 删除不再需要的分支
- 评论 \`/keep branch-name\` 以保留特定分支
`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '陈旧分支清理',
body: body,
labels: ['housekeeping']
});
5. 按需辅助
5.1 @提及机器人
# .github/workflows/mention-bot.yml
name: AI提及机器人
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
respond:
if: contains(github.event.comment.body, '@ai-helper')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 提取问题
id: question
run: |
# 提取@ai-helper后的文本
question=$(echo "${{ github.event.comment.body }}" | sed 's/.*@ai-helper//')
echo "question=$question" >> $GITHUB_OUTPUT
- name: 获取上下文
id: context
run: |
if [ "${{ github.event.issue.pull_request }}" != "" ]; then
# 是PR - 获取差异
gh pr diff ${{ github.event.issue.number }} > context.txt
else
# 是问题 - 获取描述
gh issue view ${{ github.event.issue.number }} --json body -q .body > context.txt
fi
echo "context=$(cat context.txt)" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: AI响应
uses: actions/github-script@v7
with:
script: |
const response = await ai.chat(`
上下文: ${process.env.CONTEXT}
问题: ${process.env.QUESTION}
提供有帮助、具体的回答。如果相关,包括代码示例。
`);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: response
});
env:
CONTEXT: ${{ steps.context.outputs.context }}
QUESTION: ${{ steps.question.outputs.question }}
5.2 命令模式
## 可用命令
| 命令 | 描述 |
| :------------------- | :-------------------------- |
| `@ai-helper explain` | 解释此PR中的代码 |
| `@ai-helper review` | 请求AI代码审查 |
| `@ai-helper fix` | 建议问题的修复方法 |
| `@ai-helper test` | 生成测试用例 |
| `@ai-helper docs` | 生成文档 |
| `/rebase` | 将PR变基到main分支 |
| `/update` | 从main分支更新PR分支 |
| `/approve` | 标记为机器人批准 |
| `/label bug` | 添加'bug'标签 |
| `/assign @user` | 分配给用户 |
6. 仓库配置
6.1 CODEOWNERS
# .github/CODEOWNERS
# 全局所有者
* @org/core-team
# 前端
/src/frontend/ @org/frontend-team
*.tsx @org/frontend-team
*.css @org/frontend-team
# 后端
/src/api/ @org/backend-team
/src/database/ @org/backend-team
# 基础设施
/.github/ @org/devops-team
/terraform/ @org/devops-team
Dockerfile @org/devops-team
# 文档
/docs/ @org/docs-team
*.md @org/docs-team
# 安全敏感
/src/auth/ @org/security-team
/src/crypto/ @org/security-team
6.2 分支保护
# 通过GitHub API设置
- name: 配置分支保护
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.updateBranchProtection({
owner: context.repo.owner,
repo: context.repo.repo,
branch: 'main',
required_status_checks: {
strict: true,
contexts: ['test', 'lint', 'ai-review']
},
enforce_admins: true,
required_pull_request_reviews: {
required_approving_review_count: 1,
require_code_owner_reviews: true,
dismiss_stale_reviews: true
},
restrictions: null,
required_linear_history: true,
allow_force_pushes: false,
allow_deletions: false
});
最佳实践
安全
- [ ] 将API密钥存储在GitHub Secrets中
- [ ] 在工作流中使用最小权限
- [ ] 验证所有输入
- [ ] 不在日志中暴露敏感数据
性能
- [ ] 缓存依赖项
- [ ] 使用矩阵构建进行并行测试
- [ ] 使用路径过滤器跳过不必要的工作
- [ ] 使用自托管运行器处理繁重工作负载
可靠性
- [ ] 为作业添加超时
- [ ] 优雅处理速率限制
- [ ] 实现重试逻辑
- [ ] 有回滚程序