UNPKG

cfn-forge

Version:

CloudFormation deployment automation tool with git-based workflows

190 lines (161 loc) โ€ข 5.88 kB
/** * Global Error Handler for CFN-Forge CLI * Catches unhandled errors and provides helpful guidance */ const { logger } = require('./logger'); const { handleAWSError } = require('./aws-error-parser'); /** * Setup global error handlers */ function setupGlobalErrorHandlers() { // Handle uncaught exceptions process.on('uncaughtException', (error) => { logger.section('Uncaught Exception'); logger.errorWithContext(error, 'Uncaught Exception'); logger.info('\n๐Ÿ’ฅ CFN-Forge encountered an unexpected error'); logger.info('๐Ÿ™ Please report this issue at: https://github.com/dmleblanc/cfn-forge/issues'); if (error.code && error.code.includes('AWS')) { handleAWSError(error, 'Global Handler'); } logger.reportErrorSummary(); // Give time for logs to flush setTimeout(() => { process.exit(1); }, 100); }); // Handle unhandled promise rejections process.on('unhandledRejection', (reason, promise) => { logger.section('Unhandled Promise Rejection'); const error = reason instanceof Error ? reason : new Error(String(reason)); logger.errorWithContext(error, 'Unhandled Promise Rejection'); logger.info('\n๐Ÿ’ฅ CFN-Forge encountered an unhandled promise rejection'); logger.info('๐Ÿ” This usually indicates a missing .catch() or try/catch block'); if (error.code && error.code.includes('AWS')) { handleAWSError(error, 'Promise Rejection'); } logger.reportErrorSummary(); // Give time for logs to flush setTimeout(() => { process.exit(1); }, 100); }); // Handle SIGINT (Ctrl+C) gracefully process.on('SIGINT', () => { logger.info('\n\n๐Ÿ›‘ CFN-Forge interrupted by user'); logger.info('๐Ÿ‘‹ Goodbye!'); process.exit(0); }); // Handle SIGTERM gracefully process.on('SIGTERM', () => { logger.info('\n\n๐Ÿ›‘ CFN-Forge terminated'); logger.info('๐Ÿงน Cleaning up...'); process.exit(0); }); // Handle exit event process.on('exit', (code) => { if (code !== 0 && logger.errorHistory && logger.errorHistory.length > 0) { // Final error summary on non-zero exit const errorCount = logger.errorHistory.length; console.error(`\nโŒ CFN-Forge exited with ${errorCount} error${errorCount > 1 ? 's' : ''}`); if (process.env.DEBUG) { logger.reportErrorSummary(); } else { console.error('๐Ÿ’ก Run with DEBUG=1 for detailed error information'); } } }); } /** * Create error context for commands */ function createCommandContext(commandName, options = {}) { return { command: commandName, timestamp: new Date().toISOString(), cwd: process.cwd(), nodeVersion: process.version, platform: process.platform, arch: process.arch, env: { DEBUG: process.env.DEBUG, CFN_FORGE_DEBUG: process.env.CFN_FORGE_DEBUG, AWS_REGION: process.env.AWS_REGION, AWS_DEFAULT_REGION: process.env.AWS_DEFAULT_REGION, AWS_PROFILE: process.env.AWS_PROFILE, }, options, }; } /** * Wrap command functions with enhanced error handling */ function withCommandErrorHandling(commandName, commandFn) { return async (...args) => { const context = createCommandContext(commandName, args[args.length - 1]); logger.setContext('commandContext', context); try { const startTime = Date.now(); logger.debug(`Starting command: ${commandName}`); const result = await commandFn(...args); const duration = Date.now() - startTime; logger.debug(`Command completed: ${commandName} (${logger.formatDuration(duration)})`); return result; } catch (error) { // Enhanced error handling for common error types if (error.code && error.code.includes('AWS')) { handleAWSError(error, `${commandName} Command`); } else if (error.code === 'ENOENT') { logger.errorWithContext(error, `${commandName} Command - File Not Found`); logger.info('\n๐Ÿ’ก Common file issues:'); logger.info(' โ€ข Check file paths in your configuration'); logger.info(' โ€ข Ensure you\'re in the correct directory'); logger.info(' โ€ข Run `cfn-forge init` if this is a new project'); } else if (error.code === 'EACCES') { logger.errorWithContext(error, `${commandName} Command - Permission Denied`); logger.info('\n๐Ÿ’ก Permission issues:'); logger.info(' โ€ข Check file/directory permissions'); logger.info(' โ€ข Run with appropriate user privileges'); logger.info(' โ€ข Ensure files are not locked by other processes'); } else { logger.errorWithContext(error, `${commandName} Command`); } throw error; } finally { logger.clearContext(); } }; } /** * Display system information for debugging */ function displaySystemInfo() { if (!logger.debugEnabled) return; logger.debug('System Information:'); logger.debug(` Node.js: ${process.version}`); logger.debug(` Platform: ${process.platform} ${process.arch}`); logger.debug(` CWD: ${process.cwd()}`); logger.debug(` User: ${process.env.USER || process.env.USERNAME || 'unknown'}`); logger.debug(` Shell: ${process.env.SHELL || 'unknown'}`); // AWS Environment const awsVars = [ 'AWS_REGION', 'AWS_DEFAULT_REGION', 'AWS_PROFILE', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', ]; logger.debug('AWS Environment:'); awsVars.forEach((varName) => { const value = process.env[varName]; if (value) { // Mask sensitive values const maskedValue = varName.includes('KEY') || varName.includes('SECRET') ? `${value.substring(0, 4)}****` : value; logger.debug(` ${varName}: ${maskedValue}`); } }); } module.exports = { setupGlobalErrorHandlers, createCommandContext, withCommandErrorHandling, displaySystemInfo, };