Skip to content

Workflows

Workflows #6

# Gemini AI-Powered Code Analysis
# Analyzes code changes in PRs, pushes, and branches - FOCUSES ON CODE CHANGES
name: AI Code Analysis
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main, develop, 'feature/*', 'bugfix/*']
workflow_dispatch:
# Cancel previous workflow runs for the same context
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
issues: write
jobs:
ai-analysis:
name: AI Analysis & Assistant
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node.js for Google AI SDK
uses: actions/setup-node@v5
with:
node-version: '20'
- name: Get Code Changes
id: get-changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.before || '' }}
HEAD_SHA: ${{ github.sha }}
REPO_FULL_NAME: ${{ github.repository }}
run: |
echo "📋 Collecting code changes for analysis..."
echo "🔍 Debug info: BASE_SHA=$BASE_SHA, HEAD_SHA=$HEAD_SHA"
if [ "$EVENT_NAME" = "pull_request" ]; then
# For PRs, use git diff as primary method
PR_BASE_SHA="${{ github.event.pull_request.base.sha }}"
PR_HEAD_SHA="${{ github.event.pull_request.head.sha }}"
echo "🔍 PR Debug: BASE=$PR_BASE_SHA, HEAD=$PR_HEAD_SHA"
# Use git diff as PRIMARY method (more reliable)
echo "🔧 Using git diff (primary method)..."
if git diff "$PR_BASE_SHA".."$PR_HEAD_SHA" > code_changes.diff 2>git_error.log; then
echo "✅ Git diff successful - collected $(wc -l < code_changes.diff) lines"
else
echo "❌ Git diff failed, trying GitHub API as fallback..."
cat git_error.log 2>/dev/null || echo "No git error details"
# GitHub API as fallback
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3.diff" \
"https://api.github.com/repos/$REPO_FULL_NAME/compare/$PR_BASE_SHA..$PR_HEAD_SHA" \
> code_changes.diff
if [ -s code_changes.diff ]; then
echo "✅ GitHub API fallback successful"
else
echo "❌ Both methods failed for PR"
fi
fi
elif [ "$EVENT_NAME" = "push" ]; then
# For pushes, get the diff from the previous commit
if [ -n "$BASE_SHA" ] && [ "$BASE_SHA" != "0000000000000000000000000000000000000000" ]; then
echo "🔍 Push Debug: Comparing $BASE_SHA to $HEAD_SHA"
# Use git diff as PRIMARY method (more reliable)
echo "🔧 Using git diff (primary method)..."
if git diff "$BASE_SHA".."$HEAD_SHA" > code_changes.diff 2>git_error.log; then
echo "✅ Git diff successful - collected $(wc -l < code_changes.diff) lines"
else
echo "❌ Git diff failed, trying GitHub API as fallback..."
cat git_error.log 2>/dev/null || echo "No git error details"
# GitHub API as fallback only
echo "🌐 Attempting GitHub API diff as fallback..."
echo "🔍 URL: https://api.github.com/repos/$REPO_FULL_NAME/compare/$BASE_SHA..$HEAD_SHA"
HTTP_CODE=$(curl -s -w "%{http_code}" \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3.diff" \
"https://api.github.com/repos/$REPO_FULL_NAME/compare/$BASE_SHA..$HEAD_SHA" \
-o code_changes.diff 2>api_error.log)
if [ "$HTTP_CODE" = "200" ] && [ -s code_changes.diff ]; then
echo "✅ GitHub API fallback successful"
else
echo "❌ GitHub API also failed (HTTP $HTTP_CODE)"
fi
fi
# Final fallback: git show if no diff available
if [ ! -s code_changes.diff ]; then
echo "⚠️ No diff available, showing recent commit changes..."
echo "🔧 Running: git show --stat $HEAD_SHA"
git show --stat "$HEAD_SHA" > code_changes.diff 2>>git_error.log
echo "" >> code_changes.diff
git show "$HEAD_SHA" >> code_changes.diff 2>>git_error.log
if [ -s code_changes.diff ]; then
echo "✅ Git show successful as final fallback"
else
echo "❌ All methods failed - no code changes available"
fi
fi
else
echo "📄 Initial commit or no previous commit - showing current files..."
git show --name-only $HEAD_SHA | head -10 | while read file; do
if [ -f "$file" ]; then
echo "=== $file ===" >> code_changes.diff
head -50 "$file" >> code_changes.diff
echo "" >> code_changes.diff
fi
done
fi
else
echo "No code changes available for this event type" > code_changes.diff
fi
# Check if we got changes
if [ -s code_changes.diff ]; then
echo "✅ Code changes collected: $(wc -l < code_changes.diff) lines"
echo "changes-available=true" >> $GITHUB_OUTPUT
else
echo "⚠️ No code changes found"
echo "changes-available=false" >> $GITHUB_OUTPUT
fi
- name: Install Google AI SDK and Create Analysis Script
run: |
echo "🔧 Installing Google AI SDK..."
npm install @google/generative-ai
echo "📦 Creating Gemini analysis script..."
cat > gemini-analyze.js << 'SCRIPT_EOF'
const { GoogleGenerativeAI } = require('@google/generative-ai');
const fs = require('fs');
async function analyzeCode() {
try {
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error('GEMINI_API_KEY environment variable not found');
}
console.log('🔑 API key configured, length:', apiKey.length);
console.log('🤖 Initializing Gemini AI...');
const genAI = new GoogleGenerativeAI(apiKey);
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
const prompt = fs.readFileSync('analysis_prompt.txt', 'utf8');
console.log('📝 Prompt loaded, size:', prompt.length, 'characters');
console.log('🚀 Generating analysis...');
const result = await model.generateContent(prompt);
const response = await result.response;
const text = response.text();
fs.writeFileSync('ai_analysis_result.txt', text);
console.log('✅ Analysis completed successfully');
console.log('📄 Result size:', text.length, 'characters');
} catch (error) {
console.error('❌ Gemini analysis failed:', error.message);
console.error('🔍 Full error details:', error);
const fallbackContent = [
'## 🤖 AI Analysis Status',
'',
'The automated AI analysis encountered an issue: ' + error.message,
'',
'This may be due to:',
'- API key configuration issues',
'- Network connectivity problems',
'- Gemini API rate limits or service issues',
'- Invalid prompt format or size',
'',
'### Manual Review Recommended',
'Please conduct a manual code review focusing on:',
'- WordPress security best practices',
'- Coding standards compliance',
'- Performance considerations',
'- Plugin-specific requirements',
'',
'The PR can still be reviewed and merged based on manual inspection.'
].join('\n');
fs.writeFileSync('ai_analysis_result.txt', fallbackContent);
process.exit(1);
}
}
analyzeCode().catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});
SCRIPT_EOF
echo "✅ Analysis script created successfully"
- name: Create Analysis Prompt
env:
PR_TITLE: ${{ github.event.pull_request.title || format('Push Analysis - {0}', github.ref_name) }}
PR_AUTHOR: ${{ github.event.pull_request.user.login || github.actor }}
CHANGES_AVAILABLE: ${{ steps.get-changes.outputs.changes-available }}
run: |
echo "📝 Creating analysis prompt..."
echo "You are an expert WordPress plugin developer and security consultant." > analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "CRITICAL INSTRUCTION: FOCUS ON THE CODE CHANGES AND PROVIDE SECURITY ANALYSIS." >> analysis_prompt.txt
echo "Analyze what was changed, added, or removed and review those specific modifications." >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "Context: $PR_TITLE by @$PR_AUTHOR" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "Please analyze this WordPress plugin code for:" >> analysis_prompt.txt
echo "1. Security vulnerabilities" >> analysis_prompt.txt
echo "2. WordPress coding standards compliance" >> analysis_prompt.txt
echo "3. Performance considerations" >> analysis_prompt.txt
echo "4. Best practice recommendations" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "Provide specific, actionable feedback." >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
# Add the actual code changes
if [ "$CHANGES_AVAILABLE" = "true" ]; then
echo "Here are the code changes to analyze:" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
cat code_changes.diff >> analysis_prompt.txt
else
echo "No code changes were detected in this commit." >> analysis_prompt.txt
fi
- name: Run AI Analysis
id: ai-analysis
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
run: |
echo "🤖 Starting AI analysis with official Google SDK..."
echo "📝 Prompt file size: $(wc -c < analysis_prompt.txt) bytes"
if node gemini-analyze.js; then
echo "analysis-success=true" >> $GITHUB_OUTPUT
echo "✅ AI analysis completed successfully"
else
echo "analysis-success=false" >> $GITHUB_OUTPUT
echo "❌ AI analysis failed - check logs for details"
fi
- name: Output Analysis Results
env:
PR_NUMBER: ${{ github.event.number || '' }}
IS_PR: ${{ github.event_name == 'pull_request' }}
EVENT_NAME: ${{ github.event_name }}
run: |
echo "📊 Analysis Results for $EVENT_NAME event:"
echo "============================================================"
if [ -f ai_analysis_result.txt ]; then
cat ai_analysis_result.txt
else
echo "❌ Analysis result file not found"
fi
echo "============================================================"
echo "✅ Analysis output complete"