exports.deployment = async (req, res) => { try { const fs = require('fs'); const path = require('path'); const { spawn } = require('child_process'); const logger = require("../services/logger"); const providedKey = (req.query.apikey || '').toString(); const BITBUCKET_API_KEY = process.env.BITBUCKET_API_KEY || ''; const EXPECTED_REPO = process.env.EXPECTED_REPO; const EXPECTED_BRANCH = process.env.EXPECTED_BRANCH; const DEPLOY_SCRIPT = process.env.DEPLOY_SCRIPT; // Utility: pick branch name from a changes object function getBranchNamesFromChanges(changes = []) { const names = []; for (const ch of changes) { if (!ch || typeof ch !== 'object') continue; if (ch.new && ch.new.name) names.push(ch.new.name); if (ch.old && ch.old.name) names.push(ch.old.name); // some payloads may have 'ref' or other places; add if needed } return names; } if (!BITBUCKET_API_KEY) { // appendLog('ERROR: Server API_KEY not configured in env.'); logger.info("Server misconfigured - API_KEY"); return res.status(500).json({ ok: false, message: 'Server misconfigured - API_KEY' }); } if (!EXPECTED_REPO) { // appendLog('ERROR: Server API_KEY not configured in env.'); logger.info("Server misconfigured - REPO"); return res.status(500).json({ ok: false, message: 'Server misconfigured - REPO ' }); } if (!EXPECTED_BRANCH) { // appendLog('ERROR: Server API_KEY not configured in env.'); logger.info("Server misconfigured - BRANCH"); return res.status(500).json({ ok: false, message: 'Server misconfigured - BRANCH ' }); } if (!DEPLOY_SCRIPT) { // appendLog('ERROR: Server API_KEY not configured in env.'); logger.info("Server misconfigured - Script"); return res.status(500).json({ ok: false, message: 'Server misconfigured - Script ' }); } if (!providedKey) { // appendLog('ERROR: Server API_KEY not configured in env.'); logger.info("API key missing"); return res.status(401).json({ ok: false, message: 'API key missing' }); } if (providedKey != BITBUCKET_API_KEY) { // appendLog('ERROR: Server API_KEY not configured in env.'); logger.info("Invalid API key"); return res.status(401).json({ ok: false, message: 'Invalid API key' }); } // ############################################################## const payload = req.body; if (!payload || typeof payload !== 'object') { logger.info('BAD_PAYLOAD: empty or invalid JSON body'); return res.status(400).json({ ok: false, message: 'Invalid payload' }); } const repoFullName = payload.repository && payload.repository.full_name; if (repoFullName !== EXPECTED_REPO) { logger.info('IGNORED: repo mismatch', 'expected=' + EXPECTED_REPO, 'got=' + repoFullName); // do nothing except log return res.status(200).json({ ok: true, action: 'ignored', reason: 'repository mismatch' }); } const changes = (payload.push && payload.push.changes) || []; const branchNames = getBranchNamesFromChanges(changes); const hasMaster = branchNames.includes(EXPECTED_BRANCH); if (!hasMaster) { logger.info('IGNORED: branch not master', 'branches=' + JSON.stringify(branchNames)); return res.status(200).json({ ok: true, action: 'ignored', reason: 'branch not as exp' }); } // All checks passed — call the deploy script if (!fs.existsSync(DEPLOY_SCRIPT)) { logger.info('ERROR: deploy script not found at', DEPLOY_SCRIPT); return res.status(500).json({ ok: false, message: 'Deploy script missing' }); } logger.info('DEPLOY_TRIGGER: repo ' + repoFullName + 'branch - ' + EXPECTED_BRANCH + 'script - ' + DEPLOY_SCRIPT); // spawn the script (non-blocking). Adjust args as required. const child = spawn(DEPLOY_SCRIPT, [], { cwd: path.dirname(DEPLOY_SCRIPT), env: process.env, detached: true, stdio: ['ignore', 'ignore', 'ignore'] // detach fully }); child.unref(); // capture output for logs // child.stdout.on('data', (d) => logger.info('SCRIPT_OUT:' + d.toString().trim())); // child.stderr.on('data', (d) => logger.info('SCRIPT_ERR:' + d.toString().trim())); // child.on('close', (code) => logger.info('SCRIPT_EXIT:' + `code=${code}`)); // child.on('error', (err) => logger.info('SCRIPT_ERROR:' + (err && err.message ? err.message : String(err))) ); // Respond immediately saying it was started with child id return res.status(200).json({ ok: true, action: 'deploy_started', pid: child.pid }); // ############################################################## } catch (err) { logger.error(err.message); logger.error(`Stack trace: ${err.stack}`); res.status(500).send({'status':"failed",'message': "Internal server error" }); } };