1+ # Gemini AI-Powered Code Analysis
2+ # Analyzes code changes in PRs, pushes, and branches - FOCUSES ON CODE CHANGES
3+
4+ name : AI Code Analysis
5+
6+ on :
7+ pull_request :
8+ types : [opened, synchronize, reopened]
9+ push :
10+ branches : [main, develop, 'feature/*', 'bugfix/*']
11+ workflow_dispatch :
12+
13+ # Cancel previous workflow runs for the same context
14+ concurrency :
15+ group : ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.number || github.ref }}
16+ cancel-in-progress : true
17+
18+ permissions :
19+ contents : read
20+ pull-requests : write
21+ issues : write
22+
23+ jobs :
24+ ai-analysis :
25+ name : AI Analysis & Assistant
26+ runs-on : ubuntu-latest
27+
28+ steps :
29+ - name : Checkout code
30+ uses : actions/checkout@v5
31+ with :
32+ fetch-depth : 0
33+
34+ - name : Setup Node.js for Google AI SDK
35+ uses : actions/setup-node@v5
36+ with :
37+ node-version : ' 20'
38+
39+ - name : Get Code Changes
40+ id : get-changes
41+ env :
42+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
43+ EVENT_NAME : ${{ github.event_name }}
44+ BASE_SHA : ${{ github.event.before || '' }}
45+ HEAD_SHA : ${{ github.sha }}
46+ REPO_FULL_NAME : ${{ github.repository }}
47+ run : |
48+ echo "📋 Collecting code changes for analysis..."
49+ echo "🔍 Debug info: BASE_SHA=$BASE_SHA, HEAD_SHA=$HEAD_SHA"
50+
51+ if [ "$EVENT_NAME" = "pull_request" ]; then
52+ # For PRs, get the diff between base and head
53+ PR_BASE_SHA="${{ github.event.pull_request.base.sha }}"
54+ PR_HEAD_SHA="${{ github.event.pull_request.head.sha }}"
55+ echo "🔍 PR Debug: BASE=$PR_BASE_SHA, HEAD=$PR_HEAD_SHA"
56+
57+ curl -s -H "Authorization: token $GITHUB_TOKEN" \
58+ -H "Accept: application/vnd.github.v3.diff" \
59+ "https://api.github.com/repos/$REPO_FULL_NAME/compare/$PR_BASE_SHA..$PR_HEAD_SHA" \
60+ > code_changes.diff
61+
62+ if [ $? -ne 0 ] || [ ! -s code_changes.diff ]; then
63+ echo "⚠️ API diff failed, using git diff..."
64+ git diff $PR_BASE_SHA..$PR_HEAD_SHA > code_changes.diff
65+ fi
66+
67+ elif [ "$EVENT_NAME" = "push" ]; then
68+ # For pushes, get the diff from the previous commit
69+ if [ -n "$BASE_SHA" ] && [ "$BASE_SHA" != "0000000000000000000000000000000000000000" ]; then
70+ echo "🔍 Push Debug: Comparing $BASE_SHA to $HEAD_SHA"
71+
72+ # Try API first with better error checking
73+ echo "🌐 Attempting GitHub API diff..."
74+ HTTP_CODE=$(curl -s -w "%{http_code}" \
75+ -H "Authorization: token $GITHUB_TOKEN" \
76+ -H "Accept: application/vnd.github.v3.diff" \
77+ "https://api.github.com/repos/$REPO_FULL_NAME/compare/$BASE_SHA..$HEAD_SHA" \
78+ -o code_changes.diff)
79+
80+ echo "🔍 API returned HTTP $HTTP_CODE"
81+
82+ # Check if API call was successful (200 status and file has content)
83+ if [ "$HTTP_CODE" != "200" ] || [ ! -s code_changes.diff ]; then
84+ echo "⚠️ API diff failed (HTTP $HTTP_CODE), using git diff..."
85+
86+ # Use git diff as fallback
87+ git diff $BASE_SHA..$HEAD_SHA > code_changes.diff
88+
89+ # If git diff also fails or is empty, use git show
90+ if [ ! -s code_changes.diff ]; then
91+ echo "⚠️ No diff available, showing recent commit changes..."
92+ git show --stat $HEAD_SHA > code_changes.diff
93+ echo "" >> code_changes.diff
94+ git show $HEAD_SHA >> code_changes.diff
95+ fi
96+ else
97+ echo "✅ GitHub API diff successful"
98+ fi
99+ else
100+ echo "📄 Initial commit or no previous commit - showing current files..."
101+ git show --name-only $HEAD_SHA | head -10 | while read file; do
102+ if [ -f "$file" ]; then
103+ echo "=== $file ===" >> code_changes.diff
104+ head -50 "$file" >> code_changes.diff
105+ echo "" >> code_changes.diff
106+ fi
107+ done
108+ fi
109+ else
110+ echo "No code changes available for this event type" > code_changes.diff
111+ fi
112+
113+ # Check if we got changes
114+ if [ -s code_changes.diff ]; then
115+ echo "✅ Code changes collected: $(wc -l < code_changes.diff) lines"
116+ echo "changes-available=true" >> $GITHUB_OUTPUT
117+ else
118+ echo "⚠️ No code changes found"
119+ echo "changes-available=false" >> $GITHUB_OUTPUT
120+ fi
121+
122+ - name : Install Google AI SDK and Create Analysis Script
123+ run : |
124+ echo "🔧 Installing Google AI SDK..."
125+ npm install @google/generative-ai
126+
127+ echo "📦 Creating Gemini analysis script..."
128+ cat > gemini-analyze.js << 'SCRIPT_EOF'
129+ const { GoogleGenerativeAI } = require('@google/generative-ai');
130+ const fs = require('fs');
131+
132+ async function analyzeCode() {
133+ try {
134+ const apiKey = process.env.GEMINI_API_KEY;
135+ if (!apiKey) {
136+ throw new Error('GEMINI_API_KEY environment variable not found');
137+ }
138+
139+ console.log('🔑 API key configured, length:', apiKey.length);
140+ console.log('🤖 Initializing Gemini AI...');
141+
142+ const genAI = new GoogleGenerativeAI(apiKey);
143+ const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
144+
145+ const prompt = fs.readFileSync('analysis_prompt.txt', 'utf8');
146+ console.log('📝 Prompt loaded, size:', prompt.length, 'characters');
147+
148+ console.log('🚀 Generating analysis...');
149+ const result = await model.generateContent(prompt);
150+ const response = await result.response;
151+ const text = response.text();
152+
153+ fs.writeFileSync('ai_analysis_result.txt', text);
154+ console.log('✅ Analysis completed successfully');
155+ console.log('📄 Result size:', text.length, 'characters');
156+
157+ } catch (error) {
158+ console.error('❌ Gemini analysis failed:', error.message);
159+ console.error('🔍 Full error details:', error);
160+
161+ const fallbackContent = [
162+ '## 🤖 AI Analysis Status',
163+ '',
164+ 'The automated AI analysis encountered an issue: ' + error.message,
165+ '',
166+ 'This may be due to:',
167+ '- API key configuration issues',
168+ '- Network connectivity problems',
169+ '- Gemini API rate limits or service issues',
170+ '- Invalid prompt format or size',
171+ '',
172+ '### Manual Review Recommended',
173+ 'Please conduct a manual code review focusing on:',
174+ '- Linux security best practices',
175+ '- Bash scripting standards compliance',
176+ '- LEMP stack performance considerations',
177+ '- Server automation requirements',
178+ '- Nginx, PHP, MariaDB, Redis security configurations',
179+ '',
180+ 'The PR can still be reviewed and merged based on manual inspection.'
181+ ].join('\n');
182+
183+ fs.writeFileSync('ai_analysis_result.txt', fallbackContent);
184+ process.exit(1);
185+ }
186+ }
187+
188+ analyzeCode().catch(error => {
189+ console.error('Fatal error:', error);
190+ process.exit(1);
191+ });
192+ SCRIPT_EOF
193+
194+ echo "✅ Analysis script created successfully"
195+
196+ - name : Create Analysis Prompt
197+ env :
198+ PR_TITLE : ${{ github.event.pull_request.title || format('Push Analysis - {0}', github.ref_name) }}
199+ PR_AUTHOR : ${{ github.event.pull_request.user.login || github.actor }}
200+ CHANGES_AVAILABLE : ${{ steps.get-changes.outputs.changes-available }}
201+ run : |
202+ echo "📝 Creating analysis prompt..."
203+ echo "You are an expert Linux system administrator, bash scripting specialist, and LEMP stack automation consultant." > analysis_prompt.txt
204+ echo "" >> analysis_prompt.txt
205+ echo "CRITICAL INSTRUCTION: FOCUS ON THE CODE CHANGES AND PROVIDE SECURITY AND CONFIGURATION ANALYSIS." >> analysis_prompt.txt
206+ echo "Analyze what was changed, added, or removed and review those specific server automation modifications." >> analysis_prompt.txt
207+ echo "" >> analysis_prompt.txt
208+ echo "Context: $PR_TITLE by @$PR_AUTHOR" >> analysis_prompt.txt
209+ echo "" >> analysis_prompt.txt
210+ echo "Please analyze this EngineScript server automation code for:" >> analysis_prompt.txt
211+ echo "1. Security vulnerabilities in bash scripts and server configurations" >> analysis_prompt.txt
212+ echo "2. Linux system administration best practices compliance" >> analysis_prompt.txt
213+ echo "3. LEMP stack performance and security considerations" >> analysis_prompt.txt
214+ echo "4. Server automation and deployment best practice recommendations" >> analysis_prompt.txt
215+ echo "5. Nginx, PHP, MariaDB, and Redis configuration correctness" >> analysis_prompt.txt
216+ echo "6. Cloudflare integration and SSL/TLS security" >> analysis_prompt.txt
217+ echo "" >> analysis_prompt.txt
218+ echo "Provide specific, actionable feedback for server administration improvements." >> analysis_prompt.txt
219+ echo "" >> analysis_prompt.txt
220+
221+ # Add the actual code changes
222+ if [ "$CHANGES_AVAILABLE" = "true" ]; then
223+ echo "Here are the code changes to analyze:" >> analysis_prompt.txt
224+ echo "" >> analysis_prompt.txt
225+ cat code_changes.diff >> analysis_prompt.txt
226+ else
227+ echo "No code changes were detected in this commit." >> analysis_prompt.txt
228+ fi
229+
230+ - name : Run AI Analysis
231+ id : ai-analysis
232+ env :
233+ GEMINI_API_KEY : ${{ secrets.GEMINI_API_KEY }}
234+ run : |
235+ echo "🤖 Starting AI analysis with official Google SDK..."
236+ echo "📝 Prompt file size: $(wc -c < analysis_prompt.txt) bytes"
237+
238+ if node gemini-analyze.js; then
239+ echo "analysis-success=true" >> $GITHUB_OUTPUT
240+ echo "✅ AI analysis completed successfully"
241+ else
242+ echo "analysis-success=false" >> $GITHUB_OUTPUT
243+ echo "❌ AI analysis failed - check logs for details"
244+ fi
245+
246+ - name : Output Analysis Results
247+ env :
248+ PR_NUMBER : ${{ github.event.number || '' }}
249+ IS_PR : ${{ github.event_name == 'pull_request' }}
250+ EVENT_NAME : ${{ github.event_name }}
251+ run : |
252+ echo "📊 Analysis Results for $EVENT_NAME event:"
253+ echo "============================================================"
254+
255+ if [ -f ai_analysis_result.txt ]; then
256+ cat ai_analysis_result.txt
257+ else
258+ echo "❌ Analysis result file not found"
259+ fi
260+
261+ echo "============================================================"
262+ echo "✅ Analysis output complete"
0 commit comments