diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..85fed36 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "ostream": "cpp" + }, + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} diff --git a/README.md b/README.md index 64e8f08..a695f42 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # Simple CI/CD package for any application +[![package version](https://img.shields.io/npm/v/nodecid.svg?style=flat-square)](https://npmjs.org/package/nodecid) +[![package downloads](https://img.shields.io/npm/dm/nodecid.svg?style=flat-square)](https://npmjs.org/package/nodecid) +[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![package license](https://img.shields.io/npm/l/nodecid.svg?style=flat-square)](https://npmjs.org/package/nodecid) + Integrate a simple CI/CD process into your application without the hassle. _**NOTE:** This package needs `node` installed to work_ @@ -90,6 +95,14 @@ _NOTE:_ This also works for other languages, example: This app just runs whatever command you send it in an isolated child process, the command will be run as if being run in a terminal. +#### All Available options in `nodecid.config.json` file + +- **`start`**: _string_: The start Command +- **`preflight`**: _string | Array_: Array of commands or shell script file to run before reloading application +- **`redeploy_path`**: _string_: _Optional_: The path to trigger a redeployment. Default `./REDEPLOY` +- **`port`**: _string | number_: _Optional_: A port to kill if running a server. _NOTE_: it is important to provide this option if running a server else the process may not terminate properly +- **`first_run`**: _boolean_: _Optional_: If the preflight should run on first run. Default `false`. + ### Redeployment For continuos deployment and integration there needs to be a text file located in your project which the application can watch. Any time the content of this file is changed the application will rebuild and rerun your `start` command. diff --git a/deploy/start.js b/deploy/start.js index 5ee1dd1..a12aa22 100755 --- a/deploy/start.js +++ b/deploy/start.js @@ -11,6 +11,7 @@ const { ChildProcess, } = require("child_process"); const colors = require("../utils/console-colors"); +const kill = require("kill-port"); //////////////////////////////////////////// //////////////////////////////////////////// @@ -20,17 +21,21 @@ let redeployments = 0; /** @type {NodeJS.Signals | number} */ const KILL_SIGNAL = "SIGTERM"; +// const KILL_SIGNAL = "SIGINT"; /** @type {ChildProcess | null} */ let childProcess = null; +const pTitle = "nodecid"; +process.title = pTitle; + /** * # 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] + * @param {string | number} [param0.port] - The port to kill on rebuild * @param {boolean} [param0.first_run] - Whether to run the preflight on first run. Default `false` */ function startProcess({ command, preflight, redeploy_file, port, first_run }) { @@ -130,8 +135,13 @@ function run(command) { let childProcess = spawn(firstCommand, startCommandArray, { stdio: "inherit", + killSignal: KILL_SIGNAL, }); + // let childProcess = execSync(command, { + // stdio: "inherit", + // }); + redeployments++; return childProcess; @@ -192,7 +202,7 @@ function preflightFn(preflight) { //////////////////////////////////////////// /** - * ## Preflight Function + * ## Kill Child Process Function * @param {string | number} [port] * @returns {Promise} */ @@ -200,24 +210,12 @@ 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.kill(); - childProcess = null; + if (port) { + await kill(Number(port)); + } return true; } catch (error) { diff --git a/index.js b/index.js index fa4993c..381b4da 100755 --- a/index.js +++ b/index.js @@ -16,47 +16,64 @@ const WORK_DIR = process.cwd(); /////////////////////////////////////////////// /////////////////////////////////////////////// -try { - const configText = fs.readFileSync( - path.join(WORK_DIR, "nodecid.config.json"), - "utf-8" - ); +function run() { + try { + const configText = fs.readFileSync( + path.join(WORK_DIR, "nodecid.config.json"), + "utf-8" + ); - /** @type {NodeCIConfig} */ - const config = JSON.parse(configText); + /** @type {NodeCIConfig} */ + const config = JSON.parse(configText); - const { start, preflight, redeploy_path, first_run } = config; + const { start, preflight, redeploy_path, first_run, port } = config; - /** @type {string | undefined} */ - let redeployFile; + /** @type {string | undefined} */ + let redeployFile; - if (!redeploy_path) { - const defaultRedeployPath = path.join(WORK_DIR, "REDEPLOY"); - const checkExistingPath = fs.existsSync(defaultRedeployPath); + if (!redeploy_path) { + const defaultRedeployPath = path.join(WORK_DIR, "REDEPLOY"); + const checkExistingPath = fs.existsSync(defaultRedeployPath); - if (!checkExistingPath) { - fs.writeFileSync( - defaultRedeployPath, - Date.now().toString(), - "utf-8" - ); + if (!checkExistingPath) { + fs.writeFileSync( + defaultRedeployPath, + Date.now().toString(), + "utf-8" + ); + } + + redeployFile = path.join(WORK_DIR, "REDEPLOY"); + } else { + redeployFile = path.resolve(WORK_DIR, redeploy_path); } - redeployFile = path.join(WORK_DIR, "REDEPLOY"); - } else { - redeployFile = path.resolve(WORK_DIR, redeploy_path); + if (!redeployFile) throw new Error("Redeploy file not found!"); + + startProcess({ + command: start, + preflight, + redeploy_file: redeployFile, + first_run, + port, + }); + } catch (error) { + console.log( + `${colors.FgRed}ERROR:${colors.Reset} CI process failed! => ${error.message}` + ); } - - if (!redeployFile) throw new Error("Redeploy file not found!"); - - startProcess({ - command: start, - preflight, - redeploy_file: redeployFile, - first_run, - }); -} catch (error) { - console.log( - `${colors.FgRed}ERROR:${colors.Reset} CI process failed! => ${error.message}` - ); } + +run(); + +//////////////////////////////////////////// +//////////////////////////////////////////// +//////////////////////////////////////////// + +process.on("exit", () => { + console.log("Process exiting ..."); +}); + +process.on("beforeExit", () => { + console.log("Process Before exit ..."); +}); diff --git a/package-lock.json b/package-lock.json index 8da0a60..45ac17d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,42 @@ { "name": "nodecid", - "version": "1.0.0", + "version": "1.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nodecid", - "version": "1.0.0", + "version": "1.0.5", "license": "MIT", + "dependencies": { + "kill-port": "^2.0.1" + }, "bin": { "node-ci-cd": "index.js", "nodecid": "index.js" } + }, + "node_modules/get-them-args": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz", + "integrity": "sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==" + }, + "node_modules/kill-port": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kill-port/-/kill-port-2.0.1.tgz", + "integrity": "sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==", + "dependencies": { + "get-them-args": "1.3.2", + "shell-exec": "1.0.2" + }, + "bin": { + "kill-port": "cli.js" + } + }, + "node_modules/shell-exec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz", + "integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==" } } } diff --git a/package.json b/package.json index 8435a96..1467b13 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodecid", - "version": "1.0.5", + "version": "1.0.6", "description": "Simple CI/CD process", "main": "index.js", "bin": { @@ -13,5 +13,8 @@ "Continous Deployment" ], "author": "Benjamin Toby", - "license": "MIT" + "license": "MIT", + "dependencies": { + "kill-port": "^2.0.1" + } } diff --git a/types.d.js b/types.d.js index 333c71e..5fd8135 100644 --- a/types.d.js +++ b/types.d.js @@ -6,4 +6,5 @@ * @property {string} [redeploy_path] - The path to the file that will trigger a * redeployment if content is changed. Default file path is `./REDEPLOY` * @property {boolean} [first_run] - Whether to run the preflight on first run. Default `false` + * @property {string | number} [port] - The port to kill on reload */