diff --git a/.gitignore b/.gitignore index 9f721fd..649a06f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules +/node_modules /test \ No newline at end of file diff --git a/config/nodecid.schema.json b/config/nodecid.schema.json index bfd93d3..227412a 100644 --- a/config/nodecid.schema.json +++ b/config/nodecid.schema.json @@ -3,7 +3,17 @@ "type": "object", "properties": { "start": { - "type": "string" + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + } + ] }, "preflight": { "anyOf": [ diff --git a/deploy/start.js b/deploy/start.js index 0fd790c..75ec8d8 100755 --- a/deploy/start.js +++ b/deploy/start.js @@ -16,21 +16,32 @@ const colors = require("../utils/console-colors"); //////////////////////////////////////////// //////////////////////////////////////////// +let redeployments = 0; + +/** @type {NodeJS.Signals | number} */ +const KILL_SIGNAL = "SIGTERM"; + +/** @type {ChildProcess | null} */ +let childProcess = null; + /** * # Start the process * @param {object} param0 * @param {string} param0.command * @param {string[] | string} param0.preflight * @param {string} param0.redeploy_file + * @param {string | number} [param0.port] */ -function startProcess({ command, preflight, redeploy_file }) { - /** @type {ChildProcess | null} */ - let childProcess = null; - +function startProcess({ command, preflight, redeploy_file, port }) { try { + console.log("First Run ..."); + const runPreflight = preflightFn(preflight); if (!preflight) { + console.log( + `${colors.FgRed}Error:${colors.Reset} No preflight included in config file. If you don't want to run any preflight command simply add an empty array.` + ); process.exit(); } @@ -42,32 +53,51 @@ function startProcess({ command, preflight, redeploy_file }) { ); process.exit(); } + + console.log("Watching", redeploy_file); + + fs.watchFile(redeploy_file, { interval: 100 }, (curr, prev) => { + console.log(`${colors.BgBlue}File Changed${colors.Reset}`); + + if (redeployments == 0) return; + + if (childProcess) { + console.log("******************************"); + console.log( + `******** ${colors.FgBlue}Rebuilding ${colors.FgMagenta}${redeployments}${colors.Reset} ********` + ); + console.log("******************************"); + + try { + const runPreflight = preflightFn(preflight); + + if (!preflight) { + console.log( + `${colors.FgRed}Error:${colors.Reset} No preflight included in config file. If you don't want to run any preflight command simply add an empty array.` + ); + process.exit(); + } + + killChild(port).then((kill) => { + if (kill) { + childProcess = run(command); + } else { + process.exit(); + } + }); + } catch (/** @type {*} */ error) { + console.log( + `${colors.FgRed}Error:${colors.Reset} killing child processes => ${error.message}` + ); + process.exit(); + } + } + }); } catch (/** @type {*} */ error) { console.log( `${colors.FgRed}Error:${colors.Reset} First run failed! => ${error.message}` ); } - - fs.watchFile(redeploy_file, { interval: 1000 }, (curr, prev) => { - if (childProcess) { - console.log("Rebuilding ..."); - - try { - const runPreflight = preflightFn(preflight); - - if (!preflight) { - process.exit(); - } - childProcess.kill("SIGTERM"); - } catch (/** @type {*} */ error) { - console.log( - `${colors.FgRed}Error:${colors.Reset} killing child processes => ${error.message}` - ); - } - - childProcess = run(command); - } - }); } //////////////////////////////////////////// @@ -80,20 +110,27 @@ function startProcess({ command, preflight, redeploy_file }) { * @returns {ChildProcess | null} */ function run(command) { + console.log("\n******************************"); + console.log( + `****** ${colors.FgGreen}Starting App ...${colors.Reset} ******` + ); + console.log("******************************\n"); + const startCommandArray = command.split(" ").filter((str) => str.trim()); try { - const firstCommand = startCommandArray.shift()?.[0]; + const firstCommand = startCommandArray.shift(); if (!firstCommand) { throw new Error("No Starting Command Found in command string!"); } - let childProcess = spawn(firstCommand, ["server.js"], { - cwd: process.cwd(), + let childProcess = spawn(firstCommand, startCommandArray, { stdio: "inherit", }); + redeployments++; + return childProcess; } catch (/** @type {*} */ error) { console.log( @@ -140,4 +177,84 @@ function preflightFn(preflight) { //////////////////////////////////////////// //////////////////////////////////////////// +/** + * ## Preflight Function + * @param {string | number} [port] + * @returns {Promise} + */ +async function killChild(port) { + if (!childProcess) return false; + + try { + childProcess.kill(KILL_SIGNAL); + const childProcessPID = childProcess.pid; + try { + if (childProcessPID) { + if (process.platform.match(/linux/i)) { + execSync(`kill -9 ${childProcessPID}`); + } + if (process.platform.match(/win/i)) { + execSync(`taskkill /F /PID ${childProcessPID}`); + } + } + } catch (error) { + console.log( + `${colors.FgYellow}WARNING:${colors.Reset} Process ${childProcessPID} couldn't be killed => ${error.message}` + ); + } + + childProcess = null; + + // await new Promise((resolve) => { + // setTimeout(() => { + // resolve(true); + // }, 1000); + // }); + + // console.log("Child Process Killed?", childProcess.killed); + + // if (childProcess.killed) { + // return true; + // } else { + // console.log( + // `${colors.FgYellow}WARNING:${colors.Reset} Child Process Not Killed` + // ); + + // console.log(childProcess); + + // let killRetries = 0; + + // while (!childProcess.killed) { + // console.log("Trying to Kill child =>", killRetries); + // killRetries++; + + // childProcess.kill(KILL_SIGNAL); + + // if (childProcess.killed) { + // return true; + // break; + // } + + // if (killRetries > 20) { + // console.log( + // `${colors.FgRed}Error:${colors.Reset} Child Process couldn't be killed!` + // ); + // process.exit(); + // } + // } + // } + + return true; + } catch (error) { + console.log( + `${colors.FgRed}Error:${colors.Reset} Child Process couldn't be killed! ${error.message}` + ); + return false; + } +} + +//////////////////////////////////////////// +//////////////////////////////////////////// +//////////////////////////////////////////// + module.exports = startProcess; diff --git a/index.js b/index.js old mode 100644 new mode 100755 index 3e4d43c..1e29542 --- a/index.js +++ b/index.js @@ -31,13 +31,18 @@ try { let redeployFile; if (!redeploy_path) { - fs.writeFileSync( - path.join(WORK_DIR, "REDEPLY"), - Date.now().toString(), - "utf-8" - ); + const defaultRedeployPath = path.join(WORK_DIR, "REDEPLOY"); + const checkExistingPath = fs.existsSync(defaultRedeployPath); - redeployFile = path.join(WORK_DIR, "REDEPLY"); + if (!checkExistingPath) { + fs.writeFileSync( + defaultRedeployPath, + Date.now().toString(), + "utf-8" + ); + } + + redeployFile = path.join(WORK_DIR, "REDEPLOY"); } else { redeployFile = path.resolve(WORK_DIR, redeploy_path); } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8da0a60 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,17 @@ +{ + "name": "nodecid", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nodecid", + "version": "1.0.0", + "license": "MIT", + "bin": { + "node-ci-cd": "index.js", + "nodecid": "index.js" + } + } + } +} diff --git a/publish.sh b/publish.sh new file mode 100755 index 0000000..bf341f5 --- /dev/null +++ b/publish.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +if [ -z "$1" ]; then + msg="Updates" +else + msg="$1" +fi + +git add . && git commit -m "$msg" && git push && npm publish \ No newline at end of file