1117bd0bd7
- docker-compose.test.yml: API 和 MongoDB 端口改为 expose(仅容器内部可见) - webhook-server.js: 端口改为 19001,绑定 127.0.0.1(仅本机访问) - 新增 deploy/nginx-test.conf Nginx 反向代理配置 - API: miniapp-api-test.dxz99wyr.cn → miniapp-api_test:3001 - Webhook: miniapp-api-test-webhook.dxz99wyr.cn/webhook → 127.0.0.1:19001 - 更新 setup.sh 和 README.md 文档
107 lines
3.6 KiB
JavaScript
107 lines
3.6 KiB
JavaScript
const http = require('http');
|
|
const { exec } = require('child_process');
|
|
const path = require('path');
|
|
const crypto = require('crypto');
|
|
|
|
const PORT = 19001;
|
|
const DEPLOY_DIR = '/opt/miniapp-api_test';
|
|
const COMPOSE_FILE = 'docker-compose.test.yml';
|
|
|
|
const SECRET = process.env.WEBHOOK_SECRET || 'miniapp-api-deploy-secret';
|
|
|
|
function verifySignature(payload, signature) {
|
|
const hmac = crypto.createHmac('sha256', SECRET);
|
|
const digest = 'sha256=' + hmac.update(payload).digest('hex');
|
|
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signature));
|
|
}
|
|
|
|
function runCommand(command, cwd) {
|
|
return new Promise((resolve, reject) => {
|
|
console.log(`[${new Date().toISOString()}] 执行命令: ${command}`);
|
|
const child = exec(command, { cwd, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`[${new Date().toISOString()}] 命令执行失败:`, error.message);
|
|
console.error('stderr:', stderr);
|
|
reject(error);
|
|
return;
|
|
}
|
|
console.log(`[${new Date().toISOString()}] 命令输出:\n${stdout}`);
|
|
if (stderr) console.error(`stderr: ${stderr}`);
|
|
resolve(stdout);
|
|
});
|
|
});
|
|
}
|
|
|
|
async function deploy() {
|
|
const timestamp = new Date().toISOString();
|
|
console.log(`\n========== 开始部署 miniapp-api_test [${timestamp}] ==========`);
|
|
|
|
try {
|
|
await runCommand('git fetch origin', DEPLOY_DIR);
|
|
await runCommand('git reset --hard origin/main', DEPLOY_DIR);
|
|
|
|
await runCommand(`docker-compose -f ${COMPOSE_FILE} build --no-cache`, DEPLOY_DIR);
|
|
await runCommand(`docker-compose -f ${COMPOSE_FILE} up -d`, DEPLOY_DIR);
|
|
|
|
await runCommand('docker image prune -f', DEPLOY_DIR);
|
|
|
|
console.log(`[${new Date().toISOString()}] 部署成功完成`);
|
|
return { success: true, message: '部署成功' };
|
|
} catch (error) {
|
|
console.error(`[${new Date().toISOString()}] 部署失败:`, error.message);
|
|
return { success: false, message: error.message };
|
|
}
|
|
}
|
|
|
|
const server = http.createServer(async (req, res) => {
|
|
if (req.method !== 'POST' || req.url !== '/webhook') {
|
|
res.writeHead(404);
|
|
res.end('Not Found');
|
|
return;
|
|
}
|
|
|
|
let body = '';
|
|
req.on('data', chunk => { body += chunk; });
|
|
req.on('end', async () => {
|
|
const signature = req.headers['x-hub-signature-256'] || req.headers['x-gitlab-token'];
|
|
|
|
if (SECRET !== 'your_webhook_secret_here' && signature) {
|
|
const isValid = verifySignature(body, signature);
|
|
if (!isValid) {
|
|
console.warn(`[${new Date().toISOString()}] Webhook 签名验证失败`);
|
|
res.writeHead(401);
|
|
res.end('Unauthorized');
|
|
return;
|
|
}
|
|
}
|
|
|
|
let payload;
|
|
try {
|
|
payload = JSON.parse(body);
|
|
} catch (e) {
|
|
payload = {};
|
|
}
|
|
|
|
const ref = payload.ref || payload.object_attributes?.ref || 'unknown';
|
|
console.log(`[${new Date().toISOString()}] 收到 Webhook 请求, ref: ${ref}`);
|
|
|
|
if (ref === 'refs/heads/main' || ref === 'main' || !ref.includes('refs/')) {
|
|
res.writeHead(202);
|
|
res.end(JSON.stringify({ status: 'accepted', message: '部署任务已启动' }));
|
|
|
|
const result = await deploy();
|
|
console.log(`[${new Date().toISOString()}] 部署结果:`, result);
|
|
} else {
|
|
res.writeHead(200);
|
|
res.end(JSON.stringify({ status: 'ignored', message: '非 main 分支推送, 忽略' }));
|
|
}
|
|
});
|
|
});
|
|
|
|
server.listen(PORT, '127.0.0.1', () => {
|
|
console.log(`Webhook 服务器已启动, 监听端口 ${PORT}`);
|
|
console.log(`部署目录: ${DEPLOY_DIR}`);
|
|
console.log(`接收地址: http://127.0.0.1:${PORT}/webhook`);
|
|
console.log(`Nginx 代理地址: http://your-server-ip/webhook`);
|
|
});
|