UNPKG

forge-deploy-cli

Version:

Professional CLI for local deployments with automatic subdomain routing, SSL certificates, and infrastructure management

333 lines (331 loc) 11.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initCommand = initCommand; const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const inquirer_1 = __importDefault(require("inquirer")); const chalk_1 = __importDefault(require("chalk")); const types_1 = require("../types"); const config_1 = require("../services/config"); const dependencies_1 = require("../installers/dependencies"); async function initCommand(options) { console.log(chalk_1.default.blue.bold('Initializing Forge project...')); const configService = new config_1.ConfigService(); const dependencyInstaller = new dependencies_1.DependencyInstaller(); try { // Check if already initialized if (await fs_extra_1.default.pathExists('forge.config.json')) { const { overwrite } = await inquirer_1.default.prompt([{ type: 'confirm', name: 'overwrite', message: 'Forge project already initialized. Overwrite?', default: false }]); if (!overwrite) { console.log(chalk_1.default.yellow('Initialization cancelled.')); return; } } let projectName; let framework; let buildCommand; let outputDirectory; if (options.yes) { // Use defaults projectName = path_1.default.basename(process.cwd()); framework = await detectFramework(); buildCommand = getDefaultBuildCommand(framework); outputDirectory = getDefaultOutputDirectory(framework); } else { // Interactive setup const answers = await inquirer_1.default.prompt([ { type: 'input', name: 'projectName', message: 'Project name:', default: path_1.default.basename(process.cwd()), validate: (input) => input.length > 0 || 'Project name is required' }, { type: 'list', name: 'framework', message: 'Select framework:', choices: [ { name: 'Next.js', value: types_1.Framework.NEXTJS }, { name: 'React', value: types_1.Framework.REACT }, { name: 'Vue.js', value: types_1.Framework.VUE }, { name: 'Nuxt.js', value: types_1.Framework.NUXT }, { name: 'Svelte', value: types_1.Framework.SVELTE }, { name: 'Angular', value: types_1.Framework.ANGULAR }, { name: 'Express.js', value: types_1.Framework.EXPRESS }, { name: 'Fastify', value: types_1.Framework.FASTIFY }, { name: 'NestJS', value: types_1.Framework.NEST }, { name: 'Django', value: types_1.Framework.DJANGO }, { name: 'Flask', value: types_1.Framework.FLASK }, { name: 'Laravel', value: types_1.Framework.LARAVEL }, { name: 'Static Site', value: types_1.Framework.STATIC } ], default: await detectFramework() }, { type: 'input', name: 'buildCommand', message: 'Build command:', default: (answers) => getDefaultBuildCommand(answers.framework) }, { type: 'input', name: 'outputDirectory', message: 'Output directory:', default: (answers) => getDefaultOutputDirectory(answers.framework) } ]); projectName = answers.projectName; framework = answers.framework; buildCommand = answers.buildCommand; outputDirectory = answers.outputDirectory; } // Create forge.config.json const config = { projectName, framework, buildCommand, outputDirectory, environmentVariables: {} }; await configService.saveProjectConfig(config); // Install system dependencies console.log(chalk_1.default.blue('Setting up deployment dependencies...')); await dependencyInstaller.installSystemDependencies(framework); // Generate deployment templates await generateDeploymentTemplates(framework); console.log(chalk_1.default.green.bold('Project initialized successfully!')); console.log(); console.log(chalk_1.default.gray('Next steps:')); console.log(chalk_1.default.gray(' 1. forge login')); console.log(chalk_1.default.gray(' 2. forge deploy')); } catch (error) { console.error(chalk_1.default.red('Failed to initialize project:'), error); process.exit(1); } } async function detectFramework() { try { const packageJson = await fs_extra_1.default.readJSON('package.json'); const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies }; if (dependencies.next) return types_1.Framework.NEXTJS; if (dependencies.nuxt) return types_1.Framework.NUXT; if (dependencies.react) return types_1.Framework.REACT; if (dependencies.vue) return types_1.Framework.VUE; if (dependencies.svelte) return types_1.Framework.SVELTE; if (dependencies['@angular/core']) return types_1.Framework.ANGULAR; if (dependencies.express) return types_1.Framework.EXPRESS; if (dependencies.fastify) return types_1.Framework.FASTIFY; if (dependencies['@nestjs/core']) return types_1.Framework.NEST; // Check for Python frameworks if (await fs_extra_1.default.pathExists('requirements.txt')) { const requirements = await fs_extra_1.default.readFile('requirements.txt', 'utf8'); if (requirements.includes('Django')) return types_1.Framework.DJANGO; if (requirements.includes('Flask')) return types_1.Framework.FLASK; } // Check for PHP frameworks if (await fs_extra_1.default.pathExists('composer.json')) { const composer = await fs_extra_1.default.readJSON('composer.json'); if (composer.require && composer.require['laravel/framework']) { return types_1.Framework.LARAVEL; } } } catch (error) { // Ignore errors and return static as default } return types_1.Framework.STATIC; } function getDefaultBuildCommand(framework) { switch (framework) { case types_1.Framework.NEXTJS: return 'npm run build'; case types_1.Framework.REACT: return 'npm run build'; case types_1.Framework.VUE: return 'npm run build'; case types_1.Framework.NUXT: return 'npm run build'; case types_1.Framework.SVELTE: return 'npm run build'; case types_1.Framework.ANGULAR: return 'ng build --prod'; case types_1.Framework.EXPRESS: return 'npm run build'; case types_1.Framework.FASTIFY: return 'npm run build'; case types_1.Framework.NEST: return 'npm run build'; case types_1.Framework.DJANGO: return 'python manage.py collectstatic --noinput'; case types_1.Framework.FLASK: return 'pip install -r requirements.txt'; case types_1.Framework.LARAVEL: return 'composer install --no-dev && php artisan config:cache'; default: return 'echo "No build command needed"'; } } function getDefaultOutputDirectory(framework) { switch (framework) { case types_1.Framework.NEXTJS: return '.next'; case types_1.Framework.REACT: return 'build'; case types_1.Framework.VUE: return 'dist'; case types_1.Framework.NUXT: return '.nuxt'; case types_1.Framework.SVELTE: return 'public'; case types_1.Framework.ANGULAR: return 'dist'; case types_1.Framework.EXPRESS: case types_1.Framework.FASTIFY: case types_1.Framework.NEST: return 'dist'; case types_1.Framework.DJANGO: return 'staticfiles'; case types_1.Framework.FLASK: return '.'; case types_1.Framework.LARAVEL: return 'public'; default: return '.'; } } async function generateDeploymentTemplates(framework) { console.log(chalk_1.default.gray('Generating deployment templates...')); // Create .forgeignore file const forgeIgnoreContent = ` node_modules/ .git/ .env* *.log .DS_Store dist/ build/ .next/ coverage/ .nyc_output/ *.tgz *.tar.gz __pycache__/ *.pyc *.pyo *.pyd .Python .venv/ venv/ ENV/ env/ .cache/ .pytest_cache/ .coverage vendor/ storage/ .idea/ .vscode/ `.trim(); await fs_extra_1.default.writeFile('.forgeignore', forgeIgnoreContent); // Generate framework-specific configuration files switch (framework) { case types_1.Framework.NEXTJS: await generateNextJsConfig(); break; case types_1.Framework.DJANGO: await generateDjangoConfig(); break; case types_1.Framework.FLASK: await generateFlaskConfig(); break; case types_1.Framework.LARAVEL: await generateLaravelConfig(); break; } } async function generateNextJsConfig() { const ecosystem = { apps: [{ name: 'nextjs-app', script: 'npm', args: 'start', env: { NODE_ENV: 'production', PORT: 3000 }, instances: 1, exec_mode: 'cluster' }] }; await fs_extra_1.default.writeJSON('ecosystem.config.js', ecosystem, { spaces: 2 }); } async function generateDjangoConfig() { const gunicornConfig = ` bind = "0.0.0.0:8000" workers = 2 worker_class = "sync" worker_connections = 1000 max_requests = 1000 max_requests_jitter = 50 timeout = 30 keepalive = 2 `.trim(); await fs_extra_1.default.writeFile('gunicorn.conf.py', gunicornConfig); } async function generateFlaskConfig() { const gunicornConfig = ` bind = "0.0.0.0:5000" workers = 2 worker_class = "sync" worker_connections = 1000 max_requests = 1000 max_requests_jitter = 50 timeout = 30 keepalive = 2 `.trim(); await fs_extra_1.default.writeFile('gunicorn.conf.py', gunicornConfig); } async function generateLaravelConfig() { const nginxConfig = ` server { listen 80; server_name _; root /var/www/html/public; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \\.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } } `.trim(); await fs_extra_1.default.ensureDir('deploy'); await fs_extra_1.default.writeFile('deploy/nginx.conf', nginxConfig); } //# sourceMappingURL=init.js.map