github-workflow-automation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese🔧 GitHub Workflow Automation
🔧 GitHub工作流自动化
Patterns for automating GitHub workflows with AI assistance, inspired by Gemini CLI and modern DevOps practices.
受Gemini CLI和现代DevOps实践启发,借助AI辅助实现GitHub工作流自动化的模式。
When to Use This Skill
何时使用该技能
Use this skill when:
- Automating PR reviews with AI
- Setting up issue triage automation
- Creating GitHub Actions workflows
- Integrating AI into CI/CD pipelines
- Automating Git operations (rebases, cherry-picks)
在以下场景使用此技能:
- 借助AI自动化PR评审
- 搭建问题分类自动化流程
- 创建GitHub Actions工作流
- 将AI集成到CI/CD流水线中
- 自动化Git操作(变基、樱桃拣选)
1. Automated PR Review
1. 自动化PR评审
1.1 PR Review Action
1.1 PR评审Action
yaml
undefinedyaml
undefined.github/workflows/ai-review.yml
.github/workflows/ai-review.yml
name: AI Code Review
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: Get changed files
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: Get diff
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 Review
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: `Review this PR diff and provide feedback:
Changed files: ${{ steps.changed.outputs.files }}
Diff:
${{ steps.diff.outputs.diff }}
Provide:
1. Summary of changes
2. Potential issues or bugs
3. Suggestions for improvement
4. Security concerns if any
Format as 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 }}undefinedname: AI Code Review
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: Get changed files
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: Get diff
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 Review
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: `Review this PR diff and provide feedback:
Changed files: ${{ steps.changed.outputs.files }}
Diff:
${{ steps.diff.outputs.diff }}
Provide:
1. Summary of changes
2. Potential issues or bugs
3. Suggestions for improvement
4. Security concerns if any
Format as 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 }}undefined1.2 Review Comment Patterns
1.2 评审评论模板
markdown
undefinedmarkdown
undefinedAI Review Structure
AI评审结构
📋 Summary
📋 摘要
Brief description of what this PR does.
该PR功能的简要描述。
✅ What looks good
✅ 亮点
- Well-structured code
- Good test coverage
- Clear naming conventions
- 代码结构清晰
- 测试覆盖率充足
- 命名规范明确
⚠️ Potential Issues
⚠️ 潜在问题
- Line 42: Possible null pointer exception
javascript
// Current user.profile.name; // Suggested user?.profile?.name ?? "Unknown";
2. **Line 78**: Consider error handling
```javascript
// Add try-catch or .catch()
```- 第42行:可能存在空指针异常
javascript
// 当前代码 user.profile.name; // 建议修改 user?.profile?.name ?? "Unknown";
2. **第78行**:建议添加错误处理
```javascript
// 添加try-catch或.catch()
```💡 Suggestions
💡 优化建议
- Consider extracting the validation logic into a separate function
- Add JSDoc comments for public methods
- 考虑将验证逻辑提取到独立函数中
- 为公共方法添加JSDoc注释
🔒 Security Notes
🔒 安全说明
- No sensitive data exposure detected
- API key handling looks correct
undefined- 未检测到敏感数据泄露
- API密钥处理方式合规
undefined1.3 Focused Reviews
1.3 聚焦式评审
yaml
undefinedyaml
undefinedReview only specific file types
仅评审特定文件类型
- name: Filter code files
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: Filter code files
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
Review with context
带上下文的评审
-
name: AI Review with context run: |
Include relevant context files
context="" for file in ${{ steps.changed.outputs.files }}; do if [[ -f "$file" ]]; then context+="=== $file ===\n$(cat $file)\n\n" fi doneSend to AI with full file context
----
name: AI Review with context run: |
包含相关上下文文件
context="" for file in ${{ steps.changed.outputs.files }}; do if [[ -f "$file" ]]; then context+="=== $file ===\n$(cat $file)\n\n" fi done携带完整文件上下文发送给AI
---2. Issue Triage Automation
2. 问题分类自动化
2.1 Auto-label Issues
2.1 自动标记问题
yaml
undefinedyaml
undefined.github/workflows/issue-triage.yml
.github/workflows/issue-triage.yml
name: Issue Triage
on:
issues:
types: [opened]
jobs:
triage:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Analyze issue
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
// Call AI to analyze
const analysis = await analyzeIssue(issue.title, issue.body);
// Apply labels
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
});
// Add initial response
if (analysis.type === 'bug' && !analysis.hasReproSteps) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `Thanks for reporting this issue!To help us investigate, could you please provide:
- Steps to reproduce the issue
- Expected behavior
- Actual behavior
- Environment (OS, version, etc.)
This will help us resolve your issue faster. 🙏`
});
}
undefinedname: Issue Triage
on:
issues:
types: [opened]
jobs:
triage:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Analyze issue
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: `感谢反馈该问题!为帮助我们更快排查,请提供以下信息:
- 问题复现步骤
- 预期行为
- 实际行为
- 运行环境(操作系统、版本等)
感谢您的贡献! 🙏`
});
}
undefined2.2 Issue Analysis Prompt
2.2 问题分析提示词
typescript
const TRIAGE_PROMPT = `
Analyze this GitHub issue and classify it:
Title: {title}
Body: {body}
Return JSON with:
{
"type": "bug" | "feature" | "question" | "docs" | "other",
"severity": "low" | "medium" | "high" | "critical",
"area": "frontend" | "backend" | "api" | "docs" | "ci" | "other",
"summary": "one-line summary",
"hasReproSteps": boolean,
"isFirstContribution": boolean,
"suggestedLabels": ["label1", "label2"],
"suggestedAssignees": ["username"] // based on area expertise
}
`;typescript
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 Stale Issue Management
2.3 陈旧问题管理
yaml
undefinedyaml
undefined.github/workflows/stale.yml
.github/workflows/stale.yml
name: Manage Stale Issues
on:
schedule:
- cron: "0 0 * * *" # Daily
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: |
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed in 14 days if no further activity occurs.
If this issue is still relevant:
- Add a comment with an update
- Remove the `stale` label
Thank you for your contributions! 🙏
stale-pr-message: |
This PR has been automatically marked as stale. Please update it or it
will be closed in 14 days.
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"
---name: Manage Stale Issues
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 Integration
3. CI/CD集成
3.1 Smart Test Selection
3.1 智能测试选择
yaml
undefinedyaml
undefined.github/workflows/smart-tests.yml
.github/workflows/smart-tests.yml
name: Smart Test Selection
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: Analyze changes
id: analyze
run: |
# Get changed files
changed=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
# Determine which test suites to run
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 nothing specific, run all
if [ "$suites" = "[]" ]; then
suites='["all"]'
fi
echo "suites=$suites" >> $GITHUB_OUTPUTtest:
needs: analyze
runs-on: ubuntu-latest
strategy:
matrix:
suite: ${{ fromJson(needs.analyze.outputs.test_suites) }}
steps:
- uses: actions/checkout@v4
- name: Run tests
run: |
if [ "${{ matrix.suite }}" = "all" ]; then
npm test
else
npm test -- --suite ${{ matrix.suite }}
fiundefinedname: Smart Test Selection
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: Analyze changes
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_OUTPUTtest:
needs: analyze
runs-on: ubuntu-latest
strategy:
matrix:
suite: ${{ fromJson(needs.analyze.outputs.test_suites) }}
steps:
- uses: actions/checkout@v4
- name: Run tests
run: |
if [ "${{ matrix.suite }}" = "all" ]; then
npm test
else
npm test -- --suite ${{ matrix.suite }}
fiundefined3.2 Deployment with AI Validation
3.2 带AI验证的部署
yaml
undefinedyaml
undefined.github/workflows/deploy.yml
.github/workflows/deploy.yml
name: Deploy with AI Validation
on:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get deployment changes
id: changes
run: |
# Get commits since last deployment
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 Risk Assessment
id: assess
uses: actions/github-script@v7
with:
script: |
// Analyze changes for deployment risk
const prompt = `
Analyze these changes for deployment risk:
${process.env.CHANGES}
Return JSON:
{
"riskLevel": "low" | "medium" | "high",
"concerns": ["concern1", "concern2"],
"recommendations": ["rec1", "rec2"],
"requiresManualApproval": boolean
}
`;
// Call AI and parse response
const analysis = await callAI(prompt);
if (analysis.riskLevel === 'high') {
core.setFailed('High-risk deployment detected. Manual review required.');
}
return analysis;
env:
CHANGES: ${{ steps.changes.outputs.changes }}deploy:
needs: validate
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy
run: |
echo "Deploying to production..."
# Deployment commands here
undefinedname: Deploy with AI Validation
on:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get deployment changes
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: Deploy
run: |
echo "正在部署到生产环境..."
# 部署命令
undefined3.3 Rollback Automation
3.3 回滚自动化
yaml
undefinedyaml
undefined.github/workflows/rollback.yml
.github/workflows/rollback.yml
name: Automated Rollback
on:
workflow_dispatch:
inputs:
reason:
description: "Reason for rollback"
required: true
jobs:
rollback:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Find last stable version
id: stable
run: |
# Find last successful deployment
stable=$(git tag -l 'v*' --sort=-version:refname | head -1)
echo "version=$stable" >> $GITHUB_OUTPUT
- name: Rollback
run: |
git checkout ${{ steps.stable.outputs.version }}
# Deploy stable version
npm run deploy
- name: Notify team
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "🔄 Production rolled back to ${{ steps.stable.outputs.version }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Rollback executed*\n• Version: `${{ steps.stable.outputs.version }}`\n• Reason: ${{ inputs.reason }}\n• Triggered by: ${{ github.actor }}"
}
}
]
}
---name: Automated Rollback
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": "*已执行回滚*\n• 版本: `${{ steps.stable.outputs.version }}`\n• 原因: ${{ inputs.reason }}\n• 触发人: ${{ github.actor }}"
}
}
]
}
---4. Git Operations
4. Git操作自动化
4.1 Automated Rebasing
4.1 自动变基
yaml
undefinedyaml
undefined.github/workflows/auto-rebase.yml
.github/workflows/auto-rebase.yml
name: Auto Rebase
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: Setup Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Rebase PR
run: |
# Fetch PR branch
gh pr checkout ${{ github.event.issue.number }}
# Rebase onto main
git fetch origin main
git rebase origin/main
# Force push
git push --force-with-lease
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Comment result
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: '✅ Successfully rebased onto main!'
})undefinedname: Auto Rebase
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分支完成变基!'
})undefined4.2 Smart Cherry-Pick
4.2 智能樱桃拣选
typescript
// AI-assisted cherry-pick that handles conflicts
async function smartCherryPick(commitHash: string, targetBranch: string) {
// Get commit info
const commitInfo = await exec(`git show ${commitHash} --stat`);
// Check for potential conflicts
const targetDiff = await exec(
`git diff ${targetBranch}...HEAD -- ${affectedFiles}`
);
// AI analysis
const analysis = await ai.analyze(`
I need to cherry-pick this commit to ${targetBranch}:
${commitInfo}
Current state of affected files on ${targetBranch}:
${targetDiff}
Will there be conflicts? If so, suggest resolution strategy.
`);
if (analysis.willConflict) {
// Create branch for manual resolution
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-assisted conflict resolution
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}`);
}
}typescript
// 借助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 Branch Cleanup
4.3 分支清理
yaml
undefinedyaml
undefined.github/workflows/branch-cleanup.yml
.github/workflows/branch-cleanup.yml
name: Branch Cleanup
on:
schedule:
- cron: '0 0 * * 0' # Weekly
workflow_dispatch:
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Find stale branches
id: stale
run: |
# Branches not updated in 30 days
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: Create cleanup PR
if: steps.stale.outputs.branches != ''
uses: actions/github-script@v7
with:
script: |
const branches = `${{ steps.stale.outputs.branches }}`.split('\n').filter(Boolean);
const body = `## 🧹 Stale Branch CleanupThe following branches haven't been updated in over 30 days:
${branches.map(b => ${b}``).join('\n')}
- \name: Branch Cleanup
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('\n').filter(Boolean);
const body = `## 🧹 陈旧分支清理以下分支已超过30天未更新:
${branches.map(b => ${b}``).join('\n')}
- \Actions:
操作步骤:
-
Review each branch
-
Delete branches that are no longer needed
-
Comment `/keep branch-name` to preserve specific branches `;
await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: 'Stale Branch Cleanup', body: body, labels: ['housekeeping'] });
----
审核每个分支
-
删除不再需要的分支
-
评论`/keep branch-name`保留特定分支 `;
await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: '陈旧分支清理', body: body, labels: ['housekeeping'] });
---5. On-Demand Assistance
5. 按需辅助
5.1 @mention Bot
5.1 @提及机器人
yaml
undefinedyaml
undefined.github/workflows/mention-bot.yml
.github/workflows/mention-bot.yml
name: AI Mention Bot
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: Extract question
id: question
run: |
# Extract text after @ai-helper
question=$(echo "${{ github.event.comment.body }}" | sed 's/.*@ai-helper//')
echo "question=$question" >> $GITHUB_OUTPUT
- name: Get context
id: context
run: |
if [ "${{ github.event.issue.pull_request }}" != "" ]; then
# It's a PR - get diff
gh pr diff ${{ github.event.issue.number }} > context.txt
else
# It's an issue - get description
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 Response
uses: actions/github-script@v7
with:
script: |
const response = await ai.chat(`
Context: ${process.env.CONTEXT}
Question: ${process.env.QUESTION}
Provide a helpful, specific answer. Include code examples if relevant.
`);
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 }}undefinedname: AI Mention Bot
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 }}undefined5.2 Command Patterns
5.2 命令模板
markdown
undefinedmarkdown
undefinedAvailable Commands
可用命令
| Command | Description |
|---|---|
| Explain the code in this PR |
| Request AI code review |
| Suggest fixes for issues |
| Generate test cases |
| Generate documentation |
| Rebase PR onto main |
| Update PR branch from main |
| Mark as approved by bot |
| Add 'bug' label |
| Assign to user |
---| 命令 | 说明 |
|---|---|
| 解释PR中的代码逻辑 |
| 请求AI进行代码评审 |
| 针对问题提供修复建议 |
| 生成测试用例 |
| 生成文档内容 |
| 将PR变基到main分支 |
| 从main分支更新PR分支 |
| 由机器人标记为已批准 |
| 添加'bug'标签 |
| 将问题分配给指定用户 |
---6. Repository Configuration
6. 仓库配置
6.1 CODEOWNERS
6.1 CODEOWNERS
undefinedundefined.github/CODEOWNERS
.github/CODEOWNERS
Global owners
全局负责人
- @org/core-team
- @org/core-team
Frontend
前端团队
/src/frontend/ @org/frontend-team
*.tsx @org/frontend-team
*.css @org/frontend-team
/src/frontend/ @org/frontend-team
*.tsx @org/frontend-team
*.css @org/frontend-team
Backend
后端团队
/src/api/ @org/backend-team
/src/database/ @org/backend-team
/src/api/ @org/backend-team
/src/database/ @org/backend-team
Infrastructure
基础设施团队
/.github/ @org/devops-team
/terraform/ @org/devops-team
Dockerfile @org/devops-team
/.github/ @org/devops-team
/terraform/ @org/devops-team
Dockerfile @org/devops-team
Docs
文档团队
/docs/ @org/docs-team
*.md @org/docs-team
/docs/ @org/docs-team
*.md @org/docs-team
Security-sensitive
安全敏感模块
/src/auth/ @org/security-team
/src/crypto/ @org/security-team
undefined/src/auth/ @org/security-team
/src/crypto/ @org/security-team
undefined6.2 Branch Protection
6.2 分支保护
yaml
undefinedyaml
undefinedSet up via GitHub API
通过GitHub API配置
- name: Configure branch protection 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 });
---- name: Configure branch protection 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 });
---Best Practices
最佳实践
Security
安全
- Store API keys in GitHub Secrets
- Use minimal permissions in workflows
- Validate all inputs
- Don't expose sensitive data in logs
- 将API密钥存储在GitHub Secrets中
- 在工作流中使用最小权限
- 验证所有输入内容
- 避免在日志中暴露敏感数据
Performance
性能
- Cache dependencies
- Use matrix builds for parallel testing
- Skip unnecessary jobs with path filters
- Use self-hosted runners for heavy workloads
- 缓存依赖包
- 使用矩阵构建实现并行测试
- 通过路径过滤跳过不必要的任务
- 针对重负载任务使用自托管运行器
Reliability
可靠性
- Add timeouts to jobs
- Handle rate limits gracefully
- Implement retry logic
- Have rollback procedures
- 为任务添加超时设置
- 优雅处理速率限制
- 实现重试逻辑
- 制定回滚流程