Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions actions/setup/js/parse_mcp_gateway_log.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -197,6 +281,7 @@ if (typeof module !== "undefined" && module.exports) {
generateGatewayLogSummary,
generatePlainTextGatewaySummary,
generatePlainTextLegacySummary,
printAllGatewayFiles,
};
}

Expand Down
249 changes: 248 additions & 1 deletion actions/setup/js/parse_mcp_gateway_log.test.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check
/// <reference types="@actions/github-script" />

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.
Expand Down Expand Up @@ -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 });
}
});
});
});