diff --git a/actions/setup/js/parse_mcp_gateway_log.cjs b/actions/setup/js/parse_mcp_gateway_log.cjs index f08c77aee4..91e9de17b0 100644 --- a/actions/setup/js/parse_mcp_gateway_log.cjs +++ b/actions/setup/js/parse_mcp_gateway_log.cjs @@ -12,11 +12,95 @@ const { getErrorMessage } = require("./error_helpers.cjs"); * - /tmp/gh-aw/mcp-logs/stderr.log (stderr output, fallback) */ +/** + * Prints all gateway-related files to core.info for debugging + */ +function printAllGatewayFiles() { + core.info("=== Listing All Gateway-Related Files ==="); + core.info(""); + + const gatewayDirs = ["/tmp/gh-aw/mcp-logs"]; + + for (const dir of gatewayDirs) { + if (!fs.existsSync(dir)) { + core.info(`Directory does not exist: ${dir}`); + core.info(""); + continue; + } + + core.info(`Directory: ${dir}`); + try { + const files = fs.readdirSync(dir); + if (files.length === 0) { + core.info(" (empty directory)"); + core.info(""); + continue; + } + + for (const file of files) { + const filePath = `${dir}/${file}`; + try { + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + core.info(` ${file}/ (directory)`); + } else { + core.info(` ${file} (${stats.size} bytes)`); + + // Print file content if it's a text file and not too large + if (stats.size > 0 && stats.size < 1024 * 1024) { + // Max 1MB + try { + const content = fs.readFileSync(filePath, "utf8"); + const maxOutputBytes = 10 * 1024; // 10KB limit per file + const contentToDisplay = content.length > maxOutputBytes ? content.substring(0, maxOutputBytes) : content; + const wasTruncated = content.length > maxOutputBytes; + + core.info(` --- Content of ${file} ---`); + // Split content into lines and prefix each line for readability + const lines = contentToDisplay.split("\n"); + for (const line of lines) { + core.info(` ${line}`); + } + if (wasTruncated) { + core.info(` ...`); + core.info(` (truncated, showing first ${maxOutputBytes} bytes of ${content.length} total)`); + } + core.info(` --- End of ${file} ---`); + } catch (/** @type {unknown} */ readError) { + const errorMessage = readError instanceof Error ? readError.message : String(readError); + core.info(` (could not read file as text: ${errorMessage})`); + } + } else if (stats.size === 0) { + core.info(` (empty file)`); + } else { + core.info(` (file too large to display, ${stats.size} bytes)`); + } + } + } catch (/** @type {unknown} */ statError) { + const errorMessage = statError instanceof Error ? statError.message : String(statError); + core.info(` ${file} (error reading file info: ${errorMessage})`); + } + } + } catch (/** @type {unknown} */ readError) { + const errorMessage = readError instanceof Error ? readError.message : String(readError); + core.info(` Error reading directory: ${errorMessage}`); + } + core.info(""); + } + + core.info("=== End of Gateway-Related Files ==="); + core.info(""); +} + /** * Main function to parse and display MCP gateway logs */ async function main() { try { + // First, print all gateway-related files for debugging + printAllGatewayFiles(); + const gatewayMdPath = "/tmp/gh-aw/mcp-logs/gateway.md"; const gatewayLogPath = "/tmp/gh-aw/mcp-logs/gateway.log"; const stderrLogPath = "/tmp/gh-aw/mcp-logs/stderr.log"; @@ -197,6 +281,7 @@ if (typeof module !== "undefined" && module.exports) { generateGatewayLogSummary, generatePlainTextGatewaySummary, generatePlainTextLegacySummary, + printAllGatewayFiles, }; } diff --git a/actions/setup/js/parse_mcp_gateway_log.test.cjs b/actions/setup/js/parse_mcp_gateway_log.test.cjs index c5c6dceb02..e3b3480386 100644 --- a/actions/setup/js/parse_mcp_gateway_log.test.cjs +++ b/actions/setup/js/parse_mcp_gateway_log.test.cjs @@ -1,7 +1,7 @@ // @ts-check /// -const { generateGatewayLogSummary, generatePlainTextGatewaySummary, generatePlainTextLegacySummary } = require("./parse_mcp_gateway_log.cjs"); +const { generateGatewayLogSummary, generatePlainTextGatewaySummary, generatePlainTextLegacySummary, printAllGatewayFiles } = require("./parse_mcp_gateway_log.cjs"); describe("parse_mcp_gateway_log", () => { // Note: The main() function now checks for gateway.md first before falling back to log files. @@ -322,4 +322,251 @@ Some content here.`; } }); }); + + describe("printAllGatewayFiles", () => { + const fs = require("fs"); + const path = require("path"); + const os = require("os"); + + test("prints all files in gateway directories with content", () => { + // Create a temporary directory structure + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-test-")); + const logsDir = path.join(tmpDir, "mcp-logs"); + + try { + // Create directory structure + fs.mkdirSync(logsDir, { recursive: true }); + + // Create test files + fs.writeFileSync(path.join(logsDir, "gateway.log"), "Gateway log content\nLine 2"); + fs.writeFileSync(path.join(logsDir, "stderr.log"), "Error message"); + fs.writeFileSync(path.join(logsDir, "gateway.md"), "# Gateway Summary"); + + // Mock core + const mockCore = { info: vi.fn() }; + global.core = mockCore; + + // Mock fs to redirect to our test directories + const originalExistsSync = fs.existsSync; + const originalReaddirSync = fs.readdirSync; + const originalStatSync = fs.statSync; + const originalReadFileSync = fs.readFileSync; + + fs.existsSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs") return true; + return originalExistsSync(filepath); + }); + + fs.readdirSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs") return originalReaddirSync(logsDir); + return originalReaddirSync(filepath); + }); + + fs.statSync = vi.fn(filepath => { + if (filepath.startsWith("/tmp/gh-aw/mcp-logs/")) { + const filename = filepath.replace("/tmp/gh-aw/mcp-logs/", ""); + return originalStatSync(path.join(logsDir, filename)); + } + return originalStatSync(filepath); + }); + + fs.readFileSync = vi.fn((filepath, encoding) => { + if (filepath.startsWith("/tmp/gh-aw/mcp-logs/")) { + const filename = filepath.replace("/tmp/gh-aw/mcp-logs/", ""); + return originalReadFileSync(path.join(logsDir, filename), encoding); + } + return originalReadFileSync(filepath, encoding); + }); + + // Call the function + printAllGatewayFiles(); + + // Verify the output + const infoMessages = mockCore.info.mock.calls.map(call => call[0]); + const allOutput = infoMessages.join("\n"); + + // Check header + expect(allOutput).toContain("=== Listing All Gateway-Related Files ==="); + expect(allOutput).toContain("=== End of Gateway-Related Files ==="); + + // Check directories are listed + expect(allOutput).toContain("Directory: /tmp/gh-aw/mcp-logs"); + + // Check files are listed + expect(allOutput).toContain("gateway.log"); + expect(allOutput).toContain("stderr.log"); + expect(allOutput).toContain("gateway.md"); + + // Check file contents are printed + expect(allOutput).toContain("Gateway log content"); + expect(allOutput).toContain("Error message"); + expect(allOutput).toContain("# Gateway Summary"); + + // Restore original functions + fs.existsSync = originalExistsSync; + fs.readdirSync = originalReaddirSync; + fs.statSync = originalStatSync; + fs.readFileSync = originalReadFileSync; + delete global.core; + } finally { + // Clean up test files + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + }); + + test("handles missing directories gracefully", () => { + // Mock core + const mockCore = { info: vi.fn() }; + global.core = mockCore; + + // Mock fs to return false for directory existence + const fs = require("fs"); + const originalExistsSync = fs.existsSync; + + fs.existsSync = vi.fn(() => false); + + try { + // Call the function + printAllGatewayFiles(); + + // Verify the output + const infoMessages = mockCore.info.mock.calls.map(call => call[0]); + const allOutput = infoMessages.join("\n"); + + // Check that it reports missing directories + expect(allOutput).toContain("Directory does not exist: /tmp/gh-aw/mcp-logs"); + } finally { + // Restore original functions + fs.existsSync = originalExistsSync; + delete global.core; + } + }); + + test("handles empty directories", () => { + const fs = require("fs"); + const path = require("path"); + const os = require("os"); + + // Create empty directories + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-test-")); + const logsDir = path.join(tmpDir, "mcp-logs"); + + try { + fs.mkdirSync(logsDir, { recursive: true }); + + // Mock core + const mockCore = { info: vi.fn() }; + global.core = mockCore; + + // Mock fs to use our test directories + const originalExistsSync = fs.existsSync; + const originalReaddirSync = fs.readdirSync; + + fs.existsSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs") return true; + return originalExistsSync(filepath); + }); + + fs.readdirSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs") return originalReaddirSync(logsDir); + return originalReaddirSync(filepath); + }); + + // Call the function + printAllGatewayFiles(); + + // Verify the output + const infoMessages = mockCore.info.mock.calls.map(call => call[0]); + const allOutput = infoMessages.join("\n"); + + // Check that it reports empty directories + expect(allOutput).toContain("(empty directory)"); + + // Restore original functions + fs.existsSync = originalExistsSync; + fs.readdirSync = originalReaddirSync; + delete global.core; + } finally { + // Clean up + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + }); + + test("truncates files larger than 10KB", () => { + const fs = require("fs"); + const path = require("path"); + const os = require("os"); + + // Create test directory + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-test-")); + const logsDir = path.join(tmpDir, "mcp-logs"); + + try { + fs.mkdirSync(logsDir, { recursive: true }); + + // Create a large file (15KB) + const largeContent = "A".repeat(15 * 1024); + fs.writeFileSync(path.join(logsDir, "large.log"), largeContent); + + // Mock core + const mockCore = { info: vi.fn() }; + global.core = mockCore; + + // Mock fs to use our test directories + const originalExistsSync = fs.existsSync; + const originalReaddirSync = fs.readdirSync; + const originalStatSync = fs.statSync; + const originalReadFileSync = fs.readFileSync; + + fs.existsSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs") return true; + return originalExistsSync(filepath); + }); + + fs.readdirSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs") return originalReaddirSync(logsDir); + return originalReaddirSync(filepath); + }); + + fs.statSync = vi.fn(filepath => { + if (filepath.startsWith("/tmp/gh-aw/mcp-logs/")) { + const filename = filepath.replace("/tmp/gh-aw/mcp-logs/", ""); + return originalStatSync(path.join(logsDir, filename)); + } + return originalStatSync(filepath); + }); + + fs.readFileSync = vi.fn((filepath, encoding) => { + if (filepath.startsWith("/tmp/gh-aw/mcp-logs/")) { + const filename = filepath.replace("/tmp/gh-aw/mcp-logs/", ""); + return originalReadFileSync(path.join(logsDir, filename), encoding); + } + return originalReadFileSync(filepath, encoding); + }); + + // Call the function + printAllGatewayFiles(); + + // Verify the output + const infoMessages = mockCore.info.mock.calls.map(call => call[0]); + const allOutput = infoMessages.join("\n"); + + // Check that file was truncated + expect(allOutput).toContain("..."); + expect(allOutput).toContain("truncated"); + expect(allOutput).toContain("10240 bytes"); + expect(allOutput).toContain("15360 total"); + + // Restore original functions + fs.existsSync = originalExistsSync; + fs.readdirSync = originalReaddirSync; + fs.statSync = originalStatSync; + fs.readFileSync = originalReadFileSync; + delete global.core; + } finally { + // Clean up + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + }); + }); });