Skip to content

Bump the actions group across 1 directory with 2 updates #4

Bump the actions group across 1 directory with 2 updates

Bump the actions group across 1 directory with 2 updates #4

name: Gemini Issue Assistant
on:
issues:
types: [opened, edited]
issue_comment:
types: [created, edited]
jobs:
analyze-issue:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
- 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 analyzeIssue() {
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);
// Try different model names prioritizing quality first, then fallback on rate limits
// Order: 2.5 models (highest quality) -> 2.0 models (higher RPM) -> legacy
const modelNames = [
"gemini-2.5-pro", // 5 RPM, 250K TPM - Highest quality
"gemini-2.5-flash", // 10 RPM, 250K TPM - Best 2.5 balance
"gemini-2.5-flash-preview", // 10 RPM, 250K TPM - Latest 2.5 features
"gemini-2.5-flash-lite", // 15 RPM, 250K TPM - Faster 2.5
"gemini-2.5-flash-lite-preview", // 15 RPM, 250K TPM - Latest 2.5 lite
"gemini-2.0-flash", // 15 RPM, 1M TPM - Good 2.0 balance
"gemini-2.0-flash-lite", // 30 RPM, 1M TPM - Highest RPM fallback
"gemini-1.5-flash", // 15 RPM, 250K TPM - DEPRECATED fallback
"gemini-pro" // Legacy final fallback
];
let model = null;
let modelUsed = null;
for (const modelName of modelNames) {
try {
console.log('🔧 Trying model:', modelName);
model = genAI.getGenerativeModel({ model: modelName });
// Test the model with a small request to check availability/rate limits
console.log('🧪 Testing model availability...');
await model.generateContent("test");
modelUsed = modelName;
console.log('✅ Successfully initialized and tested model:', modelName);
break;
} catch (modelError) {
console.log('❌ Model', modelName, 'failed:', modelError.message);
// Check for rate limit errors specifically
if (modelError.message && (
modelError.message.includes('rate limit') ||
modelError.message.includes('quota') ||
modelError.message.includes('429') ||
modelError.status === 429
)) {
console.log('⚠️ Rate limit detected, trying next model with higher RPM...');
} else if (modelError.message && modelError.message.includes('404')) {
console.log('⚠️ Model not found, trying next available model...');
}
continue;
}
}
if (!model) {
throw new Error('No supported Gemini model could be initialized');
}
const prompt = fs.readFileSync('analysis_prompt.txt', 'utf8');
console.log('📝 Prompt loaded, size:', prompt.length, 'characters');
console.log('🚀 Generating analysis with model:', modelUsed);
const result = await model.generateContent(prompt);
const response = await result.response;
const text = response.text();
fs.writeFileSync('gemini_response.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 review this issue manually and check the repository for related code.',
''
].join('\n');
fs.writeFileSync('gemini_response.txt', fallbackContent);
process.exit(1);
}
}
analyzeIssue().catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});
SCRIPT_EOF
echo "✅ Analysis script created successfully"
- name: Determine analysis type
id: analysis-type
env:
EVENT_NAME: ${{ github.event_name }}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
run: |
if [ "$EVENT_NAME" = "issues" ]; then
echo "type=issue-analysis" >> $GITHUB_OUTPUT
echo "Issue: $ISSUE_TITLE"
echo "Author: $ISSUE_AUTHOR"
elif [ "$EVENT_NAME" = "issue_comment" ]; then
echo "type=comment-analysis" >> $GITHUB_OUTPUT
echo "Comment on issue: $ISSUE_TITLE"
echo "Comment author: $COMMENT_AUTHOR"
else
echo "type=skip" >> $GITHUB_OUTPUT
fi
- name: Scan Codebase for Context
id: scan-code
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO_FULL_NAME: ${{ github.repository }}
run: |
echo "📋 Scanning codebase for relevant context..."
# Get recent commits for context with git as primary method
echo "📜 Collecting recent commits..."
if git log --oneline -5 > recent_commits.txt 2>git_error.log; then
echo "✅ Recent commits collected via git"
else
echo "⚠️ Failed to get recent commits via git:"
cat git_error.log 2>/dev/null || echo "No git error details"
echo "No recent commits available" > recent_commits.txt
fi
# Get main plugin files for context using reliable file system operations
echo "📁 Collecting plugin file structure..."
echo "🔍 Main plugin files:" > codebase_context.txt
# Use git ls-files as primary method (more reliable than find)
echo "🔧 Using git ls-files (primary method)..."
if git ls-files "*.php" | head -10 > found_files.txt 2>git_error.log; then
echo "✅ Git ls-files successful"
while read file; do
if [ -f "$file" ] && [ -n "$file" ]; then
echo "=== $file ===" >> codebase_context.txt
echo "🔍 Processing: $file"
if head -30 "$file" >> codebase_context.txt 2>/dev/null; then
echo "✅ Added content from $file"
else
echo "⚠️ Failed to read $file"
fi
echo "" >> codebase_context.txt
fi
done < found_files.txt
else
echo "⚠️ Git ls-files failed, using find as fallback..."
cat git_error.log 2>/dev/null || echo "No git error details"
# Find as fallback method
if find . -name "*.php" -path "./.*" -prune -o -name "*.php" -print 2>/dev/null | head -10 > found_files.txt; then
echo "✅ Find fallback successful"
while read file; do
if [ -f "$file" ] && [ -n "$file" ]; then
echo "=== $file ===" >> codebase_context.txt
head -30 "$file" >> codebase_context.txt 2>/dev/null
echo "" >> codebase_context.txt
fi
done < found_files.txt
else
echo "❌ Both git and find methods failed"
echo "No PHP files found" >> codebase_context.txt
fi
fi
# Add recent commits to context
echo "" >> codebase_context.txt
echo "📜 Recent Git History:" >> codebase_context.txt
cat recent_commits.txt >> codebase_context.txt
# Check if we collected context with better validation
if [ -s codebase_context.txt ] && [ $(wc -l < codebase_context.txt) -gt 5 ]; then
echo "✅ Codebase context collected: $(wc -l < codebase_context.txt) lines"
echo "context-available=true" >> $GITHUB_OUTPUT
else
echo "❌ Insufficient codebase context collected"
echo "🔍 Context file size: $(wc -l < codebase_context.txt 2>/dev/null || echo '0') lines"
echo "context-available=false" >> $GITHUB_OUTPUT
fi
- name: Create analysis prompt
env:
ANALYSIS_TYPE: ${{ steps.analysis-type.outputs.type }}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
COMMENT_BODY: ${{ github.event.comment.body }}
COMMENT_AUTHOR: ${{ github.event.comment.user.login }}
CONTEXT_AVAILABLE: ${{ steps.scan-code.outputs.context-available }}
run: |
# Skip analysis if not relevant
if [ "$ANALYSIS_TYPE" = "skip" ]; then
echo "No relevant issue activity. Skipping analysis." > analysis_prompt.txt
echo "analysis-skipped=true" >> $GITHUB_OUTPUT
exit 0
elif [ "$ANALYSIS_TYPE" = "issue-analysis" ]; then
# Create issue-focused prompt - FOCUS ON USER'S PROBLEM FIRST
echo "You are an expert WordPress plugin developer helping users solve problems." > analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "CRITICAL INSTRUCTION: FOCUS FIRST ON UNDERSTANDING THE USER'S ISSUE." >> analysis_prompt.txt
echo "Then scan the codebase to find potential solutions or identify code-related causes." >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "ISSUE DETAILS:" >> analysis_prompt.txt
echo "Title: $ISSUE_TITLE" >> analysis_prompt.txt
echo "Author: @$ISSUE_AUTHOR" >> analysis_prompt.txt
echo "Description:" >> analysis_prompt.txt
echo "$ISSUE_BODY" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "ANALYSIS APPROACH:" >> analysis_prompt.txt
echo "1. Understand the user's problem/request thoroughly" >> analysis_prompt.txt
echo "2. Scan the codebase for related functionality" >> analysis_prompt.txt
echo "3. Identify potential code-based solutions or fixes" >> analysis_prompt.txt
echo "4. Check for existing similar functionality" >> analysis_prompt.txt
echo "5. Provide actionable recommendations" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "REPOSITORY CONTEXT: WordPress plugin project (WordPress 6.5+, PHP 7.4+)" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
elif [ "$ANALYSIS_TYPE" = "comment-analysis" ]; then
# Create comment-focused prompt - FOCUS ON CONVERSATION CONTEXT
echo "You are an expert WordPress plugin developer analyzing an issue conversation." > analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "CRITICAL INSTRUCTION: FOCUS ON THE CONVERSATION CONTEXT AND NEW INFORMATION." >> analysis_prompt.txt
echo "Analyze the new comment in relation to the original issue and provide relevant insights." >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "ORIGINAL ISSUE:" >> analysis_prompt.txt
echo "Title: $ISSUE_TITLE" >> analysis_prompt.txt
echo "Description: $ISSUE_BODY" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "NEW COMMENT:" >> analysis_prompt.txt
echo "Author: @$COMMENT_AUTHOR" >> analysis_prompt.txt
echo "Content: $COMMENT_BODY" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "ANALYSIS FOCUS:" >> analysis_prompt.txt
echo "1. How does this comment relate to the original issue?" >> analysis_prompt.txt
echo "2. What new information or clarification is provided?" >> analysis_prompt.txt
echo "3. Are there code implications from this comment?" >> analysis_prompt.txt
echo "4. What follow-up actions are suggested?" >> analysis_prompt.txt
echo "" >> analysis_prompt.txt
echo "REPOSITORY CONTEXT: WordPress plugin project (WordPress 6.5+, PHP 7.4+)" >> analysis_prompt.txt
fi
# Add codebase context if available
if [ "$CONTEXT_AVAILABLE" = "true" ]; then
echo "" >> analysis_prompt.txt
echo "CODEBASE CONTEXT FOR REFERENCE:" >> analysis_prompt.txt
cat codebase_context.txt >> analysis_prompt.txt
fi
- name: Run AI Analysis
id: ai-analysis
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
ANALYSIS_SKIPPED: ${{ steps.analysis-type.outputs.analysis-skipped }}
run: |
if [ "$ANALYSIS_SKIPPED" = "true" ]; then
echo "Analysis skipped"
exit 0
fi
echo "🤖 Starting AI issue analysis with official Google SDK..."
echo "📝 Prompt file size: $(wc -c < analysis_prompt.txt) bytes"
echo "🔑 API key status: $([ -n "$GEMINI_API_KEY" ] && echo "✅ Set" || echo "❌ Missing")"
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
# Format the response with enhanced error handling
echo "## 🤖 Gemini Issue Analysis" > formatted_response.txt
echo "" >> formatted_response.txt
if [ -s gemini_response.txt ]; then
echo "📄 Adding analysis results ($(wc -c < gemini_response.txt) characters)"
cat gemini_response.txt >> formatted_response.txt
else
echo "⚠️ No analysis results found - adding fallback message"
echo "Analysis completed but encountered issues. Please review the issue manually and check the repository for related functionality." >> formatted_response.txt
fi
echo "" >> formatted_response.txt
echo "---" >> formatted_response.txt
echo "*Analysis performed by Gemini AI on $(date)*" >> formatted_response.txt
# Debug: Show final response size
echo "📊 Final response size: $(wc -c < formatted_response.txt) characters"
- name: Comment on Issue
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
let response = '';
if (fs.existsSync('formatted_response.txt')) {
response = fs.readFileSync('formatted_response.txt', 'utf8');
} else {
response = '## 🤖 Gemini Issue Analysis\n\nAnalysis completed. Please review the codebase for potential solutions to this issue.';
}
// Get the issue number
const issueNumber = context.issue.number;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: response
});