UNPKG

clicksuite

Version:

A CLI tool for managing ClickHouse database migrations with environment-specific configurations

225 lines (224 loc) 9.81 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCli = createCli; const yargs_1 = __importDefault(require("yargs")); const helpers_1 = require("yargs/helpers"); const dotenv_1 = __importDefault(require("dotenv")); const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); const chalk_1 = __importDefault(require("chalk")); const runner_1 = require("./runner"); const index_1 = require("./index"); // Load environment variables from .env file for CLI usage dotenv_1.default.config(); function createCli() { return (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv)) .option('non-interactive', { alias: 'y', type: 'boolean', description: 'Run in non-interactive mode (confirming actions automatically)', default: false, }) .option('verbose', { type: 'boolean', description: 'Show detailed SQL logs and verbose output', default: false, }) .command('init', 'Initialize Clicksuite for the current project', async (argv) => { const context = (0, index_1.getContext)(argv); try { console.log(chalk_1.default.blue(`ℹ️ Clicksuite base configuration directory: ${path.resolve(process.env.CLICKSUITE_MIGRATIONS_DIR || '.')}`)); console.log(chalk_1.default.blue(`⏳ Ensuring actual migrations (.yml files) directory exists at: ${context.migrationsDir}`)); await fs.mkdir(context.migrationsDir, { recursive: true }); console.log(chalk_1.default.green(`✅ Migrations directory for .yml files is ready at: ${context.migrationsDir}`)); const runner = new runner_1.Runner(context); await runner.init(); } catch (error) { console.error(chalk_1.default.bold.red('❌ Initialization failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('generate <name>', 'Generate a new migration file', (yargsInstance) => { return yargsInstance.positional('name', { describe: 'Name of the migration (e.g., \'create_users_table\')', type: 'string', demandOption: true, }); }, async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.generate(argv.name); } catch (error) { console.error(chalk_1.default.bold.red('❌ Migration generation failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('migrate:status', 'Show the status of all migrations', async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.status(); } catch (error) { console.error(chalk_1.default.bold.red('❌ Failed to get migration status:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('migrate', 'Run all pending migrations (equivalent to migrate:up)', async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.migrate(); } catch (error) { console.error(chalk_1.default.bold.red('❌ Migration run failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('migrate:up [migrationVersion]', 'Run pending migrations. If no version is specified, runs all pending.', (yargsInstance) => { return yargsInstance .positional('migrationVersion', { describe: 'Optional: Target migration version to run up to (inclusive).', type: 'string', }) .option('dry-run', { describe: 'Preview migrations without executing them', type: 'boolean', default: false, }); }, async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.up(argv.migrationVersion); } catch (error) { console.error(chalk_1.default.bold.red('❌ Migrate UP failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('migrate:down [migrationVersion]', 'Roll back migrations. If no version, rolls back the last applied. Otherwise, rolls back the specified version.', (yargsInstance) => { return yargsInstance .positional('migrationVersion', { describe: 'Optional: The migration version to roll back (e.g., \'20230101120000\'). If omitted, rolls back the last applied migration.', type: 'string', }) .option('dry-run', { describe: 'Preview rollbacks without executing them', type: 'boolean', default: false, }); }, async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.down(argv.migrationVersion); } catch (error) { console.error(chalk_1.default.bold.red('❌ Migrate DOWN failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('migrate:reset', 'Roll back all applied migrations and clear the migrations table (requires confirmation)', async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.reset(); } catch (error) { console.error(chalk_1.default.bold.red('❌ Migration reset failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .command('schema:load', 'Load all local migrations into the database as APPLIED without running their SQL scripts', async (argv) => { const context = (0, index_1.getContext)(argv); const runner = new runner_1.Runner(context); try { await runner.schemaLoad(); } catch (error) { console.error(chalk_1.default.bold.red('❌ Schema loading failed:'), error.message); if (error.stack && !context.nonInteractive) console.error(chalk_1.default.gray(error.stack)); process.exit(1); } }) .strict() .demandCommand(1, chalk_1.default.yellow('⚠️ Please specify a command. Use --help for available commands.')) .alias('h', 'help') .alias('v', 'version') .epilogue(chalk_1.default.gray('For more information, find the documentation at https://github.com/GamebeastGG/clicksuite')) .fail((msg, err, yargsInstance) => { if (err && err.message && !err.message.startsWith('⚠️')) { console.error(chalk_1.default.bold.red('❌ Error:'), err.message); try { const nonInteractive = !!process.env.CI; if (err.stack && !nonInteractive) console.error(chalk_1.default.gray(err.stack)); } catch (_) { } } else if (msg && !err) { console.error(chalk_1.default.red(`❌ ${msg}`)); yargsInstance.showHelp(); } process.exit(1); }); } if (require.main === module) { createCli().parse(); }