UNPKG

scripts-orchestrator

Version:

A powerful script orchestrator for running parallel commands with dependency management, background processes, and health checks

115 lines (99 loc) 3.41 kB
#!/usr/bin/env node /** * @file index.js * @description CLI entry point for the scripts-orchestrator package */ import path from 'path'; import fs from 'fs'; import { Orchestrator } from './lib/index.js'; import { log } from './lib/logger.js'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; // Parse command line arguments using yargs const argv = yargs(hideBin(process.argv)) .option('verbose', { alias: 'v', type: 'boolean', description: 'Run with verbose logging', }) .option('phase', { type: 'string', description: 'Start execution from a specific phase', }) .option('phases', { type: 'string', description: 'Comma-separated list of phases to run (for optional phases)', }) .option('logFolder', { type: 'string', description: 'Specify the directory for log files', }) .option('sequential', { type: 'boolean', description: 'Run all commands sequentially instead of in parallel (for low CPU machines)', }) .option('force', { type: 'boolean', description: 'Force execution even if git state is unchanged', }) .help() .alias('h', 'help') .parse(); // Extract arguments const args = argv._; const configPath = args[0] || './scripts-orchestrator.config.js'; let startPhase = argv.phase; let logFolder = argv.logFolder; const phases = argv.phases ? argv.phases.split(',').map(p => p.trim()) : null; const sequential = argv.sequential || false; const force = argv.force || false; // Validate config file exists if (!fs.existsSync(configPath)) { log.error(`Error: Config file not found at ${configPath}`); log.error('Use --help for usage information'); process.exit(1); } // Import the config file const configFilePath = path.resolve(process.cwd(), configPath); const fileUrl = new URL(`file://${configFilePath}`).href; const commandsConfig = (await import(fileUrl)).default; // Check for start_phase in config if not provided via command line if (!startPhase && commandsConfig.start_phase) { startPhase = commandsConfig.start_phase; } // Check for log_folder in config if not provided via command line if (!logFolder && commandsConfig.log_folder) { logFolder = commandsConfig.log_folder; } // Set the log folder for the main orchestrator logs if specified if (logFolder) { log.setLogFolder(logFolder); } // Create and run the orchestrator const orchestrator = new Orchestrator(commandsConfig, startPhase, logFolder, phases, sequential, force); // Enhanced signal handlers const handleSignal = async (signal) => { log.warn(`\nReceived ${signal} signal. Cleaning up...`); try { await orchestrator.processManager.cleanup(); } catch (error) { log.error(`Cleanup failed: ${error.message}`); } process.exit(1); }; // Attach handlers for various signals process.on('SIGINT', () => handleSignal('interrupt')); process.on('SIGTERM', () => handleSignal('termination')); process.on('SIGQUIT', () => handleSignal('quit')); process.on('SIGHUP', () => handleSignal('hangup')); // Handle uncaught exceptions and rejections process.on('uncaughtException', async (error) => { log.error(`Uncaught Exception: ${error.message}`); await handleSignal('exception'); }); process.on('unhandledRejection', async (reason, promise) => { log.error(`Unhandled Rejection at: ${promise}, reason: ${reason}`); await handleSignal('rejection'); }); // Run the orchestrator orchestrator.run();