Skip to content

Add Claude AI workflows for automated code review and PR management #3

Add Claude AI workflows for automated code review and PR management

Add Claude AI workflows for automated code review and PR management #3

Workflow file for this run

name: Claude AI Review
on:
issue_comment:
types: [created]
pull_request:
types: [opened, synchronize]
branches: [main]
pull_request_review_comment:
types: [created]
permissions:
contents: write
pull-requests: write
issues: write
jobs:
claude-review:
name: Claude Auto Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main'
steps:
- name: Checkout PR
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v44
with:
separator: ","
- name: Check for stale/out-of-scope files
id: scope-check
run: |
echo "🔍 Checking for stale files and out-of-scope changes..." > scope_check.md
echo "" >> scope_check.md
SCOPE_ISSUES=0
CHANGED_FILES="${{ steps.changed-files.outputs.all_changed_files }}"
echo "### Stale File Check" >> scope_check.md
for file in $CHANGED_FILES; do
if [ -f "$file" ]; then
FILE_AGE=$(git log -1 --format="%cr" origin/main -- "$file" 2>/dev/null || echo "new file")
FILE_DATE=$(git log -1 --format="%ci" origin/main -- "$file" 2>/dev/null || echo "")
if [ -n "$FILE_DATE" ]; then
YEARS_OLD=$(( ($(date +%s) - $(date -d "$FILE_DATE" +%s)) / 31536000 ))
if [ $YEARS_OLD -gt 2 ]; then
echo "⚠️ **WARNING**: \`$file\` is $YEARS_OLD years old (last modified: $FILE_AGE)" >> scope_check.md
SCOPE_ISSUES=$((SCOPE_ISSUES + 1))
fi
fi
fi
done
if [ $SCOPE_ISSUES -eq 0 ]; then
echo "✅ No stale files detected" >> scope_check.md
fi
echo "" >> scope_check.md
echo "### Scope Check" >> scope_check.md
echo "Checking file relevance (blocks binaries, temp files, etc.)..." >> scope_check.md
echo "" >> scope_check.md
RELEVANT_PATTERNS=(
"lib/"
"test/"
"config/"
"priv/"
"mix.exs"
"mix.lock"
".github/"
".githooks/"
"flake.nix"
"flake.lock"
".formatter.exs"
".credo.exs"
"README.md"
"CHANGELOG.md"
"LICENSE"
"CONTRIBUTING.md"
"*.md"
"scripts/"
".envrc"
"renovate.json5"
)
OUT_OF_SCOPE_FILES=()
for file in $CHANGED_FILES; do
MATCHES_PATTERN=false
for pattern in "${RELEVANT_PATTERNS[@]}"; do
if [[ "$file" == $pattern ]] || [[ "$file" == *"$pattern"* ]]; then
MATCHES_PATTERN=true
break
fi
done
if [ "$MATCHES_PATTERN" = false ]; then
case "$file" in
*.exe|*.dll|*.so|*.dylib|*.bin|*.dat|*.tmp|*.log|*.beam|node_modules/*|.DS_Store|thumbs.db|_build/*|deps/*)
echo "❌ **OUT OF SCOPE**: \`$file\` - Binary/temp/build file not relevant to library" >> scope_check.md
OUT_OF_SCOPE_FILES+=("$file")
SCOPE_ISSUES=$((SCOPE_ISSUES + 1))
;;
*.jpg|*.png|*.gif|*.mp4|*.avi|*.mov)
if [[ ! "$file" =~ ^docs/ ]] && [[ ! "$file" =~ ^assets/ ]]; then
echo "⚠️ **REVIEW NEEDED**: \`$file\` - Media file, ensure it's for documentation" >> scope_check.md
fi
;;
esac
fi
done
if [ ${#OUT_OF_SCOPE_FILES[@]} -eq 0 ]; then
echo "✅ All changes appear relevant (includes .github/ workflows, lib/, test/, config)" >> scope_check.md
fi
echo "" >> scope_check.md
GITHUB_FILES=$(echo "$CHANGED_FILES" | tr ' ' '\n' | grep -c "^.github/" || true)
if [ "$GITHUB_FILES" -gt 0 ]; then
echo "ℹ️ **Note**: $GITHUB_FILES .github/ file(s) changed - workflows/actions are critical infrastructure" >> scope_check.md
echo "" >> scope_check.md
fi
echo "SCOPE_ISSUES=$SCOPE_ISSUES" >> $GITHUB_OUTPUT
cat scope_check.md
- name: Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
show_full_output: true
prompt: |
Review this PR for an Elixir workflow orchestration library (Singularity.Workflow).
Focus on:
1. Elixir code quality (mix format, credo checks)
2. Security vulnerabilities (SQL injection, XSS, etc.)
3. Test coverage (ExUnit tests)
4. Documentation completeness (@doc, @moduledoc)
5. Whether changes are appropriate for a library package
Scope check results:
$(cat scope_check.md 2>/dev/null || echo "No scope issues")
Provide a concise review. If the code looks good, say "LGTM - auto-approving".
If there are issues, list them clearly.
claude_args: "--max-turns 3 --model sonnet"
- name: Determine auto-approve
id: claude-analysis
run: |
SCOPE_ISSUES=${{ steps.scope-check.outputs.SCOPE_ISSUES }}
if [ $SCOPE_ISSUES -eq 0 ]; then
echo "AUTO_APPROVE=true" >> $GITHUB_OUTPUT
echo "✅ No scope issues detected - eligible for auto-approve"
else
echo "AUTO_APPROVE=false" >> $GITHUB_OUTPUT
echo "⚠️ $SCOPE_ISSUES scope issue(s) found - human review required"
fi
- name: Post scope check results
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let comment_body = '## 🔍 Automated Checks\n\n';
try {
const scope_check = fs.readFileSync('scope_check.md', 'utf8');
comment_body += scope_check;
} catch (error) {
comment_body += '✅ Scope check passed\n';
}
comment_body += '\n---\n';
comment_body += '*Claude is reviewing the code... Check the "Claude Code Review" step for detailed feedback.*\n';
const pr_number = context.payload.pull_request.number;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr_number,
body: comment_body
});
- name: Set review status
id: review-status
uses: actions/github-script@v7
env:
AUTO_APPROVE: ${{ steps.claude-analysis.outputs.AUTO_APPROVE }}
with:
github-token: ${{ secrets.ORG_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const pr_number = context.payload.pull_request.number;
const auto_approve = process.env.AUTO_APPROVE === 'true';
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr_number,
body: auto_approve
? '✅ Claude AI approved this PR! All checks passed. Will auto-merge when CI is green.'
: '⚠️ Claude AI review found issues. Human review required.',
event: auto_approve ? 'APPROVE' : 'COMMENT'
});
return { auto_approve };
- name: Enable auto-merge
if: steps.claude-analysis.outputs.AUTO_APPROVE == 'true'
env:
GH_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
gh pr merge $PR_NUMBER --auto --squash || echo "Auto-merge may already be enabled or not allowed"
echo "✅ Auto-merge enabled! PR will merge automatically when:"
echo " - All required checks pass (test, quality, coverage)"
echo " - All conversations are resolved"
echo " - Branch is up to date with main"