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.

View Source
name:github-workflow-automationdescription:"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."

🔧 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
  • ⚠️ Potential Issues

  • Line 42: Possible null pointer exception
  • javascript
    // Current
    user.profile.name;
    // Suggested
    user?.profile?.name ?? "Unknown";

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

    Review only specific file types


  • name: Filter code files

  • run:
    grep -E '\.(ts

    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
    done

    # Send to AI with full file context

    ---

    2. Issue Triage Automation

    2.1 Auto-label Issues

    yaml

    .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
    typescript
    const TRIAGE_PROMPT =
    Analyze this GitHub issue and classify it:

    Title: {title}
    Body: {body}

    Return JSON with:
    {

    "type": "bug""feature""question""docs""other",
    "area": "frontend""backend""api""docs""ci"

    "summary": "one-line summary",
    "hasReproSteps": boolean,
    "isFirstContribution": boolean,
    "suggestedLabels": ["label1", "label2"],
    "suggestedAssignees": ["username"] // based on area expertise
    }
    ;
    ### 2.3 Stale Issue Management
    yaml

    .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

    yaml

    .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

    fi

    if echo "$changed"grep -q "^src/frontend/"; then

    fi

    if echo "$changed"grep -q "^src/database/"; then

    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
    yaml

    .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<> $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
    yaml

    .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

    yaml

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

    ### 4.2 Smart Cherry-Pick
    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});
    }
    }

    ### 4.3 Branch Cleanup
    yaml

    .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 -v 'origin/main\origin/develop'
    cut -d' ' -f1sed 's

    echo "branches<> $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

    yaml

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

    ### 5.2 Command Patterns
    markdown

    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
    yaml

    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',
    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
  • 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

  • GitHub Actions Documentation

  • GitHub REST API

  • CODEOWNERS Syntax

    1. github-workflow-automation - Agent Skills