Skip to main content
Glama
index.js8.2 kB
#!/usr/bin/env node /** * GitHub Action 主執行檔 * 執行分析並在 PR 中回覆結果 * 支援規則式分析和 AI 分析兩種模式 */ import * as core from '@actions/core'; import { runAllAnalyses, runModernizationAnalysis } from './analyzer.js'; import { commentOnPR, commentAIReport } from './commenter.js'; import { analyzeWithAI } from './ai-service.js'; import { getPRDiff, getPRInfo, getPRFiles } from './pr-diff.js'; async function main() { try { // 取得輸入參數 const projectPath = core.getInput('project-path') || '.'; const includePatternsStr = core.getInput('include-patterns') || '["**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx"]'; const excludePatternsStr = core.getInput('exclude-patterns') || '["node_modules/**", "dist/**", "build/**"]'; const browserslistConfig = core.getInput('browserslist-config') || ''; const enableModernization = core.getBooleanInput('enable-modernization'); const enableCompatibility = core.getBooleanInput('enable-compatibility'); const enableBrowserCheck = core.getBooleanInput('enable-browser-check'); const githubToken = core.getInput('github-token'); const commentOnPRFlag = core.getBooleanInput('comment-on-pr'); // AI 相關參數 const aiEnabled = core.getBooleanInput('ai-enabled'); const aiProvider = core.getInput('ai-provider') || 'openai'; const aiModel = core.getInput('ai-model') || ''; const aiApiKey = core.getInput('ai-api-key') || ''; // 解析 JSON 陣列 let includePatterns, excludePatterns; try { includePatterns = JSON.parse(includePatternsStr); excludePatterns = JSON.parse(excludePatternsStr); } catch (error) { core.setFailed(`無法解析檔案模式: ${error instanceof Error ? error.message : String(error)}`); return; } core.info('🚀 開始執行開發決策顧問分析...'); // AI 分析模式 if (aiEnabled) { core.info('🤖 使用 AI 分析模式'); core.info(` - 提供者: ${aiProvider}`); core.info(` - 模型: ${aiModel || '預設'}`); if (!aiApiKey) { core.setFailed('啟用 AI 分析時必須提供 ai-api-key'); return; } try { // 取得 PR diff 和變更檔案列表 core.info('📥 取得 PR 變更內容...'); const diff = await getPRDiff(githubToken); const prInfo = await getPRInfo(githubToken); const prFiles = await getPRFiles(githubToken); if (!diff || diff.length === 0) { core.warning('PR 沒有程式碼變更,跳過 AI 分析'); return; } // 限制 diff 大小(避免 token 超過限制) const maxDiffLength = 50000; // 約 50KB let truncatedDiff = diff; if (diff.length > maxDiffLength) { truncatedDiff = diff.substring(0, maxDiffLength) + '\n\n... (diff 內容過長,已截斷)'; core.warning(`Diff 內容過長 (${diff.length} 字元),已截斷至 ${maxDiffLength} 字元`); } // 整合規則式分析(只針對 PR 變更的檔案) let ruleBasedAnalysis = null; if (enableModernization && prFiles && prFiles.length > 0) { try { core.info('📊 執行規則式分析(針對 PR 變更的檔案)...'); // 過濾出 JavaScript/TypeScript 檔案 const jsFiles = prFiles .filter(file => { const filename = file.filename.toLowerCase(); return filename.endsWith('.js') || filename.endsWith('.ts') || filename.endsWith('.jsx') || filename.endsWith('.tsx'); }) .map(file => file.filename); if (jsFiles.length > 0) { // 將檔案列表轉換為 glob 模式(直接使用檔案路徑作為模式) // 這樣可以只分析 PR 變更的檔案 ruleBasedAnalysis = await runModernizationAnalysis( projectPath, jsFiles, // 檔案路徑可以直接作為 glob 模式使用 excludePatterns ); core.info(`✅ 規則式分析完成,發現 ${ruleBasedAnalysis.summary.totalSuggestions} 個建議`); } } catch (error) { core.warning(`規則式分析失敗,將繼續使用 AI 分析: ${error instanceof Error ? error.message : String(error)}`); } } core.info('🧠 呼叫 AI 分析中(整合規則式分析結果)...'); const aiReport = await analyzeWithAI({ provider: aiProvider, model: aiModel, apiKey: aiApiKey, diff: truncatedDiff, ruleBasedAnalysis: ruleBasedAnalysis, changedFiles: prFiles?.map(f => f.filename) || [] }); core.info('✅ AI 分析完成'); core.setOutput('ai-report', aiReport); // 在 PR 中留言 if (githubToken && commentOnPRFlag) { try { await commentAIReport(githubToken, aiReport, aiProvider, aiModel, prInfo); core.info('✅ PR 評論已發送'); } catch (error) { core.warning(`發送 PR 評論失敗: ${error instanceof Error ? error.message : String(error)}`); } } core.info('🎉 AI 分析完成!'); return; } catch (error) { core.setFailed(`AI 分析失敗: ${error instanceof Error ? error.message : String(error)}`); return; } } // 規則式分析模式(原有邏輯) core.info('📊 使用規則式分析模式'); core.info(`📁 專案路徑: ${projectPath}`); core.info(`📝 包含模式: ${includePatterns.join(', ')}`); core.info(`🚫 排除模式: ${excludePatterns.join(', ')}`); core.info(`🔧 現代化分析: ${enableModernization ? '啟用' : '停用'}`); core.info(`🌐 相容性分析: ${enableCompatibility ? '啟用' : '停用'}`); core.info(`🔍 瀏覽器檢查: ${enableBrowserCheck ? '啟用' : '停用'}`); // 執行分析 const results = await runAllAnalyses({ projectPath, includePatterns, excludePatterns, browserslistConfig: browserslistConfig || undefined, enableModernization, enableCompatibility }); // 設定輸出 if (results.modernization) { core.setOutput('modernization-report', results.modernization.report); core.info('✅ 現代化分析完成'); core.info(` - 掃描檔案: ${results.modernization.summary.totalFiles}`); core.info(` - 發現建議: ${results.modernization.summary.totalSuggestions}`); } if (results.compatibility) { core.setOutput('compatibility-report', results.compatibility.report); core.info('✅ 相容性分析完成'); core.info(` - 分析的 API: ${results.compatibility.summary.totalApis}`); core.info(` - 整體相容性: ${results.compatibility.summary.overallCompatibility}%`); } // 生成摘要 const summary = { modernization: results.modernization?.summary || null, compatibility: results.compatibility?.summary || null, errors: results.errors }; core.setOutput('summary', JSON.stringify(summary)); // 檢查錯誤 if (results.errors.length > 0) { core.warning(`分析過程中發生 ${results.errors.length} 個錯誤:`); for (const error of results.errors) { core.warning(` - ${error.type}: ${error.error}`); } } // 在 PR 中留言 if (githubToken && commentOnPRFlag) { try { await commentOnPR(githubToken, results, commentOnPRFlag); core.info('✅ PR 評論已發送'); } catch (error) { core.warning(`發送 PR 評論失敗: ${error instanceof Error ? error.message : String(error)}`); // 不因為評論失敗而讓整個 action 失敗 } } core.info('🎉 分析完成!'); } catch (error) { core.setFailed(`執行失敗: ${error instanceof Error ? error.message : String(error)}`); if (error instanceof Error && error.stack) { core.debug(error.stack); } } } // 執行主函數 main();

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mukiwu/dev-advisor-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server