UNPKG

@git.zone/cli

Version:

A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.

518 lines (449 loc) 17.5 kB
import * as plugins from './mod.plugins.js'; import * as helpers from './helpers.js'; import { logger } from '../gitzone.logging.js'; import { DockerContainer } from './classes.dockercontainer.js'; export interface IServiceConfig { PROJECT_NAME: string; MONGODB_HOST: string; MONGODB_NAME: string; MONGODB_PORT: string; MONGODB_USER: string; MONGODB_PASS: string; MONGODB_URL: string; S3_HOST: string; S3_PORT: string; S3_CONSOLE_PORT: string; S3_ACCESSKEY: string; S3_SECRETKEY: string; S3_BUCKET: string; S3_ENDPOINT: string; S3_USESSL: boolean; ELASTICSEARCH_HOST: string; ELASTICSEARCH_PORT: string; ELASTICSEARCH_USER: string; ELASTICSEARCH_PASS: string; ELASTICSEARCH_URL: string; } export class ServiceConfiguration { private configPath: string; private config: IServiceConfig; private docker: DockerContainer; constructor() { this.configPath = plugins.path.join(process.cwd(), '.nogit', 'env.json'); this.docker = new DockerContainer(); } /** * Load or create the configuration */ public async loadOrCreate(): Promise<IServiceConfig> { await this.ensureNogitDirectory(); if (await this.configExists()) { await this.loadConfig(); await this.updateMissingFields(); } else { await this.createDefaultConfig(); } // Sync ports from existing Docker containers if they exist await this.syncPortsFromDocker(); return this.config; } /** * Get the current configuration */ public getConfig(): IServiceConfig { return this.config; } /** * Save the configuration to file */ public async saveConfig(): Promise<void> { await plugins.smartfs .file(this.configPath) .encoding('utf8') .write(JSON.stringify(this.config, null, 2)); } /** * Ensure .nogit directory exists */ private async ensureNogitDirectory(): Promise<void> { const nogitPath = plugins.path.join(process.cwd(), '.nogit'); await plugins.smartfs.directory(nogitPath).recursive().create(); } /** * Check if configuration file exists */ private async configExists(): Promise<boolean> { return plugins.smartfs.file(this.configPath).exists(); } /** * Load configuration from file */ private async loadConfig(): Promise<void> { const configContent = (await plugins.smartfs .file(this.configPath) .encoding('utf8') .read()) as string; this.config = JSON.parse(configContent); } /** * Create default configuration */ private async createDefaultConfig(): Promise<void> { const projectName = await helpers.getProjectName(); const mongoPort = await helpers.getRandomAvailablePort(); const s3Port = await helpers.getRandomAvailablePort(); let s3ConsolePort = s3Port + 1; // Ensure console port is also available while (!(await helpers.isPortAvailable(s3ConsolePort))) { s3ConsolePort++; } const mongoUser = 'defaultadmin'; const mongoPass = 'defaultpass'; const mongoHost = 'localhost'; const mongoName = projectName; const mongoPortStr = mongoPort.toString(); const s3Host = 'localhost'; const s3PortStr = s3Port.toString(); const esHost = 'localhost'; const esPort = '9200'; const esUser = 'elastic'; const esPass = 'elastic'; this.config = { PROJECT_NAME: projectName, MONGODB_HOST: mongoHost, MONGODB_NAME: mongoName, MONGODB_PORT: mongoPortStr, MONGODB_USER: mongoUser, MONGODB_PASS: mongoPass, MONGODB_URL: `mongodb://${mongoUser}:${mongoPass}@${mongoHost}:${mongoPortStr}/${mongoName}?authSource=admin`, S3_HOST: s3Host, S3_PORT: s3PortStr, S3_CONSOLE_PORT: s3ConsolePort.toString(), S3_ACCESSKEY: 'defaultadmin', S3_SECRETKEY: 'defaultpass', S3_BUCKET: `${projectName}-documents`, S3_ENDPOINT: s3Host, S3_USESSL: false, ELASTICSEARCH_HOST: esHost, ELASTICSEARCH_PORT: esPort, ELASTICSEARCH_USER: esUser, ELASTICSEARCH_PASS: esPass, ELASTICSEARCH_URL: `http://${esUser}:${esPass}@${esHost}:${esPort}` }; await this.saveConfig(); logger.log('ok', '✅ Created .nogit/env.json with project defaults'); logger.log('info', `📍 MongoDB port: ${mongoPort}`); logger.log('info', `📍 S3 API port: ${s3Port}`); logger.log('info', `📍 S3 Console port: ${s3ConsolePort}`); logger.log('info', `📍 Elasticsearch port: ${esPort}`); } /** * Update missing fields in existing configuration */ private async updateMissingFields(): Promise<void> { const projectName = await helpers.getProjectName(); let updated = false; const fieldsAdded: string[] = []; // Check and add missing fields if (!this.config.PROJECT_NAME) { this.config.PROJECT_NAME = projectName; fieldsAdded.push('PROJECT_NAME'); updated = true; } if (!this.config.MONGODB_HOST) { this.config.MONGODB_HOST = 'localhost'; fieldsAdded.push('MONGODB_HOST'); updated = true; } if (!this.config.MONGODB_NAME) { this.config.MONGODB_NAME = projectName; fieldsAdded.push('MONGODB_NAME'); updated = true; } if (!this.config.MONGODB_PORT) { const port = await helpers.getRandomAvailablePort(); this.config.MONGODB_PORT = port.toString(); fieldsAdded.push(`MONGODB_PORT(${port})`); updated = true; } if (!this.config.MONGODB_USER) { this.config.MONGODB_USER = 'defaultadmin'; fieldsAdded.push('MONGODB_USER'); updated = true; } if (!this.config.MONGODB_PASS) { this.config.MONGODB_PASS = 'defaultpass'; fieldsAdded.push('MONGODB_PASS'); updated = true; } // Always update MONGODB_URL based on current settings const oldUrl = this.config.MONGODB_URL; this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; if (oldUrl !== this.config.MONGODB_URL) { fieldsAdded.push('MONGODB_URL'); updated = true; } if (!this.config.S3_HOST) { this.config.S3_HOST = 'localhost'; fieldsAdded.push('S3_HOST'); updated = true; } if (!this.config.S3_PORT) { const port = await helpers.getRandomAvailablePort(); this.config.S3_PORT = port.toString(); fieldsAdded.push(`S3_PORT(${port})`); updated = true; } if (!this.config.S3_CONSOLE_PORT) { const s3Port = parseInt(this.config.S3_PORT); let consolePort = s3Port + 1; while (!(await helpers.isPortAvailable(consolePort))) { consolePort++; } this.config.S3_CONSOLE_PORT = consolePort.toString(); fieldsAdded.push(`S3_CONSOLE_PORT(${consolePort})`); updated = true; } if (!this.config.S3_ACCESSKEY) { this.config.S3_ACCESSKEY = 'defaultadmin'; fieldsAdded.push('S3_ACCESSKEY'); updated = true; } if (!this.config.S3_SECRETKEY) { this.config.S3_SECRETKEY = 'defaultpass'; fieldsAdded.push('S3_SECRETKEY'); updated = true; } if (!this.config.S3_BUCKET) { this.config.S3_BUCKET = `${projectName}-documents`; fieldsAdded.push('S3_BUCKET'); updated = true; } if (!this.config.S3_USESSL) { this.config.S3_USESSL = false; fieldsAdded.push('S3_USESSL'); updated = true; } // Always update S3_ENDPOINT based on current settings const oldEndpoint = this.config.S3_ENDPOINT; this.config.S3_ENDPOINT = this.config.S3_HOST; if (oldEndpoint !== this.config.S3_ENDPOINT) { fieldsAdded.push('S3_ENDPOINT'); updated = true; } if (!this.config.ELASTICSEARCH_HOST) { this.config.ELASTICSEARCH_HOST = 'localhost'; fieldsAdded.push('ELASTICSEARCH_HOST'); updated = true; } if (!this.config.ELASTICSEARCH_PORT) { this.config.ELASTICSEARCH_PORT = '9200'; fieldsAdded.push('ELASTICSEARCH_PORT'); updated = true; } if (!this.config.ELASTICSEARCH_USER) { this.config.ELASTICSEARCH_USER = 'elastic'; fieldsAdded.push('ELASTICSEARCH_USER'); updated = true; } if (!this.config.ELASTICSEARCH_PASS) { this.config.ELASTICSEARCH_PASS = 'elastic'; fieldsAdded.push('ELASTICSEARCH_PASS'); updated = true; } // Always update ELASTICSEARCH_URL based on current settings const oldEsUrl = this.config.ELASTICSEARCH_URL; this.config.ELASTICSEARCH_URL = `http://${this.config.ELASTICSEARCH_USER}:${this.config.ELASTICSEARCH_PASS}@${this.config.ELASTICSEARCH_HOST}:${this.config.ELASTICSEARCH_PORT}`; if (oldEsUrl !== this.config.ELASTICSEARCH_URL) { fieldsAdded.push('ELASTICSEARCH_URL'); updated = true; } if (updated) { await this.saveConfig(); logger.log('ok', `✅ Added missing fields: ${fieldsAdded.join(', ')}`); } else { logger.log('ok', '✅ Configuration complete'); } } /** * Get MongoDB connection string */ public getMongoConnectionString(useNetworkIp: boolean = false): string { const host = useNetworkIp ? '${networkIp}' : this.config.MONGODB_HOST; return `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${host}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; } /** * Get container names */ public getContainerNames() { return { mongo: `${this.config.PROJECT_NAME}-mongodb`, minio: `${this.config.PROJECT_NAME}-minio`, elasticsearch: `${this.config.PROJECT_NAME}-elasticsearch` }; } /** * Get data directories */ public getDataDirectories() { return { mongo: plugins.path.join(process.cwd(), '.nogit', 'mongodata'), minio: plugins.path.join(process.cwd(), '.nogit', 'miniodata'), elasticsearch: plugins.path.join(process.cwd(), '.nogit', 'esdata') }; } /** * Sync port configuration from existing Docker containers */ private async syncPortsFromDocker(): Promise<void> { const containers = this.getContainerNames(); let updated = false; // Check MongoDB container const mongoStatus = await this.docker.getStatus(containers.mongo); if (mongoStatus !== 'not_exists') { const portMappings = await this.docker.getPortMappings(containers.mongo); if (portMappings && portMappings['27017']) { const dockerPort = portMappings['27017']; if (this.config.MONGODB_PORT !== dockerPort) { logger.log('note', `📍 Syncing MongoDB port from Docker: ${dockerPort}`); this.config.MONGODB_PORT = dockerPort; updated = true; } } } // Check MinIO container const minioStatus = await this.docker.getStatus(containers.minio); if (minioStatus !== 'not_exists') { const portMappings = await this.docker.getPortMappings(containers.minio); if (portMappings) { if (portMappings['9000']) { const dockerPort = portMappings['9000']; if (this.config.S3_PORT !== dockerPort) { logger.log('note', `📍 Syncing S3 API port from Docker: ${dockerPort}`); this.config.S3_PORT = dockerPort; updated = true; } } if (portMappings['9001']) { const dockerPort = portMappings['9001']; if (this.config.S3_CONSOLE_PORT !== dockerPort) { logger.log('note', `📍 Syncing S3 Console port from Docker: ${dockerPort}`); this.config.S3_CONSOLE_PORT = dockerPort; updated = true; } } } } // Check Elasticsearch container const esStatus = await this.docker.getStatus(containers.elasticsearch); if (esStatus !== 'not_exists') { const portMappings = await this.docker.getPortMappings(containers.elasticsearch); if (portMappings && portMappings['9200']) { const dockerPort = portMappings['9200']; if (this.config.ELASTICSEARCH_PORT !== dockerPort) { logger.log('note', `📍 Syncing Elasticsearch port from Docker: ${dockerPort}`); this.config.ELASTICSEARCH_PORT = dockerPort; updated = true; } } } if (updated) { // Update derived fields this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; this.config.S3_ENDPOINT = this.config.S3_HOST; this.config.ELASTICSEARCH_URL = `http://${this.config.ELASTICSEARCH_USER}:${this.config.ELASTICSEARCH_PASS}@${this.config.ELASTICSEARCH_HOST}:${this.config.ELASTICSEARCH_PORT}`; await this.saveConfig(); logger.log('ok', '✅ Configuration synced with Docker containers'); } } /** * Validate and update ports if they're not available */ public async validateAndUpdatePorts(): Promise<boolean> { let updated = false; const containers = this.getContainerNames(); // Check if containers exist - if they do, ports are fine const mongoExists = await this.docker.exists(containers.mongo); const minioExists = await this.docker.exists(containers.minio); const esExists = await this.docker.exists(containers.elasticsearch); // Only check port availability if containers don't exist if (!mongoExists) { const mongoPort = parseInt(this.config.MONGODB_PORT); if (!(await helpers.isPortAvailable(mongoPort))) { logger.log('note', `⚠️ MongoDB port ${mongoPort} is in use, finding new port...`); const newPort = await helpers.getRandomAvailablePort(); this.config.MONGODB_PORT = newPort.toString(); logger.log('ok', `✅ New MongoDB port: ${newPort}`); updated = true; } } if (!minioExists) { const s3Port = parseInt(this.config.S3_PORT); const s3ConsolePort = parseInt(this.config.S3_CONSOLE_PORT); if (!(await helpers.isPortAvailable(s3Port))) { logger.log('note', `⚠️ S3 API port ${s3Port} is in use, finding new port...`); const newPort = await helpers.getRandomAvailablePort(); this.config.S3_PORT = newPort.toString(); logger.log('ok', `✅ New S3 API port: ${newPort}`); updated = true; } if (!(await helpers.isPortAvailable(s3ConsolePort))) { logger.log('note', `⚠️ S3 Console port ${s3ConsolePort} is in use, finding new port...`); let newPort = parseInt(this.config.S3_PORT) + 1; while (!(await helpers.isPortAvailable(newPort))) { newPort++; } this.config.S3_CONSOLE_PORT = newPort.toString(); logger.log('ok', `✅ New S3 Console port: ${newPort}`); updated = true; } } if (!esExists) { const esPort = parseInt(this.config.ELASTICSEARCH_PORT); if (!(await helpers.isPortAvailable(esPort))) { logger.log('note', `⚠️ Elasticsearch port ${esPort} is in use, finding new port...`); const newPort = await helpers.getRandomAvailablePort(); this.config.ELASTICSEARCH_PORT = newPort.toString(); logger.log('ok', `✅ New Elasticsearch port: ${newPort}`); updated = true; } } if (updated) { // Update derived fields this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; this.config.S3_ENDPOINT = this.config.S3_HOST; this.config.ELASTICSEARCH_URL = `http://${this.config.ELASTICSEARCH_USER}:${this.config.ELASTICSEARCH_PASS}@${this.config.ELASTICSEARCH_HOST}:${this.config.ELASTICSEARCH_PORT}`; await this.saveConfig(); } return updated; } /** * Force reconfigure all ports with new available ones */ public async reconfigurePorts(): Promise<void> { logger.log('note', '🔄 Finding new available ports...'); const mongoPort = await helpers.getRandomAvailablePort(); const s3Port = await helpers.getRandomAvailablePort(); let s3ConsolePort = s3Port + 1; // Ensure console port is also available while (!(await helpers.isPortAvailable(s3ConsolePort))) { s3ConsolePort++; } // Elasticsearch uses standard port 9200 const esPort = '9200'; this.config.MONGODB_PORT = mongoPort.toString(); this.config.S3_PORT = s3Port.toString(); this.config.S3_CONSOLE_PORT = s3ConsolePort.toString(); this.config.ELASTICSEARCH_PORT = esPort; // Update derived fields this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`; this.config.S3_ENDPOINT = this.config.S3_HOST; this.config.ELASTICSEARCH_URL = `http://${this.config.ELASTICSEARCH_USER}:${this.config.ELASTICSEARCH_PASS}@${this.config.ELASTICSEARCH_HOST}:${this.config.ELASTICSEARCH_PORT}`; await this.saveConfig(); logger.log('ok', '✅ New port configuration:'); logger.log('info', ` 📍 MongoDB: ${mongoPort}`); logger.log('info', ` 📍 S3 API: ${s3Port}`); logger.log('info', ` 📍 S3 Console: ${s3ConsolePort}`); logger.log('info', ` 📍 Elasticsearch: ${esPort}`); } }