import { NodeSSH } from 'node-ssh'; import path from 'node:path'; import fs from 'node:fs'; import process from 'node:process'; const loadConfig = async () => { try { const { default: config } = await import('./.deployrc.js'); return config; } catch (error) { if (error.code !== 'ERR_MODULE_NOT_FOUND') throw error; return { host: process.env.DEPLOY_HOST, port: process.env.DEPLOY_PORT || 22, username: process.env.DEPLOY_USER, password: process.env.DEPLOY_PASSWORD, privateKey: process.env.DEPLOY_PRIVATE_KEY_PATH ? fs.readFileSync(path.resolve(process.env.DEPLOY_PRIVATE_KEY_PATH)) : null, remotePath: process.env.DEPLOY_REMOTE_PATH, cleanRemote: process.env.DEPLOY_CLEAN === 'true' }; } }; const ssh = new NodeSSH(); async function deploy() { try { const config = await loadConfig(); validateConfig(config); console.log('๐Ÿ”„ Connecting to server...'); await ssh.connect({ host: config.host, port: config.port, username: config.username, password: config.password, privateKey: config.privateKey }); console.log('๐Ÿ“‚ Ensuring remote directory exists...'); await ssh.execCommand(`mkdir -p ${config.remotePath}`); if (config.cleanRemote) { console.log('๐Ÿงน Cleaning remote directory...'); await ssh.execCommand(`rm -rf ${config.remotePath}/*`); } console.log('๐Ÿš€ Uploading files...'); const uploadResult = await ssh.putDirectory('./dist', config.remotePath, { recursive: true, concurrency: 10, tick: (localPath, remotePath, error) => { const relativePath = path.relative(process.cwd(), localPath); console[error ? 'error' : 'log'](`${error ? 'โŒ' : 'โœ…'} ${error ? 'Failed' : 'Uploaded'}: ${relativePath}`); } }); if (!uploadResult) throw new Error('Upload failed without specific error'); console.log('๐ŸŽ‰ Deployment completed successfully!'); } catch (error) { console.error('๐Ÿ”ฅ Deployment failed:', error.message); process.exit(1); } finally { ssh.dispose(); } } function validateConfig(config) { const requiredFields = ['host', 'username', 'remotePath']; const missing = requiredFields.filter((field) => !config[field]); if (missing.length) { throw new Error(`Missing required config fields: ${missing.join(', ')}`); } if (!config.password && !config.privateKey) { throw new Error('Either password or privateKey must be provided'); } } // ๆ‰ง่กŒ้ƒจ็ฝฒ deploy();