LLMSkillHub
mirroredCopied from agent-skills-hub/agent-skills-hub under MIT. agent-skills-hub has not claimed this page, and is not affiliated with LLM SkillHub.

agent-skills-hub / github-workflow-automation

Automate GitHub workflows with AI assistance. Includes PR reviews, issue triage, CI/CD integration, and Git operations. Use when automating GitHub workflows, setting up PR review automation, creating GitHub Actions, or triaging issues.

0
SKILL.md
21.2 KB
⚠This file contains 1 character(s) that do not render as themselves (U+FE0F). They are shown highlighted below.

🔧 GitHub Workflow Automation

Patterns for automating GitHub workflows with AI assistance, inspired by Gemini CLI and modern DevOps practices.

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)

1. Automated PR Review

1.1 PR Review Action

# .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 }}

1.2 Review Comment Patterns

# AI Review Structure

## 📋 Summary

Brief description of what this PR does.

## ✅ What looks good

- Well-structured code
- Good test coverage
- Clear naming conventions

## ⚠‹VARIATION SELECTOR U+FE0F› Potential Issues

1. **Line 42**: Possible null pointer exception

// Current
user.profile.name;
// Suggested
user?.profile?.name ?? "Unknown";
`


2. **Line 78**: Consider error handling

// Add try-catch or .catch()
`

💡 Suggestions

  • Consider extracting the validation logic into a separate function
  • Add JSDoc comments for public methods

🔒 Security Notes

  • No sensitive data exposure detected
  • API key handling looks correct

### 1.3 Focused Reviews

Review 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 "codefiles=$files" >> $GITHUBOUTPUT

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
    done

    # Send to AI with full file context


---

## 2. Issue Triage Automation

### 2.1 Auto-label Issues

.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. 🙏`
});
}


### 2.2 Issue Analysis Prompt

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
}
`;


### 2.3 Stale Issue Management

.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"


---

## 3. CI/CD Integration

### 3.1 Smart Test Selection

.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_OUTPUT

test:
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 }}
    fi


### 3.2 Deployment with AI Validation

.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


### 3.3 Rollback Automation

.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 }}"
    }
    }
    ]
    }


---

## 4. Git Operations

### 4.1 Automated Rebasing

.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:
    GHTOKEN: ${{ secrets.GITHUBTOKEN }}

  • 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!'
    })


### 4.2 Smart Cherry-Pick

// 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});
}
}


### 4.3 Branch Cleanup

.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 Cleanup

The following branches haven't been updated in over 30 days:

${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']
});


---

## 5. On-Demand Assistance

### 5.1 @mention Bot

.github/workflows/mention-bot.yml

name: AI Mention Bot

on:
issue_comment:
types: [created]
pullrequestreview_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:
    GHTOKEN: ${{ secrets.GITHUBTOKEN }}

  • 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 }}


### 5.2 Command Patterns

Available Commands

CommandDescription
@ai-helper explainExplain the code in this PR
@ai-helper reviewRequest AI code review
@ai-helper fixSuggest fixes for issues
@ai-helper testGenerate test cases
@ai-helper docsGenerate documentation
/rebaseRebase PR onto main
/updateUpdate PR branch from main
/approveMark as approved by bot
/label bugAdd 'bug' label
/assign @userAssign to user

---

## 6. Repository Configuration

### 6.1 CODEOWNERS

.github/CODEOWNERS

Global owners

  • @org/core-team

Frontend

/src/frontend/ @org/frontend-team
*.tsx @org/frontend-team
*.css @org/frontend-team

Backend

/src/api/ @org/backend-team
/src/database/ @org/backend-team

Infrastructure

/.github/ @org/devops-team
/terraform/ @org/devops-team
Dockerfile @org/devops-team

Docs

/docs/ @org/docs-team
*.md @org/docs-team

Security-sensitive

/src/auth/ @org/security-team
/src/crypto/ @org/security-team


### 6.2 Branch Protection

Set up via 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',
    requiredstatuschecks: {
    strict: true,
    contexts: ['test', 'lint', 'ai-review']
    },
    enforce_admins: true,
    requiredpullrequest_reviews: {
    requiredapprovingreview_count: 1,
    requirecodeowner_reviews: true,
    dismissstalereviews: true
    },
    restrictions: null,
    requiredlinearhistory: true,
    allowforcepushes: 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

### 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

---

## Resources

- [Gemini CLI GitHub Action](https://github.com/google-github-actions/run-gemini-cli)
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
- [GitHub REST API](https://docs.github.com/en/rest)
- [CODEOWNERS Syntax](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners)