asinkj-ui/deploy.js

91 lines
2.7 KiB
JavaScript
Raw Permalink Normal View History

2025-04-12 11:09:40 +08:00
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();