diff --git a/.bithoundrc b/.bithoundrc index e54a40fc5..94a26fe14 100644 --- a/.bithoundrc +++ b/.bithoundrc @@ -5,6 +5,6 @@ "**/examples/**" ], "critics": { - "lint": {"engine": "semistandard"} + "lint": {"engine": "eslint"} } } diff --git a/.changelogrc b/.changelogrc new file mode 100644 index 000000000..b18dc0254 --- /dev/null +++ b/.changelogrc @@ -0,0 +1,61 @@ +{ + "app_name": "", + "logo": "", + "intro": "", + "branch" : "development", + "repo_url": "https://github.com/Unitech/pm2", + "version_name" : "v2.10.1", + "tag": "2.10.0", + "file": "currentTagChangelog.md", + "template": "changelogTemplate.md", + "sections": [ + { + "title": "Bug Fixes", + "grep": "^fix" + }, + { + "title": "Hot Fixes", + "grep": "^hotfix" + }, + { + "title": "Features", + "grep": "^feat" + }, + { + "title": "Documentation", + "grep": "^docs" + }, + { + "title": "Breaking changes", + "grep": "BREAKING" + }, + { + "title": "Refactor", + "grep": "^refactor" + }, + { + "title": "Performance improvement", + "grep": "^perf" + }, + { + "title": "Style", + "grep": "^style" + }, + { + "title": "Test", + "grep": "^test" + }, + { + "title": "Chore", + "grep": "^chore" + }, + { + "title": "Branchs merged", + "grep": "^Merge branch" + }, + { + "title" : "Pull requests merged", + "grep": "^Merge pull request" + } + ] +} diff --git a/.drone.yml b/.drone.yml index e3ec8d34e..89a44e2de 100644 --- a/.drone.yml +++ b/.drone.yml @@ -20,7 +20,6 @@ pipeline: image: keymetrics/alpine-pm2-builder:latest environment: - AWS_REPO_BUCKET=alpine-apk.pm2.io - - PM2_TARGET_VERSION=2.7.2 secrets: ['apk_rsa_priv_key', 'apk_rsa_pub_key', 'aws_access_key_id', 'aws_secret_access_key'] when: event: tag diff --git a/.gitignore b/.gitignore index 7903de4bc..31e1bf66d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ /node_modules *.log -*.log *.pid test/child *.iml @@ -15,3 +14,4 @@ package-lock.json .DS_Store *.swp *.swo +currentTagChangelog.md diff --git a/.travis.yml b/.travis.yml index d76fc89cc..25b0a3678 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "4" - "6" - "8" - - "0.12" os: - linux before_install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 929e87b84..856ceb671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,162 @@ +## v2.10.1 ( Mon Feb 26 2018 11:38:18 GMT+0100 (CET) ) + + +## Bug Fixes + - restore --raw option #3476 + ([340011ca](https://github.com/Unitech/pm2/commit/340011cace2b90c2a1ead8d86baba517f5570e15)) + + +## v2.10.0 ( Mon Feb 19 2018 14:51:19 GMT+0100 (CET) ) + + +### Bug Fixes + - add livescript in default modules + ([a315eeb6](https://github.com/Unitech/pm2/commit/a315eeb65f04b22643a903f0cb1c0f416615ad8b)) + - replace dash with underscore + ([203df768](https://github.com/Unitech/pm2/commit/203df7688ca348967c00bc45289ae70fd2c4aaaa)) + - make sure not pm2 is running + ([bd798fd7](https://github.com/Unitech/pm2/commit/bd798fd748665e935db4bb91f9d1d66952d9842a)) + - auto-exit edge case fix + pm2 no daemon mode + log in raw by default + less logs + ([704ae518](https://github.com/Unitech/pm2/commit/704ae518f5d7df0a631349e518d81cef51249a58)) + - impact v8 flag in fork mode also + ([41bf6ef7](https://github.com/Unitech/pm2/commit/41bf6ef7d3633180b4c1e90f36eb206d82fab2b1)) + - fixup! #2182 Get rid of annoying popups in Windows 10 + ([3a85b59d](https://github.com/Unitech/pm2/commit/3a85b59de4a76796ad0880368d8d085a7ba55d36)) + + + + +### Hot Fixes + - \#3420 ([673acf36](https://github.com/Unitech/pm2/commit/673acf36b4ca1fd65c5135a92d56081f76237a8b)) + + + + +### Features + - add dependencies section into ecosystem.json file. + ([828a30d0](https://github.com/Unitech/pm2/commit/828a30d0ccc88b3f6e2b66d517ccf5f2394bd08b)) + - --deep-monitoring available from pm2-runtime + ([99e62e3b](https://github.com/Unitech/pm2/commit/99e62e3bb808f071d6e4850c234b34f7de65b1c2)) + - add deep_metrics to deep_monitoring flag + ([4d1bea5e](https://github.com/Unitech/pm2/commit/4d1bea5e0bbaab1f16f75d012bca25702cdff88e)) + - add flag to enable deep-monitoring + ([c5418688](https://github.com/Unitech/pm2/commit/c541868837a1c4421394de5dd1029d2619b5ac82)) + - allow pm2 to install a set of module as one single command and add deep-monitoring. + ([9dddc80d](https://github.com/Unitech/pm2/commit/9dddc80db5e496def44d4d36716b7de54e5171cf)) + - pm2 pid command + ([6687d499](https://github.com/Unitech/pm2/commit/6687d499415151bd62489fed5331f414576ec354)) + - allow pm2 to install and enable event-loop-inspector data collecting + ([e6b0c474](https://github.com/Unitech/pm2/commit/e6b0c47443d3e6a839bf29057ef0a80ef135c47e)) + - ignore signal when running in --no-daemon + ([b9c01c99](https://github.com/Unitech/pm2/commit/b9c01c99d54aba98ab790b8888500ac0f0af05c9)) + - upgrade pmx to git development branch + ([21be05a0](https://github.com/Unitech/pm2/commit/21be05a07bd93eacaddedde3b647c16468937473)) + - allow pm2 to enable v8 data collecting from pmx + ([aa180fa8](https://github.com/Unitech/pm2/commit/aa180fa8ab47f0c687d7c21854d005ad0ebf8475)) + - allow pm2 to install gc-stats + ([15634168](https://github.com/Unitech/pm2/commit/15634168582e4c7b3c5f47a3f58a0fcf8b732a76)) + - feat add changelog generation support + ([14f53fc0](https://github.com/Unitech/pm2/commit/14f53fc0c28be4084778785aeace3763ed0d827f)) + + - **pm2** + - add pm2 init option to generate an ecosystem file + ([5d56fac7](https://github.com/Unitech/pm2/commit/5d56fac7cc12590af29ee46c68ba32a82a2b813b)) + - add pm2 init option to generate an ecosystem file + ([a38fd199](https://github.com/Unitech/pm2/commit/a38fd199b90d27a2405f8cabab0e4f6e45c69b08)) + + + + +### Documentation + - add documentation on new pm2 install command + ([c90c453f](https://github.com/Unitech/pm2/commit/c90c453f85b07adb346bc55c2b685d689a2e96f7)) + - add sendDataToProcessId into typescript definitions + ([4a2e8d2d](https://github.com/Unitech/pm2/commit/4a2e8d2d2c4b38fe0ff2377dfe32fce9a43c8044)) + + + + +### Refactor + - delete all "if" condition when installing new module, create an object with all modules and a generic installation process + ([1b92a9c4](https://github.com/Unitech/pm2/commit/1b92a9c4000734367e68d8dbd60d0901009f4c56)) + - deep pm2-runtime refactor #3408 #3257 #3266 + ([c13b2364](https://github.com/Unitech/pm2/commit/c13b23648269529a1f998d816be10f895665861e)) + - no more interactive spinner for connection to KM + change pm2 log format + remove some logs + ([d1916f40](https://github.com/Unitech/pm2/commit/d1916f40962b2cc8a1866172eab7d5d89db093be)) + + + + +### Chore + - pmx to 1.6.3-rc2 + ([41815e0b](https://github.com/Unitech/pm2/commit/41815e0ba0298979f936b3d4badb196f8d9783d8)) + - switch pmx to development + ([748019d1](https://github.com/Unitech/pm2/commit/748019d1ef0cf760b5e8de9d5b6af6fee300db02)) + - 2.10.0-beta + ([0d2b7172](https://github.com/Unitech/pm2/commit/0d2b7172a093d0638deabb5f23383cc9eec5dda9)) + - upgrade pmx to 1.6.3-next + ([5a1b4343](https://github.com/Unitech/pm2/commit/5a1b4343cc1e1f5018e21451a111340351706213)) + - upgrade pmx dep + ([4bbeec3d](https://github.com/Unitech/pm2/commit/4bbeec3d170ba63af0c0ae0e2d07beec2ab49772)) + - switch to published pmx(@next) + ([859d18fb](https://github.com/Unitech/pm2/commit/859d18fbc79e2a2760fe90e9c17e71209f8177ce)) + - remove --exit from mocha.opts + ([36bf03e1](https://github.com/Unitech/pm2/commit/36bf03e1eed69a27e518151e2f7aa958b15db2fb)) + - remove unused files + ([65d233e5](https://github.com/Unitech/pm2/commit/65d233e5b5290f65796b7cf3daa20706e0f3bee6)) + + + + +### Branchs merged + - Merge branch 'development' of ssh://github.com/deltasource/pm2 into hotfix/scoped-package-support + ([94ea9d9e](https://github.com/Unitech/pm2/commit/94ea9d9eeff40faca8aa9f7edfc81aa29c08e740)) + - Merge branch 'master' into development + ([46606903](https://github.com/Unitech/pm2/commit/46606903f25d0f4d0eee226da863e20e4b396dc9)) + - Merge branch 'development' of github.com:Unitech/pm2 into v8_option + ([757562f7](https://github.com/Unitech/pm2/commit/757562f755b09124bbd006209ae38a096d692529)) + - Merge branch 'development' of github.com:Unitech/pm2 into gc-stats + ([3ed1a747](https://github.com/Unitech/pm2/commit/3ed1a7471aec7d79f7d604447ac7445720bdaced)) + - Merge branch 'master' into development + ([ee7651e4](https://github.com/Unitech/pm2/commit/ee7651e47e944c3c829933494c6cc765deb4bb29)) + + + + +### Pull requests merged + - Merge pull request #3466 from natcl/development + ([c6d7ace8](https://github.com/Unitech/pm2/commit/c6d7ace802e667def75bc68344effa4856830fb4)) + - Merge pull request #3464 from andyfleming/patch-1 + ([dd9ebb60](https://github.com/Unitech/pm2/commit/dd9ebb6051708ee5a13cc68dbcb8238e41860bb9)) + - Merge pull request #3459 from rmonnier/master + ([46948a98](https://github.com/Unitech/pm2/commit/46948a98e90c7864f7b8100db5c519fe9d37f11a)) + - Merge pull request #3458 from Unitech/pm2_install_command + ([f3b35726](https://github.com/Unitech/pm2/commit/f3b35726895bd82b92813f308b787d68e9df1fa4)) + - Merge pull request #3453 from deltasource/hotfix/scoped-package-support + ([974f9bf0](https://github.com/Unitech/pm2/commit/974f9bf0dc7a7aa7ff6860f8640da3593b802296)) + - Merge pull request #3448 from Unitech/deep_monitoring_flag + ([331bc741](https://github.com/Unitech/pm2/commit/331bc741d7285094738a91cd816bc9755cc76605)) + - Merge pull request #3447 from Unitech/deep-monitoring + ([719d328e](https://github.com/Unitech/pm2/commit/719d328e8d14871b34fd33df54fd80f4f8e7825f)) + - Merge pull request #3443 from Unitech/event-loop-inspector + ([77a35274](https://github.com/Unitech/pm2/commit/77a3527407f3d090c7a5fa0bedaf943a7536b5eb)) + - Merge pull request #3442 from Unitech/event-loop-inspector + ([dad98e6e](https://github.com/Unitech/pm2/commit/dad98e6e0738983717fee155ff0f6519955ffc1b)) + - Merge pull request #3424 from Unitech/sendDataToProcessId_def + ([95e85eef](https://github.com/Unitech/pm2/commit/95e85eef84510dddfb0c6b13f0ada38a7dd66cae)) + - Merge pull request #3438 from Unitech/v8_option + ([e46b15dc](https://github.com/Unitech/pm2/commit/e46b15dc32c18e8b24f66da0c79cc06f91cf11b5)) + - Merge pull request #3437 from Unitech/gc-stats + ([1a6771aa](https://github.com/Unitech/pm2/commit/1a6771aa361bb5718bafd6e33e616725f9c0d328)) + - Merge pull request #3400 from toddwong/windowsHide2 + ([f65e8794](https://github.com/Unitech/pm2/commit/f65e8794df6e67f4ff60dfbec7c05a37721cb6f9)) + - Merge pull request #3421 from Unitech/generate_changelog + ([b0690618](https://github.com/Unitech/pm2/commit/b0690618d940c11e28eeb5115c060bf363c7b62b)) + - Merge pull request #3419 from Rohja/fix-build-number-deb-rpm + ([b4343de2](https://github.com/Unitech/pm2/commit/b4343de2703fce03f3cf48cc303b12bc6b69b743)) + + + ## 2.9.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cc70eea70..83fa8beac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,29 @@ When you modify the Daemon (lib/Daemon.js, lib/God.js, lib/God/*, lib/Watcher.js $ pm2 update ``` +## Commit rules + +### Commit message + +A good commit message should describe what changed and why. + +It should : + * contain a short description of the change (preferably 50 characters or less) + * be entirely in lowercase with the exception of proper nouns, acronyms, and the words that refer to code, like function/variable names + * be prefixed with one of the following word + * fix : bug fix + * hotfix : urgent bug fix + * feat : new or updated feature + * docs : documentation updates + * BREAKING : if commit is a breaking change + * refactor : code refactoring (no functional change) + * perf : performance improvement + * style : UX and display updates + * test : tests and CI updates + * chore : updates on build, tools, configuration ... + * Merge branch : when merging branch + * Merge pull request : when merging PR + ## Tests There are two tests type. Programmatic and Behavioral. diff --git a/bin/pm2 b/bin/pm2 index c97798997..05072f4bc 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -85,6 +85,9 @@ commander.version(pkg.version) .option('--disable-trace', 'disable transaction tracing with km') .option('--attach', 'attach logging after your start/restart/stop/reload') .option('--sort ', 'sort process according to field\'s name') + .option('--v8', 'enable v8 data collecting') + .option('--event-loop-inspector', 'enable event-loop-inspector dump in pmx') + .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)') .usage('[cmd] app'); commander.on('--help', function() { @@ -309,6 +312,12 @@ commander.command('startOrReload ') pm2._startJson(file, commander, 'reloadProcessId'); }); +commander.command('pid [app_name]') + .description('return pid of [app_name] or all') + .action(function(app) { + pm2.getPID(app); + }); + commander.command('startOrGracefulReload ') .description('start or gracefully reload JSON file') .action(function(file) { @@ -455,11 +464,11 @@ commander.command('update') /** * Module specifics */ -commander.command('install ') +commander.command('install [module|git:// url|json]') .alias('module:install') .option('--v1', 'install module in v1 manner (do not use it)') .option('--safe [time]', 'keep module backup, if new module fail = restore with previous') - .description('install or update a module and run it forever') + .description('install or update a module (or a set of modules) and run it forever') .action(function(plugin_name, opts) { if (opts.v1) commander.v1 = true; diff --git a/changelogTemplate.md b/changelogTemplate.md new file mode 100644 index 000000000..b82e71d2c --- /dev/null +++ b/changelogTemplate.md @@ -0,0 +1,13 @@ +<% if(logo) { %>pm2 logo <% } %> +<% if(logo) { %># <%= title %> <% } %> +<% if(intro) { %><%= '\n' %><%= intro %><%= '\n' %><% } %> +<% if(version && (version.name || version.number)) { %>##<% if(version.name){%> <%= version.name %><% } %> <% if(version.date){ %>( <%= version.date %> )<% } %><%= '\n' %><% } %> +<% _.forEach(sections, function(section){ + if(section.commitsCount > 0) { %> +## <%= section.title %> +<% _.forEach(section.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %> +<% _.forEach(section.components, function(component){ %> - **<%= component.name %>** +<% _.forEach(component.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %> +<% }) %> +<% } %> +<% }) %> diff --git a/constants.js b/constants.js index b569670bc..c86f87720 100644 --- a/constants.js +++ b/constants.js @@ -28,6 +28,7 @@ var csts = { TEMPLATE_FOLDER : p.join(__dirname, 'lib/templates'), + APP_CONF_DEFAULT_FILE : 'ecosystem.json', APP_CONF_TPL : 'ecosystem.tpl', APP_CONF_TPL_SIMPLE : 'ecosystem-simple.tpl', SAMPLE_CONF_FILE : 'sample-conf.js', diff --git a/lib/API.js b/lib/API.js index bcb5073bc..59bc227f1 100644 --- a/lib/API.js +++ b/lib/API.js @@ -668,6 +668,10 @@ API.prototype._startScript = function(script, opts, cb) { else app_conf.exec_mode = 'fork'; + // Options set via environment variables + if (process.env.PM2_DEEP_MONITORING) + app_conf.deep_monitoring = true; + if (typeof app_conf.name == 'function'){ delete app_conf.name; } @@ -1450,6 +1454,10 @@ API.prototype._handleAttributeUpdate = function(opts) { delete appConf.watch } + // Options set via environment variables + if (process.env.PM2_DEEP_MONITORING) + appConf.deep_monitoring = true; + // Force deletion of defaults values set by commander // to avoid overriding specified configuration by user if (appConf.treekill === true) diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 0c017ab6e..00f445dde 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -117,6 +117,34 @@ module.exports = function(CLI) { }); }; + CLI.prototype.getPID = function(app_name, cb) { + var that = this; + + if (typeof(app_name) === 'function') { + cb = app_name; + app_name = null; + } + + this.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError(cst.PREFIX_MSG_ERR + err); + return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT); + } + + var pids = []; + + list.forEach(function(app) { + if (!app_name || app_name == app.name) + pids.push(app.pid); + }) + + if (!cb) { + Common.printOut(pids.join("\n")) + return that.exitCli(cst.SUCCESS_EXIT); + } + return cb(null, pids); + }) + } /** * Create PM2 memory snapshot * @method getVersion diff --git a/lib/API/Log.js b/lib/API/Log.js index 1e1c552c0..37ad02974 100644 --- a/lib/API/Log.js +++ b/lib/API/Log.js @@ -194,34 +194,42 @@ Log.devStream = function(Client, id, raw, timestamp, exclusive) { }); }; -Log.jsonStream = function(Client, app_name) { +Log.jsonStream = function(Client, id) { var that = this; Client.launchBus(function(err, bus) { if (err) console.error(err); bus.on('process:event', function(packet) { - console.log(JSON.stringify({ + process.stdout.write(JSON.stringify({ timestamp : moment(packet.at), type : 'process_event', status : packet.event, app_name : packet.process.name })); + process.stdout.write('\n'); }); bus.on('log:*', function(type, packet) { - if (app_name != 'all' && app_name && app_name != packet.process.name) return false; + if (id !== 'all' + && packet.process.name != id + && packet.process.pm_id != id) + return; + + if (type === 'PM2') + return; if (typeof(packet.data) == 'string') packet.data = packet.data.replace(/(\r\n|\n|\r)/gm,''); - console.log(JSON.stringify({ + process.stdout.write(JSON.stringify({ message : packet.data, timestamp : moment(packet.at), type : type, process_id : packet.process.pm_id, app_name : packet.process.name })); + process.stdout.write('\n'); }); }); }; diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 00e7e3988..7093324bf 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -21,6 +21,20 @@ var mkdirp = require('mkdirp'); var MODULE_CONF_PREFIX = 'module-db-v2'; +var KNOWN_MODULES = { + 'deep-monitoring': { + dependencies: [{name: 'v8-profiler-node8'}, {name: 'gc-stats'}, {name: 'event-loop-inspector'}] + }, + 'gc-stats': {name: 'gc-stats'}, + 'event-loop-inspector': {name: 'event-loop-inspector'}, + 'v8-profiler': {name: 'v8-profiler-node8'}, + 'profiler': {name: 'v8-profiler-node8'}, + 'typescript': {dependencies: [{name: 'typescript'}, {name: 'ts-node@latest'}]}, + 'livescript': {name: 'livescript'}, + 'coffee-script': {name: 'coffee-script', message: 'Coffeescript v1 support'}, + 'coffeescript': {name: 'coffeescript', message: 'Coffeescript v2 support'} +}; + /** * PM2 Module System. * Features: @@ -32,74 +46,100 @@ var MODULE_CONF_PREFIX = 'module-db-v2'; * - Auto discover script to launch (first it checks the apps field, then bin and finally main attr) * - Generate sample module via pm2 module:generate */ -Modularizer.install = function(CLI, module_name, opts, cb) { - Common.printOut(cst.PREFIX_MSG_MOD + 'Installing module ' + module_name); +Modularizer.install = function (CLI, moduleName, opts, cb) { + // if user want to install module from ecosystem.json file + // it can also be a custom json file's name + if (!moduleName || moduleName.length === 0 || moduleName.indexOf('.json') > 0) { + var file = moduleName || cst.APP_CONF_DEFAULT_FILE; + var isAbsolute = require('../../tools/IsAbsolute.js')(file); + var filePath = isAbsolute ? file : path.join(CLI.cwd, file); - var canonic_module_name = Utility.getCanonicModuleName(module_name); + try { + var data = fs.readFileSync(filePath); + } catch (e) { + Common.printError(cst.PREFIX_MSG_ERR + 'File ' + file + ' not found'); + return cb(Common.retErr(e)); + } - if (module_name == 'v8-profiler' || module_name == 'profiler') { - installLangModule('v8-profiler-node8', function(err) { - if (err) { - Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green('Profiling installation has FAILED (checkout previous logs)')); - return cb(err); - } + try { + var config = Common.parseConfig(data, file); + } catch (e) { + Common.printError(cst.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); + console.error(e); + return cb(Common.retErr(e)); + } - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('V8 profiling ENABLED')); - return cb(); - }); - return false; + Modularizer.installMultipleModules(config.dependencies, cb); + return; } - if (module_name.indexOf('typescript') > -1) { - // Special dependency install - return installLangModule(module_name, function(e) { - installLangModule('ts-node@latest', function(e) { - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Typescript support enabled')); - return cb(e); - }); - }); - } + Common.printOut(cst.PREFIX_MSG_MOD + 'Installing module ' + moduleName); - if (module_name == 'livescript') { - return installLangModule('livescript', function(e) { - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Livescript support enabled')); - return cb(e); - }); - } + var canonicModuleName = Utility.getCanonicModuleName(moduleName); - if (module_name.indexOf('coffee-script') > -1) { - return installLangModule(module_name, function(e) { - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Coffeescript v1 support enabled')); - return cb(e); - }); - } + if (KNOWN_MODULES.hasOwnProperty(moduleName)) { + var currentModule = KNOWN_MODULES[moduleName]; - if (module_name.indexOf('coffeescript') > -1) { - return installLangModule(module_name, function(e) { - Common.printOut(cst.PREFIX_MSG + chalk.bold.green('Coffeescript v2 support enabled')); - return cb(e); - }); + if (currentModule && currentModule.hasOwnProperty('dependencies')) { + Modularizer.installMultipleModules(currentModule.dependencies, cb); + } else { + installModuleByName(currentModule, cb); + } + + return false; } - moduleExist(CLI, canonic_module_name, function(exists) { + moduleExist(CLI, canonicModuleName, function (exists) { if (exists) { // Update Common.printOut(cst.PREFIX_MSG_MOD + 'Module already installed. Updating.'); // Create a backup - Rollback.backup(module_name); + Rollback.backup(moduleName); return uninstallModule(CLI, { - module_name : canonic_module_name, - deep_uninstall : false - }, function(err) { - return Modularizer.installModule(CLI, module_name, opts, cb); + module_name: canonicModuleName, + deep_uninstall: false + }, function () { + return Modularizer.installModule(CLI, moduleName, opts, cb); }); } // Install - Modularizer.installModule(CLI, module_name, opts, cb); - }) + Modularizer.installModule(CLI, moduleName, opts, cb); + }); +}; + +Modularizer.installMultipleModules = function (modules, cb) { + var functionList = []; + for (var i = 0; i < modules.length; i++) { + functionList.push((function (index) { + return function (callback) { + var module = modules[index]; + if (typeof modules[index] === 'string') { + module = {name: modules[index]}; + } + + installModuleByName(module, function (err) { + callback(null, {module: module, err: err}); + }, false); + }; + })(i)); + } + + async.parallel(functionList, function (err, results) { + for (var i = 0; i < results.length; i++) { + var display = results[i].module.message || results[i].module.name; + if (results[i].err) { + err = results[i].err; + Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)')); + } else { + Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED')); + } + } + + cb(err); + }); }; Modularizer.installModule = function(CLI, module_name, opts, cb) { @@ -543,6 +583,27 @@ Modularizer.generateSample = function(app_name, cb) { }); }; +function installModuleByName (module, cb, verbose) { + if (!module || !module.name || module.name.length === 0) { + return cb(new Error('No module name !')); + } + + if (typeof verbose === 'undefined') { + verbose = true; + } + + installLangModule(module.name, function (err) { + var display = module.message || module.name; + if (err) { + if (verbose) { Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)')); } + return cb(err); + } + + if (verbose) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED')); } + return cb(); + }); +} + function installLangModule(module_name, cb) { var node_module_path = path.resolve(path.join(__dirname, '../../../')); Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[NPM]') + ' to install ' + module_name + ' ...'); diff --git a/lib/API/schema.json b/lib/API/schema.json index 22fbacace..75db9a98b 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -229,6 +229,21 @@ "default": true, "description": "Enable or disable the transaction tracing" }, + "v8": { + "type": [ + "boolean" + ] + }, + "event_loop_inspector": { + "type": [ + "boolean" + ] + }, + "deep_monitoring": { + "type": [ + "boolean" + ] + }, "increment_var": { "type": "string", "description": "Specify the name of an environnement variable to inject which increments for each cluster" @@ -266,5 +281,9 @@ "type" : "string", "default": "Current user gid", "description": "Set group id" + }, + "windowsHide": { + "type": "boolean", + "default" : true } } \ No newline at end of file diff --git a/lib/Client.js b/lib/Client.js index 1a5dce15d..74103fd3b 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -69,7 +69,8 @@ Client.prototype.start = function(cb) { var daemon = new Daemon({ pub_socket_file : that.conf.DAEMON_PUB_PORT, rpc_socket_file : that.conf.DAEMON_RPC_PORT, - pid_file : that.conf.PM2_PID_FILE_PATH + pid_file : that.conf.PM2_PID_FILE_PATH, + ignore_signals : true }); console.log('Launching in no daemon mode'); @@ -86,7 +87,7 @@ Client.prototype.start = function(cb) { that.launchRPC(function(err, meta) { return cb(null, { daemon_mode : that.conf.daemon_mode, - new_pm2_instance : false, + new_pm2_instance : true, rpc_socket_file : that.rpc_socket_file, pub_socket_file : that.pub_socket_file, pm2_home : that.pm2_home diff --git a/lib/Daemon.js b/lib/Daemon.js index 019197522..26c9c98ef 100644 --- a/lib/Daemon.js +++ b/lib/Daemon.js @@ -20,6 +20,7 @@ var fmt = require('./tools/fmt.js'); var Daemon = module.exports = function(opts) { if (!opts) opts = {}; + this.ignore_signals = opts.ignore_signals || false; this.rpc_socket_ready = false; this.pub_socket_ready = false; @@ -89,7 +90,8 @@ Daemon.prototype.innerStart = function(cb) { console.error(e.stack || e); } - this.handleSignals(); + if (this.ignore_signals != true) + this.handleSignals(); /** * Pub system for real time notifications @@ -255,18 +257,11 @@ Daemon.prototype.close = function(opts, cb) { msg : 'pm2 has been killed via CLI' }); - fmt.sep(); - fmt.title('Stopping PM2'); - fmt.field('Time', new Date()); - fmt.sep(); - /** * Cleanly kill pm2 */ that.rpc_socket.close(function() { - console.log('RPC closed'); that.pub_socket.close(function() { - console.log('PUB closed'); // notify cli that the daemon is shuting down (only under unix since windows doesnt handle signals) if (cst.IS_WINDOWS === false) { @@ -335,7 +330,7 @@ Daemon.prototype.gracefullExit = function() { try { fs.unlinkSync(that.pid_path); } catch(e) {} - console.log('[PM2] Exited peacefully'); + console.log('Exited peacefully'); process.exit(0); }); }); diff --git a/lib/God.js b/lib/God.js index bf3bedda6..dc0019972 100644 --- a/lib/God.js +++ b/lib/God.js @@ -31,6 +31,7 @@ var async = require('async'); * Override cluster module configuration */ cluster.setupMaster({ + windowsHide: true, exec : path.resolve(path.dirname(module.filename), 'ProcessContainer.js') }); @@ -358,7 +359,7 @@ God.handleExit = function handleExit(clu, exit_code, kill_signal) { God.notify('exit', proc); if (God.pm2_being_killed) { - console.log('[HandleExit] PM2 is being killed, stopping restart procedure...'); + //console.log('[HandleExit] PM2 is being killed, stopping restart procedure...'); return false; } @@ -451,7 +452,7 @@ God.finalizeProcedure = function finalizeProcedure(proc) { !proc.pm2_env || proc.pm2_env.status == cst.STOPPED_STATUS || proc.pm2_env.status == cst.STOPPING_STATUS) { - return console.error('Proc is not defined anymore or is being killed'); + return console.error('Cancelling versioning data parsing'); } proc.pm2_env.vizion_running = false; diff --git a/lib/God/ForkMode.js b/lib/God/ForkMode.js index 870519962..d5ac57bcb 100644 --- a/lib/God/ForkMode.js +++ b/lib/God/ForkMode.js @@ -90,11 +90,17 @@ module.exports = function ForkMode(God) { return cb(err); }; + var windowsHide; + if (typeof(pm2_env.windowsHide) === "boolean") { + windowsHide = pm2_env.windowsHide; + } else { + windowsHide = true; + } try { var cspr = spawn(command, args, { env : pm2_env, detached : true, - windowsHide: true, + windowsHide: windowsHide, cwd : pm2_env.pm_cwd || process.cwd(), stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core }); diff --git a/lib/Interactor/InteractorDaemonizer.js b/lib/Interactor/InteractorDaemonizer.js index c50905ddd..2d87715ff 100644 --- a/lib/Interactor/InteractorDaemonizer.js +++ b/lib/Interactor/InteractorDaemonizer.js @@ -232,7 +232,7 @@ var daemonize = function(conf, infos, cb) { stdio : ['ipc', out, err] }); - UX.processing.start(); + console.log('[KM] Connecting'); fs.writeFileSync(conf.INTERACTOR_PID_PATH, child.pid); @@ -246,8 +246,6 @@ var daemonize = function(conf, infos, cb) { child.unref(); var t = setTimeout(function() { - UX.processing.stop(); - Common.printOut(cst.PREFIX_MSG_WARNING + ' Not managed to connect to Keymetrics, retrying in background. (check %s)', cst.INTERACTOR_LOG_FILE_PATH); child.removeAllListeners('message'); child.removeAllListeners('error'); @@ -259,8 +257,6 @@ var daemonize = function(conf, infos, cb) { clearTimeout(t); debug('Interactor daemon launched', msg); - UX.processing.stop(); - if (msg.debug) { return cb(null, msg, child); } diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 2b1b3f176..db9540dd6 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -30,16 +30,19 @@ delete process.env.pm2_env; (function ProcessContainer() { var fs = require('fs'); - if (process.env.pmx !== 'false') + if (process.env.pmx !== 'false') { require('pmx').init({ - transactions: process.env.km_link == 'true' && process.env.trace == 'true' || false, - http: process.env.km_link == 'true' || false + transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false }); + } var stdFile = pm2_env.pm_log_path; var outFile = pm2_env.pm_out_log_path; var errFile = pm2_env.pm_err_log_path; - var pmId = pm2_env.pm_id; var pidFile = pm2_env.pm_pid_path; var script = pm2_env.pm_exec_path; var cronRestart = pm2_env.cron_restart; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index c612adb6d..6d1b0cebb 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -4,10 +4,13 @@ * can be found in the LICENSE file. */ // Inject custom modules -if (process.env.pmx !== "false") { +if (process.env.pmx !== 'false') { require('pmx').init({ - transactions: process.env.km_link == 'true' && process.env.trace == 'true' || false, - http: process.env.km_link == 'true' || false + transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false }); } @@ -61,7 +64,7 @@ if (process.env.uid || process.env.gid) { process.setgid(process.env.gid); if (process.env.uid){ // If no gid specified - set gid to uid - var new_gid = process.env.gid == null ? process.env.uid : process.env.gid; + var new_gid = process.env.gid == null ? process.env.uid : process.env.gid; process.initgroups(process.env.uid, new_gid); process.setgid(new_gid); process.setuid(process.env.uid); diff --git a/lib/TreeKill.js b/lib/TreeKill.js index 329aab851..4365e2eac 100644 --- a/lib/TreeKill.js +++ b/lib/TreeKill.js @@ -14,7 +14,7 @@ module.exports = function (pid, signal, callback) { switch (process.platform) { case 'win32': - exec('taskkill /pid ' + pid + ' /T /F', callback); + exec('taskkill /pid ' + pid + ' /T /F', { windowsHide: true }, callback); break; case 'darwin': buildProcessTree(pid, tree, pidsToProcess, function (parentPid) { diff --git a/lib/Utility.js b/lib/Utility.js index 169d86fd8..71f65b03c 100644 --- a/lib/Utility.js +++ b/lib/Utility.js @@ -84,7 +84,7 @@ var Utility = module.exports = { // Generate timestamp prefix function timestamp(){ - return moment().format(cst.PM2_LOG_DATE_FORMAT) + ': '; + return '[' + moment().format(cst.PM2_LOG_DATE_FORMAT) + ']'; } var hacks = ['info', 'log', 'error', 'warn'], consoled = {}; @@ -108,7 +108,7 @@ var Utility = module.exports = { }); } // do not destroy variable insertion - arguments[0] && (arguments[0] = timestamp() + arguments[0]); + arguments[0] && (arguments[0] = timestamp() + ' PM2 ' + k + ': ' + arguments[0]); consoled[k].apply(console, arguments); }; }); @@ -223,12 +223,14 @@ var Utility = module.exports = { //pm2 install username/module else if(canonic_module_name.indexOf('/') !== -1) { - canonic_module_name = canonic_module_name.split('/')[1]; + if (canonic_module_name.charAt(0) !== "@"){ + canonic_module_name = canonic_module_name.split('/')[1]; + } } - //pm2 install module@2.1.0-beta - if(canonic_module_name.indexOf('@') !== -1) { - canonic_module_name = canonic_module_name.split('@')[0]; + //pm2 install @somescope/module@2.1.0-beta + if(canonic_module_name.lastIndexOf('@') > 0) { + canonic_module_name = canonic_module_name.substr(0,canonic_module_name.lastIndexOf("@")); } //pm2 install module#some-branch diff --git a/lib/binaries/Runtime4Docker.js b/lib/binaries/Runtime4Docker.js index 8d05fc682..e3b48d3de 100644 --- a/lib/binaries/Runtime4Docker.js +++ b/lib/binaries/Runtime4Docker.js @@ -1,7 +1,7 @@ 'use strict'; /** - * Specialized PM2 CLI for Docker + * Specialized PM2 CLI for Containers */ var commander = require('commander'); var debug = require('debug')('pm2:cli'); @@ -10,20 +10,27 @@ var Log = require('../../lib/API/Log'); var cst = require('../../constants.js'); var pkg = require('../../package.json'); var path = require('path'); -var pm2; -// Do not print banner process.env.PM2_DISCRETE_MODE = true; commander.version(pkg.version) - .description('pm2-docker is a drop-in replacement node.js binary with some interesting production features') + .description('pm2-runtime is a drop-in replacement Node.js binary for containers') .option('-i --instances ', 'launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.') .option('--secret [key]', '[MONITORING] keymetrics secret key') + .option('--no-autorestart', 'start an app without automatic restart') + .option('--node-args ', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"') + .option('-n --name ', 'set a for script') + .option('--max-memory-restart ', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)') + .option('-c --cron ', 'restart a running process based on a cron pattern') + .option('--interpreter ', 'the interpreter pm2 should use for executing app (bash, python...)') .option('--public [key]', '[MONITORING] keymetrics public key') .option('--machine-name [name]', '[MONITORING] keymetrics machine name') - .option('--raw', 'raw log output') - .option('--json', 'output logs in json format') + .option('--trace', 'enable transaction tracing with km') + .option('--v8', 'enable v8 data collecting') .option('--format', 'output logs formated like key=val') + .option('--raw', 'raw output (default mode)') + .option('--formatted', 'formatted log output |id|app|log') + .option('--json', 'output logs in json format') .option('--delay ', 'delay start of configuration file by ', 0) .option('--web [port]', 'launch process web api on [port] (default to 9615)') .option('--only ', 'only act on one application of configuration') @@ -32,42 +39,19 @@ commander.version(pkg.version) .option('--watch', 'watch and restart application on file change') .option('--error ', 'error log file destination (default disabled)', '/dev/null') .option('--output ', 'output log file destination (default disabled)', '/dev/null') + .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)') + .allowUnknownOption() .usage('app.js'); -function start(cmd, opts) { - pm2 = new PM2.custom({ - pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'), - secret_key : process.env.KEYMETRICS_SECRET || commander.secret, - public_key : process.env.KEYMETRICS_PUBLIC || commander.public, - machine_name : process.env.INSTANCE_NAME || commander.machineName, - daemon_mode : true - }); - - if (commander.autoExit) { - autoExit(); - } - - pm2.connect(function() { - - if (opts.web) { - var port = opts.web === true ? cst.WEB_PORT : opts.web; - pm2.web(port); - } - - run(cmd, opts); - }); -} - commander.command('*') .action(function(cmd){ - start(cmd, commander); + Runtime.instanciate(cmd); }); -// @todo need to allow passing same option than pm2 start commander.command('start ') .description('start an application or json ecosystem file') .action(function(cmd) { - start(cmd, commander); + Runtime.instanciate(cmd); }); if (process.argv.length == 2) { @@ -75,102 +59,127 @@ if (process.argv.length == 2) { process.exit(1); } -var autoExitIndex = process.argv.indexOf('--auto-exit'); -if (autoExitIndex > -1) { - console.warn( - "Warning: --auto-exit has been removed, as it's now the default behavior" + - "; if you want to disable it, use the new --no-auto-exit flag." - ); - - process.argv.splice(autoExitIndex, 1); -} - -commander.parse(process.argv); - -process.on('SIGINT', function() { - exitPM2(); -}); - -process.on('SIGTERM', function() { - exitPM2(); -}); - -function run(cmd, opts) { - var needRaw = commander.raw; - var timestamp = commander.timestamp; +var Runtime = { + pm2 : null, + instanciate : function(cmd) { + this.pm2 = new PM2.custom({ + pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'), + secret_key : process.env.KEYMETRICS_SECRET || commander.secret, + public_key : process.env.KEYMETRICS_PUBLIC || commander.public, + machine_name : process.env.INSTANCE_NAME || commander.machineName, + daemon_mode : process.env.PM2_RUNTIME_DEBUG || false + }); - function exec() { - pm2.start(cmd, opts, function(err, obj) { - if (err) { - console.error(err.message || err); - return exitPM2(); + this.pm2.connect(function(err, pm2_meta) { + if (pm2_meta.new_pm2_instance == false) { + console.warn('[WARN] PM2 Daemon is already running') } - var pm_id = obj[0].pm2_env.pm_id; - - if (commander.json === true) - Log.jsonStream(pm2.Client, pm_id); - else if (commander.format === true) - Log.formatStream(pm2.Client, pm_id, false, 'YYYY-MM-DD-HH:mm:ssZZ'); - else - Log.stream(pm2.Client, 'all', needRaw, timestamp, false); + process.on('SIGINT', function() { + Runtime.exit(); + }); - if (process.env.PM2_RUNTIME_DEBUG) - pm2.disconnect(function() {}); + process.on('SIGTERM', function() { + Runtime.exit(); + }); + Runtime.startLogStreaming(); + Runtime.startApp(cmd, function(err) { + if (err) { + console.error(err.message || err); + return Runtime.exit(); + } + }); }); - } - setTimeout(exec.bind(this), opts.delay * 1000); -} - -function exitPM2() { - console.log('Exiting PM2'); - pm2.kill(function() { - process.exit(0); - }); -} + }, + + /** + * Log Streaming Management + */ + startLogStreaming : function() { + if (commander.json === true) + Log.jsonStream(this.pm2.Client, 'all'); + else if (commander.format === true) + Log.formatStream(this.pm2.Client, 'all', false, 'YYYY-MM-DD-HH:mm:ssZZ'); + else + Log.stream(this.pm2.Client, 'all', !commander.formatted, commander.timestamp, true); + }, + + /** + * Application Startup + */ + startApp : function(cmd, cb) { + function exec() { + this.pm2.start(cmd, commander, function(err, obj) { + if (err) + return cb(err); + if (obj && obj.length == 0) + return cb(new Error('Failed to start application')) + + if (commander.web) { + var port = commander.web === true ? cst.WEB_PORT : commander.web; + Runtime.pm2.web(port); + } -/** - * Exit current PM2 instance if 0 app is online - * function activated via --auto-exit - */ -function autoExit() { - var interval = 3000; - var aliveInterval = interval * 1.5; - - setTimeout(function () { - var alive = false - var aliveTimer = setTimeout(function () { - if (!alive) { - console.error('PM2 Daemon is dead'); - process.exit(1); - } - }, aliveInterval); + if (commander.autoExit) + Runtime.autoExitWorker(); - pm2.list(function (err, apps) { - if (err) { - console.log('pm2.list got error') - console.error(err); - exitPM2(); - } + // For Testing purpose (allow to auto exit CLI) + if (process.env.PM2_RUNTIME_DEBUG) + Runtime.pm2.disconnect(function() {}); - clearTimeout(aliveTimer); - alive = true; + return cb(null, obj); + }); + } + // via --delay option + setTimeout(exec.bind(this), commander.delay * 1000); + }, + + /** + * Exit runtime mgmt + */ + exit : function() { + if (!this.pm2) return process.exit(1); + + this.pm2.kill(function() { + process.exit(0); + }); + }, + + /** + * Exit current PM2 instance if 0 app is online + * function activated via --auto-exit + */ + autoExitWorker : function() { + var interval = 1000; + + var timer = setTimeout(function () { + Runtime.pm2.list(function (err, apps) { + if (err) { + console.error('Could not run pm2 list'); + return Runtime.autoExitWorker(); + } - var appOnline = 0; + var appOnline = 0; - apps.forEach(function (app) { - if (app.pm2_env.status === cst.ONLINE_STATUS || + apps.forEach(function (app) { + if (app.pm2_env.status === cst.ONLINE_STATUS || app.pm2_env.status === cst.LAUNCHING_STATUS) { - appOnline++; + appOnline++; + } + }); + + if (appOnline === 0) { + console.log('0 application online, exiting'); + return Runtime.exit(); } + + Runtime.autoExitWorker(); }); + }, interval); - if (appOnline === 0) { - console.log('0 application online, exiting'); - exitPM2(); - } - autoExit(); - }); - }, interval); + timer.unref(); + } } + +commander.parse(process.argv); diff --git a/package.json b/package.json index 6db86cc86..3bd207d6d 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "pm2", "preferGlobal": true, - "version": "2.9.3", + "version": "2.10.1", "engines": { - "node": ">=0.12" + "node": ">=4.0.0" }, "directories": { "bin": "./bin", @@ -161,27 +161,27 @@ "dependencies": { "async": "^2.5", "blessed": "^0.1.81", - "chalk": "^1.1", - "chokidar": "^1.7", + "chalk": "^2.3.1", + "chokidar": "^2.0.2", "cli-table-redemption": "^1.0.0", - "commander": "2.12.2", + "commander": "2.14.1", "cron": "^1.3", "debug": "^3.0", - "eventemitter2": "1.0.5", + "eventemitter2": "5.0.1", "fclone": "1.0.11", "mkdirp": "0.5.1", "moment": "^2.19", - "needle": "1.6.0", + "needle": "^2.2.0", "nssocket": "0.6.0", "pidusage": "^1.2.0", "pm2-axon": "3.1.0", "pm2-axon-rpc": "0.5.0", "pm2-deploy": "^0.3.9", "pm2-multimeter": "^0.1.2", - "pmx": "~1.5.*", + "pmx": "^1.6", "promptly": "2.2.0", "semver": "^5.3", - "shelljs": "0.7.8", + "shelljs": "0.8.1", "source-map-support": "^0.5", "sprintf-js": "1.1.1", "v8-compile-cache": "^1.1.0", @@ -190,7 +190,7 @@ }, "devDependencies": { "mocha": "^3.5", - "should": "^11" + "should": "^13" }, "optionalDependencies": { "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz" diff --git a/packager/build-deb-rpm.sh b/packager/build-deb-rpm.sh index f05587900..d8a195f8a 100755 --- a/packager/build-deb-rpm.sh +++ b/packager/build-deb-rpm.sh @@ -17,7 +17,7 @@ echo "Cleaning PACKAGE_TMPDIR..." rm -rf $PACKAGE_TMPDIR PM2_VERSION=`node dist/bin/pm2 --version` -VERSION=$PM2_VERSION"-"$DRONE_BUILD_NUMBER +VERSION=$PM2_VERSION TARBALL_NAME=dist/pm2-v$PM2_VERSION.tar.gz OUTPUT_DIR=artifacts @@ -121,7 +121,7 @@ fpm --input-type dir --chdir $PACKAGE_TMPDIR \ --description '$(cat packager/debian/description)' \ --vendor 'Keymetrics ' \ --maintainer 'Alexandre Strzelewicz ' \ - --version $PM2_VERSION --iteration $DRONE_BUILD_NUMBER \ + --version $PM2_VERSION \ --after-install packager/rhel/postinst \ --before-remove packager/rhel/prerm \ --after-remove packager/rhel/postrm \ diff --git a/packager/publish_deb_rpm.sh b/packager/publish_deb_rpm.sh index 99ed4902a..911172124 100755 --- a/packager/publish_deb_rpm.sh +++ b/packager/publish_deb_rpm.sh @@ -2,7 +2,7 @@ REPOSITORY_NAME="keymetrics/pm2" -for OSDIST in 'ubuntu/xenial' 'ubuntu/yakkety' 'ubuntu/zesty' 'ubuntu/artful' 'debian/wheezy' 'debian/jessie' 'debian/stretch' 'debian/buster' 'raspbian/wheezy' 'raspbian/jessie' 'raspbian/stretch' 'raspbian/buster' +for OSDIST in 'ubuntu/trusty' 'ubuntu/xenial' 'ubuntu/yakkety' 'ubuntu/zesty' 'ubuntu/artful' 'debian/wheezy' 'debian/jessie' 'debian/stretch' 'debian/buster' 'raspbian/wheezy' 'raspbian/jessie' 'raspbian/stretch' 'raspbian/buster' do package_cloud push $REPOSITORY_NAME/$OSDIST `find -name "*.deb"` done diff --git a/test/bash/cli-actions-2.sh b/test/bash/cli-actions-2.sh index 7cab8b283..02b50fc58 100644 --- a/test/bash/cli-actions-2.sh +++ b/test/bash/cli-actions-2.sh @@ -30,6 +30,13 @@ should 'should app be online once restart called' 'online' 1 $pm2 delete all +############## PID +$pm2 start 001-test.js --name "test" +should 'should app be online' 'online' 1 +$pm2 pid > /tmp/pid-tmp +$pm2 pid test +$pm2 delete all + ############### echo "Start application with filename starting with a numeric" diff --git a/test/bash/interpreter.sh b/test/bash/interpreter.sh index e497c8146..3257e85c0 100644 --- a/test/bash/interpreter.sh +++ b/test/bash/interpreter.sh @@ -77,7 +77,7 @@ spec "Should work on Livescript files in cluster mode" $pm2 delete all $pm2 start echo.ts sleep 1 -should 'process should be errored without coffee installed' "status: 'errored'" 1 +should 'process should be errored without typescript installed' "status: 'errored'" 1 ########### Install diff --git a/test/bash/options-via-env.sh b/test/bash/options-via-env.sh new file mode 100644 index 000000000..c2049f509 --- /dev/null +++ b/test/bash/options-via-env.sh @@ -0,0 +1,24 @@ + +#!/usr/bin/env bash + +SRC=$(cd $(dirname "$0"); pwd) +source "${SRC}/include.sh" + +cd $file_path + +# With start +$pm2 start echo.js +should 'should deep_monitoring' 'deep_monitoring' 0 + +$pm2 delete all + +PM2_DEEP_MONITORING=true $pm2 start echo.js +should 'should deep_monitoring' 'deep_monitoring' 1 + +$pm2 delete all + +# With restart +$pm2 start echo.js +should 'should deep_monitoring' 'deep_monitoring' 0 +PM2_DEEP_MONITORING=true $pm2 restart echo +should 'should deep_monitoring' 'deep_monitoring' 1 diff --git a/test/bash/pm2-runtime.sh b/test/bash/pm2-runtime.sh index c58e55c84..da29b919f 100644 --- a/test/bash/pm2-runtime.sh +++ b/test/bash/pm2-runtime.sh @@ -3,27 +3,55 @@ SRC=$(cd $(dirname "$0"); pwd) source "${SRC}/include.sh" -export PM2_HOME="$HOME/.pm3" - -pm2runtime="`type -P node` `pwd`/bin/pm2-runtime" +pm2_runtime="`type -P node` `pwd`/bin/pm2-runtime" export PM2_RUNTIME_DEBUG='true' cd $file_path/pm2-dev -$pm2 delete all +# +# Simple start with 4 apps +# +$pm2 kill +pkill -f PM2 -# Test with js -$pm2runtime app.js -i 4 +$pm2_runtime app.js -i 4 should 'should have started 4 apps' 'online' 4 -$pm2 delete all +$pm2 kill +# # Test with json and args -$pm2runtime app.json +# +$pm2_runtime app.json should 'should have started 1 apps' 'online' 1 $pm2 prettylist | grep "watch: \[ 'server', 'client' \]" spec "Should application have two watch arguments" $pm2 prettylist | grep "ignore_watch: \[ 'node_modules', 'client/img' \]" spec "Should application have two ignore_watch arguments" $pm2 kill + +# Restore default behavior for exit checks +unset PM2_RUNTIME_DEBUG + +# +# --no-autorestart checks +# +# $pm2_runtime app.js --no-autorestart +# PID_PM2=$! +# $pm2 pid app +# echo "OK" +# PID=`cat /tmp/pid` +# echo $PID +# kill $PID +# sleep 3 +# pgrep "PM2" +# ispec "PM2 runtime should be killed because no app is running" + +# +# Auto Exit Worker +# +$pm2_runtime exited_app.js 2> /dev/null +sleep 1 +pgrep "PM2" +ispec "PM2 runtime should be killed because no app is running" diff --git a/test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json b/test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json deleted file mode 100644 index 9e26dfeeb..000000000 --- a/test/fixtures/pm2-dev/$HOME/.pm3/module_conf.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/test/fixtures/pm2-dev/$HOME/.pm3/touch b/test/fixtures/pm2-dev/$HOME/.pm3/touch deleted file mode 100644 index ad2dd20b0..000000000 --- a/test/fixtures/pm2-dev/$HOME/.pm3/touch +++ /dev/null @@ -1 +0,0 @@ -1498811729303 \ No newline at end of file diff --git a/test/fixtures/pm2-dev/exited_app.js b/test/fixtures/pm2-dev/exited_app.js new file mode 100644 index 000000000..df1fc8096 --- /dev/null +++ b/test/fixtures/pm2-dev/exited_app.js @@ -0,0 +1,2 @@ + +throw new Error('exit') diff --git a/test/interface/utility.mocha.js b/test/interface/utility.mocha.js index e5e76adc9..d2c1c7bd3 100644 --- a/test/interface/utility.mocha.js +++ b/test/interface/utility.mocha.js @@ -18,7 +18,8 @@ describe('Utility', function() { assert(Utility.getCanonicModuleName('ma-zal/pm2-slack') === 'pm2-slack'); assert(Utility.getCanonicModuleName('ma-zal/pm2-slack#own-branch') === 'pm2-slack'); assert(Utility.getCanonicModuleName('pm2-slack') === 'pm2-slack'); - assert(Utility.getCanonicModuleName('@org/pm2-slack') === 'pm2-slack'); + assert(Utility.getCanonicModuleName('@org/pm2-slack') === '@org/pm2-slack'); + assert(Utility.getCanonicModuleName('@org/pm2-slack@latest') === '@org/pm2-slack'); assert(Utility.getCanonicModuleName('git+https://github.com/user/pm2-slack') === 'pm2-slack'); assert(Utility.getCanonicModuleName('git+https://github.com/user/pm2-slack.git') === 'pm2-slack'); assert(Utility.getCanonicModuleName('file:///home/user/pm2-slack') === 'pm2-slack'); diff --git a/test/pm2_behavior_tests.sh b/test/pm2_behavior_tests.sh index da98dfadd..6b1fa6306 100644 --- a/test/pm2_behavior_tests.sh +++ b/test/pm2_behavior_tests.sh @@ -23,6 +23,8 @@ bash ./test/bash/pm2-dev.sh spec "pm2-dev" bash ./test/bash/pm2-runtime.sh spec "pm2-runtime" +bash ./test/bash/options-via-env.sh +spec "set option via environment" bash ./test/bash/startup.sh spec "upstart startup test" bash ./test/bash/dump.sh diff --git a/types/index.d.ts b/types/index.d.ts index b78d1fd27..42ff4293a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -170,6 +170,14 @@ export function sendSignalToProcessName(signal:string|number, process: number|st */ export function startup(platform: Platform, errback: ErrResultCallback): void; +/** + * - Send an set of data as object to a specific process + * @param proc_id + * @param packet + * @param cb + */ +export function sendDataToProcessId(proc_id: number, packet: object, cb: ErrResultCallback): void; + // Interfaces export interface Proc { @@ -375,7 +383,7 @@ export interface StartOptions { /** * If set to true, the application will be restarted on change of the script file. */ - watch?: boolean; + watch?: boolean|string[]; /** * (Default: false) By default, pm2 will only start a script if that script isn’t * already running (a script is a path to an application, not the name of an application