From cfd0d2f67845fffb9d5974514b65e43b22ed8040 Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Wed, 11 Oct 2017 22:35:42 -0500 Subject: [PATCH 01/72] refactor: modify the directory of logDir (#8) - export this.child - export getFrameworkPath - support customize stdout and stderr --- lib/cmd/start.js | 79 +++++++++++++++-------------- package.json | 7 +-- test/fixtures/example/app/router.js | 4 ++ test/start.test.js | 50 ++++++++++++++++-- test/stop.test.js | 16 ++++-- 5 files changed, 108 insertions(+), 48 deletions(-) diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 783d304..0e3ed6a 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -44,6 +44,14 @@ class StartCommand extends Command { description: 'whether run at background daemon mode', type: 'boolean', }, + stdout: { + description: 'A file that stdout redirect to', + type: 'string', + }, + stderr: { + description: 'A file that stderr redirect to', + type: 'string', + }, }; } @@ -53,6 +61,8 @@ class StartCommand extends Command { * run(context) { const argv = Object.assign({}, context.argv); + const HOME = homedir(); + const logDir = path.join(HOME, 'logs'); // egg-script start // egg-script start ./server @@ -63,33 +73,26 @@ class StartCommand extends Command { const isDaemon = argv.daemon; - argv.framework = utils.getFrameworkPath({ + argv.framework = yield this.getFrameworkPath({ framework: argv.framework, baseDir, }); - const env = context.env; - env.PWD = baseDir; - env.HOME = homedir(); - env.NODE_ENV = 'production'; - - // cli argv -> process.env.EGG_SERVER_ENV -> `undefined` then egg will use `prod` - if (argv.env) { - // if undefined, should not pass key due to `spwan`, https://github.com/nodejs/node/blob/master/lib/child_process.js#L470 - env.EGG_SERVER_ENV = argv.env; - argv.env = undefined; - } - const pkgInfo = require(path.join(baseDir, 'package.json')); - const logDir = path.join(env.HOME, 'logs', pkgInfo.name); - argv.title = argv.title || `egg-server-${pkgInfo.name}`; + argv.stdout = argv.stdout || path.join(logDir, 'master-stdout.log'); + argv.stderr = argv.stderr || path.join(logDir, 'master-stderr.log'); + + const env = context.env; + env.HOME = HOME; + env.NODE_ENV = 'production'; + // adjust env for win - let envPath = env.PATH || env.Path; + const envPath = env.PATH || env.Path; if (envPath) { // for nodeinstall - envPath = path.join(baseDir, 'node_modules/.bin') + path.delimiter + envPath; + env.PATH = path.join(baseDir, 'node_modules/.bin') + path.delimiter + envPath; } // for alinode @@ -97,12 +100,20 @@ class StartCommand extends Command { env.NODE_LOG_DIR = env.NODE_LOG_DIR || path.join(logDir, 'alinode'); yield mkdirp(env.NODE_LOG_DIR); + // cli argv -> process.env.EGG_SERVER_ENV -> `undefined` then egg will use `prod` + if (argv.env) { + // if undefined, should not pass key due to `spwan`, https://github.com/nodejs/node/blob/master/lib/child_process.js#L470 + env.EGG_SERVER_ENV = argv.env; + argv.env = undefined; + } + // remove unused properties, alias had been remove by `removeAlias` argv._ = undefined; argv.$0 = undefined; argv.daemon = undefined; const options = { + cwd: baseDir, execArgv: context.execArgv, env, stdio: 'inherit', @@ -117,11 +128,11 @@ class StartCommand extends Command { // whether run in the background. if (isDaemon) { this.logger.info(`save log file to ${logDir}`); - const { stdout, stderr } = yield getRotatelog(logDir); + const [ stdout, stderr ] = yield [ getRotatelog(argv.stdout), getRotatelog(argv.stderr) ]; options.stdio = [ 'ignore', stdout, stderr, 'ipc' ]; options.detached = true; - const child = spawn('node', eggArgs, options); + const child = this.child = spawn('node', eggArgs, options); child.on('message', msg => { if (msg && msg.action === 'egg-ready') { this.logger.info(`egg started on ${msg.data.address}`); @@ -135,32 +146,24 @@ class StartCommand extends Command { this.helper.spawn('node', eggArgs, options); } } -} -function* getRotatelog(logDir) { - const stdoutPath = path.join(logDir, 'master-stdout.log'); - const stderrPath = path.join(logDir, 'master-stderr.log'); + * getFrameworkPath(params) { + return utils.getFrameworkPath(params); + } - // format style: .20150602.193100 - const timestamp = moment().format('.YYYYMMDD.HHmmss'); +} - yield mkdirp(logDir); +function* getRotatelog(logfile) { + yield mkdirp(path.dirname(logfile)); - /* istanbul ignore else */ - if (yield fs.exists(stdoutPath)) { + if (yield fs.exists(logfile)) { + // format style: .20150602.193100 + const timestamp = moment().format('.YYYYMMDD.HHmmss'); // Note: rename last log to next start time, not when last log file created - yield fs.rename(stdoutPath, stdoutPath + timestamp); - } - - /* istanbul ignore else */ - if (yield fs.exists(stderrPath)) { - yield fs.rename(stderrPath, stderrPath + timestamp); + yield fs.rename(logfile, logfile + timestamp); } - return yield { - stdout: fs.open(stdoutPath, 'a'), - stderr: fs.open(stderrPath, 'a'), - }; + return yield fs.open(logfile, 'a'); } module.exports = StartCommand; diff --git a/package.json b/package.json index 902f861..59f1435 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,12 @@ "node": ">=6.0.0" }, "scripts": { - "test": "npm run lint -- --fix && npm run test-local", + "pkgfiles": "egg-bin pkgfiles", + "test": "npm run lint -- --fix && npm run pkgfiles && npm run test-local", "test-local": "egg-bin test", "cov": "egg-bin cov", "lint": "eslint .", - "ci": "egg-bin pkgfiles --check && npm run lint && npm run cov", + "ci": "npm run pkgfiles -- --check && npm run lint && npm run cov", "autod": "autod" }, "files": [ @@ -57,4 +58,4 @@ }, "author": "TZ ", "license": "MIT" -} \ No newline at end of file +} diff --git a/test/fixtures/example/app/router.js b/test/fixtures/example/app/router.js index 425da8a..cd29c09 100644 --- a/test/fixtures/example/app/router.js +++ b/test/fixtures/example/app/router.js @@ -8,4 +8,8 @@ module.exports = app => { app.get('/env', function* () { this.body = app.config.env + ', ' + app.config.pre; }); + + app.get('/path', function* () { + this.body = process.env.PATH; + }); }; diff --git a/test/start.test.js b/test/start.test.js index b07fb9b..a034ac9 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -7,7 +7,6 @@ const sleep = require('mz-modules/sleep'); const rimraf = require('mz-modules/rimraf'); const mkdirp = require('mz-modules/mkdirp'); const coffee = require('coffee'); -const homedir = require('node-homedir'); const httpclient = require('urllib'); const mm = require('mm'); const utils = require('./utils'); @@ -15,10 +14,17 @@ const utils = require('./utils'); describe('test/start.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); const fixturePath = path.join(__dirname, 'fixtures/example'); - const homePath = homedir(); - const logDir = path.join(homePath, 'logs/example'); + const homePath = path.join(__dirname, 'fixtures/home'); + const logDir = path.join(homePath, 'logs'); const waitTime = '10s'; + before(function* () { + yield mkdirp(homePath); + }); + after(function* () { + yield rimraf(homePath); + }); + beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); afterEach(() => mm.restore); describe('start without daemon', () => { @@ -262,8 +268,43 @@ describe('test/start.test.js', () => { assert(app.stdout.includes('## EGG_SERVER_ENV is not pass')); assert(app.stdout.includes('## CUSTOM_ENV: pre')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001/env'); + let result = yield httpclient.request('http://127.0.0.1:7001/env'); assert(result.data.toString() === 'pre, true'); + result = yield httpclient.request('http://127.0.0.1:7001/path'); + assert(result.data.toString().match(new RegExp(`^${fixturePath}/node_modules/.bin${path.delimiter}`))); + }); + }); + + describe('--stdout --stderr', () => { + let app; + + before(function* () { + yield utils.cleanup(fixturePath); + yield rimraf(logDir); + yield mkdirp(logDir); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + yield rimraf(path.join(fixturePath, 'stdout.log')); + yield rimraf(path.join(fixturePath, 'stderr.log')); + }); + + it('should start', function* () { + const stdout = path.join(fixturePath, 'stdout.log'); + const stderr = path.join(fixturePath, 'stderr.log'); + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--daemon', `--stdout=${stdout}`, `--stderr=${stderr}`, fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + let content = yield fs.readFile(stdout, 'utf-8'); + assert(content.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); + + content = yield fs.readFile(stderr, 'utf-8'); + assert(content === ''); }); }); @@ -337,4 +378,5 @@ describe('test/start.test.js', () => { assert(result.data.toString() === 'hi, egg'); }); }); + }); diff --git a/test/stop.test.js b/test/stop.test.js index 22f0470..2fd109f 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -5,18 +5,28 @@ const assert = require('assert'); const fs = require('mz/fs'); const sleep = require('mz-modules/sleep'); const rimraf = require('mz-modules/rimraf'); +const mkdirp = require('mz-modules/mkdirp'); const coffee = require('coffee'); -const homedir = require('node-homedir'); const httpclient = require('urllib'); +const mm = require('mm'); const utils = require('./utils'); describe('test/stop.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); const fixturePath = path.join(__dirname, 'fixtures/example'); - const homePath = homedir(); - const logDir = path.join(homePath, 'logs/example'); + const homePath = path.join(__dirname, 'fixtures/home'); + const logDir = path.join(homePath, 'logs'); const waitTime = '10s'; + before(function* () { + yield mkdirp(homePath); + }); + after(function* () { + yield rimraf(homePath); + }); + beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); + afterEach(() => mm.restore); + describe('stop without daemon', () => { let app; let killer; From 0f7ca502999c06a9cb05d8e5617f6045704511df Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Fri, 13 Oct 2017 00:20:24 -0500 Subject: [PATCH 02/72] feat: [BREAKING_CHANGE] check the status of app when start on daemon (#9) --- .eslintignore | 1 - .gitignore | 4 +- README.md | 6 +- lib/cmd/start.js | 70 +++++++++++++- package.json | 24 ++--- .../cluster-config/config/config.prod.js | 4 +- .../fixtures/egg-app/config/config.default.js | 8 ++ .../egg-app/node_modules/egg/index.js | 3 + .../egg-app/node_modules/egg/package.json | 4 + test/fixtures/egg-app/package.json | 6 ++ .../node_modules/custom-framework/index.js | 2 +- .../example/node_modules/yadan/index.js | 2 - test/fixtures/status/app.js | 13 +++ test/fixtures/status/config/config.default.js | 8 ++ .../node_modules/custom-framework/index.js | 21 +++++ .../custom-framework/package.json | 7 ++ test/fixtures/status/package.json | 10 ++ test/start.test.js | 91 +++++++++++++++---- test/stop.test.js | 52 +++++------ 19 files changed, 261 insertions(+), 75 deletions(-) create mode 100644 test/fixtures/egg-app/config/config.default.js create mode 100644 test/fixtures/egg-app/node_modules/egg/index.js create mode 100644 test/fixtures/egg-app/node_modules/egg/package.json create mode 100644 test/fixtures/egg-app/package.json create mode 100644 test/fixtures/status/app.js create mode 100644 test/fixtures/status/config/config.default.js create mode 100644 test/fixtures/status/node_modules/custom-framework/index.js create mode 100644 test/fixtures/status/node_modules/custom-framework/package.json create mode 100644 test/fixtures/status/package.json diff --git a/.eslintignore b/.eslintignore index a24e501..4ebc8ae 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1 @@ -test/fixtures coverage diff --git a/.gitignore b/.gitignore index f18c766..446bbe1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,8 @@ logs/ npm-debug.log -node_modules/ +/node_modules coverage/ .idea/ run/ .DS_Store *.swp -!test/fixtures/example/node_modules - diff --git a/README.md b/README.md index 04dabf7..a1b3b66 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ deploy tool for egg project. +**Note: Windows is not supported** + ## Install ```bash @@ -54,8 +56,6 @@ $ egg-scripts start [options] [baseDir] Stop egg gracefull. -**Note:** **Windows is not supported yet**, try to kill master process which command contains `start-cluster` or `--title=egg-server` yourself, good luck. - ```bash # stop egg $ egg-scripts stop [baseDir] @@ -63,4 +63,4 @@ $ egg-scripts stop [baseDir] ``` - **Arguments** - - `baseDir` - directory of application, default to `process.cwd()`. \ No newline at end of file + - `baseDir` - directory of application, default to `process.cwd()`. diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 0e3ed6a..12dc48f 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -2,9 +2,11 @@ const path = require('path'); const mkdirp = require('mz-modules/mkdirp'); +const sleep = require('mz-modules/sleep'); const homedir = require('node-homedir'); const utils = require('egg-utils'); const fs = require('mz/fs'); +const { exec } = require('mz/child_process'); const moment = require('moment'); const spawn = require('child_process').spawn; const Command = require('../command'); @@ -33,7 +35,7 @@ class StartCommand extends Command { default: process.env.PORT, }, env: { - description: 'egg server env, default to `process.env.EGG_SERVER_ENV`', + description: 'server env, default to `process.env.EGG_SERVER_ENV`', default: process.env.EGG_SERVER_ENV, }, framework: { @@ -52,6 +54,11 @@ class StartCommand extends Command { description: 'A file that stderr redirect to', type: 'string', }, + timeout: { + description: 'a timeout for start when daemon', + type: 'number', + default: 300 * 1000, + }, }; } @@ -78,6 +85,8 @@ class StartCommand extends Command { baseDir, }); + this.frameworkName = yield this.getFrameworkName(argv.framework); + const pkgInfo = require(path.join(baseDir, 'package.json')); argv.title = argv.title || `egg-server-${pkgInfo.name}`; @@ -120,27 +129,32 @@ class StartCommand extends Command { detached: false, }; - this.logger.info(`starting egg application at ${baseDir}`); + this.logger.info('Starting %s application at %s', this.frameworkName, baseDir); const eggArgs = [ this.serverBin, JSON.stringify(argv), `--title=${argv.title}` ]; - this.logger.info('run node %s', eggArgs.join(' ')); + this.logger.info('Run node %s', eggArgs.join(' ')); // whether run in the background. if (isDaemon) { - this.logger.info(`save log file to ${logDir}`); + this.logger.info(`Save log file to ${logDir}`); const [ stdout, stderr ] = yield [ getRotatelog(argv.stdout), getRotatelog(argv.stderr) ]; options.stdio = [ 'ignore', stdout, stderr, 'ipc' ]; options.detached = true; const child = this.child = spawn('node', eggArgs, options); + this.isReady = false; child.on('message', msg => { if (msg && msg.action === 'egg-ready') { - this.logger.info(`egg started on ${msg.data.address}`); + this.isReady = true; + this.logger.info('%s started on %s', this.frameworkName, msg.data.address); child.unref(); child.disconnect(); process.exit(0); } }); + + // check start status + yield this.checkStatus(argv); } else { // signal event had been handler at common-bin helper this.helper.spawn('node', eggArgs, options); @@ -151,6 +165,52 @@ class StartCommand extends Command { return utils.getFrameworkPath(params); } + * getFrameworkName(framework) { + const pkgPath = path.join(framework, 'package.json'); + let name = 'egg'; + try { + const pkg = require(pkgPath); + if (pkg.name) name = pkg.name; + } catch (_) { + /* istanbul next */ + } + return name; + } + + * checkStatus({ stderr, timeout }) { + let count = 0; + let isSuccess = true; + timeout = timeout / 1000; + while (!this.isReady) { + try { + const stat = yield fs.stat(stderr); + if (stat && stat.size > 0) { + const [ stdout ] = yield exec('tail -n 100 ' + stderr); + this.logger.error(stdout); + this.logger.error('Start failed, see %s', stderr); + isSuccess = false; + break; + } + } catch (_) { + // nothing + } + + if (count >= timeout) { + this.logger.error('Start failed, %ds timeout', timeout); + isSuccess = false; + break; + } + + yield sleep(1000); + this.logger.log('Wait Start: %d...', ++count); + } + + if (!isSuccess) { + this.child.kill('SIGTERM'); + yield sleep(1000); + process.exit(1); + } + } } function* getRotatelog(logfile) { diff --git a/package.json b/package.json index 59f1435..c39c68f 100644 --- a/package.json +++ b/package.json @@ -7,25 +7,25 @@ "egg-scripts": "bin/egg-scripts.js" }, "dependencies": { - "common-bin": "^2.5.0", + "common-bin": "^2.7.1", "egg-utils": "^2.2.0", - "moment": "^2.18.1", - "mz": "^2.6.0", - "mz-modules": "^1.0.0", - "node-homedir": "^1.0.0", + "moment": "^2.19.1", + "mz": "^2.7.0", + "mz-modules": "^2.0.0", + "node-homedir": "^1.1.0", "runscript": "^1.3.0", "zlogger": "^1.1.0" }, "devDependencies": { - "autod": "^2.9.0", + "autod": "^2.10.1", "coffee": "^4.1.0", - "egg": "^1.7.0", - "egg-bin": "^4.1.0", + "egg": "^1.9.0", + "egg-bin": "^4.3.5", "egg-ci": "^1.8.0", - "eslint": "^4.4.1", - "eslint-config-egg": "^5.0.0", - "mm": "^2.1.0", - "urllib": "^2.24.0", + "eslint": "^4.8.0", + "eslint-config-egg": "^5.1.1", + "mm": "^2.2.0", + "urllib": "^2.25.0", "webstorm-disable-index": "^1.2.0" }, "engines": { diff --git a/test/fixtures/cluster-config/config/config.prod.js b/test/fixtures/cluster-config/config/config.prod.js index fa189b2..e7523db 100644 --- a/test/fixtures/cluster-config/config/config.prod.js +++ b/test/fixtures/cluster-config/config/config.prod.js @@ -3,5 +3,5 @@ exports.cluster = { listen: { port: 8000, - } -} + }, +}; diff --git a/test/fixtures/egg-app/config/config.default.js b/test/fixtures/egg-app/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/egg-app/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/egg-app/node_modules/egg/index.js b/test/fixtures/egg-app/node_modules/egg/index.js new file mode 100644 index 0000000..7a1482f --- /dev/null +++ b/test/fixtures/egg-app/node_modules/egg/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('../../../../../node_modules/egg'); diff --git a/test/fixtures/egg-app/node_modules/egg/package.json b/test/fixtures/egg-app/node_modules/egg/package.json new file mode 100644 index 0000000..034e266 --- /dev/null +++ b/test/fixtures/egg-app/node_modules/egg/package.json @@ -0,0 +1,4 @@ +{ + "name": "egg", + "version": "1.0.0" +} diff --git a/test/fixtures/egg-app/package.json b/test/fixtures/egg-app/package.json new file mode 100644 index 0000000..f833722 --- /dev/null +++ b/test/fixtures/egg-app/package.json @@ -0,0 +1,6 @@ +{ + "name": "example", + "dependencies": { + "egg": "^1.0.0" + } +} diff --git a/test/fixtures/example/node_modules/custom-framework/index.js b/test/fixtures/example/node_modules/custom-framework/index.js index 50b41a0..071acea 100644 --- a/test/fixtures/example/node_modules/custom-framework/index.js +++ b/test/fixtures/example/node_modules/custom-framework/index.js @@ -17,5 +17,5 @@ module.exports = Object.assign(egg, { process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; } return originStartCluster(...args); - } + }, }); diff --git a/test/fixtures/example/node_modules/yadan/index.js b/test/fixtures/example/node_modules/yadan/index.js index 5ce51a8..246811a 100644 --- a/test/fixtures/example/node_modules/yadan/index.js +++ b/test/fixtures/example/node_modules/yadan/index.js @@ -2,8 +2,6 @@ const egg = require('../../../../../node_modules/egg'); -const originStartCluster = egg.startCluster; - module.exports = Object.assign(egg, { Application: class CustomApplication extends egg.Application { get [Symbol.for('egg#eggPath')]() { diff --git a/test/fixtures/status/app.js b/test/fixtures/status/app.js new file mode 100644 index 0000000..7ba4259 --- /dev/null +++ b/test/fixtures/status/app.js @@ -0,0 +1,13 @@ +'use strict'; + +const sleep = require('mz-modules/sleep'); + +module.exports = app => { + if (process.env.ERROR) { + app.logger.error(new Error(process.env.ERROR)); + } + + app.beforeStart(function* () { + yield sleep(process.env.WAIT_TIME); + }); +}; diff --git a/test/fixtures/status/config/config.default.js b/test/fixtures/status/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/status/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/status/node_modules/custom-framework/index.js b/test/fixtures/status/node_modules/custom-framework/index.js new file mode 100644 index 0000000..071acea --- /dev/null +++ b/test/fixtures/status/node_modules/custom-framework/index.js @@ -0,0 +1,21 @@ +'use strict'; + +const egg = require('../../../../../node_modules/egg'); + +const originStartCluster = egg.startCluster; + +module.exports = Object.assign(egg, { + Application: class CustomApplication extends egg.Application { + get [Symbol.for('egg#eggPath')]() { + return __dirname; + } + }, + startCluster(...args) { + if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { + console.log('## EGG_SERVER_ENV is not pass'); + console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); + process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; + } + return originStartCluster(...args); + }, +}); diff --git a/test/fixtures/status/node_modules/custom-framework/package.json b/test/fixtures/status/node_modules/custom-framework/package.json new file mode 100644 index 0000000..a9328f7 --- /dev/null +++ b/test/fixtures/status/node_modules/custom-framework/package.json @@ -0,0 +1,7 @@ +{ + "name": "custom-framework", + "version": "1.0.0", + "dependencies": { + "egg": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/status/package.json b/test/fixtures/status/package.json new file mode 100644 index 0000000..5fc5476 --- /dev/null +++ b/test/fixtures/status/package.json @@ -0,0 +1,10 @@ +{ + "name": "example", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + }, + "egg": { + "framework": "custom-framework" + } +} diff --git a/test/start.test.js b/test/start.test.js index a034ac9..f00ce80 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -25,7 +25,7 @@ describe('test/start.test.js', () => { yield rimraf(homePath); }); beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); - afterEach(() => mm.restore); + afterEach(mm.restore); describe('start without daemon', () => { describe('full path', () => { @@ -338,30 +338,29 @@ describe('test/start.test.js', () => { }); describe('start with daemon', () => { - let app; - - before(function* () { - yield utils.cleanup(fixturePath); + let cwd; + beforeEach(function* () { + yield utils.cleanup(cwd); yield rimraf(logDir); yield mkdirp(logDir); yield fs.writeFile(path.join(logDir, 'master-stdout.log'), 'just for test'); yield fs.writeFile(path.join(logDir, 'master-stderr.log'), 'just for test'); }); - - after(function* () { - app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + afterEach(function* () { + yield coffee.fork(eggBin, [ 'stop', cwd ]) + .debug() + .end(); + yield utils.cleanup(cwd); }); - it('should start', function* () { - app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', '--port=7002', fixturePath ]); - // app.debug(); - app.expect('code', 0); - - yield sleep(waitTime); - - assert(app.stdout.match(/starting egg.*example/)); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7002/)); + it('should start custom-framework', function* () { + cwd = fixturePath; + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', '--port=7002', cwd ]) + // .debug() + .expect('stdout', /Starting custom-framework application/) + .expect('stdout', /custom-framework started on http:\/\/127\.0\.0\.1:7002/) + .expect('code', 0) + .end(); // master log const stdout = yield fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); @@ -377,6 +376,62 @@ describe('test/start.test.js', () => { const result = yield httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString() === 'hi, egg'); }); + + it('should start default egg', function* () { + cwd = path.join(__dirname, 'fixtures/egg-app'); + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', cwd ]) + .debug() + .expect('stdout', /Starting egg application/) + .expect('stdout', /egg started on http:\/\/127\.0\.0\.1:7001/) + .expect('code', 0) + .end(); + }); }); + describe('check status', () => { + const cwd = path.join(__dirname, 'fixtures/status'); + + after(function* () { + yield coffee.fork(eggBin, [ 'stop', cwd ]) + // .debug() + .end(); + yield utils.cleanup(cwd); + }); + + it('should status check success, exit with 0', function* () { + mm(process.env, 'WAIT_TIME', 5000); + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) + // .debug() + .expect('stdout', /Wait Start: 5.../) + .expect('stdout', /custom-framework started/) + .expect('code', 0) + .end(); + }); + + it('should status check fail, exit with 1', function* () { + mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'ERROR', 'error message'); + + const stderr = path.join(homePath, 'logs/master-stderr.log'); + + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) + // .debug() + .expect('stderr', /nodejs.Error: error message/) + .expect('stderr', new RegExp(`Start failed, see ${stderr}`)) + .expect('code', 1) + .end(); + }); + + it('should status check timeout and exit with code 1', function* () { + mm(process.env, 'WAIT_TIME', 10000); + + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--timeout=5000' ], { cwd }) + // .debug() + .expect('stdout', /Wait Start: 1.../) + .expect('stderr', /Start failed, 5s timeout/) + .expect('code', 1) + .end(); + }); + + }); }); diff --git a/test/stop.test.js b/test/stop.test.js index 2fd109f..bb79773 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -114,32 +114,29 @@ describe('test/stop.test.js', () => { }); describe('stop with daemon', () => { - let app; - let killer; - - before(function* () { + beforeEach(function* () { yield utils.cleanup(fixturePath); yield rimraf(logDir); - app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', fixturePath ]); - // app.debug(); - app.expect('code', 0); - yield sleep('10s'); + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', fixturePath ]) + .debug() + .expect('code', 0) + .end(); const result = yield httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - - after(function* () { - app.proc.kill('SIGTERM'); + afterEach(function* () { yield utils.cleanup(fixturePath); }); it('should stop', function* () { - killer = coffee.fork(eggBin, [ 'stop', fixturePath ]); - killer.debug(); - killer.expect('code', 0); + yield coffee.fork(eggBin, [ 'stop', fixturePath ]) + .debug() + .expect('stdout', new RegExp(`\\[egg-scripts] stopping egg application at ${fixturePath}`)) + .expect('stdout', /got master pid \["\d+\"\]/i) + .expect('code', 0) + .end(); - yield killer.end(); yield sleep(waitTime); // master log @@ -148,25 +145,24 @@ describe('test/stop.test.js', () => { assert(stdout.includes('[master] receive signal SIGTERM, closing')); assert(stdout.includes('[master] exit with code:0')); assert(stdout.includes('[app_worker] exit with code:0')); - // assert(stdout.includes('[agent_worker] exit with code:0')); - assert(killer.stdout.includes(`[egg-scripts] stopping egg application at ${fixturePath}`)); - assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); + + yield coffee.fork(eggBin, [ 'stop', fixturePath ]) + .debug() + .expect('stderr', /can't detect any running egg process/) + .expect('code', 0) + .end(); }); }); describe('stop with not exist', () => { - let killer; - it('should work', function* () { yield utils.cleanup(fixturePath); - killer = coffee.fork(eggBin, [ 'stop', fixturePath ]); - killer.debug(); - killer.expect('code', 0); - - yield sleep('5s'); - - assert(killer.stdout.includes(`[egg-scripts] stopping egg application at ${fixturePath}`)); - assert(killer.stderr.includes('can\'t detect any running egg process')); + yield coffee.fork(eggBin, [ 'stop', fixturePath ]) + .debug() + .expect('stdout', new RegExp(`\\[egg-scripts] stopping egg application at ${fixturePath}`)) + .expect('stderr', /can't detect any running egg process/) + .expect('code', 0) + .end(); }); }); }); From e20705246483006e77723ef153e01f78ae0a67e0 Mon Sep 17 00:00:00 2001 From: popomore Date: Fri, 13 Oct 2017 22:06:50 +0800 Subject: [PATCH 03/72] Release 2.0.0 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index cbdc986..bfc6481 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.0.0 / 2017-10-13 +================== + +**features** + * [[`0f7ca50`](http://github.com/eggjs/egg-scripts/commit/0f7ca502999c06a9cb05d8e5617f6045704511df)] - feat: [BREAKING_CHANGE] check the status of app when start on daemon (#9) (Haoliang Gao <>) + +**others** + * [[`cfd0d2f`](http://github.com/eggjs/egg-scripts/commit/cfd0d2f67845fffb9d5974514b65e43b22ed8040)] - refactor: modify the directory of logDir (#8) (Haoliang Gao <>) + 1.2.0 / 2017-09-11 ================== diff --git a/package.json b/package.json index c39c68f..a9487a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "1.2.0", + "version": "2.0.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From ac40135d5b9a3200ea1bdfdb19d0f7e12d0c511a Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Mon, 16 Oct 2017 07:06:16 -0500 Subject: [PATCH 04/72] feat: add eggctl bin (#10) --- README.md | 21 ++++++++++++--------- lib/cmd/start.js | 6 +++--- package.json | 3 ++- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a1b3b66..ce7c284 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ $ npm i egg-scripts --save ## Usage -Add `egg-scripts` to `package.json` scripts: +Add `eggctl` to `package.json` scripts: ```json { "scripts": { - "start": "egg-scripts start --daemon", - "stop": "egg-scripts stop" + "start": "eggctl start --daemon", + "stop": "eggctl stop" } } ``` @@ -36,10 +36,10 @@ Then run as: Start egg at prod mode. ```bash -$ egg-scripts start [options] [baseDir] +$ eggctl start [options] [baseDir] # Usage -# egg-scripts start --port=7001 -# egg-scripts start ./server +# eggctl start --port=7001 +# eggctl start ./server ``` - **Arguments** @@ -50,7 +50,10 @@ $ egg-scripts start [options] [baseDir] - `workers` - numbers of app workers, default to `process.env.EGG_WORKERS`, if unset, egg will use `os.cpus().length` as default. - `daemon` - whether run at background daemon mode. - `framework` - specify framework that can be absolute path or npm package, default to auto detect. - - `env` - egg server env, default to `process.env.EGG_SERVER_ENV`, recommended to keep empty then use framwork default env. + - `env` - server env, default to `process.env.EGG_SERVER_ENV`, recommended to keep empty then use framwork default env. + - `stdout` - customize stdout file, default to `$HOME/logs/master-stdout.log`. + - `stderr` - customize stderr file, default to `$HOME/logs/master-stderr.log`. + - `timeout` - the maximum timeout when app starts, default to 300s. ### stop @@ -58,8 +61,8 @@ Stop egg gracefull. ```bash # stop egg -$ egg-scripts stop [baseDir] -# egg-scripts stop ./server +$ eggctl stop [baseDir] +# eggctl stop ./server ``` - **Arguments** diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 12dc48f..5271f90 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -47,15 +47,15 @@ class StartCommand extends Command { type: 'boolean', }, stdout: { - description: 'A file that stdout redirect to', + description: 'customize stdout file', type: 'string', }, stderr: { - description: 'A file that stderr redirect to', + description: 'customize stderr file', type: 'string', }, timeout: { - description: 'a timeout for start when daemon', + description: 'the maximum timeout when app starts', type: 'number', default: 300 * 1000, }, diff --git a/package.json b/package.json index a9487a6..6d65b18 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "deploy tool for egg project", "main": "index.js", "bin": { - "egg-scripts": "bin/egg-scripts.js" + "egg-scripts": "bin/egg-scripts.js", + "eggctl": "bin/egg-scripts.js" }, "dependencies": { "common-bin": "^2.7.1", From f5d502e35d6436f4f06d87444d964bd72f28d652 Mon Sep 17 00:00:00 2001 From: popomore Date: Mon, 16 Oct 2017 20:09:29 +0800 Subject: [PATCH 05/72] Release 2.1.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index bfc6481..d5ff0dc 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.1.0 / 2017-10-16 +================== + +**features** + * [[`ac40135`](http://github.com/eggjs/egg-scripts/commit/ac40135d5b9a3200ea1bdfdb19d0f7e12d0c511a)] - feat: add eggctl bin (#10) (Haoliang Gao <>) + 2.0.0 / 2017-10-13 ================== diff --git a/package.json b/package.json index 6d65b18..78ffd82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.0.0", + "version": "2.1.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 7324d99b504cac5fef7dbf280f7d9e6243c16bb7 Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Tue, 14 Nov 2017 14:26:14 +0800 Subject: [PATCH 06/72] fix: should stop app when baseDir is symlink (#12) --- lib/cmd/stop.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index 250014e..ec5fb56 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -37,7 +37,7 @@ class StopCommand extends Command { // node /Users/tz/Workspaces/eggjs/egg-scripts/lib/start-cluster {"title":"egg-server","workers":4,"port":7001,"baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg"} let processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; - return cmd.includes(this.serverBin) && cmd.includes(`"baseDir":"${baseDir}"`); + return cmd.includes('start-cluster'); }); let pids = processList.map(x => x.pid); @@ -55,7 +55,7 @@ class StopCommand extends Command { // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; - return cmd.includes(`"baseDir":"${baseDir}"`) && (cmd.includes('app_worker.js') || cmd.includes('agent_worker.js')); + return cmd.includes('egg-cluster/lib/app_worker.js') || cmd.includes('egg-cluster/lib/agent_worker.js'); }); pids = processList.map(x => x.pid); From 0c376a14312b9f7809514276a20221850fc6affd Mon Sep 17 00:00:00 2001 From: popomore Date: Tue, 14 Nov 2017 14:27:18 +0800 Subject: [PATCH 07/72] Release 2.1.1 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index d5ff0dc..8720bc0 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.1.1 / 2017-11-14 +================== + +**fixes** + * [[`7324d99`](http://github.com/eggjs/egg-scripts/commit/7324d99b504cac5fef7dbf280f7d9e6243c16bb7)] - fix: should stop app when baseDir is symlink (#12) (Haoliang Gao <>) + 2.1.0 / 2017-10-16 ================== diff --git a/package.json b/package.json index 78ffd82..dc4566f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.1.0", + "version": "2.1.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From ac58d00a974fdfff6b5c722743e4b32174963c52 Mon Sep 17 00:00:00 2001 From: zhennann Date: Wed, 22 Nov 2017 23:11:18 +0800 Subject: [PATCH 08/72] feat: cwd maybe not baseDir (#15) --- lib/cmd/start.js | 1 - .../subdir-as-basedir/base-dir/app/router.js | 15 ++++++++++ .../base-dir/config/config.default.js | 3 ++ .../subdir-as-basedir/base-dir/package.json | 3 ++ test/fixtures/subdir-as-basedir/package.json | 3 ++ test/start.test.js | 28 +++++++++++++++++++ 6 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/subdir-as-basedir/base-dir/app/router.js create mode 100644 test/fixtures/subdir-as-basedir/base-dir/config/config.default.js create mode 100644 test/fixtures/subdir-as-basedir/base-dir/package.json create mode 100644 test/fixtures/subdir-as-basedir/package.json diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 5271f90..53361bc 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -122,7 +122,6 @@ class StartCommand extends Command { argv.daemon = undefined; const options = { - cwd: baseDir, execArgv: context.execArgv, env, stdio: 'inherit', diff --git a/test/fixtures/subdir-as-basedir/base-dir/app/router.js b/test/fixtures/subdir-as-basedir/base-dir/app/router.js new file mode 100644 index 0000000..cd29c09 --- /dev/null +++ b/test/fixtures/subdir-as-basedir/base-dir/app/router.js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = app => { + app.get('/', function* () { + this.body = `hi, ${app.config.framework || 'egg'}`; + }); + + app.get('/env', function* () { + this.body = app.config.env + ', ' + app.config.pre; + }); + + app.get('/path', function* () { + this.body = process.env.PATH; + }); +}; diff --git a/test/fixtures/subdir-as-basedir/base-dir/config/config.default.js b/test/fixtures/subdir-as-basedir/base-dir/config/config.default.js new file mode 100644 index 0000000..c997e00 --- /dev/null +++ b/test/fixtures/subdir-as-basedir/base-dir/config/config.default.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.keys = '123456'; diff --git a/test/fixtures/subdir-as-basedir/base-dir/package.json b/test/fixtures/subdir-as-basedir/base-dir/package.json new file mode 100644 index 0000000..37ddf6c --- /dev/null +++ b/test/fixtures/subdir-as-basedir/base-dir/package.json @@ -0,0 +1,3 @@ +{ + "name": "base-dir" +} \ No newline at end of file diff --git a/test/fixtures/subdir-as-basedir/package.json b/test/fixtures/subdir-as-basedir/package.json new file mode 100644 index 0000000..fbbc6a0 --- /dev/null +++ b/test/fixtures/subdir-as-basedir/package.json @@ -0,0 +1,3 @@ +{ + "name": "subdir-as-basedir" +} \ No newline at end of file diff --git a/test/start.test.js b/test/start.test.js index f00ce80..8ae67bb 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -335,6 +335,34 @@ describe('test/start.test.js', () => { assert(result.data.toString() === 'hi, egg'); }); }); + + describe('subDir as baseDir', () => { + let app; + const rootDir = path.join(__dirname, '..'); + const subDir = path.join(__dirname, 'fixtures/subdir-as-basedir/base-dir'); + + before(function* () { + yield utils.cleanup(rootDir); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(rootDir); + }); + + it('should start', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=2', subDir ], { cwd: rootDir }); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, egg'); + }); + }); }); describe('start with daemon', () => { From e1a11c2988594696d68cb902c1cf58766adadd2f Mon Sep 17 00:00:00 2001 From: popomore Date: Wed, 22 Nov 2017 23:12:14 +0800 Subject: [PATCH 09/72] Release 2.2.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 8720bc0..12023a4 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.2.0 / 2017-11-22 +================== + +**features** + * [[`ac58d00`](http://github.com/eggjs/egg-scripts/commit/ac58d00a974fdfff6b5c722743e4b32174963c52)] - feat: cwd maybe not baseDir (#15) (zhennann <>) + 2.1.1 / 2017-11-14 ================== diff --git a/package.json b/package.json index dc4566f..294a525 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.1.1", + "version": "2.2.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 4c41319f9e309402b2ccb5c7afd5a6d3cda2453f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Tue, 28 Nov 2017 18:54:46 +0800 Subject: [PATCH 10/72] feat: support stop --title (#16) * feat: support stop --title * feat: remove stop baseDir --- README.md | 9 +-- lib/cmd/start.js | 2 +- lib/cmd/stop.js | 25 ++++--- package.json | 12 +-- test/stop.test.js | 184 +++++++++++++++++++++++++++++++--------------- 5 files changed, 148 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index ce7c284..1b7e96a 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ $ eggctl start [options] [baseDir] - `baseDir` - directory of application, default to `process.cwd()`. - **Options** - `port` - listening port, default to `process.env.PORT`, if unset, egg will use `7001` as default. - - `title` - process title description, use for kill grep, default to `egg-server-APPNAME`. + - `title` - process title description, use for kill grep, default to `egg-server-${APP_NAME}`. - `workers` - numbers of app workers, default to `process.env.EGG_WORKERS`, if unset, egg will use `os.cpus().length` as default. - `daemon` - whether run at background daemon mode. - `framework` - specify framework that can be absolute path or npm package, default to auto detect. @@ -61,9 +61,8 @@ Stop egg gracefull. ```bash # stop egg -$ eggctl stop [baseDir] -# eggctl stop ./server +$ eggctl stop [--title=example] ``` -- **Arguments** - - `baseDir` - directory of application, default to `process.cwd()`. +- **Options** + - `title` - process title description, use for kill grep. \ No newline at end of file diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 53361bc..09fbd50 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -19,7 +19,7 @@ class StartCommand extends Command { this.options = { title: { - description: 'process title description, use for kill grep, default to `egg-server-APPNAME`', + description: 'process title description, use for kill grep, default to `egg-server-${APP_NAME}`', type: 'string', }, workers: { diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index ec5fb56..09585c8 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -8,8 +8,14 @@ class StopCommand extends Command { constructor(rawArgv) { super(rawArgv); - this.usage = 'Usage: egg-scripts stop [baseDir]'; + this.usage = 'Usage: egg-scripts stop [--title=example]'; this.serverBin = path.join(__dirname, '../start-cluster'); + this.options = { + title: { + description: 'process title description, use for kill grep', + type: 'string', + }, + }; } get description() { @@ -25,19 +31,14 @@ class StopCommand extends Command { const { argv } = context; - // egg-script stop - // egg-script stop ./server - // egg-script stop /opt/app - let baseDir = argv._[0] || context.cwd; - if (!path.isAbsolute(baseDir)) baseDir = path.join(context.cwd, baseDir); - argv.baseDir = baseDir; - - this.logger.info(`stopping egg application at ${baseDir}`); + this.logger.info(`stopping egg application ${argv.title ? `with --title=${argv.title}` : ''}`); // node /Users/tz/Workspaces/eggjs/egg-scripts/lib/start-cluster {"title":"egg-server","workers":4,"port":7001,"baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg"} let processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; - return cmd.includes('start-cluster'); + return argv.title ? + cmd.includes('start-cluster') && cmd.includes(`"title":"${argv.title}"`) : + cmd.includes('start-cluster'); }); let pids = processList.map(x => x.pid); @@ -55,7 +56,9 @@ class StopCommand extends Command { // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; - return cmd.includes('egg-cluster/lib/app_worker.js') || cmd.includes('egg-cluster/lib/agent_worker.js'); + return argv.title ? + (cmd.includes('egg-cluster/lib/app_worker.js') || cmd.includes('egg-cluster/lib/agent_worker.js')) && cmd.includes(`"title":"${argv.title}"`) : + (cmd.includes('egg-cluster/lib/app_worker.js') || cmd.includes('egg-cluster/lib/agent_worker.js')); }); pids = processList.map(x => x.pid); diff --git a/package.json b/package.json index 294a525..fe17c02 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ }, "dependencies": { "common-bin": "^2.7.1", - "egg-utils": "^2.2.0", - "moment": "^2.19.1", + "egg-utils": "^2.3.0", + "moment": "^2.19.2", "mz": "^2.7.0", "mz-modules": "^2.0.0", "node-homedir": "^1.1.0", @@ -18,15 +18,15 @@ "zlogger": "^1.1.0" }, "devDependencies": { - "autod": "^2.10.1", + "autod": "^3.0.1", "coffee": "^4.1.0", - "egg": "^1.9.0", + "egg": "^1.11.0", "egg-bin": "^4.3.5", "egg-ci": "^1.8.0", - "eslint": "^4.8.0", + "eslint": "^4.11.0", "eslint-config-egg": "^5.1.1", "mm": "^2.2.0", - "urllib": "^2.25.0", + "urllib": "^2.25.1", "webstorm-disable-index": "^1.2.0" }, "engines": { diff --git a/test/stop.test.js b/test/stop.test.js index bb79773..d623700 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -49,67 +49,23 @@ describe('test/stop.test.js', () => { yield utils.cleanup(fixturePath); }); - describe('full path', () => { - it('should stop', function* () { - killer = coffee.fork(eggBin, [ 'stop', fixturePath ]); - killer.debug(); - killer.expect('code', 0); - - // yield killer.end(); - yield sleep(waitTime); - - // make sure is kill not auto exist - assert(!app.stdout.includes('exist by env')); - - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); - // assert(app.stdout.includes('[agent_worker] exit with code:0')); - assert(killer.stdout.includes(`[egg-scripts] stopping egg application at ${fixturePath}`)); - assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); - }); - }); + it('should stop', function* () { + killer = coffee.fork(eggBin, [ 'stop', fixturePath ]); + killer.debug(); + killer.expect('code', 0); - describe('relative path', () => { - it('should stop', function* () { - killer = coffee.fork(eggBin, [ 'stop', path.relative(process.cwd(), fixturePath) ]); - killer.debug(); - killer.expect('code', 0); - - // yield killer.end(); - yield sleep(waitTime); - - // make sure is kill not auto exist - assert(!app.stdout.includes('exist by env')); - - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); - // assert(app.stdout.includes('[agent_worker] exit with code:0')); - assert(killer.stdout.includes(`[egg-scripts] stopping egg application at ${fixturePath}`)); - assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); - }); - }); + // yield killer.end(); + yield sleep(waitTime); + + // make sure is kill not auto exist + assert(!app.stdout.includes('exist by env')); - describe('without baseDir', () => { - it('should stop', function* () { - killer = coffee.fork(eggBin, [ 'stop' ], { cwd: fixturePath }); - killer.debug(); - killer.expect('code', 0); - - // yield killer.end(); - yield sleep(waitTime); - - // make sure is kill not auto exist - assert(!app.stdout.includes('exist by env')); - - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); - // assert(app.stdout.includes('[agent_worker] exit with code:0')); - assert(killer.stdout.includes(`[egg-scripts] stopping egg application at ${fixturePath}`)); - assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); - }); + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[app_worker] exit with code:0')); + // assert(app.stdout.includes('[agent_worker] exit with code:0')); + assert(killer.stdout.includes('[egg-scripts] stopping egg application')); + assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); }); }); @@ -132,7 +88,7 @@ describe('test/stop.test.js', () => { it('should stop', function* () { yield coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() - .expect('stdout', new RegExp(`\\[egg-scripts] stopping egg application at ${fixturePath}`)) + .expect('stdout', /\[egg-scripts] stopping egg application/) .expect('stdout', /got master pid \["\d+\"\]/i) .expect('code', 0) .end(); @@ -159,10 +115,116 @@ describe('test/stop.test.js', () => { yield utils.cleanup(fixturePath); yield coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() - .expect('stdout', new RegExp(`\\[egg-scripts] stopping egg application at ${fixturePath}`)) + .expect('stdout', /\[egg-scripts] stopping egg application/) + .expect('stderr', /can't detect any running egg process/) + .expect('code', 0) + .end(); + }); + }); + + describe('stop --title', () => { + let app; + let killer; + + beforeEach(function* () { + yield utils.cleanup(fixturePath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]); + // app.debug(); + app.expect('code', 0); + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, egg'); + }); + + afterEach(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should stop', function* () { + yield coffee.fork(eggBin, [ 'stop', '--title=random', fixturePath ]) + .debug() + .expect('stdout', /\[egg-scripts] stopping egg application with --title=random/) .expect('stderr', /can't detect any running egg process/) .expect('code', 0) .end(); + + killer = coffee.fork(eggBin, [ 'stop', '--title=example' ], { cwd: fixturePath }); + killer.debug(); + killer.expect('code', 0); + + // yield killer.end(); + yield sleep(waitTime); + + // make sure is kill not auto exist + assert(!app.stdout.includes('exist by env')); + + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[app_worker] exit with code:0')); + // assert(app.stdout.includes('[agent_worker] exit with code:0')); + assert(killer.stdout.includes('[egg-scripts] stopping egg application with --title=example')); + assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); + }); + }); + + describe('stop all', () => { + let app; + let app2; + let killer; + + beforeEach(function* () { + yield utils.cleanup(fixturePath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]); + // app.debug(); + app.expect('code', 0); + + app2 = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=test', '--port=7002', fixturePath ]); + app2.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, egg'); + + assert(app2.stderr === ''); + assert(app2.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); + const result2 = yield httpclient.request('http://127.0.0.1:7002'); + assert(result2.data.toString() === 'hi, egg'); + }); + + afterEach(function* () { + app.proc.kill('SIGTERM'); + app2.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should stop', function* () { + killer = coffee.fork(eggBin, [ 'stop' ], { cwd: fixturePath }); + killer.debug(); + killer.expect('code', 0); + + // yield killer.end(); + yield sleep(waitTime); + + // make sure is kill not auto exist + assert(!app.stdout.includes('exist by env')); + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[app_worker] exit with code:0')); + // assert(app.stdout.includes('[agent_worker] exit with code:0')); + assert(killer.stdout.includes('[egg-scripts] stopping egg application')); + assert(killer.stdout.match(/got master pid \["\d+\","\d+\"\]/i)); + + assert(!app2.stdout.includes('exist by env')); + assert(app2.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app2.stdout.includes('[master] exit with code:0')); + assert(app2.stdout.includes('[app_worker] exit with code:0')); }); }); }); From c6cdf0961c4a5d35c931a44a05807189e9e523e0 Mon Sep 17 00:00:00 2001 From: popomore Date: Wed, 29 Nov 2017 09:25:54 +0800 Subject: [PATCH 11/72] Release 2.3.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 12023a4..e7c266f 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.3.0 / 2017-11-29 +================== + +**features** + * [[`4c41319`](http://github.com/eggjs/egg-scripts/commit/4c41319f9e309402b2ccb5c7afd5a6d3cda2453f)] - feat: support stop --title (#16) (TZ | 天猪 <>) + 2.2.0 / 2017-11-22 ================== diff --git a/package.json b/package.json index fe17c02..d61a163 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.2.0", + "version": "2.3.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 4dd24a45d92b2c2a8e1e450e0f13ba4143550ca9 Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Thu, 30 Nov 2017 09:23:06 +0800 Subject: [PATCH 12/72] test: add testcase for #12 (#13) --- test/stop.test.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/stop.test.js b/test/stop.test.js index d623700..1ea012e 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -227,4 +227,41 @@ describe('test/stop.test.js', () => { assert(app2.stdout.includes('[app_worker] exit with code:0')); }); }); + + describe('stop with symlink', () => { + const baseDir = path.join(__dirname, 'fixtures/tmp'); + + beforeEach(function* () { + yield fs.symlink(fixturePath, baseDir); + + yield utils.cleanup(fixturePath); + yield rimraf(logDir); + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2' ], { cwd: baseDir }) + .debug() + .expect('stdout', new RegExp(`Starting custom-framework application at ${fixturePath}`)) + .expect('code', 0) + .end(); + + yield rimraf(baseDir); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, egg'); + }); + afterEach(function* () { + yield utils.cleanup(fixturePath); + yield rimraf(baseDir); + }); + + it('should stop', function* () { + yield rimraf(baseDir); + yield fs.symlink(path.join(__dirname, 'fixtures/status'), baseDir); + + yield coffee.fork(eggBin, [ 'stop', baseDir ]) + .debug() + .expect('stdout', /\[egg-scripts] stopping egg application/) + .expect('stdout', /got master pid \["\d+\"\]/i) + .expect('code', 0) + .end(); + }); + }); + }); From 8eda3d10cfea5757f220fd82b562fd5fef433440 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 30 Nov 2017 16:44:38 +0800 Subject: [PATCH 13/72] feat: add `${baseDir}/.node/bin` to PATH if exists (#14) --- .travis.yml | 1 + appveyor.yml | 1 + lib/cmd/start.js | 16 +++++++--- package.json | 2 +- test/fixtures/custom-node-dir/.node/bin/foo | 1 + test/fixtures/custom-node-dir/app/router.js | 7 ++++ .../custom-node-dir/config/config.default.js | 3 ++ test/fixtures/custom-node-dir/package.json | 7 ++++ test/start.test.js | 32 +++++++++++++++++++ 9 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/custom-node-dir/.node/bin/foo create mode 100644 test/fixtures/custom-node-dir/app/router.js create mode 100644 test/fixtures/custom-node-dir/config/config.default.js create mode 100644 test/fixtures/custom-node-dir/package.json diff --git a/.travis.yml b/.travis.yml index 47cc542..f4f869c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: node_js node_js: - '6' - '8' + - '9' install: - npm i npminstall && npminstall script: diff --git a/appveyor.yml b/appveyor.yml index 3d15e52..f876d1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,6 +2,7 @@ environment: matrix: - nodejs_version: '6' - nodejs_version: '8' + - nodejs_version: '9' install: - ps: Install-Product node $env:nodejs_version diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 09fbd50..81b4f57 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -98,10 +98,18 @@ class StartCommand extends Command { env.NODE_ENV = 'production'; // adjust env for win - const envPath = env.PATH || env.Path; - if (envPath) { - // for nodeinstall - env.PATH = path.join(baseDir, 'node_modules/.bin') + path.delimiter + envPath; + const currentPATH = env.PATH || env.Path; + // for nodeinstall + let newPATH = `${path.join(baseDir, 'node_modules/.bin')}${path.delimiter}`; + // support `${baseDir}/.node/bin` + const customNodeBinDir = path.join(baseDir, '.node/bin'); + if (yield fs.exists(customNodeBinDir)) { + newPATH += `${customNodeBinDir}${path.delimiter}`; + } + if (currentPATH) { + env.PATH = `${newPATH}${currentPATH}`; + } else { + env.PATH = newPATH; } // for alinode diff --git a/package.json b/package.json index d61a163..3702fab 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "bin" ], "ci": { - "version": "6, 8" + "version": "6, 8, 9" }, "bug": { "url": "https://github.com/eggjs/egg/issues" diff --git a/test/fixtures/custom-node-dir/.node/bin/foo b/test/fixtures/custom-node-dir/.node/bin/foo new file mode 100644 index 0000000..5716ca5 --- /dev/null +++ b/test/fixtures/custom-node-dir/.node/bin/foo @@ -0,0 +1 @@ +bar diff --git a/test/fixtures/custom-node-dir/app/router.js b/test/fixtures/custom-node-dir/app/router.js new file mode 100644 index 0000000..20c9024 --- /dev/null +++ b/test/fixtures/custom-node-dir/app/router.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = app => { + app.get('/', function* () { + this.body = `hi, ${process.env.PATH}`; + }); +}; diff --git a/test/fixtures/custom-node-dir/config/config.default.js b/test/fixtures/custom-node-dir/config/config.default.js new file mode 100644 index 0000000..c997e00 --- /dev/null +++ b/test/fixtures/custom-node-dir/config/config.default.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.keys = '123456'; diff --git a/test/fixtures/custom-node-dir/package.json b/test/fixtures/custom-node-dir/package.json new file mode 100644 index 0000000..78ad6bb --- /dev/null +++ b/test/fixtures/custom-node-dir/package.json @@ -0,0 +1,7 @@ +{ + "name": "example", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + } +} diff --git a/test/start.test.js b/test/start.test.js index 8ae67bb..27106fe 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -363,6 +363,38 @@ describe('test/start.test.js', () => { assert(result.data.toString() === 'hi, egg'); }); }); + + describe('auto set custom node dir to PATH', () => { + let app; + const fixturePath = path.join(__dirname, 'fixtures/custom-node-dir'); + + before(function* () { + yield utils.cleanup(fixturePath); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should start', function* () { + const expectPATH = [ + path.join(fixturePath, 'node_modules/.bin'), + path.join(fixturePath, '.node/bin'), + ].join(path.delimiter) + path.delimiter; + app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + assert(!app.stdout.includes('app_worker#3:')); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString().startsWith(`hi, ${expectPATH}`)); + }); + }); }); describe('start with daemon', () => { From 3684d9f6b48184d8ca63e93bf2df1d63dde1a5d6 Mon Sep 17 00:00:00 2001 From: TZ Date: Thu, 30 Nov 2017 16:48:08 +0800 Subject: [PATCH 14/72] Release 2.4.0 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index e7c266f..3ef0436 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.4.0 / 2017-11-30 +================== + +**features** + * [[`8eda3d1`](https://github.com/eggjs/egg-scripts/commit/8eda3d10cfea5757f220fd82b562fd5fef433440)] - feat: add `${baseDir}/.node/bin` to PATH if exists (#14) (fengmk2 <>) + +**others** + * [[`4dd24a4`](https://github.com/eggjs/egg-scripts/commit/4dd24a45d92b2c2a8e1e450e0f13ba4143550ca9)] - test: add testcase for #12 (#13) (Haoliang Gao <>) + 2.3.0 / 2017-11-29 ================== diff --git a/package.json b/package.json index 3702fab..cb6a2e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.3.0", + "version": "2.4.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From b5559d54228543b5422047e6f056829df11f8c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Tue, 12 Dec 2017 17:42:47 +0800 Subject: [PATCH 15/72] feat: support --ignore-error (#17) --- README.md | 1 + lib/cmd/start.js | 78 ++++++++++++++++++++++++++++------------------ test/start.test.js | 16 +++++++++- 3 files changed, 63 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 1b7e96a..2631494 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ $ eggctl start [options] [baseDir] - `stdout` - customize stdout file, default to `$HOME/logs/master-stdout.log`. - `stderr` - customize stderr file, default to `$HOME/logs/master-stderr.log`. - `timeout` - the maximum timeout when app starts, default to 300s. + - `ignore-stderr` - whether ignore stderr when app starts. ### stop diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 81b4f57..720a2cb 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -59,6 +59,10 @@ class StartCommand extends Command { type: 'number', default: 300 * 1000, }, + 'ignore-stderr': { + description: 'whether ignore stderr when app starts', + type: 'boolean', + }, }; } @@ -67,15 +71,16 @@ class StartCommand extends Command { } * run(context) { - const argv = Object.assign({}, context.argv); + const { argv, env, cwd, execArgv } = context; + const HOME = homedir(); const logDir = path.join(HOME, 'logs'); // egg-script start // egg-script start ./server // egg-script start /opt/app - let baseDir = argv._[0] || context.cwd; - if (!path.isAbsolute(baseDir)) baseDir = path.join(context.cwd, baseDir); + let baseDir = argv._[0] || cwd; + if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); argv.baseDir = baseDir; const isDaemon = argv.daemon; @@ -93,24 +98,18 @@ class StartCommand extends Command { argv.stdout = argv.stdout || path.join(logDir, 'master-stdout.log'); argv.stderr = argv.stderr || path.join(logDir, 'master-stderr.log'); - const env = context.env; + // normalize env env.HOME = HOME; env.NODE_ENV = 'production'; - // adjust env for win - const currentPATH = env.PATH || env.Path; - // for nodeinstall - let newPATH = `${path.join(baseDir, 'node_modules/.bin')}${path.delimiter}`; - // support `${baseDir}/.node/bin` - const customNodeBinDir = path.join(baseDir, '.node/bin'); - if (yield fs.exists(customNodeBinDir)) { - newPATH += `${customNodeBinDir}${path.delimiter}`; - } - if (currentPATH) { - env.PATH = `${newPATH}${currentPATH}`; - } else { - env.PATH = newPATH; - } + env.PATH = [ + // for nodeinstall + path.join(baseDir, 'node_modules/.bin'), + // support `.node/bin`, due to npm5 will remove `node_modules/.bin` + path.join(baseDir, '.node/bin'), + // adjust env for win + env.PATH || env.Path, + ].filter(x => !!x).join(path.delimiter); // for alinode env.ENABLE_NODE_LOG = 'YES'; @@ -121,16 +120,10 @@ class StartCommand extends Command { if (argv.env) { // if undefined, should not pass key due to `spwan`, https://github.com/nodejs/node/blob/master/lib/child_process.js#L470 env.EGG_SERVER_ENV = argv.env; - argv.env = undefined; } - // remove unused properties, alias had been remove by `removeAlias` - argv._ = undefined; - argv.$0 = undefined; - argv.daemon = undefined; - const options = { - execArgv: context.execArgv, + execArgv, env, stdio: 'inherit', detached: false, @@ -138,7 +131,9 @@ class StartCommand extends Command { this.logger.info('Starting %s application at %s', this.frameworkName, baseDir); - const eggArgs = [ this.serverBin, JSON.stringify(argv), `--title=${argv.title}` ]; + // remove unused properties from stringify, alias had been remove by `removeAlias` + const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr' ]; + const eggArgs = [ this.serverBin, stringify(argv, ignoreKeys), `--title=${argv.title}` ]; this.logger.info('Run node %s', eggArgs.join(' ')); // whether run in the background. @@ -151,6 +146,7 @@ class StartCommand extends Command { const child = this.child = spawn('node', eggArgs, options); this.isReady = false; child.on('message', msg => { + /* istanbul ignore else */ if (msg && msg.action === 'egg-ready') { this.isReady = true; this.logger.info('%s started on %s', this.frameworkName, msg.data.address); @@ -177,6 +173,7 @@ class StartCommand extends Command { let name = 'egg'; try { const pkg = require(pkgPath); + /* istanbul ignore else */ if (pkg.name) name = pkg.name; } catch (_) { /* istanbul next */ @@ -184,18 +181,16 @@ class StartCommand extends Command { return name; } - * checkStatus({ stderr, timeout }) { + * checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) { let count = 0; + let hasError = false; let isSuccess = true; timeout = timeout / 1000; while (!this.isReady) { try { const stat = yield fs.stat(stderr); if (stat && stat.size > 0) { - const [ stdout ] = yield exec('tail -n 100 ' + stderr); - this.logger.error(stdout); - this.logger.error('Start failed, see %s', stderr); - isSuccess = false; + hasError = true; break; } } catch (_) { @@ -212,6 +207,17 @@ class StartCommand extends Command { this.logger.log('Wait Start: %d...', ++count); } + if (hasError) { + try { + const [ stdout ] = yield exec('tail -n 100 ' + stderr); + this.logger.error(stdout); + } catch (_) { + // nothing + } + isSuccess = ignoreStdErr; + this.logger.error('Start got error, see %s', stderr); + } + if (!isSuccess) { this.child.kill('SIGTERM'); yield sleep(1000); @@ -233,4 +239,14 @@ function* getRotatelog(logfile) { return yield fs.open(logfile, 'a'); } +function stringify(obj, ignore) { + const result = {}; + Object.keys(obj).forEach(key => { + if (!ignore.includes(key)) { + result[key] = obj[key]; + } + }); + return JSON.stringify(result); +} + module.exports = StartCommand; diff --git a/test/start.test.js b/test/start.test.js index 27106fe..9ef961e 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -468,6 +468,20 @@ describe('test/start.test.js', () => { .end(); }); + it('should status check fail `--ignore-stderr`, exit with 0', function* () { + mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'ERROR', 'error message'); + + const stderr = path.join(homePath, 'logs/master-stderr.log'); + + yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--ignore-stderr' ], { cwd }) + // .debug() + .expect('stderr', /nodejs.Error: error message/) + .expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + .expect('code', 0) + .end(); + }); + it('should status check fail, exit with 1', function* () { mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); @@ -477,7 +491,7 @@ describe('test/start.test.js', () => { yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) // .debug() .expect('stderr', /nodejs.Error: error message/) - .expect('stderr', new RegExp(`Start failed, see ${stderr}`)) + .expect('stderr', new RegExp(`Start got error, see ${stderr}`)) .expect('code', 1) .end(); }); From 9ce6764e5f41a468fd3a4db6d38a29222fd9900f Mon Sep 17 00:00:00 2001 From: popomore Date: Tue, 12 Dec 2017 18:11:17 +0800 Subject: [PATCH 16/72] Release 2.5.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 3ef0436..c96fc57 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.5.0 / 2017-12-12 +================== + +**features** + * [[`b5559d5`](http://github.com/eggjs/egg-scripts/commit/b5559d54228543b5422047e6f056829df11f8c87)] - feat: support --ignore-error (#17) (TZ | 天猪 <>) + 2.4.0 / 2017-11-30 ================== diff --git a/package.json b/package.json index cb6a2e8..bfed5d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.4.0", + "version": "2.5.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From c323edf7ab64dfb0890c921ade872213ebb72096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Tue, 6 Feb 2018 10:39:18 +0800 Subject: [PATCH 17/72] chore: add description for ignore-stderr (#18) --- README.md | 4 +++- lib/cmd/start.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2631494..e2e9775 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ $ eggctl start [options] [baseDir] - `port` - listening port, default to `process.env.PORT`, if unset, egg will use `7001` as default. - `title` - process title description, use for kill grep, default to `egg-server-${APP_NAME}`. - `workers` - numbers of app workers, default to `process.env.EGG_WORKERS`, if unset, egg will use `os.cpus().length` as default. - - `daemon` - whether run at background daemon mode. + - `daemon` - whether run at background daemon mode, don't use it if in docker mode. - `framework` - specify framework that can be absolute path or npm package, default to auto detect. - `env` - server env, default to `process.env.EGG_SERVER_ENV`, recommended to keep empty then use framwork default env. - `stdout` - customize stdout file, default to `$HOME/logs/master-stdout.log`. @@ -60,6 +60,8 @@ $ eggctl start [options] [baseDir] Stop egg gracefull. +**Note:** if exec without `--title`, it will kill all egg process. + ```bash # stop egg $ eggctl stop [--title=example] diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 720a2cb..6286043 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -210,12 +210,14 @@ class StartCommand extends Command { if (hasError) { try { const [ stdout ] = yield exec('tail -n 100 ' + stderr); + this.logger.error('Got error when startup: '); this.logger.error(stdout); } catch (_) { // nothing } isSuccess = ignoreStdErr; this.logger.error('Start got error, see %s', stderr); + this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.'); } if (!isSuccess) { From 0016e289167cb66113f00b0542d04b5ccbb7265e Mon Sep 17 00:00:00 2001 From: TZ Date: Tue, 6 Feb 2018 10:40:13 +0800 Subject: [PATCH 18/72] Release 2.5.1 --- History.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index c96fc57..e6e22ae 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +2.5.1 / 2018-02-06 +================== + + * chore: add description for ignore-stderr (#18) + 2.5.0 / 2017-12-12 ================== diff --git a/package.json b/package.json index bfed5d2..cdd963c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.5.0", + "version": "2.5.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 6e3fef51f38e372d9f02f105c3ad941f4e25ca32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Tue, 3 Apr 2018 19:11:42 +0800 Subject: [PATCH 19/72] feat: provides source map support for stack traces (#19) --- .eslintignore | 2 + .gitignore | 4 +- README.md | 2 + lib/cmd/start.js | 4 +- lib/command.js | 38 ++++++ package.json | 2 + test/fixtures/ts-pkg/app/controller/home.ts | 15 +++ test/fixtures/ts-pkg/app/router.js | 6 + test/fixtures/ts-pkg/config/config.default.js | 3 + test/fixtures/ts-pkg/package.json | 13 ++ test/fixtures/ts-pkg/tsconfig.json | 29 +++++ test/fixtures/ts/app/controller/home.ts | 15 +++ test/fixtures/ts/app/router.js | 6 + test/fixtures/ts/config/config.default.js | 3 + test/fixtures/ts/package.json | 10 ++ test/fixtures/ts/tsconfig.json | 29 +++++ test/start.test.js | 18 +-- test/ts.test.js | 112 ++++++++++++++++++ 18 files changed, 301 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/ts-pkg/app/controller/home.ts create mode 100644 test/fixtures/ts-pkg/app/router.js create mode 100644 test/fixtures/ts-pkg/config/config.default.js create mode 100644 test/fixtures/ts-pkg/package.json create mode 100644 test/fixtures/ts-pkg/tsconfig.json create mode 100644 test/fixtures/ts/app/controller/home.ts create mode 100644 test/fixtures/ts/app/router.js create mode 100644 test/fixtures/ts/config/config.default.js create mode 100644 test/fixtures/ts/package.json create mode 100644 test/fixtures/ts/tsconfig.json create mode 100644 test/ts.test.js diff --git a/.eslintignore b/.eslintignore index 4ebc8ae..8cc505f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ coverage +test/fixtures/ts/app/controller/home.js +test/fixtures/ts-pkg/app/controller/home.js \ No newline at end of file diff --git a/.gitignore b/.gitignore index 446bbe1..125fe6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ logs/ npm-debug.log -/node_modules +node_modules coverage/ .idea/ run/ .DS_Store *.swp +test/fixtures/ts/app/controller/home.js +test/fixtures/ts-pkg/app/controller/home.js \ No newline at end of file diff --git a/README.md b/README.md index e2e9775..5bf8a17 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Add `eggctl` to `package.json` scripts: ``` Then run as: + - `npm start` - `npm stop` @@ -55,6 +56,7 @@ $ eggctl start [options] [baseDir] - `stderr` - customize stderr file, default to `$HOME/logs/master-stderr.log`. - `timeout` - the maximum timeout when app starts, default to 300s. - `ignore-stderr` - whether ignore stderr when app starts. + - `sourcemap` / `typescript` / `ts` - provides source map support for stack traces. ### stop diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 6286043..5d562d6 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -133,7 +133,9 @@ class StartCommand extends Command { // remove unused properties from stringify, alias had been remove by `removeAlias` const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr' ]; - const eggArgs = [ this.serverBin, stringify(argv, ignoreKeys), `--title=${argv.title}` ]; + const clusterOptions = stringify(argv, ignoreKeys); + // Note: `spawn` is not like `fork`, had to pass `execArgv` youself + const eggArgs = [ ...(execArgv || []), this.serverBin, clusterOptions, `--title=${argv.title}` ]; this.logger.info('Run node %s', eggArgs.join(' ')); // whether run in the background. diff --git a/lib/command.js b/lib/command.js index 77f1a8e..c484252 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1,5 +1,7 @@ 'use strict'; +const fs = require('fs'); +const path = require('path'); const BaseCommand = require('common-bin'); const Logger = require('zlogger'); const helper = require('./helper'); @@ -16,11 +18,47 @@ class Command extends BaseCommand { execArgv: true, }; + // common-bin setter, don't care about override at sub class + // https://github.com/node-modules/common-bin/blob/master/lib/command.js#L158 + this.options = { + sourcemap: { + description: 'whether enable sourcemap support, will load `source-map-support` etc', + type: 'boolean', + alias: [ 'ts', 'typescript' ], + }, + }; + this.logger = new Logger({ prefix: '[egg-scripts] ', time: false, }); } + + get context() { + const context = super.context; + const { argv, execArgvObj, cwd } = context; + + // read `egg.typescript` from package.json + let baseDir = argv._[0] || cwd; + if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); + const pkgFile = path.join(baseDir, 'package.json'); + if (fs.existsSync(pkgFile)) { + const pkgInfo = require(pkgFile); + if (pkgInfo && pkgInfo.egg && pkgInfo.egg.typescript) { + argv.sourcemap = true; + } + } + + // execArgv + if (argv.sourcemap) { + execArgvObj.require = execArgvObj.require || []; + execArgvObj.require.push(require.resolve('source-map-support/register')); + } + + argv.sourcemap = argv.typescript = argv.ts = undefined; + + return context; + } } module.exports = Command; diff --git a/package.json b/package.json index cdd963c..f888b83 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "mz-modules": "^2.0.0", "node-homedir": "^1.1.0", "runscript": "^1.3.0", + "source-map-support": "^0.5.4", "zlogger": "^1.1.0" }, "devDependencies": { @@ -26,6 +27,7 @@ "eslint": "^4.11.0", "eslint-config-egg": "^5.1.1", "mm": "^2.2.0", + "typescript": "^2.8.1", "urllib": "^2.25.1", "webstorm-disable-index": "^1.2.0" }, diff --git a/test/fixtures/ts-pkg/app/controller/home.ts b/test/fixtures/ts-pkg/app/controller/home.ts new file mode 100644 index 0000000..f6a07cd --- /dev/null +++ b/test/fixtures/ts-pkg/app/controller/home.ts @@ -0,0 +1,15 @@ +import { Controller } from 'egg'; + +export default class AppController extends Controller { + public index() { + try { + throw new Error('some err'); + } catch (err) { + this.ctx.logger.error(err); + this.ctx.body = { + msg: err.message, + stack: err.stack, + }; + } + } +}; diff --git a/test/fixtures/ts-pkg/app/router.js b/test/fixtures/ts-pkg/app/router.js new file mode 100644 index 0000000..bece6e7 --- /dev/null +++ b/test/fixtures/ts-pkg/app/router.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = app => { + const { router, controller } = app; + router.get('/', controller.home.index); +}; diff --git a/test/fixtures/ts-pkg/config/config.default.js b/test/fixtures/ts-pkg/config/config.default.js new file mode 100644 index 0000000..c997e00 --- /dev/null +++ b/test/fixtures/ts-pkg/config/config.default.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.keys = '123456'; diff --git a/test/fixtures/ts-pkg/package.json b/test/fixtures/ts-pkg/package.json new file mode 100644 index 0000000..818511f --- /dev/null +++ b/test/fixtures/ts-pkg/package.json @@ -0,0 +1,13 @@ +{ + "name": "ts-pkg", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + }, + "egg": { + "typescript": true + }, + "scripts": { + "build": "node ../../../node_modules/.bin/tsc" + } +} diff --git a/test/fixtures/ts-pkg/tsconfig.json b/test/fixtures/ts-pkg/tsconfig.json new file mode 100644 index 0000000..f5bd4ba --- /dev/null +++ b/test/fixtures/ts-pkg/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "strict": true, + "noImplicitAny": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "charset": "utf8", + "allowJs": false, + "pretty": true, + "noEmitOnError": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "strictPropertyInitialization": false, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "inlineSourceMap": true, + "importHelpers": true + }, + "exclude": [ + "app/public", + "app/views" + ] +} \ No newline at end of file diff --git a/test/fixtures/ts/app/controller/home.ts b/test/fixtures/ts/app/controller/home.ts new file mode 100644 index 0000000..f6a07cd --- /dev/null +++ b/test/fixtures/ts/app/controller/home.ts @@ -0,0 +1,15 @@ +import { Controller } from 'egg'; + +export default class AppController extends Controller { + public index() { + try { + throw new Error('some err'); + } catch (err) { + this.ctx.logger.error(err); + this.ctx.body = { + msg: err.message, + stack: err.stack, + }; + } + } +}; diff --git a/test/fixtures/ts/app/router.js b/test/fixtures/ts/app/router.js new file mode 100644 index 0000000..bece6e7 --- /dev/null +++ b/test/fixtures/ts/app/router.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = app => { + const { router, controller } = app; + router.get('/', controller.home.index); +}; diff --git a/test/fixtures/ts/config/config.default.js b/test/fixtures/ts/config/config.default.js new file mode 100644 index 0000000..c997e00 --- /dev/null +++ b/test/fixtures/ts/config/config.default.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.keys = '123456'; diff --git a/test/fixtures/ts/package.json b/test/fixtures/ts/package.json new file mode 100644 index 0000000..5c422dd --- /dev/null +++ b/test/fixtures/ts/package.json @@ -0,0 +1,10 @@ +{ + "name": "ts", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + }, + "scripts": { + "build": "node ../../../node_modules/.bin/tsc" + } +} diff --git a/test/fixtures/ts/tsconfig.json b/test/fixtures/ts/tsconfig.json new file mode 100644 index 0000000..f5bd4ba --- /dev/null +++ b/test/fixtures/ts/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "strict": true, + "noImplicitAny": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "charset": "utf8", + "allowJs": false, + "pretty": true, + "noEmitOnError": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "strictPropertyInitialization": false, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "inlineSourceMap": true, + "importHelpers": true + }, + "exclude": [ + "app/public", + "app/views" + ] +} \ No newline at end of file diff --git a/test/start.test.js b/test/start.test.js index 9ef961e..42bc54a 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -310,9 +310,10 @@ describe('test/start.test.js', () => { describe('read cluster config', () => { let app; - const fixturePath = path.join(__dirname, 'fixtures/cluster-config'); + let fixturePath; before(function* () { + fixturePath = path.join(__dirname, 'fixtures/cluster-config'); yield utils.cleanup(fixturePath); }); @@ -366,9 +367,10 @@ describe('test/start.test.js', () => { describe('auto set custom node dir to PATH', () => { let app; - const fixturePath = path.join(__dirname, 'fixtures/custom-node-dir'); + let fixturePath; before(function* () { + fixturePath = path.join(__dirname, 'fixtures/custom-node-dir'); yield utils.cleanup(fixturePath); }); @@ -382,16 +384,16 @@ describe('test/start.test.js', () => { path.join(fixturePath, 'node_modules/.bin'), path.join(fixturePath, '.node/bin'), ].join(path.delimiter) + path.delimiter; - app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); - app.debug(); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--port=7002', fixturePath ]); + // app.debug(); app.expect('code', 0); yield sleep(waitTime); assert(app.stderr === ''); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7002/)); assert(!app.stdout.includes('app_worker#3:')); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = yield httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString().startsWith(`hi, ${expectPATH}`)); }); }); @@ -408,7 +410,7 @@ describe('test/start.test.js', () => { }); afterEach(function* () { yield coffee.fork(eggBin, [ 'stop', cwd ]) - .debug() + // .debug() .end(); yield utils.cleanup(cwd); }); @@ -440,7 +442,7 @@ describe('test/start.test.js', () => { it('should start default egg', function* () { cwd = path.join(__dirname, 'fixtures/egg-app'); yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', cwd ]) - .debug() + // .debug() .expect('stdout', /Starting egg application/) .expect('stdout', /egg started on http:\/\/127\.0\.0\.1:7001/) .expect('code', 0) diff --git a/test/ts.test.js b/test/ts.test.js new file mode 100644 index 0000000..f2cf913 --- /dev/null +++ b/test/ts.test.js @@ -0,0 +1,112 @@ +'use strict'; + +const path = require('path'); +const assert = require('assert'); +const cp = require('child_process'); +const sleep = require('mz-modules/sleep'); +const rimraf = require('mz-modules/rimraf'); +const mkdirp = require('mz-modules/mkdirp'); +const coffee = require('coffee'); +const httpclient = require('urllib'); +const mm = require('mm'); +const utils = require('./utils'); + +describe('test/ts.test.js', () => { + const eggBin = require.resolve('../bin/egg-scripts.js'); + const homePath = path.join(__dirname, 'fixtures/home'); + const waitTime = '10s'; + let fixturePath; + + beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); + afterEach(mm.restore); + + before(() => mkdirp(homePath)); + after(() => rimraf(homePath)); + + describe('should display correct stack traces', () => { + let app; + beforeEach(function* () { + fixturePath = path.join(__dirname, 'fixtures/ts'); + yield utils.cleanup(fixturePath); + const result = cp.spawnSync('npm', [ 'run', 'build' ], { cwd: fixturePath }); + assert(!result.stderr.toString()); + }); + + afterEach(function* () { + app && app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('--ts', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--ts', fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes('app/controller/home.ts:6:13')); + }); + + it('--typescript', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--typescript', fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes('app/controller/home.ts:6:13')); + }); + + it('--sourcemap', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--sourcemap', fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes('app/controller/home.ts:6:13')); + }); + }); + + describe('pkg.egg.typescript', () => { + let app; + beforeEach(function* () { + fixturePath = path.join(__dirname, 'fixtures/ts-pkg'); + yield utils.cleanup(fixturePath); + const result = cp.spawnSync('npm', [ 'run', 'build' ], { cwd: fixturePath }); + assert(!result.stderr.toString()); + }); + + afterEach(function* () { + app && app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should got correct stack', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes('app/controller/home.ts:6:13')); + }); + }); +}); + From 82f4125245ddde5378401d04404b89fb27c86765 Mon Sep 17 00:00:00 2001 From: TZ Date: Tue, 3 Apr 2018 19:44:43 +0800 Subject: [PATCH 20/72] Release 2.6.0 --- History.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index e6e22ae..457b4ba 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +2.6.0 / 2018-04-03 +================== + + * feat: provides source map support for stack traces (#19) + 2.5.1 / 2018-02-06 ================== diff --git a/package.json b/package.json index f888b83..6f2de64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.5.1", + "version": "2.6.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 22faa4cfbb84cc5bc819d981dce962d8f95f8357 Mon Sep 17 00:00:00 2001 From: Baffin Lee Date: Wed, 11 Jul 2018 09:40:42 +0800 Subject: [PATCH 21/72] feat: stop command support windows (#22) --- README.md | 2 +- lib/cmd/stop.js | 18 ++++---- lib/helper.js | 9 ++-- test/fixtures/ts-pkg/package.json | 3 +- test/fixtures/ts/package.json | 3 +- test/start.test.js | 42 ++++++++++-------- test/stop.test.js | 71 ++++++++++++++++++++++--------- test/ts.test.js | 13 +++--- test/utils.js | 7 ++- 9 files changed, 108 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 5bf8a17..11e04b3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ deploy tool for egg project. -**Note: Windows is not supported** +**Note: Windows is partially supported, see [#22](https://github.com/eggjs/egg-scripts/pull/22)** ## Install diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index 09585c8..2380dd2 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -3,6 +3,12 @@ const path = require('path'); const sleep = require('mz-modules/sleep'); const Command = require('../command'); +const isWin = process.platform === 'win32'; +const osRelated = { + titlePrefix: isWin ? '\\"title\\":\\"' : '"title":"', + appWorkerPath: isWin ? 'egg-cluster\\lib\\app_worker.js' : 'egg-cluster/lib/app_worker.js', + agentWorkerPath: isWin ? 'egg-cluster\\lib\\agent_worker.js' : 'egg-cluster/lib/agent_worker.js', +}; class StopCommand extends Command { @@ -23,12 +29,6 @@ class StopCommand extends Command { } * run(context) { - /* istanbul ignore next */ - if (process.platform === 'win32') { - this.logger.warn('Windows is not supported, try to kill master process which command contains `start-cluster` or `--type=egg-server` yourself, good luck.'); - process.exit(0); - } - const { argv } = context; this.logger.info(`stopping egg application ${argv.title ? `with --title=${argv.title}` : ''}`); @@ -37,7 +37,7 @@ class StopCommand extends Command { let processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; return argv.title ? - cmd.includes('start-cluster') && cmd.includes(`"title":"${argv.title}"`) : + cmd.includes('start-cluster') && cmd.includes(`${osRelated.titlePrefix}${argv.title}`) : cmd.includes('start-cluster'); }); let pids = processList.map(x => x.pid); @@ -57,8 +57,8 @@ class StopCommand extends Command { processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; return argv.title ? - (cmd.includes('egg-cluster/lib/app_worker.js') || cmd.includes('egg-cluster/lib/agent_worker.js')) && cmd.includes(`"title":"${argv.title}"`) : - (cmd.includes('egg-cluster/lib/app_worker.js') || cmd.includes('egg-cluster/lib/agent_worker.js')); + (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)) && cmd.includes(`${osRelated.titlePrefix}${argv.title}`) : + (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)); }); pids = processList.map(x => x.pid); diff --git a/lib/helper.js b/lib/helper.js index 881d869..e7fd4e7 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -1,10 +1,13 @@ 'use strict'; const runScript = require('runscript'); -const REGEX = /^\s*(\d+)\s+(.*)/; +const isWin = process.platform === 'win32'; +const REGEX = isWin ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/; exports.findNodeProcess = function* (filterFn) { - const command = 'ps -eo "pid,command"'; + const command = isWin ? + 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' : + 'ps -eo "pid,command"'; const stdio = yield runScript(command, { stdio: 'pipe' }); const processList = stdio.stdout.toString().split('\n') .reduce((arr, line) => { @@ -12,7 +15,7 @@ exports.findNodeProcess = function* (filterFn) { const m = line.match(REGEX); /* istanbul ignore else */ if (m) { - const item = { pid: m[1], cmd: m[2] }; + const item = isWin ? { pid: m[2], cmd: m[1] } : { pid: m[1], cmd: m[2] }; if (!filterFn || filterFn(item)) { arr.push(item); } diff --git a/test/fixtures/ts-pkg/package.json b/test/fixtures/ts-pkg/package.json index 818511f..c2c929d 100644 --- a/test/fixtures/ts-pkg/package.json +++ b/test/fixtures/ts-pkg/package.json @@ -8,6 +8,7 @@ "typescript": true }, "scripts": { - "build": "node ../../../node_modules/.bin/tsc" + "build": "node ../../../node_modules/.bin/tsc", + "windows-build": "call ../../../node_modules/.bin/tsc.cmd" } } diff --git a/test/fixtures/ts/package.json b/test/fixtures/ts/package.json index 5c422dd..183b153 100644 --- a/test/fixtures/ts/package.json +++ b/test/fixtures/ts/package.json @@ -5,6 +5,7 @@ "egg": "^1.0.0" }, "scripts": { - "build": "node ../../../node_modules/.bin/tsc" + "build": "node ../../../node_modules/.bin/tsc", + "windows-build": "call ../../../node_modules/.bin/tsc.cmd" } } diff --git a/test/start.test.js b/test/start.test.js index 42bc54a..9c9a49d 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -10,6 +10,7 @@ const coffee = require('coffee'); const httpclient = require('urllib'); const mm = require('mm'); const utils = require('./utils'); +const isWin = process.platform === 'win32'; describe('test/start.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); @@ -271,7 +272,8 @@ describe('test/start.test.js', () => { let result = yield httpclient.request('http://127.0.0.1:7001/env'); assert(result.data.toString() === 'pre, true'); result = yield httpclient.request('http://127.0.0.1:7001/path'); - assert(result.data.toString().match(new RegExp(`^${fixturePath}/node_modules/.bin${path.delimiter}`))); + const appBinPath = path.join(fixturePath, 'node_modules/.bin'); + assert(result.data.toString().startsWith(`${appBinPath}${path.delimiter}`)); }); }); @@ -402,7 +404,7 @@ describe('test/start.test.js', () => { describe('start with daemon', () => { let cwd; beforeEach(function* () { - yield utils.cleanup(cwd); + if (cwd) yield utils.cleanup(cwd); yield rimraf(logDir); yield mkdirp(logDir); yield fs.writeFile(path.join(logDir, 'master-stdout.log'), 'just for test'); @@ -410,7 +412,7 @@ describe('test/start.test.js', () => { }); afterEach(function* () { yield coffee.fork(eggBin, [ 'stop', cwd ]) - // .debug() + // .debug() .end(); yield utils.cleanup(cwd); }); @@ -418,7 +420,7 @@ describe('test/start.test.js', () => { it('should start custom-framework', function* () { cwd = fixturePath; yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', '--port=7002', cwd ]) - // .debug() + // .debug() .expect('stdout', /Starting custom-framework application/) .expect('stdout', /custom-framework started on http:\/\/127\.0\.0\.1:7002/) .expect('code', 0) @@ -442,7 +444,7 @@ describe('test/start.test.js', () => { it('should start default egg', function* () { cwd = path.join(__dirname, 'fixtures/egg-app'); yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', cwd ]) - // .debug() + // .debug() .expect('stdout', /Starting egg application/) .expect('stdout', /egg started on http:\/\/127\.0\.0\.1:7001/) .expect('code', 0) @@ -455,7 +457,7 @@ describe('test/start.test.js', () => { after(function* () { yield coffee.fork(eggBin, [ 'stop', cwd ]) - // .debug() + // .debug() .end(); yield utils.cleanup(cwd); }); @@ -463,7 +465,7 @@ describe('test/start.test.js', () => { it('should status check success, exit with 0', function* () { mm(process.env, 'WAIT_TIME', 5000); yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) - // .debug() + // .debug() .expect('stdout', /Wait Start: 5.../) .expect('stdout', /custom-framework started/) .expect('code', 0) @@ -474,12 +476,14 @@ describe('test/start.test.js', () => { mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); - const stderr = path.join(homePath, 'logs/master-stderr.log'); + let stderr = path.join(homePath, 'logs/master-stderr.log'); + if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--ignore-stderr' ], { cwd }) - // .debug() - .expect('stderr', /nodejs.Error: error message/) - .expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + const app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--ignore-stderr' ], { cwd }); + // app.debug(); + // TODO: find a windows replacement for tail command + if (!isWin) app.expect('stderr', /nodejs.Error: error message/); + yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) .expect('code', 0) .end(); }); @@ -488,12 +492,14 @@ describe('test/start.test.js', () => { mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); - const stderr = path.join(homePath, 'logs/master-stderr.log'); + let stderr = path.join(homePath, 'logs/master-stderr.log'); + if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) - // .debug() - .expect('stderr', /nodejs.Error: error message/) - .expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + const app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }); + // app.debug() + // TODO: find a windows replacement for tail command + if (!isWin) app.expect('stderr', /nodejs.Error: error message/); + yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) .expect('code', 1) .end(); }); @@ -502,7 +508,7 @@ describe('test/start.test.js', () => { mm(process.env, 'WAIT_TIME', 10000); yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--timeout=5000' ], { cwd }) - // .debug() + // .debug() .expect('stdout', /Wait Start: 1.../) .expect('stderr', /Start failed, 5s timeout/) .expect('code', 1) diff --git a/test/stop.test.js b/test/stop.test.js index 1ea012e..525a10c 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -10,6 +10,7 @@ const coffee = require('coffee'); const httpclient = require('urllib'); const mm = require('mm'); const utils = require('./utils'); +const isWin = process.platform === 'win32'; describe('test/stop.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); @@ -60,10 +61,14 @@ describe('test/stop.test.js', () => { // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); - // assert(app.stdout.includes('[agent_worker] exit with code:0')); + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[app_worker] exit with code:0')); + // assert(app.stdout.includes('[agent_worker] exit with code:0')); + } + assert(killer.stdout.includes('[egg-scripts] stopping egg application')); assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); }); @@ -98,9 +103,12 @@ describe('test/stop.test.js', () => { // master log const stdout = yield fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); - assert(stdout.includes('[master] receive signal SIGTERM, closing')); - assert(stdout.includes('[master] exit with code:0')); - assert(stdout.includes('[app_worker] exit with code:0')); + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(stdout.includes('[master] receive signal SIGTERM, closing')); + assert(stdout.includes('[master] exit with code:0')); + assert(stdout.includes('[app_worker] exit with code:0')); + } yield coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() @@ -162,10 +170,14 @@ describe('test/stop.test.js', () => { // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); - // assert(app.stdout.includes('[agent_worker] exit with code:0')); + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[app_worker] exit with code:0')); + // assert(app.stdout.includes('[agent_worker] exit with code:0')); + } + assert(killer.stdout.includes('[egg-scripts] stopping egg application with --title=example')); assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); }); @@ -214,17 +226,26 @@ describe('test/stop.test.js', () => { // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); - // assert(app.stdout.includes('[agent_worker] exit with code:0')); + + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[app_worker] exit with code:0')); + // assert(app.stdout.includes('[agent_worker] exit with code:0')); + } + assert(killer.stdout.includes('[egg-scripts] stopping egg application')); assert(killer.stdout.match(/got master pid \["\d+\","\d+\"\]/i)); assert(!app2.stdout.includes('exist by env')); - assert(app2.stdout.includes('[master] receive signal SIGTERM, closing')); - assert(app2.stdout.includes('[master] exit with code:0')); - assert(app2.stdout.includes('[app_worker] exit with code:0')); + + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(app2.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app2.stdout.includes('[master] exit with code:0')); + assert(app2.stdout.includes('[app_worker] exit with code:0')); + } }); }); @@ -232,13 +253,23 @@ describe('test/stop.test.js', () => { const baseDir = path.join(__dirname, 'fixtures/tmp'); beforeEach(function* () { - yield fs.symlink(fixturePath, baseDir); + // if we can't create a symlink, skip the test + try { + yield fs.symlink(fixturePath, baseDir, 'dir'); + } catch (err) { + // may get Error: EPERM: operation not permitted on windows + console.log(`test skiped, can't create symlink: ${err}`); + this.skip(); + } + + // *unix get the real path of symlink, but windows wouldn't + const appPathInRegexp = isWin ? baseDir.replace(/\\/g, '\\\\') : fixturePath; yield utils.cleanup(fixturePath); yield rimraf(logDir); yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2' ], { cwd: baseDir }) .debug() - .expect('stdout', new RegExp(`Starting custom-framework application at ${fixturePath}`)) + .expect('stdout', new RegExp(`Starting custom-framework application at ${appPathInRegexp}`)) .expect('code', 0) .end(); diff --git a/test/ts.test.js b/test/ts.test.js index f2cf913..cee5bd8 100644 --- a/test/ts.test.js +++ b/test/ts.test.js @@ -10,6 +10,7 @@ const coffee = require('coffee'); const httpclient = require('urllib'); const mm = require('mm'); const utils = require('./utils'); +const isWin = process.platform === 'win32'; describe('test/ts.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); @@ -28,7 +29,7 @@ describe('test/ts.test.js', () => { beforeEach(function* () { fixturePath = path.join(__dirname, 'fixtures/ts'); yield utils.cleanup(fixturePath); - const result = cp.spawnSync('npm', [ 'run', 'build' ], { cwd: fixturePath }); + const result = cp.spawnSync('npm', [ 'run', isWin ? 'windows-build' : 'build' ], { cwd: fixturePath, shell: isWin }); assert(!result.stderr.toString()); }); @@ -48,7 +49,7 @@ describe('test/ts.test.js', () => { assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); - assert(result.data.stack.includes('app/controller/home.ts:6:13')); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); it('--typescript', function* () { @@ -62,7 +63,7 @@ describe('test/ts.test.js', () => { assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); - assert(result.data.stack.includes('app/controller/home.ts:6:13')); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); it('--sourcemap', function* () { @@ -76,7 +77,7 @@ describe('test/ts.test.js', () => { assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); - assert(result.data.stack.includes('app/controller/home.ts:6:13')); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); }); @@ -85,7 +86,7 @@ describe('test/ts.test.js', () => { beforeEach(function* () { fixturePath = path.join(__dirname, 'fixtures/ts-pkg'); yield utils.cleanup(fixturePath); - const result = cp.spawnSync('npm', [ 'run', 'build' ], { cwd: fixturePath }); + const result = cp.spawnSync('npm', [ 'run', isWin ? 'windows-build' : 'build' ], { cwd: fixturePath, shell: isWin }); assert(!result.stderr.toString()); }); @@ -105,7 +106,7 @@ describe('test/ts.test.js', () => { assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); - assert(result.data.stack.includes('app/controller/home.ts:6:13')); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); }); }); diff --git a/test/utils.js b/test/utils.js index 3e97e7a..7e21f75 100644 --- a/test/utils.js +++ b/test/utils.js @@ -2,9 +2,14 @@ const helper = require('../lib/helper'); const sleep = require('mz-modules/sleep'); +const isWin = process.platform === 'win32'; exports.cleanup = function* (baseDir) { - const processList = yield helper.findNodeProcess(x => x.cmd.includes(`"baseDir":"${baseDir}"`)); + const processList = yield helper.findNodeProcess(x => { + const dir = isWin ? baseDir.replace(/\\/g, '\\\\') : baseDir; + const prefix = isWin ? '\\"baseDir\\":\\"' : '"baseDir":"'; + return x.cmd.includes(`${prefix}${dir}`); + }); if (processList.length) { console.log(`cleanup: ${processList.length} to kill`); From e07726c176a89dd63482b588868fd1feaab1fba6 Mon Sep 17 00:00:00 2001 From: Khaidi Chu Date: Thu, 9 Aug 2018 21:31:13 +0800 Subject: [PATCH 22/72] refactor: raw spawn call to instead of helper.spawn in start non-daemon mode (#23) --- lib/cmd/start.js | 37 +++++++++++++++++++++++++++++-------- package.json | 1 + test/start.test.js | 25 ++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 5d562d6..c5e2188 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -1,15 +1,17 @@ 'use strict'; const path = require('path'); -const mkdirp = require('mz-modules/mkdirp'); -const sleep = require('mz-modules/sleep'); -const homedir = require('node-homedir'); -const utils = require('egg-utils'); -const fs = require('mz/fs'); + +const Command = require('../command'); +const debug = require('debug')('egg-script:start'); const { exec } = require('mz/child_process'); +const fs = require('mz/fs'); +const homedir = require('node-homedir'); +const mkdirp = require('mz-modules/mkdirp'); const moment = require('moment'); +const sleep = require('mz-modules/sleep'); const spawn = require('child_process').spawn; -const Command = require('../command'); +const utils = require('egg-utils'); class StartCommand extends Command { constructor(rawArgv) { @@ -161,8 +163,27 @@ class StartCommand extends Command { // check start status yield this.checkStatus(argv); } else { - // signal event had been handler at common-bin helper - this.helper.spawn('node', eggArgs, options); + options.stdio = options.stdio || 'inherit'; + debug('Run spawn `node %s`', eggArgs.join(' ')); + const child = this.child = spawn('node', eggArgs, options); + child.once('exit', code => { + if (code !== 0) { + child.emit('error', new Error(`spawn node ${eggArgs.join(' ')} fail, exit code: ${code}`)); + } + }); + + // attach master signal to child + let signal; + [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ].forEach(event => { + process.once(event, () => { + signal = event; + process.exit(0); + }); + }); + process.once('exit', () => { + debug('Kill child %s with %s', child.pid, signal); + child.kill(signal); + }); } } diff --git a/package.json b/package.json index 6f2de64..38818d7 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "common-bin": "^2.7.1", + "debug": "^3.1.0", "egg-utils": "^2.3.0", "moment": "^2.19.2", "mz": "^2.7.0", diff --git a/test/start.test.js b/test/start.test.js index 9c9a49d..972560e 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -59,6 +59,30 @@ describe('test/start.test.js', () => { }); }); + describe('child exit with 1', () => { + let app; + + before(function* () { + yield utils.cleanup(fixturePath); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should emit spawn error', function* () { + const srv = require('http').createServer(() => {}); + srv.listen(7007); + + app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); + + yield sleep(waitTime); + assert(/Error: spawn node .+ fail, exit code: 1/.test(app.stderr)); + srv.close(); + }); + }); + describe('relative path', () => { let app; @@ -514,6 +538,5 @@ describe('test/start.test.js', () => { .expect('code', 1) .end(); }); - }); }); From d4ebb3051dc56d35c95fb72624df79698391519c Mon Sep 17 00:00:00 2001 From: popomore Date: Fri, 10 Aug 2018 11:11:57 +0800 Subject: [PATCH 23/72] Release 2.7.0 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 457b4ba..fdafaed 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.7.0 / 2018-08-10 +================== + +**features** + * [[`22faa4c`](http://github.com/eggjs/egg-scripts/commit/22faa4cfbb84cc5bc819d981dce962d8f95f8357)] - feat: stop command support windows (#22) (Baffin Lee <>) + +**others** + * [[`e07726c`](http://github.com/eggjs/egg-scripts/commit/e07726c176a89dd63482b588868fd1feaab1fba6)] - refactor: raw spawn call to instead of helper.spawn in start non-daemon mode (#23) (Khaidi Chu <>) + 2.6.0 / 2018-04-03 ================== diff --git a/package.json b/package.json index 38818d7..b021680 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.6.0", + "version": "2.7.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From dac29f73ed2dfc18edc2e8743ffd509af8ab0f4a Mon Sep 17 00:00:00 2001 From: Khaidi Chu Date: Fri, 10 Aug 2018 12:50:42 +0800 Subject: [PATCH 24/72] refactor: add `this.exit` to instead of `process.exit` (#25) --- lib/cmd/start.js | 6 +++--- lib/command.js | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/cmd/start.js b/lib/cmd/start.js index c5e2188..f55e060 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -156,7 +156,7 @@ class StartCommand extends Command { this.logger.info('%s started on %s', this.frameworkName, msg.data.address); child.unref(); child.disconnect(); - process.exit(0); + this.exit(0); } }); @@ -177,7 +177,7 @@ class StartCommand extends Command { [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ].forEach(event => { process.once(event, () => { signal = event; - process.exit(0); + this.exit(0); }); }); process.once('exit', () => { @@ -246,7 +246,7 @@ class StartCommand extends Command { if (!isSuccess) { this.child.kill('SIGTERM'); yield sleep(1000); - process.exit(1); + this.exit(1); } } } diff --git a/lib/command.js b/lib/command.js index c484252..bd53436 100644 --- a/lib/command.js +++ b/lib/command.js @@ -59,6 +59,10 @@ class Command extends BaseCommand { return context; } + + exit(code) { + process.exit(code); + } } module.exports = Command; From 08f8ea9429ee9727f5047af856d41c67de8ba23c Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Fri, 10 Aug 2018 12:50:48 +0800 Subject: [PATCH 25/72] Release 2.8.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index fdafaed..993c5e9 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.8.0 / 2018-08-10 +================== + +**others** + * [[`dac29f7`](http://github.com/eggjs/egg-scripts/commit/dac29f73ed2dfc18edc2e8743ffd509af8ab0f4a)] - refactor: add `this.exit` to instead of `process.exit` (#25) (Khaidi Chu <>) + 2.7.0 / 2018-08-10 ================== diff --git a/package.json b/package.json index b021680..e6ce6ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.7.0", + "version": "2.8.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From b98fd03d1e3aaed68004b881f0b3d42fe47341dd Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Sun, 19 Aug 2018 12:39:47 +0800 Subject: [PATCH 26/72] fix: use execFile instead of exec for security reason (#26) Thanks Douglas Hall (douglas_hall) to report this security bug. --- .travis.yml | 2 +- appveyor.yml | 2 +- lib/cmd/start.js | 11 +++++++---- package.json | 2 +- test/start.test.js | 29 ++++++++++++++++++++++++++++- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index f4f869c..bdf6f64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js node_js: - '6' - '8' - - '9' + - '10' install: - npm i npminstall && npminstall script: diff --git a/appveyor.yml b/appveyor.yml index f876d1b..3dc637e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ environment: matrix: - nodejs_version: '6' - nodejs_version: '8' - - nodejs_version: '9' + - nodejs_version: '10' install: - ps: Install-Product node $env:nodejs_version diff --git a/lib/cmd/start.js b/lib/cmd/start.js index f55e060..7027a67 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -4,7 +4,7 @@ const path = require('path'); const Command = require('../command'); const debug = require('debug')('egg-script:start'); -const { exec } = require('mz/child_process'); +const { execFile } = require('mz/child_process'); const fs = require('mz/fs'); const homedir = require('node-homedir'); const mkdirp = require('mz-modules/mkdirp'); @@ -232,12 +232,15 @@ class StartCommand extends Command { if (hasError) { try { - const [ stdout ] = yield exec('tail -n 100 ' + stderr); + const args = [ '-n', '100', stderr ]; + this.logger.error('tail %s', args.join(' ')); + const [ stdout ] = yield execFile('tail', args); this.logger.error('Got error when startup: '); this.logger.error(stdout); - } catch (_) { - // nothing + } catch (err) { + this.logger.error('ignore tail error: %s', err); } + isSuccess = ignoreStdErr; this.logger.error('Start got error, see %s', stderr); this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.'); diff --git a/package.json b/package.json index e6ce6ec..d7cd6ce 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "bin" ], "ci": { - "version": "6, 8, 9" + "version": "6, 8, 10" }, "bug": { "url": "https://github.com/eggjs/egg/issues" diff --git a/test/start.test.js b/test/start.test.js index 972560e..af1984a 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -307,6 +307,7 @@ describe('test/start.test.js', () => { before(function* () { yield utils.cleanup(fixturePath); yield rimraf(logDir); + yield rimraf(path.join(fixturePath, 'start-fail')); yield mkdirp(logDir); }); @@ -315,6 +316,7 @@ describe('test/start.test.js', () => { yield utils.cleanup(fixturePath); yield rimraf(path.join(fixturePath, 'stdout.log')); yield rimraf(path.join(fixturePath, 'stderr.log')); + yield rimraf(path.join(fixturePath, 'start-fail')); }); it('should start', function* () { @@ -332,6 +334,30 @@ describe('test/start.test.js', () => { content = yield fs.readFile(stderr, 'utf-8'); assert(content === ''); }); + + it('should start with insecurity --stderr argument', function* () { + const cwd = path.join(__dirname, 'fixtures/status'); + mm(process.env, 'ERROR', 'error message'); + + const stdout = path.join(fixturePath, 'start-fail/stdout.log'); + const stderr = path.join(fixturePath, 'start-fail/stderr.log'); + const malicious = path.join(fixturePath, 'start-fail/malicious'); + app = coffee.fork(eggBin, [ + 'start', '--workers=1', '--daemon', `--stdout=${stdout}`, + `--stderr=${stderr}; touch ${malicious}`, + cwd, + ]); + // app.debug(); + + yield sleep(waitTime); + + const content = yield fs.readFile(stdout, 'utf-8'); + assert(!content.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); + let exists = yield fs.exists(stderr); + assert(!exists); + exists = yield fs.exists(malicious); + assert(!exists); + }); }); describe('read cluster config', () => { @@ -520,10 +546,11 @@ describe('test/start.test.js', () => { if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); const app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }); - // app.debug() + // app.debug(); // TODO: find a windows replacement for tail command if (!isWin) app.expect('stderr', /nodejs.Error: error message/); yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + .expect('stderr', /Got error when startup/) .expect('code', 1) .end(); }); From 2ccc21ee37b8c4e422c782dc7001479a990f6f1a Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Sun, 19 Aug 2018 12:40:42 +0800 Subject: [PATCH 27/72] Release 2.8.1 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 993c5e9..3519c90 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.8.1 / 2018-08-19 +================== + +**fixes** + * [[`b98fd03`](http://github.com/eggjs/egg-scripts/commit/b98fd03d1e3aaed68004b881f0b3d42fe47341dd)] - fix: use execFile instead of exec for security reason (#26) (fengmk2 <>) + 2.8.0 / 2018-08-10 ================== diff --git a/package.json b/package.json index d7cd6ce..fc3ab17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.8.0", + "version": "2.8.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 262ef4c97179dbf6f8de2eb0547eef4cbc56bf92 Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Wed, 22 Aug 2018 01:31:28 +0800 Subject: [PATCH 28/72] chore: add license and issues link (#27) --- LICENSE | 21 +++++++++++++++++++++ README.md | 11 ++++++++++- package.json | 3 ++- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7295685 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-present Alibaba Group Holding Limited and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 11e04b3..f52f023 100644 --- a/README.md +++ b/README.md @@ -70,4 +70,13 @@ $ eggctl stop [--title=example] ``` - **Options** - - `title` - process title description, use for kill grep. \ No newline at end of file + - `title` - process title description, use for kill grep. + +## Questions & Suggestions + +Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). + +## License + +[MIT](LICENSE) + diff --git a/package.json b/package.json index fc3ab17..f79995c 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "bin" ], "ci": { - "version": "6, 8, 10" + "version": "6, 8, 10", + "license": true }, "bug": { "url": "https://github.com/eggjs/egg/issues" From 1367883804e5ab1ece88831ea4d1a934ee757f81 Mon Sep 17 00:00:00 2001 From: Khaidi Chu Date: Thu, 23 Aug 2018 11:30:57 +0800 Subject: [PATCH 29/72] feat: add ipc channel in nonDaemon mode (#28) --- lib/cmd/start.js | 2 +- package.json | 1 + test/fixtures/ipc-bin/start.js | 36 ++++++++++++++++++++++++++++++++++ test/start.test.js | 23 +++++++++++++++++++++- 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/ipc-bin/start.js diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 7027a67..040c71e 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -163,7 +163,7 @@ class StartCommand extends Command { // check start status yield this.checkStatus(argv); } else { - options.stdio = options.stdio || 'inherit'; + options.stdio = [ 'inherit', 'inherit', 'inherit', 'ipc' ]; debug('Run spawn `node %s`', eggArgs.join(' ')); const child = this.child = spawn('node', eggArgs, options); child.once('exit', code => { diff --git a/package.json b/package.json index f79995c..77d9374 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "devDependencies": { "autod": "^3.0.1", + "co": "^4.6.0", "coffee": "^4.1.0", "egg": "^1.11.0", "egg-bin": "^4.3.5", diff --git a/test/fixtures/ipc-bin/start.js b/test/fixtures/ipc-bin/start.js new file mode 100644 index 0000000..5d1414e --- /dev/null +++ b/test/fixtures/ipc-bin/start.js @@ -0,0 +1,36 @@ +'use strict'; + +const co = require('co'); + +const BaseStartCommand = require('../../../lib/cmd/start'); + +class StartCommand extends BaseStartCommand { + * run(context) { + yield super.run(context); + const child = this.child; + child.on('message', msg => { + if (msg && msg.action === 'egg-ready') { + console.log('READY!!!'); + } + }); + } +} + +const start = new StartCommand(); + +co(function* () { + yield start.run({ + argv: { + framework: 'custom-framework', + _: [ process.env.BASE_DIR ], + workers: 2, + title: 'egg-server-example', + }, + cwd: process.env.BASE_DIR, + execArgv: [], + env: { + PATH: process.env.PATH, + }, + }); +}); + diff --git a/test/start.test.js b/test/start.test.js index af1984a..e318607 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -36,7 +36,7 @@ describe('test/start.test.js', () => { yield utils.cleanup(fixturePath); }); - after(function* () { + afterEach(function* () { app.proc.kill('SIGTERM'); yield utils.cleanup(fixturePath); }); @@ -57,6 +57,27 @@ describe('test/start.test.js', () => { const result = yield httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); + + it('should get ready', function* () { + app = coffee.fork(path.join(__dirname, './fixtures/ipc-bin/start.js'), [], { + env: { + BASE_DIR: fixturePath, + PATH: process.env.PATH, + }, + }); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.includes('READY!!!')); + assert(app.stdout.includes('--title=egg-server-example')); + assert(app.stdout.includes('"title":"egg-server-example"')); + assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); + assert(app.stdout.includes('app_worker#2:')); + assert(!app.stdout.includes('app_worker#3:')); + }); }); describe('child exit with 1', () => { From d61508351191ffd94c8fe9280fc09bd552765e05 Mon Sep 17 00:00:00 2001 From: popomore Date: Thu, 23 Aug 2018 11:32:21 +0800 Subject: [PATCH 30/72] Release 2.9.0 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 3519c90..625f9a8 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.9.0 / 2018-08-23 +================== + +**features** + * [[`1367883`](http://github.com/eggjs/egg-scripts/commit/1367883804e5ab1ece88831ea4d1a934ee757f81)] - feat: add ipc channel in nonDaemon mode (#28) (Khaidi Chu <>) + +**others** + * [[`262ef4c`](http://github.com/eggjs/egg-scripts/commit/262ef4c97179dbf6f8de2eb0547eef4cbc56bf92)] - chore: add license and issues link (#27) (Haoliang Gao <>) + 2.8.1 / 2018-08-19 ================== diff --git a/package.json b/package.json index 77d9374..c8001fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.8.1", + "version": "2.9.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 4768950d29398031fd6ae129a981c60e308bff0a Mon Sep 17 00:00:00 2001 From: Baffin Lee Date: Thu, 23 Aug 2018 19:59:24 +0800 Subject: [PATCH 31/72] fix: replace command by args in ps (#29) Closes [#2896](https://github.com/eggjs/egg/issues/2896) --- lib/helper.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helper.js b/lib/helper.js index e7fd4e7..0f42f6c 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -7,7 +7,8 @@ const REGEX = isWin ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/; exports.findNodeProcess = function* (filterFn) { const command = isWin ? 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' : - 'ps -eo "pid,command"'; + // command, cmd are alias of args, not POSIX standard, so we use args + 'ps -eo "pid,args"'; const stdio = yield runScript(command, { stdio: 'pipe' }); const processList = stdio.stdout.toString().split('\n') .reduce((arr, line) => { From 36ed7e0de087aba18317c744239dd579e3a50cfd Mon Sep 17 00:00:00 2001 From: TZ Date: Fri, 24 Aug 2018 11:32:23 +0800 Subject: [PATCH 32/72] Release 2.9.1 --- History.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/History.md b/History.md index 625f9a8..be0b2ff 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +2.9.1 / 2018-08-24 +================== + + * fix: replace command by args in ps (#29) + 2.9.0 / 2018-08-23 ================== From c2479dc6416386b654fc6e918a4dbd575cc0639e Mon Sep 17 00:00:00 2001 From: TZ Date: Fri, 24 Aug 2018 11:40:48 +0800 Subject: [PATCH 33/72] chore: update version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8001fb..23bafdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.9.0", + "version": "2.9.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From f31efb9133c5edc6176371ca725198f1b43b9aab Mon Sep 17 00:00:00 2001 From: Yiyu He Date: Tue, 9 Oct 2018 23:01:45 +0800 Subject: [PATCH 34/72] feat: support customize node path (#32) --- README.md | 1 + lib/cmd/start.js | 17 +++++++---- test/egg-scripts.test.js | 2 +- test/start.test.js | 61 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f52f023..6bba9c9 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ $ eggctl start [options] [baseDir] - `timeout` - the maximum timeout when app starts, default to 300s. - `ignore-stderr` - whether ignore stderr when app starts. - `sourcemap` / `typescript` / `ts` - provides source map support for stack traces. + - `node` - customize node command path, default will find node from $PATH ### stop diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 040c71e..2e492ae 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -65,6 +65,10 @@ class StartCommand extends Command { description: 'whether ignore stderr when app starts', type: 'boolean', }, + node: { + description: 'customize node command path', + type: 'string', + }, }; } @@ -124,6 +128,8 @@ class StartCommand extends Command { env.EGG_SERVER_ENV = argv.env; } + const command = argv.node || 'node'; + const options = { execArgv, env, @@ -134,7 +140,7 @@ class StartCommand extends Command { this.logger.info('Starting %s application at %s', this.frameworkName, baseDir); // remove unused properties from stringify, alias had been remove by `removeAlias` - const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr' ]; + const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr', 'node' ]; const clusterOptions = stringify(argv, ignoreKeys); // Note: `spawn` is not like `fork`, had to pass `execArgv` youself const eggArgs = [ ...(execArgv || []), this.serverBin, clusterOptions, `--title=${argv.title}` ]; @@ -147,7 +153,8 @@ class StartCommand extends Command { options.stdio = [ 'ignore', stdout, stderr, 'ipc' ]; options.detached = true; - const child = this.child = spawn('node', eggArgs, options); + debug('Run spawn `%s %s`', command, eggArgs.join(' ')); + const child = this.child = spawn(command, eggArgs, options); this.isReady = false; child.on('message', msg => { /* istanbul ignore else */ @@ -164,11 +171,11 @@ class StartCommand extends Command { yield this.checkStatus(argv); } else { options.stdio = [ 'inherit', 'inherit', 'inherit', 'ipc' ]; - debug('Run spawn `node %s`', eggArgs.join(' ')); - const child = this.child = spawn('node', eggArgs, options); + debug('Run spawn `%s %s`', command, eggArgs.join(' ')); + const child = this.child = spawn(command, eggArgs, options); child.once('exit', code => { if (code !== 0) { - child.emit('error', new Error(`spawn node ${eggArgs.join(' ')} fail, exit code: ${code}`)); + child.emit('error', new Error(`spawn ${command} ${eggArgs.join(' ')} fail, exit code: ${code}`)); } }); diff --git a/test/egg-scripts.test.js b/test/egg-scripts.test.js index f48b991..9fc38b5 100644 --- a/test/egg-scripts.test.js +++ b/test/egg-scripts.test.js @@ -10,7 +10,7 @@ describe('test/egg-scripts.test.js', () => { app = coffee.fork(eggBin, [ '--help' ]); app // .debug() - .expect(/Usage: egg-scripts/) + .expect('stdout', /Usage: egg-scripts/) .expect('code', 0) .end(done); }); diff --git a/test/start.test.js b/test/start.test.js index e318607..2a9f61a 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -381,6 +381,67 @@ describe('test/start.test.js', () => { }); }); + describe('--node', () => { + let app; + + beforeEach(function* () { + yield utils.cleanup(fixturePath); + }); + + beforeEach(function* () { + app && app.proc && app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + describe('daemon', () => { + it('should start', function* () { + app = coffee.fork(eggBin, [ 'start', '--daemon', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, yadan'); + }); + + it('should error if node path invalid', function* () { + app = coffee.fork(eggBin, [ 'start', '--daemon', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath ]); + // app.debug(); + app.expect('code', 1); + + yield sleep(3000); + assert(app.stderr.includes('spawn invalid ENOENT')); + }); + }); + + describe('not daemon', () => { + it('should start', function* () { + app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, yadan'); + }); + + it('should error if node path invalid', function* () { + app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath ]); + // app.debug(); + app.expect('code', 1); + + yield sleep(3000); + assert(app.stderr.includes('spawn invalid ENOENT')); + }); + }); + }); + describe('read cluster config', () => { let app; let fixturePath; From 1a8ad1f3baab7f9a1238d239bb5189ab26572be2 Mon Sep 17 00:00:00 2001 From: dead-horse Date: Wed, 10 Oct 2018 12:06:36 +0800 Subject: [PATCH 35/72] Release 2.10.0 --- History.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index be0b2ff..f495b86 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,14 @@ +2.10.0 / 2018-10-10 +================== + +**fixes** + * [[`4768950`](http://github.com/eggjs/egg-scripts/commit/4768950d29398031fd6ae129a981c60e308bff0a)] - fix: replace command by args in ps (#29) (Baffin Lee <>) + +**others** + * [[`f31efb9`](http://github.com/eggjs/egg-scripts/commit/f31efb9133c5edc6176371ca725198f1b43b9aab)] - feat: support customize node path (#32) (Yiyu He <>) + * [[`c2479dc`](http://github.com/eggjs/egg-scripts/commit/c2479dc6416386b654fc6e918a4dbd575cc0639e)] - chore: update version (TZ <>) + 2.9.1 / 2018-08-24 ================== diff --git a/package.json b/package.json index 23bafdb..deb36a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.9.1", + "version": "2.10.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 2f2cfe61b1be80f497c34db1e2f60ebf61dc2e11 Mon Sep 17 00:00:00 2001 From: plusmancn Date: Mon, 17 Dec 2018 17:12:54 +0800 Subject: [PATCH 36/72] fix: stop process only if the title matches exactly (#35) --- lib/cmd/start.js | 3 ++- lib/cmd/stop.js | 7 ++++--- test/stop.test.js | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 2e492ae..2f1a2eb 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -108,7 +108,8 @@ class StartCommand extends Command { env.HOME = HOME; env.NODE_ENV = 'production'; - env.PATH = [ + // it makes env big but more robust + env.PATH = env.Path = [ // for nodeinstall path.join(baseDir, 'node_modules/.bin'), // support `.node/bin`, due to npm5 will remove `node_modules/.bin` diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index 2380dd2..e8a24a7 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -1,11 +1,12 @@ 'use strict'; const path = require('path'); +const util = require('util'); const sleep = require('mz-modules/sleep'); const Command = require('../command'); const isWin = process.platform === 'win32'; const osRelated = { - titlePrefix: isWin ? '\\"title\\":\\"' : '"title":"', + titleTemplate: isWin ? '\\"title\\":\\"%s\\"' : '"title":"%s"', appWorkerPath: isWin ? 'egg-cluster\\lib\\app_worker.js' : 'egg-cluster/lib/app_worker.js', agentWorkerPath: isWin ? 'egg-cluster\\lib\\agent_worker.js' : 'egg-cluster/lib/agent_worker.js', }; @@ -37,7 +38,7 @@ class StopCommand extends Command { let processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; return argv.title ? - cmd.includes('start-cluster') && cmd.includes(`${osRelated.titlePrefix}${argv.title}`) : + cmd.includes('start-cluster') && cmd.includes(util.format(osRelated.titleTemplate, argv.title)) : cmd.includes('start-cluster'); }); let pids = processList.map(x => x.pid); @@ -57,7 +58,7 @@ class StopCommand extends Command { processList = yield this.helper.findNodeProcess(item => { const cmd = item.cmd; return argv.title ? - (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)) && cmd.includes(`${osRelated.titlePrefix}${argv.title}`) : + (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)) && cmd.includes(util.format(osRelated.titleTemplate, argv.title)) : (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)); }); pids = processList.map(x => x.pid); diff --git a/test/stop.test.js b/test/stop.test.js index 525a10c..5b22e15 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -152,6 +152,24 @@ describe('test/stop.test.js', () => { yield utils.cleanup(fixturePath); }); + it('shoud stop only if the title matches exactly', function* () { + // Because of'exmaple'.inclues('exmap') === true,if egg-scripts <= 2.1.0 and you run `.. stop --title=exmap`,the process with 'title:example' will also be killed unexpectedly + yield coffee.fork(eggBin, [ 'stop', '--title=examp', fixturePath ]) + .debug() + .expect('stdout', /\[egg-scripts] stopping egg application with --title=examp/) + .expect('stderr', /can't detect any running egg process/) + .expect('code', 0) + .end(); + + // stop only if the title matches exactly + yield coffee.fork(eggBin, [ 'stop', '--title=example', fixturePath ]) + .debug() + .expect('stdout', /\[egg-scripts] stopping egg application with --title=example/) + .expect('stdout', /\[egg-scripts\] got master pid \[/) + .expect('code', 0) + .end(); + }); + it('should stop', function* () { yield coffee.fork(eggBin, [ 'stop', '--title=random', fixturePath ]) .debug() From a3d2c0312490d8d5193054eb3d3ac6e57c9558ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=B0=8F=E9=BE=99?= <295697141@qq.com> Date: Mon, 17 Dec 2018 17:14:58 +0800 Subject: [PATCH 37/72] feat(stop): only sleep when master process exists (#34) --- lib/cmd/stop.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index e8a24a7..5356c40 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -46,12 +46,12 @@ class StopCommand extends Command { if (pids.length) { this.logger.info('got master pid %j', pids); this.helper.kill(pids); + // wait for 5s to confirm whether any worker process did not kill by master + yield sleep('5s'); } else { this.logger.warn('can\'t detect any running egg process'); } - // wait for 5s to confirm whether any worker process did not kill by master - yield sleep('5s'); // node --debug-port=5856 /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/agent_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} From b3e8b4754a79c7e532d611c931226c3c14ddfdd7 Mon Sep 17 00:00:00 2001 From: TZ Date: Mon, 17 Dec 2018 17:28:21 +0800 Subject: [PATCH 38/72] Release 2.11.0 --- History.md | 6 ++++++ package.json | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/History.md b/History.md index f495b86..8148d52 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.11.0 / 2018-12-17 +=================== + + * feat(stop): only sleep when master process exists (#34) + * fix: stop process only if the title matches exactly (#35) + 2.10.0 / 2018-10-10 ================== diff --git a/package.json b/package.json index deb36a2..82b6ec5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.10.0", + "version": "2.11.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { @@ -8,29 +8,29 @@ "eggctl": "bin/egg-scripts.js" }, "dependencies": { - "common-bin": "^2.7.1", - "debug": "^3.1.0", - "egg-utils": "^2.3.0", - "moment": "^2.19.2", + "common-bin": "^2.8.0", + "debug": "^4.1.0", + "egg-utils": "^2.4.1", + "moment": "^2.23.0", "mz": "^2.7.0", - "mz-modules": "^2.0.0", - "node-homedir": "^1.1.0", + "mz-modules": "^2.1.0", + "node-homedir": "^1.1.1", "runscript": "^1.3.0", - "source-map-support": "^0.5.4", + "source-map-support": "^0.5.9", "zlogger": "^1.1.0" }, "devDependencies": { "autod": "^3.0.1", "co": "^4.6.0", - "coffee": "^4.1.0", - "egg": "^1.11.0", - "egg-bin": "^4.3.5", - "egg-ci": "^1.8.0", - "eslint": "^4.11.0", - "eslint-config-egg": "^5.1.1", - "mm": "^2.2.0", + "coffee": "^5.1.1", + "egg": "^2.14.1", + "egg-bin": "^4.9.0", + "egg-ci": "^1.10.0", + "eslint": "^5.10.0", + "eslint-config-egg": "^7.1.0", + "mm": "^2.4.1", "typescript": "^2.8.1", - "urllib": "^2.25.1", + "urllib": "^2.31.3", "webstorm-disable-index": "^1.2.0" }, "engines": { From 7ae9cb054cb91ea7ac1e615e1e3a7fcdaba5f980 Mon Sep 17 00:00:00 2001 From: Maledong Date: Mon, 4 Mar 2019 15:17:35 +0800 Subject: [PATCH 39/72] test: add egg@1 and egg@2 with travis (#36) 1. For Nodejs <= 6, we don't support async,await, and this file is used in both of the two versions. So we should make this compatable with the two versions and not throw errors when compiling with Nodejs 6. 2. Remove 'egg-ci' (as a dependency). 3. Remove 'nodejs_version: 6' in 'appveyor.yml'. --- .travis.yml | 10 ++++++++++ appveyor.yml | 1 - package.json | 5 ----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index bdf6f64..07490ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,19 @@ node_js: - '6' - '8' - '10' +env: + - EGG_VERSION=1 + - EGG_VERSION=2 +matrix: + exclude: + - node_js: '6' + env: EGG_VERSION=2 install: - npm i npminstall && npminstall + - sed -i.bak '/"egg":/d' package.json + - npminstall -d script: + - eval "npminstall -d egg@$EGG_VERSION" - npm run ci after_script: - npminstall codecov && codecov diff --git a/appveyor.yml b/appveyor.yml index 3dc637e..981e82b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,5 @@ environment: matrix: - - nodejs_version: '6' - nodejs_version: '8' - nodejs_version: '10' diff --git a/package.json b/package.json index 82b6ec5..d22710a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "coffee": "^5.1.1", "egg": "^2.14.1", "egg-bin": "^4.9.0", - "egg-ci": "^1.10.0", "eslint": "^5.10.0", "eslint-config-egg": "^7.1.0", "mm": "^2.4.1", @@ -50,10 +49,6 @@ "lib", "bin" ], - "ci": { - "version": "6, 8, 10", - "license": true - }, "bug": { "url": "https://github.com/eggjs/egg/issues" }, From de61980f772c8a24010d3f078658f8c55b072067 Mon Sep 17 00:00:00 2001 From: killa Date: Thu, 10 Oct 2019 11:09:08 +0800 Subject: [PATCH 40/72] fix: start command should exit after child process exit when no daemon mode (#39) --- .travis.yml | 4 +++- lib/cmd/start.js | 13 ++++--------- package.json | 1 + test/start.test.js | 24 +++++++++++++++++++++++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 07490ef..e08a511 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,10 @@ matrix: exclude: - node_js: '6' env: EGG_VERSION=2 +before_install: + - npm install -g npminstall install: - - npm i npminstall && npminstall + - npminstall - sed -i.bak '/"egg":/d' package.json - npminstall -d script: diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 2f1a2eb..f6e5a99 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -175,23 +175,18 @@ class StartCommand extends Command { debug('Run spawn `%s %s`', command, eggArgs.join(' ')); const child = this.child = spawn(command, eggArgs, options); child.once('exit', code => { - if (code !== 0) { - child.emit('error', new Error(`spawn ${command} ${eggArgs.join(' ')} fail, exit code: ${code}`)); - } + // command should exit after child process exit + this.exit(code); }); // attach master signal to child let signal; [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ].forEach(event => { process.once(event, () => { - signal = event; - this.exit(0); + debug('Kill child %s with %s', child.pid, signal); + child.kill(event); }); }); - process.once('exit', () => { - debug('Kill child %s with %s', child.pid, signal); - child.kill(signal); - }); } } diff --git a/package.json b/package.json index d22710a..2120d01 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "eggctl": "bin/egg-scripts.js" }, "dependencies": { + "await-event": "^2.1.0", "common-bin": "^2.8.0", "debug": "^4.1.0", "egg-utils": "^2.4.1", diff --git a/test/start.test.js b/test/start.test.js index 2a9f61a..34f2880 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -10,6 +10,7 @@ const coffee = require('coffee'); const httpclient = require('urllib'); const mm = require('mm'); const utils = require('./utils'); +const awaitEvent = require('await-event'); const isWin = process.platform === 'win32'; describe('test/start.test.js', () => { @@ -99,8 +100,8 @@ describe('test/start.test.js', () => { app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); yield sleep(waitTime); - assert(/Error: spawn node .+ fail, exit code: 1/.test(app.stderr)); srv.close(); + assert(app.code === 1); }); }); @@ -531,6 +532,27 @@ describe('test/start.test.js', () => { assert(result.data.toString().startsWith(`hi, ${expectPATH}`)); }); }); + + describe('kill command', () => { + let app; + + before(function* () { + yield utils.cleanup(fixturePath); + }); + + after(function* () { + yield utils.cleanup(fixturePath); + }); + + it('should wait child process exit', function* () { + app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); + yield sleep(waitTime); + const exitEvent = awaitEvent(app.proc, 'exit'); + app.proc.kill('SIGTERM'); + const code = yield exitEvent; + assert(code === 0); + }); + }); }); describe('start with daemon', () => { From df9933aed028326b5758c318834f4834a37066eb Mon Sep 17 00:00:00 2001 From: killagu Date: Thu, 10 Oct 2019 11:10:09 +0800 Subject: [PATCH 41/72] Release 2.11.1 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 8148d52..d23ef99 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.11.1 / 2019-10-10 +================== + +**fixes** + * [[`de61980`](http://github.com/eggjs/egg-scripts/commit/de61980f772c8a24010d3f078658f8c55b072067)] - fix: start command should exit after child process exit when no daemon mode (#39) (killa <>) + +**others** + * [[`7ae9cb0`](http://github.com/eggjs/egg-scripts/commit/7ae9cb054cb91ea7ac1e615e1e3a7fcdaba5f980)] - test: add egg@1 and egg@2 with travis (#36) (Maledong <>) + 2.11.0 / 2018-12-17 =================== diff --git a/package.json b/package.json index 2120d01..ebc1499 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.11.0", + "version": "2.11.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 20483fd56ce51238431fb095ede1c768a99470f2 Mon Sep 17 00:00:00 2001 From: Yiyu He Date: Mon, 16 Dec 2019 15:33:14 +0800 Subject: [PATCH 42/72] feat: support eggScriptsConfig in package.json (#41) --- .gitignore | 3 ++- README.md | 14 +++++++++++ lib/cmd/start.js | 2 -- lib/command.js | 7 ++++++ test/fixtures/egg-scripts-config/app.js | 13 ++++++++++ .../config/config.default.js | 8 +++++++ .../node_modules/custom-framework/index.js | 21 ++++++++++++++++ .../custom-framework/package.json | 7 ++++++ test/fixtures/egg-scripts-config/package.json | 15 ++++++++++++ test/start.test.js | 24 +++++++++++++++++-- 10 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/egg-scripts-config/app.js create mode 100644 test/fixtures/egg-scripts-config/config/config.default.js create mode 100644 test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js create mode 100644 test/fixtures/egg-scripts-config/node_modules/custom-framework/package.json create mode 100644 test/fixtures/egg-scripts-config/package.json diff --git a/.gitignore b/.gitignore index 125fe6e..0c5a36f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ run/ .DS_Store *.swp test/fixtures/ts/app/controller/home.js -test/fixtures/ts-pkg/app/controller/home.js \ No newline at end of file +test/fixtures/ts-pkg/app/controller/home.js +!test/fixtures/**/node_modules diff --git a/README.md b/README.md index 6bba9c9..a02f984 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,20 @@ $ eggctl stop [--title=example] - **Options** - `title` - process title description, use for kill grep. +## Options in `package.json` + +In addition to the command line specification, options can also be specified in `package.json`. However, the command line designation takes precedence. + +```json +{ + "eggScriptsConfig": { + "port": 1234, + "ignore-stderr": true + } +} +``` + + ## Questions & Suggestions Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). diff --git a/lib/cmd/start.js b/lib/cmd/start.js index f6e5a99..ec47a2f 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -78,7 +78,6 @@ class StartCommand extends Command { * run(context) { const { argv, env, cwd, execArgv } = context; - const HOME = homedir(); const logDir = path.join(HOME, 'logs'); @@ -243,7 +242,6 @@ class StartCommand extends Command { } catch (err) { this.logger.error('ignore tail error: %s', err); } - isSuccess = ignoreStdErr; this.logger.error('Start got error, see %s', stderr); this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.'); diff --git a/lib/command.js b/lib/command.js index bd53436..d57c7ff 100644 --- a/lib/command.js +++ b/lib/command.js @@ -47,6 +47,13 @@ class Command extends BaseCommand { if (pkgInfo && pkgInfo.egg && pkgInfo.egg.typescript) { argv.sourcemap = true; } + + // read argv from eggScriptsConfig in package.json + if (pkgInfo && pkgInfo.eggScriptsConfig && typeof pkgInfo.eggScriptsConfig === 'object') { + for (const key in pkgInfo.eggScriptsConfig) { + if (argv[key] == null) argv[key] = pkgInfo.eggScriptsConfig[key]; + } + } } // execArgv diff --git a/test/fixtures/egg-scripts-config/app.js b/test/fixtures/egg-scripts-config/app.js new file mode 100644 index 0000000..7ba4259 --- /dev/null +++ b/test/fixtures/egg-scripts-config/app.js @@ -0,0 +1,13 @@ +'use strict'; + +const sleep = require('mz-modules/sleep'); + +module.exports = app => { + if (process.env.ERROR) { + app.logger.error(new Error(process.env.ERROR)); + } + + app.beforeStart(function* () { + yield sleep(process.env.WAIT_TIME); + }); +}; diff --git a/test/fixtures/egg-scripts-config/config/config.default.js b/test/fixtures/egg-scripts-config/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/egg-scripts-config/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js b/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js new file mode 100644 index 0000000..071acea --- /dev/null +++ b/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js @@ -0,0 +1,21 @@ +'use strict'; + +const egg = require('../../../../../node_modules/egg'); + +const originStartCluster = egg.startCluster; + +module.exports = Object.assign(egg, { + Application: class CustomApplication extends egg.Application { + get [Symbol.for('egg#eggPath')]() { + return __dirname; + } + }, + startCluster(...args) { + if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { + console.log('## EGG_SERVER_ENV is not pass'); + console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); + process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; + } + return originStartCluster(...args); + }, +}); diff --git a/test/fixtures/egg-scripts-config/node_modules/custom-framework/package.json b/test/fixtures/egg-scripts-config/node_modules/custom-framework/package.json new file mode 100644 index 0000000..a9328f7 --- /dev/null +++ b/test/fixtures/egg-scripts-config/node_modules/custom-framework/package.json @@ -0,0 +1,7 @@ +{ + "name": "custom-framework", + "version": "1.0.0", + "dependencies": { + "egg": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/egg-scripts-config/package.json b/test/fixtures/egg-scripts-config/package.json new file mode 100644 index 0000000..36c1f05 --- /dev/null +++ b/test/fixtures/egg-scripts-config/package.json @@ -0,0 +1,15 @@ +{ + "name": "example", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + }, + "egg": { + "framework": "custom-framework" + }, + "eggScriptsConfig": { + "ignore-stderr": true, + "daemon": true, + "workers": 1 + } +} diff --git a/test/start.test.js b/test/start.test.js index 34f2880..384ff52 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -607,11 +607,14 @@ describe('test/start.test.js', () => { }); describe('check status', () => { - const cwd = path.join(__dirname, 'fixtures/status'); + let cwd; + beforeEach(() => { + cwd = path.join(__dirname, 'fixtures/status'); + }); after(function* () { yield coffee.fork(eggBin, [ 'stop', cwd ]) - // .debug() + // .debug() .end(); yield utils.cleanup(cwd); }); @@ -642,6 +645,23 @@ describe('test/start.test.js', () => { .end(); }); + it('should status check fail `--ignore-stderr` in package.json, exit with 0', function* () { + cwd = path.join(__dirname, 'fixtures/egg-scripts-config'); + mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'ERROR', 'error message'); + + let stderr = path.join(homePath, 'logs/master-stderr.log'); + if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); + + const app = coffee.fork(eggBin, [ 'start' ], { cwd }); + // app.debug(); + // TODO: find a windows replacement for tail command + if (!isWin) app.expect('stderr', /nodejs.Error: error message/); + yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + .expect('code', 0) + .end(); + }); + it('should status check fail, exit with 1', function* () { mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); From d18487f8136350e90cbe7fdcafc2d715b78a7ce8 Mon Sep 17 00:00:00 2001 From: dead-horse Date: Mon, 16 Dec 2019 15:33:38 +0800 Subject: [PATCH 43/72] Release 2.12.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index d23ef99..187430d 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.12.0 / 2019-12-16 +================== + +**features** + * [[`20483fd`](http://github.com/eggjs/egg-scripts/commit/20483fd56ce51238431fb095ede1c768a99470f2)] - feat: support eggScriptsConfig in package.json (#41) (Yiyu He <>) + 2.11.1 / 2019-10-10 ================== diff --git a/package.json b/package.json index ebc1499..b6d9cb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.11.1", + "version": "2.12.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From c0ba73900642e488b0e6306ea028ef547ceedfae Mon Sep 17 00:00:00 2001 From: hui Date: Tue, 25 Feb 2020 11:42:33 +0800 Subject: [PATCH 44/72] feat: support stop timeout (#43) --- README.md | 1 + lib/cmd/stop.js | 2 +- test/fixtures/stop-timeout/app.js | 8 +++ test/fixtures/stop-timeout/app/router.js | 15 ++++ .../stop-timeout/config/config.default.js | 8 +++ test/fixtures/stop-timeout/package.json | 7 ++ test/stop.test.js | 69 +++++++++++++++++++ 7 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/stop-timeout/app.js create mode 100644 test/fixtures/stop-timeout/app/router.js create mode 100644 test/fixtures/stop-timeout/config/config.default.js create mode 100644 test/fixtures/stop-timeout/package.json diff --git a/README.md b/README.md index a02f984..c276e07 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ $ eggctl stop [--title=example] - **Options** - `title` - process title description, use for kill grep. + - `timeout` - the maximum timeout when app stop, default to 5s. ## Options in `package.json` diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index 5356c40..a15fc0e 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -47,7 +47,7 @@ class StopCommand extends Command { this.logger.info('got master pid %j', pids); this.helper.kill(pids); // wait for 5s to confirm whether any worker process did not kill by master - yield sleep('5s'); + yield sleep(argv.timeout || '5s'); } else { this.logger.warn('can\'t detect any running egg process'); } diff --git a/test/fixtures/stop-timeout/app.js b/test/fixtures/stop-timeout/app.js new file mode 100644 index 0000000..691386e --- /dev/null +++ b/test/fixtures/stop-timeout/app.js @@ -0,0 +1,8 @@ +'use strict'; + +const sleep = require('mz-modules/sleep'); +module.exports = app => { + app.beforeClose(function* () { + yield sleep(6000); + }); +}; diff --git a/test/fixtures/stop-timeout/app/router.js b/test/fixtures/stop-timeout/app/router.js new file mode 100644 index 0000000..cd29c09 --- /dev/null +++ b/test/fixtures/stop-timeout/app/router.js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = app => { + app.get('/', function* () { + this.body = `hi, ${app.config.framework || 'egg'}`; + }); + + app.get('/env', function* () { + this.body = app.config.env + ', ' + app.config.pre; + }); + + app.get('/path', function* () { + this.body = process.env.PATH; + }); +}; diff --git a/test/fixtures/stop-timeout/config/config.default.js b/test/fixtures/stop-timeout/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/stop-timeout/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/stop-timeout/package.json b/test/fixtures/stop-timeout/package.json new file mode 100644 index 0000000..4da9169 --- /dev/null +++ b/test/fixtures/stop-timeout/package.json @@ -0,0 +1,7 @@ +{ + "name": "stop-timeout", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + } +} diff --git a/test/stop.test.js b/test/stop.test.js index 5b22e15..16cd38e 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -15,6 +15,7 @@ const isWin = process.platform === 'win32'; describe('test/stop.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); const fixturePath = path.join(__dirname, 'fixtures/example'); + const timeoutPath = path.join(__dirname, 'fixtures/stop-timeout'); const homePath = path.join(__dirname, 'fixtures/home'); const logDir = path.join(homePath, 'logs'); const waitTime = '10s'; @@ -267,6 +268,74 @@ describe('test/stop.test.js', () => { }); }); + describe('stop all with timeout', function() { + let app; + let killer; + this.timeout(12000); + beforeEach(function* () { + yield utils.cleanup(timeoutPath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=stop-timeout', timeoutPath ]); + // app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/http:\/\/127\.0\.0\.1:7001/)); + const result = yield httpclient.request('http://127.0.0.1:7001'); + assert(result.data.toString() === 'hi, egg'); + }); + + afterEach(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(timeoutPath); + }); + + it('should stop error without timeout', function* () { + killer = coffee.fork(eggBin, [ 'stop' ], { cwd: timeoutPath }); + killer.debug(); + killer.expect('code', 0); + + // yield killer.end(); + yield sleep(waitTime); + + // make sure is kill not auto exist + assert(!app.stdout.includes('exist by env')); + + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.match(/app_worker#\d+:\d+ disconnect/)); + assert(app.stdout.match(/don't fork, because worker:\d+ will be kill soon/)); + } + + assert(killer.stdout.includes('[egg-scripts] stopping egg application')); + assert(killer.stdout.match(/got master pid \["\d+\"]/i)); + }); + + it('should stop success', function* () { + killer = coffee.fork(eggBin, [ 'stop', '--timeout=10s' ], { cwd: timeoutPath }); + killer.debug(); + killer.expect('code', 0); + + // yield killer.end(); + yield sleep(waitTime); + + // make sure is kill not auto exist + assert(!app.stdout.includes('exist by env')); + + // no way to handle the SIGTERM signal in windows ? + if (!isWin) { + assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] exit with code:0')); + assert(app.stdout.includes('[agent_worker] exit with code:0')); + } + + assert(killer.stdout.includes('[egg-scripts] stopping egg application')); + assert(killer.stdout.match(/got master pid \["\d+\"]/i)); + }); + }); + describe('stop with symlink', () => { const baseDir = path.join(__dirname, 'fixtures/tmp'); From ad585eb4e25e3b07320419b36f68174af9ad235a Mon Sep 17 00:00:00 2001 From: TZ Date: Tue, 25 Feb 2020 11:43:10 +0800 Subject: [PATCH 45/72] Release 2.13.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 187430d..2b7f8ba 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.13.0 / 2020-02-25 +================== + +**features** + * [[`c0ba739`](http://github.com/eggjs/egg-scripts/commit/c0ba73900642e488b0e6306ea028ef547ceedfae)] - feat: support stop timeout (#43) (hui <>) + 2.12.0 / 2019-12-16 ================== diff --git a/package.json b/package.json index b6d9cb6..0a4aba4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.12.0", + "version": "2.13.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From f0a342ffcd3ec1823eb2d42a9dd96c075cea3754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Fri, 11 Jun 2021 16:38:59 +0800 Subject: [PATCH 46/72] feat: --no-deprecation (#44) --- .github/workflows/nodejs.yml | 42 ++++++++++++++++++++++++++++++++++ lib/cmd/start.js | 10 +++++--- package.json | 2 +- test/fixtures/example/app.js | 6 +++++ test/fixtures/ipc-bin/start.js | 3 ++- test/start.test.js | 7 +++--- test/ts.test.js | 2 +- 7 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/nodejs.yml create mode 100644 test/fixtures/example/app.js diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..05760f6 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,42 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '0 2 * * *' + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + node-version: [12, 14] + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Checkout Git Source + uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install Dependencies + run: npm i -g npminstall && npminstall + + - name: Continuous Integration + run: npm run ci + + - name: Code Coverage + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/lib/cmd/start.js b/lib/cmd/start.js index ec47a2f..8445a63 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -77,7 +77,8 @@ class StartCommand extends Command { } * run(context) { - const { argv, env, cwd, execArgv } = context; + context.execArgvObj = context.execArgvObj || {}; + const { argv, env, cwd, execArgvObj } = context; const HOME = homedir(); const logDir = path.join(HOME, 'logs'); @@ -128,10 +129,13 @@ class StartCommand extends Command { env.EGG_SERVER_ENV = argv.env; } + // additional execArgv + execArgvObj.deprecation = false; // --no-deprecation + const command = argv.node || 'node'; const options = { - execArgv, + execArgv: context.execArgv, // getter for execArgvObj, see https://github.com/node-modules/common-bin/blob/master/lib/command.js#L332 env, stdio: 'inherit', detached: false, @@ -143,7 +147,7 @@ class StartCommand extends Command { const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr', 'node' ]; const clusterOptions = stringify(argv, ignoreKeys); // Note: `spawn` is not like `fork`, had to pass `execArgv` youself - const eggArgs = [ ...(execArgv || []), this.serverBin, clusterOptions, `--title=${argv.title}` ]; + const eggArgs = [ ...(options.execArgv || []), this.serverBin, clusterOptions, `--title=${argv.title}` ]; this.logger.info('Run node %s', eggArgs.join(' ')); // whether run in the background. diff --git a/package.json b/package.json index 0a4aba4..26f95b4 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "eslint": "^5.10.0", "eslint-config-egg": "^7.1.0", "mm": "^2.4.1", - "typescript": "^2.8.1", + "typescript": "^4", "urllib": "^2.31.3", "webstorm-disable-index": "^1.2.0" }, diff --git a/test/fixtures/example/app.js b/test/fixtures/example/app.js new file mode 100644 index 0000000..bbebd92 --- /dev/null +++ b/test/fixtures/example/app.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = () => { + // --no-deprecation + new Buffer('aaa'); +}; diff --git a/test/fixtures/ipc-bin/start.js b/test/fixtures/ipc-bin/start.js index 5d1414e..2b858ca 100644 --- a/test/fixtures/ipc-bin/start.js +++ b/test/fixtures/ipc-bin/start.js @@ -27,7 +27,8 @@ co(function* () { title: 'egg-server-example', }, cwd: process.env.BASE_DIR, - execArgv: [], + // FIXME: overide run argv so execArgvObj is missing + // execArgv: [], env: { PATH: process.env.PATH, }, diff --git a/test/start.test.js b/test/start.test.js index 384ff52..a9ed9a4 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -44,12 +44,13 @@ describe('test/start.test.js', () => { it('should start', function* () { app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); - // app.debug(); + app.debug(); app.expect('code', 0); yield sleep(waitTime); assert(app.stderr === ''); + assert(!app.stdout.includes('DeprecationWarning:')); assert(app.stdout.includes('--title=egg-server-example')); assert(app.stdout.includes('"title":"egg-server-example"')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); @@ -59,14 +60,14 @@ describe('test/start.test.js', () => { assert(result.data.toString() === 'hi, egg'); }); - it('should get ready', function* () { + it.skip('should get ready', function* () { app = coffee.fork(path.join(__dirname, './fixtures/ipc-bin/start.js'), [], { env: { BASE_DIR: fixturePath, PATH: process.env.PATH, }, }); - // app.debug(); + app.debug(); app.expect('code', 0); yield sleep(waitTime); diff --git a/test/ts.test.js b/test/ts.test.js index cee5bd8..ca0ad96 100644 --- a/test/ts.test.js +++ b/test/ts.test.js @@ -40,7 +40,7 @@ describe('test/ts.test.js', () => { it('--ts', function* () { app = coffee.fork(eggBin, [ 'start', '--workers=1', '--ts', fixturePath ]); - // app.debug(); + app.debug(); app.expect('code', 0); yield sleep(waitTime); From 499dedd69aa36c9ae2774d85978ef1dc7271e2ac Mon Sep 17 00:00:00 2001 From: TZ Date: Fri, 11 Jun 2021 16:39:22 +0800 Subject: [PATCH 47/72] Release 2.14.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 2b7f8ba..995d30f 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.14.0 / 2021-06-11 +================== + +**features** + * [[`f0a342f`](http://github.com/eggjs/egg-scripts/commit/f0a342ffcd3ec1823eb2d42a9dd96c075cea3754)] - feat: --no-deprecation (#44) (TZ | 天猪 <>) + 2.13.0 / 2020-02-25 ================== diff --git a/package.json b/package.json index 26f95b4..933c908 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.13.0", + "version": "2.14.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From fe179fda909cd7eb5b6497357202185a4ecf5ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Mon, 13 Sep 2021 18:02:06 +0800 Subject: [PATCH 48/72] feat: support pkgInfo.egg.require (#45) --- .github/workflows/nodejs.yml | 3 ++ lib/command.js | 22 +++++++++++-- .../pkg-config/config/config.default.js | 8 +++++ test/fixtures/pkg-config/inject.js | 3 ++ test/fixtures/pkg-config/package.json | 9 ++++++ test/start.test.js | 32 ++++++++++++++++++- 6 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/pkg-config/config/config.default.js create mode 100644 test/fixtures/pkg-config/inject.js create mode 100644 test/fixtures/pkg-config/package.json diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 05760f6..ba86876 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -30,6 +30,9 @@ jobs: with: node-version: ${{ matrix.node-version }} + - name: update npm + run: npm i -g npm + - name: Install Dependencies run: npm i -g npminstall && npminstall diff --git a/lib/command.js b/lib/command.js index d57c7ff..b5df59d 100644 --- a/lib/command.js +++ b/lib/command.js @@ -26,6 +26,12 @@ class Command extends BaseCommand { type: 'boolean', alias: [ 'ts', 'typescript' ], }, + + require: { + description: 'inject to execArgv --require', + type: 'array', + alias: 'r', + }, }; this.logger = new Logger({ @@ -38,18 +44,28 @@ class Command extends BaseCommand { const context = super.context; const { argv, execArgvObj, cwd } = context; - // read `egg.typescript` from package.json let baseDir = argv._[0] || cwd; if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); const pkgFile = path.join(baseDir, 'package.json'); if (fs.existsSync(pkgFile)) { const pkgInfo = require(pkgFile); - if (pkgInfo && pkgInfo.egg && pkgInfo.egg.typescript) { + const eggInfo = pkgInfo.egg; + + // read `egg.typescript` from package.json + if (eggInfo && eggInfo.typescript) { argv.sourcemap = true; } + // read `egg.require` from package.json + if (eggInfo && eggInfo.require && Array.isArray(eggInfo.require)) { + execArgvObj.require = execArgvObj.require || []; + eggInfo.require.forEach(injectScript => { + execArgvObj.require.push(path.resolve(baseDir, injectScript)); + }); + } + // read argv from eggScriptsConfig in package.json - if (pkgInfo && pkgInfo.eggScriptsConfig && typeof pkgInfo.eggScriptsConfig === 'object') { + if (pkgInfo.eggScriptsConfig && typeof pkgInfo.eggScriptsConfig === 'object') { for (const key in pkgInfo.eggScriptsConfig) { if (argv[key] == null) argv[key] = pkgInfo.eggScriptsConfig[key]; } diff --git a/test/fixtures/pkg-config/config/config.default.js b/test/fixtures/pkg-config/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/pkg-config/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/pkg-config/inject.js b/test/fixtures/pkg-config/inject.js new file mode 100644 index 0000000..fd04a2f --- /dev/null +++ b/test/fixtures/pkg-config/inject.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('@@@ inject by pkgInfo'); diff --git a/test/fixtures/pkg-config/package.json b/test/fixtures/pkg-config/package.json new file mode 100644 index 0000000..0999626 --- /dev/null +++ b/test/fixtures/pkg-config/package.json @@ -0,0 +1,9 @@ +{ + "name": "example", + "version": "1.0.0", + "egg": { + "require": [ + "./inject.js" + ] + } +} diff --git a/test/start.test.js b/test/start.test.js index a9ed9a4..7333c4d 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -473,6 +473,32 @@ describe('test/start.test.js', () => { }); }); + describe('read pkgInfo', () => { + let app; + let fixturePath; + + before(function* () { + fixturePath = path.join(__dirname, 'fixtures/pkg-config'); + yield utils.cleanup(fixturePath); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should --require', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/@@@ inject by pkgInfo/)); + }); + }); + describe('subDir as baseDir', () => { let app; const rootDir = path.join(__dirname, '..'); @@ -551,7 +577,11 @@ describe('test/start.test.js', () => { const exitEvent = awaitEvent(app.proc, 'exit'); app.proc.kill('SIGTERM'); const code = yield exitEvent; - assert(code === 0); + if (isWin) { + assert(code === null); + } else { + assert(code === 0); + } }); }); }); From 48af4f7cb88bb862472c882b8bad2b07109c357a Mon Sep 17 00:00:00 2001 From: TZ Date: Mon, 13 Sep 2021 18:02:38 +0800 Subject: [PATCH 49/72] Release 2.15.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 995d30f..ded2b08 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.15.0 / 2021-09-13 +================== + +**features** + * [[`fe179fd`](http://github.com/eggjs/egg-scripts/commit/fe179fda909cd7eb5b6497357202185a4ecf5ec6)] - feat: support pkgInfo.egg.require (#45) (TZ | 天猪 <>) + 2.14.0 / 2021-06-11 ================== diff --git a/package.json b/package.json index 933c908..0617449 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.14.0", + "version": "2.15.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From a68ac679b0eee4eff19c9e5d40ca80409ddf02eb Mon Sep 17 00:00:00 2001 From: hyj1991 Date: Tue, 14 Sep 2021 11:26:57 +0800 Subject: [PATCH 50/72] Revert "feat: support pkgInfo.egg.require (#45)" (#48) This reverts commit fe179fda909cd7eb5b6497357202185a4ecf5ec6. --- .github/workflows/nodejs.yml | 3 -- lib/command.js | 22 ++----------- .../pkg-config/config/config.default.js | 8 ----- test/fixtures/pkg-config/inject.js | 3 -- test/fixtures/pkg-config/package.json | 9 ------ test/start.test.js | 32 +------------------ 6 files changed, 4 insertions(+), 73 deletions(-) delete mode 100644 test/fixtures/pkg-config/config/config.default.js delete mode 100644 test/fixtures/pkg-config/inject.js delete mode 100644 test/fixtures/pkg-config/package.json diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index ba86876..05760f6 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -30,9 +30,6 @@ jobs: with: node-version: ${{ matrix.node-version }} - - name: update npm - run: npm i -g npm - - name: Install Dependencies run: npm i -g npminstall && npminstall diff --git a/lib/command.js b/lib/command.js index b5df59d..d57c7ff 100644 --- a/lib/command.js +++ b/lib/command.js @@ -26,12 +26,6 @@ class Command extends BaseCommand { type: 'boolean', alias: [ 'ts', 'typescript' ], }, - - require: { - description: 'inject to execArgv --require', - type: 'array', - alias: 'r', - }, }; this.logger = new Logger({ @@ -44,28 +38,18 @@ class Command extends BaseCommand { const context = super.context; const { argv, execArgvObj, cwd } = context; + // read `egg.typescript` from package.json let baseDir = argv._[0] || cwd; if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); const pkgFile = path.join(baseDir, 'package.json'); if (fs.existsSync(pkgFile)) { const pkgInfo = require(pkgFile); - const eggInfo = pkgInfo.egg; - - // read `egg.typescript` from package.json - if (eggInfo && eggInfo.typescript) { + if (pkgInfo && pkgInfo.egg && pkgInfo.egg.typescript) { argv.sourcemap = true; } - // read `egg.require` from package.json - if (eggInfo && eggInfo.require && Array.isArray(eggInfo.require)) { - execArgvObj.require = execArgvObj.require || []; - eggInfo.require.forEach(injectScript => { - execArgvObj.require.push(path.resolve(baseDir, injectScript)); - }); - } - // read argv from eggScriptsConfig in package.json - if (pkgInfo.eggScriptsConfig && typeof pkgInfo.eggScriptsConfig === 'object') { + if (pkgInfo && pkgInfo.eggScriptsConfig && typeof pkgInfo.eggScriptsConfig === 'object') { for (const key in pkgInfo.eggScriptsConfig) { if (argv[key] == null) argv[key] = pkgInfo.eggScriptsConfig[key]; } diff --git a/test/fixtures/pkg-config/config/config.default.js b/test/fixtures/pkg-config/config/config.default.js deleted file mode 100644 index 98de4f0..0000000 --- a/test/fixtures/pkg-config/config/config.default.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -exports.keys = '123456'; - -exports.logger = { - level: 'WARN', - consoleLevel: 'WARN', -}; diff --git a/test/fixtures/pkg-config/inject.js b/test/fixtures/pkg-config/inject.js deleted file mode 100644 index fd04a2f..0000000 --- a/test/fixtures/pkg-config/inject.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -console.log('@@@ inject by pkgInfo'); diff --git a/test/fixtures/pkg-config/package.json b/test/fixtures/pkg-config/package.json deleted file mode 100644 index 0999626..0000000 --- a/test/fixtures/pkg-config/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "example", - "version": "1.0.0", - "egg": { - "require": [ - "./inject.js" - ] - } -} diff --git a/test/start.test.js b/test/start.test.js index 7333c4d..a9ed9a4 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -473,32 +473,6 @@ describe('test/start.test.js', () => { }); }); - describe('read pkgInfo', () => { - let app; - let fixturePath; - - before(function* () { - fixturePath = path.join(__dirname, 'fixtures/pkg-config'); - yield utils.cleanup(fixturePath); - }); - - after(function* () { - app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); - }); - - it('should --require', function* () { - app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); - app.debug(); - app.expect('code', 0); - - yield sleep(waitTime); - - assert(app.stderr === ''); - assert(app.stdout.match(/@@@ inject by pkgInfo/)); - }); - }); - describe('subDir as baseDir', () => { let app; const rootDir = path.join(__dirname, '..'); @@ -577,11 +551,7 @@ describe('test/start.test.js', () => { const exitEvent = awaitEvent(app.proc, 'exit'); app.proc.kill('SIGTERM'); const code = yield exitEvent; - if (isWin) { - assert(code === null); - } else { - assert(code === 0); - } + assert(code === 0); }); }); }); From 1a7f09c707becaca42522ee415da0fe5961a6ad5 Mon Sep 17 00:00:00 2001 From: hyj1991 Date: Wed, 15 Sep 2021 14:32:21 +0800 Subject: [PATCH 51/72] feat: support pkgInfo.eggScriptsConfig.require (#47) --- .travis.yml | 24 --- appveyor.yml | 15 -- lib/command.js | 35 ++++- .../pkg-config/config/config.default.js | 8 + test/fixtures/pkg-config/config/plugin.js | 148 ++++++++++++++++++ test/fixtures/pkg-config/inject.js | 3 + test/fixtures/pkg-config/inject2.js | 3 + .../node_modules/custom-framework/index.js | 13 ++ .../custom-framework/package.json | 7 + .../pkg-config/node_modules/inject/index.js | 3 + test/fixtures/pkg-config/package.json | 13 ++ test/fixtures/ts-pkg/app/controller/home.ts | 2 +- test/fixtures/ts/app/controller/home.ts | 2 +- test/start.test.js | 34 +++- test/stop.test.js | 4 +- 15 files changed, 267 insertions(+), 47 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml create mode 100644 test/fixtures/pkg-config/config/config.default.js create mode 100644 test/fixtures/pkg-config/config/plugin.js create mode 100644 test/fixtures/pkg-config/inject.js create mode 100644 test/fixtures/pkg-config/inject2.js create mode 100644 test/fixtures/pkg-config/node_modules/custom-framework/index.js create mode 100644 test/fixtures/pkg-config/node_modules/custom-framework/package.json create mode 100644 test/fixtures/pkg-config/node_modules/inject/index.js create mode 100644 test/fixtures/pkg-config/package.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e08a511..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -sudo: false -language: node_js -node_js: - - '6' - - '8' - - '10' -env: - - EGG_VERSION=1 - - EGG_VERSION=2 -matrix: - exclude: - - node_js: '6' - env: EGG_VERSION=2 -before_install: - - npm install -g npminstall -install: - - npminstall - - sed -i.bak '/"egg":/d' package.json - - npminstall -d -script: - - eval "npminstall -d egg@$EGG_VERSION" - - npm run ci -after_script: - - npminstall codecov && codecov diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 981e82b..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,15 +0,0 @@ -environment: - matrix: - - nodejs_version: '8' - - nodejs_version: '10' - -install: - - ps: Install-Product node $env:nodejs_version - - npm i npminstall && node_modules\.bin\npminstall - -test_script: - - node --version - - npm --version - - npm run test - -build: off diff --git a/lib/command.js b/lib/command.js index d57c7ff..f006bf5 100644 --- a/lib/command.js +++ b/lib/command.js @@ -26,6 +26,12 @@ class Command extends BaseCommand { type: 'boolean', alias: [ 'ts', 'typescript' ], }, + + require: { + description: 'inject to execArgv --require', + type: 'array', + alias: 'r', + }, }; this.logger = new Logger({ @@ -38,22 +44,45 @@ class Command extends BaseCommand { const context = super.context; const { argv, execArgvObj, cwd } = context; - // read `egg.typescript` from package.json let baseDir = argv._[0] || cwd; if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); const pkgFile = path.join(baseDir, 'package.json'); if (fs.existsSync(pkgFile)) { const pkgInfo = require(pkgFile); - if (pkgInfo && pkgInfo.egg && pkgInfo.egg.typescript) { + const eggInfo = pkgInfo.egg; + + // read `egg.typescript` from package.json + if (eggInfo && eggInfo.typescript) { argv.sourcemap = true; } + // read `eggScriptsConfig.require` from package.json + const eggScriptsConfig = pkgInfo.eggScriptsConfig; + let requireFiles = Array.isArray(argv.require) ? argv.require : []; + if (eggScriptsConfig && Array.isArray(eggScriptsConfig.require)) { + requireFiles = requireFiles.concat(eggScriptsConfig.require); + } + execArgvObj.require = execArgvObj.require || []; + requireFiles + .filter(injectScript => injectScript) + .forEach(injectScript => { + let requirePath = ''; + if (path.isAbsolute(injectScript) || injectScript.startsWith(`.${path.sep}`)) { + requirePath = path.resolve(baseDir, injectScript); + } else { + requirePath = injectScript; + } + execArgvObj.require.push(requirePath); + }); + // read argv from eggScriptsConfig in package.json - if (pkgInfo && pkgInfo.eggScriptsConfig && typeof pkgInfo.eggScriptsConfig === 'object') { + if (eggScriptsConfig && typeof eggScriptsConfig === 'object') { for (const key in pkgInfo.eggScriptsConfig) { if (argv[key] == null) argv[key] = pkgInfo.eggScriptsConfig[key]; } } + + delete argv.require; } // execArgv diff --git a/test/fixtures/pkg-config/config/config.default.js b/test/fixtures/pkg-config/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/pkg-config/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/pkg-config/config/plugin.js b/test/fixtures/pkg-config/config/plugin.js new file mode 100644 index 0000000..18b9986 --- /dev/null +++ b/test/fixtures/pkg-config/config/plugin.js @@ -0,0 +1,148 @@ +'use strict'; + +module.exports = { + // enable plugins + + /** + * app global Error Handling + * @member {Object} Plugin#onerror + * @property {Boolean} enable - `true` by default + */ + onerror: { + enable: false, + package: 'egg-onerror', + path: 'xxxxx', + }, + + /** + * session + * @member {Object} Plugin#session + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + session: { + enable: false, + package: 'egg-session', + path: 'xxxxx', + }, + + /** + * i18n + * @member {Object} Plugin#i18n + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + i18n: { + enable: false, + package: 'egg-i18n', + path: 'xxxxx', + }, + + /** + * file and dir watcher + * @member {Object} Plugin#watcher + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + watcher: { + enable: false, + package: 'egg-watcher', + path: 'xxxxx', + }, + + /** + * multipart + * @member {Object} Plugin#multipart + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + multipart: { + enable: false, + package: 'egg-multipart', + path: 'xxxxx', + }, + + /** + * security middlewares and extends + * @member {Object} Plugin#security + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + security: { + enable: false, + package: 'egg-security', + path: 'xxxxx', + }, + + /** + * local development helper + * @member {Object} Plugin#development + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + development: { + enable: false, + package: 'egg-development', + path: 'xxxxx', + }, + + /** + * logger file rotator + * @member {Object} Plugin#logrotator + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + logrotator: { + enable: false, + package: 'egg-logrotator', + path: 'xxxxx', + }, + + /** + * schedule tasks + * @member {Object} Plugin#schedule + * @property {Boolean} enable - `true` by default + * @since 2.7.0 + */ + schedule: { + enable: false, + package: 'egg-schedule', + path: 'xxxxx', + }, + + /** + * `app/public` dir static serve + * @member {Object} Plugin#static + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + static: { + enable: false, + package: 'egg-static', + path: 'xxxxx', + }, + + /** + * jsonp support for egg + * @member {Function} Plugin#jsonp + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + jsonp: { + enable: false, + package: 'egg-jsonp', + path: 'xxxxx', + }, + + /** + * view plugin + * @member {Function} Plugin#view + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + view: { + enable: false, + package: 'egg-view', + path: 'xxxxx', + }, +}; diff --git a/test/fixtures/pkg-config/inject.js b/test/fixtures/pkg-config/inject.js new file mode 100644 index 0000000..2ead88c --- /dev/null +++ b/test/fixtures/pkg-config/inject.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('@@@ inject relative js by pkgInfo'); diff --git a/test/fixtures/pkg-config/inject2.js b/test/fixtures/pkg-config/inject2.js new file mode 100644 index 0000000..4fa540d --- /dev/null +++ b/test/fixtures/pkg-config/inject2.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('@@@ inject by cli'); diff --git a/test/fixtures/pkg-config/node_modules/custom-framework/index.js b/test/fixtures/pkg-config/node_modules/custom-framework/index.js new file mode 100644 index 0000000..499901d --- /dev/null +++ b/test/fixtures/pkg-config/node_modules/custom-framework/index.js @@ -0,0 +1,13 @@ +'use strict'; + +const egg = require('../../../../../node_modules/egg'); + +const EGG_PATH = Symbol.for('egg#eggPath'); + +class Application extends egg.Application { + get [EGG_PATH]() { + return __dirname; + } +} + +module.exports = Object.assign(egg, { Application }); diff --git a/test/fixtures/pkg-config/node_modules/custom-framework/package.json b/test/fixtures/pkg-config/node_modules/custom-framework/package.json new file mode 100644 index 0000000..073be53 --- /dev/null +++ b/test/fixtures/pkg-config/node_modules/custom-framework/package.json @@ -0,0 +1,7 @@ +{ + "name": "custom-framework", + "version": "1.0.0", + "dependencies": { + "egg": "*" + } +} diff --git a/test/fixtures/pkg-config/node_modules/inject/index.js b/test/fixtures/pkg-config/node_modules/inject/index.js new file mode 100644 index 0000000..55d5a75 --- /dev/null +++ b/test/fixtures/pkg-config/node_modules/inject/index.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('@@@ inject node_modules by pkgInfo'); diff --git a/test/fixtures/pkg-config/package.json b/test/fixtures/pkg-config/package.json new file mode 100644 index 0000000..7956e68 --- /dev/null +++ b/test/fixtures/pkg-config/package.json @@ -0,0 +1,13 @@ +{ + "name": "example", + "version": "1.0.0", + "egg": { + "framework": "custom-framework" + }, + "eggScriptsConfig": { + "require": [ + "./inject.js", + "inject" + ] + } +} diff --git a/test/fixtures/ts-pkg/app/controller/home.ts b/test/fixtures/ts-pkg/app/controller/home.ts index f6a07cd..bfb11be 100644 --- a/test/fixtures/ts-pkg/app/controller/home.ts +++ b/test/fixtures/ts-pkg/app/controller/home.ts @@ -4,7 +4,7 @@ export default class AppController extends Controller { public index() { try { throw new Error('some err'); - } catch (err) { + } catch (err: any) { this.ctx.logger.error(err); this.ctx.body = { msg: err.message, diff --git a/test/fixtures/ts/app/controller/home.ts b/test/fixtures/ts/app/controller/home.ts index f6a07cd..bfb11be 100644 --- a/test/fixtures/ts/app/controller/home.ts +++ b/test/fixtures/ts/app/controller/home.ts @@ -4,7 +4,7 @@ export default class AppController extends Controller { public index() { try { throw new Error('some err'); - } catch (err) { + } catch (err: any) { this.ctx.logger.error(err); this.ctx.body = { msg: err.message, diff --git a/test/start.test.js b/test/start.test.js index a9ed9a4..26a3f37 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -30,6 +30,34 @@ describe('test/start.test.js', () => { afterEach(mm.restore); describe('start without daemon', () => { + describe('read pkgInfo', () => { + let app; + let fixturePath; + + before(function* () { + fixturePath = path.join(__dirname, 'fixtures/pkg-config'); + yield utils.cleanup(fixturePath); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should --require', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2' ], { cwd: fixturePath }); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/@@@ inject relative js by pkgInfo/)); + assert(app.stdout.match(/@@@ inject node_modules by pkgInfo/)); + assert(app.stdout.match(/@@@ inject by cli/)); + }); + }); + describe('full path', () => { let app; @@ -551,7 +579,11 @@ describe('test/start.test.js', () => { const exitEvent = awaitEvent(app.proc, 'exit'); app.proc.kill('SIGTERM'); const code = yield exitEvent; - assert(code === 0); + if (isWin) { + assert(code === null); + } else { + assert(code === 0); + } }); }); }); diff --git a/test/stop.test.js b/test/stop.test.js index 16cd38e..95fe485 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -18,7 +18,7 @@ describe('test/stop.test.js', () => { const timeoutPath = path.join(__dirname, 'fixtures/stop-timeout'); const homePath = path.join(__dirname, 'fixtures/home'); const logDir = path.join(homePath, 'logs'); - const waitTime = '10s'; + const waitTime = '15s'; before(function* () { yield mkdirp(homePath); @@ -271,7 +271,7 @@ describe('test/stop.test.js', () => { describe('stop all with timeout', function() { let app; let killer; - this.timeout(12000); + this.timeout(17000); beforeEach(function* () { yield utils.cleanup(timeoutPath); app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=stop-timeout', timeoutPath ]); From ab978a0370fc13c5e21589fc6281e386ac45acb0 Mon Sep 17 00:00:00 2001 From: TZ Date: Wed, 15 Sep 2021 14:34:43 +0800 Subject: [PATCH 52/72] Release 2.15.1 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index ded2b08..ea3306d 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.15.1 / 2021-09-15 +================== + +**features** + * [[`1a7f09c`](http://github.com/eggjs/egg-scripts/commit/1a7f09c707becaca42522ee415da0fe5961a6ad5)] - feat: support pkgInfo.eggScriptsConfig.require (#47) (hyj1991 <>) + +**others** + * [[`a68ac67`](http://github.com/eggjs/egg-scripts/commit/a68ac679b0eee4eff19c9e5d40ca80409ddf02eb)] - Revert "feat: support pkgInfo.egg.require (#45)" (#48) (hyj1991 <>) + 2.15.0 / 2021-09-13 ================== diff --git a/package.json b/package.json index 0617449..4c083be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.15.0", + "version": "2.15.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 78c3284cb68748f4487141f5481d6e44288c9e47 Mon Sep 17 00:00:00 2001 From: hyj1991 Date: Wed, 15 Sep 2021 15:59:42 +0800 Subject: [PATCH 53/72] test: case for injecting incorrect script (#49) --- test/fixtures/pkg-config/inject.js | 3 --- test/fixtures/pkg-config/inject1.js | 3 +++ test/fixtures/pkg-config/inject2.js | 2 +- .../pkg-config/node_modules/inject/index.js | 2 +- test/fixtures/pkg-config/package.json | 2 +- test/start.test.js | 19 +++++++++++++++---- 6 files changed, 21 insertions(+), 10 deletions(-) delete mode 100644 test/fixtures/pkg-config/inject.js create mode 100644 test/fixtures/pkg-config/inject1.js diff --git a/test/fixtures/pkg-config/inject.js b/test/fixtures/pkg-config/inject.js deleted file mode 100644 index 2ead88c..0000000 --- a/test/fixtures/pkg-config/inject.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -console.log('@@@ inject relative js by pkgInfo'); diff --git a/test/fixtures/pkg-config/inject1.js b/test/fixtures/pkg-config/inject1.js new file mode 100644 index 0000000..004fc72 --- /dev/null +++ b/test/fixtures/pkg-config/inject1.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('@@@ inject script1'); diff --git a/test/fixtures/pkg-config/inject2.js b/test/fixtures/pkg-config/inject2.js index 4fa540d..eea4a92 100644 --- a/test/fixtures/pkg-config/inject2.js +++ b/test/fixtures/pkg-config/inject2.js @@ -1,3 +1,3 @@ 'use strict'; -console.log('@@@ inject by cli'); +console.log('@@@ inject script2'); diff --git a/test/fixtures/pkg-config/node_modules/inject/index.js b/test/fixtures/pkg-config/node_modules/inject/index.js index 55d5a75..638c7b9 100644 --- a/test/fixtures/pkg-config/node_modules/inject/index.js +++ b/test/fixtures/pkg-config/node_modules/inject/index.js @@ -1,3 +1,3 @@ 'use strict'; -console.log('@@@ inject node_modules by pkgInfo'); +console.log('@@@ inject script'); diff --git a/test/fixtures/pkg-config/package.json b/test/fixtures/pkg-config/package.json index 7956e68..772b332 100644 --- a/test/fixtures/pkg-config/package.json +++ b/test/fixtures/pkg-config/package.json @@ -6,7 +6,7 @@ }, "eggScriptsConfig": { "require": [ - "./inject.js", + "./inject1.js", "inject" ] } diff --git a/test/start.test.js b/test/start.test.js index 26a3f37..e6b5866 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -45,16 +45,27 @@ describe('test/start.test.js', () => { }); it('should --require', function* () { - app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2' ], { cwd: fixturePath }); + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2.js' ], { cwd: fixturePath }); app.debug(); app.expect('code', 0); yield sleep(waitTime); assert(app.stderr === ''); - assert(app.stdout.match(/@@@ inject relative js by pkgInfo/)); - assert(app.stdout.match(/@@@ inject node_modules by pkgInfo/)); - assert(app.stdout.match(/@@@ inject by cli/)); + assert(app.stdout.match(/@@@ inject script/)); + assert(app.stdout.match(/@@@ inject script1/)); + assert(app.stdout.match(/@@@ inject script2/)); + }); + + it('inject incorrect script', function* () { + const script = './inject3.js'; + app = coffee.fork(eggBin, [ 'start', '--workers=1', `--require=${script}` ], { cwd: fixturePath }); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr.includes(`Cannot find module '${path.join(fixturePath, script)}'`)); }); }); From b122d86d300df4018291d8f8d8e98ab813048f67 Mon Sep 17 00:00:00 2001 From: killa Date: Wed, 17 Nov 2021 09:56:29 +0800 Subject: [PATCH 54/72] fix: sourcemap default value should respect eggScriptConfig (#50) --- lib/command.js | 10 +- .../config/config.default.js | 8 + .../pkg-config-sourcemap/config/plugin.js | 148 ++++++++++++++++++ .../node_modules/custom-framework/index.js | 13 ++ .../custom-framework/package.json | 7 + .../node_modules/inject/index.js | 3 + .../pkg-config-sourcemap/package.json | 11 ++ test/start.test.js | 24 +++ 8 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/pkg-config-sourcemap/config/config.default.js create mode 100644 test/fixtures/pkg-config-sourcemap/config/plugin.js create mode 100644 test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js create mode 100644 test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/package.json create mode 100644 test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js create mode 100644 test/fixtures/pkg-config-sourcemap/package.json diff --git a/lib/command.js b/lib/command.js index f006bf5..589b75e 100644 --- a/lib/command.js +++ b/lib/command.js @@ -51,11 +51,6 @@ class Command extends BaseCommand { const pkgInfo = require(pkgFile); const eggInfo = pkgInfo.egg; - // read `egg.typescript` from package.json - if (eggInfo && eggInfo.typescript) { - argv.sourcemap = true; - } - // read `eggScriptsConfig.require` from package.json const eggScriptsConfig = pkgInfo.eggScriptsConfig; let requireFiles = Array.isArray(argv.require) ? argv.require : []; @@ -82,6 +77,11 @@ class Command extends BaseCommand { } } + // read `egg.typescript` from package.json + if (eggInfo && eggInfo.typescript && typeof argv.sourcemap === 'undefined') { + argv.sourcemap = true; + } + delete argv.require; } diff --git a/test/fixtures/pkg-config-sourcemap/config/config.default.js b/test/fixtures/pkg-config-sourcemap/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/pkg-config-sourcemap/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/pkg-config-sourcemap/config/plugin.js b/test/fixtures/pkg-config-sourcemap/config/plugin.js new file mode 100644 index 0000000..18b9986 --- /dev/null +++ b/test/fixtures/pkg-config-sourcemap/config/plugin.js @@ -0,0 +1,148 @@ +'use strict'; + +module.exports = { + // enable plugins + + /** + * app global Error Handling + * @member {Object} Plugin#onerror + * @property {Boolean} enable - `true` by default + */ + onerror: { + enable: false, + package: 'egg-onerror', + path: 'xxxxx', + }, + + /** + * session + * @member {Object} Plugin#session + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + session: { + enable: false, + package: 'egg-session', + path: 'xxxxx', + }, + + /** + * i18n + * @member {Object} Plugin#i18n + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + i18n: { + enable: false, + package: 'egg-i18n', + path: 'xxxxx', + }, + + /** + * file and dir watcher + * @member {Object} Plugin#watcher + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + watcher: { + enable: false, + package: 'egg-watcher', + path: 'xxxxx', + }, + + /** + * multipart + * @member {Object} Plugin#multipart + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + multipart: { + enable: false, + package: 'egg-multipart', + path: 'xxxxx', + }, + + /** + * security middlewares and extends + * @member {Object} Plugin#security + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + security: { + enable: false, + package: 'egg-security', + path: 'xxxxx', + }, + + /** + * local development helper + * @member {Object} Plugin#development + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + development: { + enable: false, + package: 'egg-development', + path: 'xxxxx', + }, + + /** + * logger file rotator + * @member {Object} Plugin#logrotator + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + logrotator: { + enable: false, + package: 'egg-logrotator', + path: 'xxxxx', + }, + + /** + * schedule tasks + * @member {Object} Plugin#schedule + * @property {Boolean} enable - `true` by default + * @since 2.7.0 + */ + schedule: { + enable: false, + package: 'egg-schedule', + path: 'xxxxx', + }, + + /** + * `app/public` dir static serve + * @member {Object} Plugin#static + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + static: { + enable: false, + package: 'egg-static', + path: 'xxxxx', + }, + + /** + * jsonp support for egg + * @member {Function} Plugin#jsonp + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + jsonp: { + enable: false, + package: 'egg-jsonp', + path: 'xxxxx', + }, + + /** + * view plugin + * @member {Function} Plugin#view + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + view: { + enable: false, + package: 'egg-view', + path: 'xxxxx', + }, +}; diff --git a/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js b/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js new file mode 100644 index 0000000..499901d --- /dev/null +++ b/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js @@ -0,0 +1,13 @@ +'use strict'; + +const egg = require('../../../../../node_modules/egg'); + +const EGG_PATH = Symbol.for('egg#eggPath'); + +class Application extends egg.Application { + get [EGG_PATH]() { + return __dirname; + } +} + +module.exports = Object.assign(egg, { Application }); diff --git a/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/package.json b/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/package.json new file mode 100644 index 0000000..073be53 --- /dev/null +++ b/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/package.json @@ -0,0 +1,7 @@ +{ + "name": "custom-framework", + "version": "1.0.0", + "dependencies": { + "egg": "*" + } +} diff --git a/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js b/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js new file mode 100644 index 0000000..638c7b9 --- /dev/null +++ b/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('@@@ inject script'); diff --git a/test/fixtures/pkg-config-sourcemap/package.json b/test/fixtures/pkg-config-sourcemap/package.json new file mode 100644 index 0000000..a35c104 --- /dev/null +++ b/test/fixtures/pkg-config-sourcemap/package.json @@ -0,0 +1,11 @@ +{ + "name": "pkg-config-sourcemap", + "version": "1.0.0", + "egg": { + "typescript": true, + "framework": "custom-framework" + }, + "eggScriptsConfig": { + "sourcemap": false + } +} diff --git a/test/start.test.js b/test/start.test.js index e6b5866..d7b217c 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -69,6 +69,30 @@ describe('test/start.test.js', () => { }); }); + describe('sourcemap default value should respect eggScriptConfig', () => { + let app; + let fixturePath; + + before(function* () { + fixturePath = path.join(__dirname, 'fixtures/pkg-config-sourcemap'); + yield utils.cleanup(fixturePath); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should not enable sourcemap-support', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1' ], { cwd: fixturePath }); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + assert(!/--require .*\/node_modules\/.*source-map-support/.test(app.stdout)); + }); + }); + describe('full path', () => { let app; From 765086ec8479cc2fbe9c50564ccfa13855b1f27b Mon Sep 17 00:00:00 2001 From: TZ Date: Wed, 17 Nov 2021 09:56:56 +0800 Subject: [PATCH 55/72] Release 2.15.2 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index ea3306d..2f5e671 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.15.2 / 2021-11-17 +================== + +**fixes** + * [[`b122d86`](http://github.com/eggjs/egg-scripts/commit/b122d86d300df4018291d8f8d8e98ab813048f67)] - fix: sourcemap default value should respect eggScriptConfig (#50) (killa <>) + +**others** + * [[`78c3284`](http://github.com/eggjs/egg-scripts/commit/78c3284cb68748f4487141f5481d6e44288c9e47)] - test: case for injecting incorrect script (#49) (hyj1991 <>) + 2.15.1 / 2021-09-15 ================== diff --git a/package.json b/package.json index 4c083be..a3f1cfa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.15.1", + "version": "2.15.2", "description": "deploy tool for egg project", "main": "index.js", "bin": { From be89f9d6bb88810ffa3237deab9e4e0d9c4000c2 Mon Sep 17 00:00:00 2001 From: shuidian <18842643145@163.com> Date: Wed, 22 Dec 2021 16:06:39 +0800 Subject: [PATCH 56/72] =?UTF-8?q?docs(doc):=20=E4=BF=AE=E6=94=B9readme?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=B8=AD=E7=9A=84stop=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E5=A4=84=E7=9A=84=E6=8F=8F=E8=BF=B0=EF=BC=8C=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=A4=BA=E4=BE=8B.=20(#51)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: jiangyan6 Reviewed-BY: hyj1991 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c276e07..ee8b389 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,9 @@ Stop egg gracefull. **Note:** if exec without `--title`, it will kill all egg process. ```bash -# stop egg -$ eggctl stop [--title=example] +$ eggctl stop [options] +# Usage +# eggctl stop --title=example ``` - **Options** From ef5496d1838a508a859cd5d77886098d7de8fec5 Mon Sep 17 00:00:00 2001 From: W Date: Tue, 8 Mar 2022 09:50:07 +0800 Subject: [PATCH 57/72] fix: ps-cmd result may be truncated (#52) Co-authored-by: klook --- lib/helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helper.js b/lib/helper.js index 0f42f6c..d9de722 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -8,7 +8,7 @@ exports.findNodeProcess = function* (filterFn) { const command = isWin ? 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' : // command, cmd are alias of args, not POSIX standard, so we use args - 'ps -eo "pid,args"'; + 'ps -wweo "pid,args"'; const stdio = yield runScript(command, { stdio: 'pipe' }); const processList = stdio.stdout.toString().split('\n') .reduce((arr, line) => { From cb00441f84295e423689f79746f21ac8dd49dd35 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Tue, 8 Mar 2022 09:53:05 +0800 Subject: [PATCH 58/72] Release 2.15.3 --- History.md | 9 +++++++++ README.md | 12 ++++++++++++ package.json | 4 +++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 2f5e671..2d8fad9 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,13 @@ +2.15.3 / 2022-03-08 +================== + +**fixes** + * [[`ef5496d`](http://github.com/eggjs/egg-scripts/commit/ef5496d1838a508a859cd5d77886098d7de8fec5)] - fix: ps-cmd result may be truncated (#52) (W <>) + +**others** + * [[`be89f9d`](http://github.com/eggjs/egg-scripts/commit/be89f9d6bb88810ffa3237deab9e4e0d9c4000c2)] - docs(doc): 修改readme文档中的stop脚本处的描述,并增加示例. (#51) (shuidian <<18842643145@163.com>>) + 2.15.2 / 2021-11-17 ================== diff --git a/README.md b/README.md index ee8b389..9bf64a5 100644 --- a/README.md +++ b/README.md @@ -97,3 +97,15 @@ Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is% [MIT](LICENSE) + + +## Contributors + +|[
atian25](https://github.com/atian25)
|[
popomore](https://github.com/popomore)
|[
fengmk2](https://github.com/fengmk2)
|[
dead-horse](https://github.com/dead-horse)
|[
XadillaX](https://github.com/XadillaX)
|[
hyj1991](https://github.com/hyj1991)
| +| :---: | :---: | :---: | :---: | :---: | :---: | +|[
killagu](https://github.com/killagu)
|[
BaffinLee](https://github.com/BaffinLee)
|[
leoner](https://github.com/leoner)
|[
plusmancn](https://github.com/plusmancn)
|[
shuidian](https://github.com/shuidian)
|[
zhennann](https://github.com/zhennann)
| +[
liyanlong](https://github.com/liyanlong)
+ +This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Tue Mar 08 2022 09:52:13 GMT+0800`. + + \ No newline at end of file diff --git a/package.json b/package.json index a3f1cfa..27af874 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.15.2", + "version": "2.15.3", "description": "deploy tool for egg project", "main": "index.js", "bin": { @@ -28,6 +28,7 @@ "egg-bin": "^4.9.0", "eslint": "^5.10.0", "eslint-config-egg": "^7.1.0", + "git-contributor": "^1.0.10", "mm": "^2.4.1", "typescript": "^4", "urllib": "^2.31.3", @@ -37,6 +38,7 @@ "node": ">=6.0.0" }, "scripts": { + "contributor": "git-contributor", "pkgfiles": "egg-bin pkgfiles", "test": "npm run lint -- --fix && npm run pkgfiles && npm run test-local", "test-local": "egg-bin test", From bb1ba0a665cab9530639d98f38b76c3c72176f76 Mon Sep 17 00:00:00 2001 From: "mansonchor.github.com" Date: Sun, 27 Mar 2022 20:21:05 +0800 Subject: [PATCH 59/72] feat: --trace-warnings (#53) * feat: start ensure no stderr, so open --trace-warnings will helpful for debug * test: ci16 * chore: github action * test: fix testcase * test: add --no-deprecation effect test * fix: testcase * fix: testcase --- .github/workflows/nodejs.yml | 8 +++++--- lib/cmd/start.js | 1 + test/fixtures/trace-warnings/app.js | 14 ++++++++++++++ test/fixtures/trace-warnings/package.json | 4 ++++ test/start.test.js | 12 ++++++++++++ test/stop.test.js | 16 ++++++++-------- 6 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 test/fixtures/trace-warnings/app.js create mode 100644 test/fixtures/trace-warnings/package.json diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 05760f6..b913cce 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -5,9 +5,11 @@ name: Node.js CI on: push: - branches: [ master ] + branches: + - master pull_request: - branches: [ master ] + branches: + - master schedule: - cron: '0 2 * * *' @@ -18,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [12, 14] + node-version: [12, 14, 16] os: [ubuntu-latest, windows-latest, macos-latest] steps: diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 8445a63..add1e2a 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -131,6 +131,7 @@ class StartCommand extends Command { // additional execArgv execArgvObj.deprecation = false; // --no-deprecation + execArgvObj.traceWarnings = true; // --trace-warnings const command = argv.node || 'node'; diff --git a/test/fixtures/trace-warnings/app.js b/test/fixtures/trace-warnings/app.js new file mode 100644 index 0000000..9eee040 --- /dev/null +++ b/test/fixtures/trace-warnings/app.js @@ -0,0 +1,14 @@ +'use strict'; + +const Event = require('events'); +const event = new Event(); +event.setMaxListeners(1); + +module.exports = () => { + // --trace-warnings test about MaxListenersExceededWarning + event.on('xx', () => {}); + event.on('xx', () => {}); + + // will not effect --no-deprecation argv + new Buffer('aaa'); +}; diff --git a/test/fixtures/trace-warnings/package.json b/test/fixtures/trace-warnings/package.json new file mode 100644 index 0000000..dfc4b17 --- /dev/null +++ b/test/fixtures/trace-warnings/package.json @@ -0,0 +1,4 @@ +{ + "name": "trace-warnings", + "version": "1.0.0" +} diff --git a/test/start.test.js b/test/start.test.js index d7b217c..ca22a4b 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -123,6 +123,18 @@ describe('test/start.test.js', () => { assert(result.data.toString() === 'hi, egg'); }); + it('should start --trace-warnings work', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', path.join(__dirname, 'fixtures/trace-warnings') ]); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr.includes('MaxListenersExceededWarning:')); + assert(app.stderr.includes('app.js:10:9')); // should had trace + assert(!app.stdout.includes('DeprecationWarning:')); + }); + it.skip('should get ready', function* () { app = coffee.fork(path.join(__dirname, './fixtures/ipc-bin/start.js'), [], { env: { diff --git a/test/stop.test.js b/test/stop.test.js index 95fe485..f15560c 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -64,7 +64,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[app_worker] exit with code:0')); // assert(app.stdout.includes('[agent_worker] exit with code:0')); @@ -106,7 +106,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(stdout.includes('[master] receive signal SIGTERM, closing')); + assert(stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(stdout.includes('[master] exit with code:0')); assert(stdout.includes('[app_worker] exit with code:0')); } @@ -191,7 +191,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[app_worker] exit with code:0')); // assert(app.stdout.includes('[agent_worker] exit with code:0')); @@ -248,7 +248,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[app_worker] exit with code:0')); // assert(app.stdout.includes('[agent_worker] exit with code:0')); @@ -261,7 +261,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(app2.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app2.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app2.stdout.includes('[master] exit with code:0')); assert(app2.stdout.includes('[app_worker] exit with code:0')); } @@ -275,7 +275,7 @@ describe('test/stop.test.js', () => { beforeEach(function* () { yield utils.cleanup(timeoutPath); app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=stop-timeout', timeoutPath ]); - // app.debug(); + app.debug(); app.expect('code', 0); yield sleep(waitTime); @@ -304,7 +304,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.match(/app_worker#\d+:\d+ disconnect/)); assert(app.stdout.match(/don't fork, because worker:\d+ will be kill soon/)); } @@ -326,7 +326,7 @@ describe('test/stop.test.js', () => { // no way to handle the SIGTERM signal in windows ? if (!isWin) { - assert(app.stdout.includes('[master] receive signal SIGTERM, closing')); + assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[agent_worker] exit with code:0')); } From 429d3c24e70ce14032c3fad48bada0d5dc754d96 Mon Sep 17 00:00:00 2001 From: mansonchor Date: Sun, 27 Mar 2022 20:25:30 +0800 Subject: [PATCH 60/72] Release 2.16.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 2d8fad9..dc1204b 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.16.0 / 2022-03-27 +================== + +**features** + * [[`bb1ba0a`](http://github.com/eggjs/egg-scripts/commit/bb1ba0a665cab9530639d98f38b76c3c72176f76)] - feat: --trace-warnings (#53) (mansonchor.github.com <>) + 2.15.3 / 2022-03-08 ================== diff --git a/package.json b/package.json index 27af874..3914e72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.15.3", + "version": "2.16.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 47f8e823e01b74028bf8dee7123fc3f9469fb3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TZ=20=7C=20=E5=A4=A9=E7=8C=AA?= Date: Thu, 28 Apr 2022 20:17:37 +0800 Subject: [PATCH 61/72] feat: eggScriptsConfig support node-options (#54) --- README.md | 8 +++--- lib/command.js | 14 +++++++++- test/fixtures/egg-scripts-node-options/app.js | 6 +++++ .../config/config.default.js | 3 +++ .../egg-scripts-node-options/package.json | 11 ++++++++ test/start.test.js | 26 +++++++++++++++++++ 6 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/egg-scripts-node-options/app.js create mode 100644 test/fixtures/egg-scripts-node-options/config/config.default.js create mode 100644 test/fixtures/egg-scripts-node-options/package.json diff --git a/README.md b/README.md index 9bf64a5..31d7c29 100644 --- a/README.md +++ b/README.md @@ -79,11 +79,13 @@ $ eggctl stop [options] In addition to the command line specification, options can also be specified in `package.json`. However, the command line designation takes precedence. -```json +```js { "eggScriptsConfig": { "port": 1234, - "ignore-stderr": true + "ignore-stderr": true, + // will pass as `node --max-http-header-size=20000` + "node-options--max-http-header-size": "20000" } } ``` @@ -108,4 +110,4 @@ Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is% This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Tue Mar 08 2022 09:52:13 GMT+0800`. - \ No newline at end of file + diff --git a/lib/command.js b/lib/command.js index 589b75e..7944ae3 100644 --- a/lib/command.js +++ b/lib/command.js @@ -73,7 +73,19 @@ class Command extends BaseCommand { // read argv from eggScriptsConfig in package.json if (eggScriptsConfig && typeof eggScriptsConfig === 'object') { for (const key in pkgInfo.eggScriptsConfig) { - if (argv[key] == null) argv[key] = pkgInfo.eggScriptsConfig[key]; + const v = pkgInfo.eggScriptsConfig[key]; + // like https://github.com/node-modules/common-bin/blob/master/lib/helper.js#L180 + if (key.startsWith('node-options--')) { + const newKey = key.replace('node-options--', ''); + if (execArgvObj[newKey] == null) { + execArgvObj[newKey] = v; + } + } else { + if (argv[key] == null) { + // only set if key is not pass from command line + argv[key] = v; + } + } } } diff --git a/test/fixtures/egg-scripts-node-options/app.js b/test/fixtures/egg-scripts-node-options/app.js new file mode 100644 index 0000000..3fa4a19 --- /dev/null +++ b/test/fixtures/egg-scripts-node-options/app.js @@ -0,0 +1,6 @@ +'use strict'; + +module.exports = () => { + console.log('process.execArgv:', process.execArgv); + console.log('maxHeaderSize:', require('http').maxHeaderSize); +}; diff --git a/test/fixtures/egg-scripts-node-options/config/config.default.js b/test/fixtures/egg-scripts-node-options/config/config.default.js new file mode 100644 index 0000000..c997e00 --- /dev/null +++ b/test/fixtures/egg-scripts-node-options/config/config.default.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.keys = '123456'; diff --git a/test/fixtures/egg-scripts-node-options/package.json b/test/fixtures/egg-scripts-node-options/package.json new file mode 100644 index 0000000..3541f16 --- /dev/null +++ b/test/fixtures/egg-scripts-node-options/package.json @@ -0,0 +1,11 @@ +{ + "name": "example", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + }, + "eggScriptsConfig": { + "workers": 1, + "node-options--max-http-header-size": "20000" + } +} diff --git a/test/start.test.js b/test/start.test.js index ca22a4b..e0aa759 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -548,6 +548,32 @@ describe('test/start.test.js', () => { }); }); + describe('read eggScriptsConfig', () => { + let app; + let fixturePath; + + before(function* () { + fixturePath = path.join(__dirname, 'fixtures/egg-scripts-node-options'); + yield utils.cleanup(fixturePath); + }); + + after(function* () { + app.proc.kill('SIGTERM'); + yield utils.cleanup(fixturePath); + }); + + it('should start', function* () { + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); + app.debug(); + app.expect('code', 0); + + yield sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/maxHeaderSize: 20000/)); + }); + }); + describe('subDir as baseDir', () => { let app; const rootDir = path.join(__dirname, '..'); From 4d9440be4a8b7a4375b3bc2caaa3ca1243a3f728 Mon Sep 17 00:00:00 2001 From: TZ Date: Thu, 28 Apr 2022 20:18:26 +0800 Subject: [PATCH 62/72] Release 2.17.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index dc1204b..bd715b9 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +2.17.0 / 2022-04-28 +================== + +**features** + * [[`47f8e82`](http://github.com/eggjs/egg-scripts/commit/47f8e823e01b74028bf8dee7123fc3f9469fb3b6)] - feat: eggScriptsConfig support node-options (#54) (TZ | 天猪 <>) + 2.16.0 / 2022-03-27 ================== diff --git a/package.json b/package.json index 3914e72..aa88636 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.16.0", + "version": "2.17.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 1c1a052f758bd39cee224a4757873e5867ae403a Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Sat, 24 Sep 2022 09:37:59 +0800 Subject: [PATCH 63/72] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..4b7e366 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,74 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '24 20 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" From 880ad19bef624c18dce2d575d149a2833e39cc1e Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Sun, 18 Dec 2022 02:04:23 +0800 Subject: [PATCH 64/72] chore: auto release (#55) --- .autod.conf.js | 25 ------------------ .github/workflows/nodejs.yml | 50 +++++++++-------------------------- .github/workflows/release.yml | 17 ++++++++++++ package.json | 25 +++++++++--------- 4 files changed, 41 insertions(+), 76 deletions(-) delete mode 100644 .autod.conf.js create mode 100644 .github/workflows/release.yml diff --git a/.autod.conf.js b/.autod.conf.js deleted file mode 100644 index b68b6be..0000000 --- a/.autod.conf.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -module.exports = { - write: true, - prefix: '^', - test: [ - 'test', - 'benchmark', - ], - dep: [ - ], - devdep: [ - 'egg', - 'egg-ci', - 'egg-bin', - 'autod', - 'eslint', - 'eslint-config-egg', - 'webstorm-disable-index', - ], - exclude: [ - './test/fixtures', - './dist', - ], -}; diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index b913cce..5c216b8 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -1,44 +1,18 @@ -# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: Node.js CI +name: CI on: push: - branches: - - master - pull_request: - branches: - - master - schedule: - - cron: '0 2 * * *' - -jobs: - build: - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - node-version: [12, 14, 16] - os: [ubuntu-latest, windows-latest, macos-latest] + branches: [ master ] - steps: - - name: Checkout Git Source - uses: actions/checkout@v2 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install Dependencies - run: npm i -g npminstall && npminstall + pull_request: + branches: [ master ] - - name: Continuous Integration - run: npm run ci + workflow_dispatch: {} - - name: Code Coverage - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} +jobs: + Job: + name: Node.js + uses: artusjs/github-actions/.github/workflows/node-test.yml@v1 + with: + os: 'ubuntu-latest, macos-latest, windows-latest' + version: '14, 16, 18' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1612587 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,17 @@ +name: Release + +on: + push: + branches: [ master ] + + workflow_dispatch: {} + +jobs: + release: + name: Node.js + uses: artusjs/github-actions/.github/workflows/node-release.yml@v1 + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} + with: + checkTest: false diff --git a/package.json b/package.json index aa88636..b9dcbd7 100644 --- a/package.json +++ b/package.json @@ -21,31 +21,30 @@ "zlogger": "^1.1.0" }, "devDependencies": { - "autod": "^3.0.1", "co": "^4.6.0", "coffee": "^5.1.1", - "egg": "^2.14.1", - "egg-bin": "^4.9.0", - "eslint": "^5.10.0", - "eslint-config-egg": "^7.1.0", + "egg": "^3.9.0", + "egg-bin": "^5.6.1", + "eslint": "^8.30.0", + "eslint-config-egg": "^12.1.0", "git-contributor": "^1.0.10", - "mm": "^2.4.1", - "typescript": "^4", - "urllib": "^2.31.3", - "webstorm-disable-index": "^1.2.0" + "mm": "^3.2.1", + "typescript": "^4.9.4", + "urllib": "^3.9.0" }, "engines": { "node": ">=6.0.0" }, + "ci": { + "version": "14, 16, 18" + }, "scripts": { "contributor": "git-contributor", - "pkgfiles": "egg-bin pkgfiles", - "test": "npm run lint -- --fix && npm run pkgfiles && npm run test-local", + "test": "npm run lint -- --fix && npm run test-local", "test-local": "egg-bin test", "cov": "egg-bin cov", "lint": "eslint .", - "ci": "npm run pkgfiles -- --check && npm run lint && npm run cov", - "autod": "autod" + "ci": "npm run lint && npm run cov" }, "files": [ "index.js", From a29469134293a9dec3a7dd5cf6ce71810e913498 Mon Sep 17 00:00:00 2001 From: killa Date: Mon, 19 Feb 2024 21:59:22 +0800 Subject: [PATCH 65/72] feat: support configure egg.revert in package.json (#58) BREAKING CHANGE: drop Node.js 14 support --- .github/workflows/nodejs.yml | 4 +- .github/workflows/release.yml | 2 +- .gitignore | 1 + lib/cmd/start.js | 60 ++- lib/cmd/stop.js | 8 +- lib/helper.js | 4 +- package.json | 4 +- .../egg-revert/config/config.default.js | 8 + .../node_modules/custom-framework/index.js | 21 + .../custom-framework/package.json | 7 + test/fixtures/egg-revert/package.json | 11 + test/start.test.js | 407 ++++++++++-------- test/stop.test.js | 154 +++---- test/ts.test.js | 40 +- test/utils.js | 6 +- 15 files changed, 419 insertions(+), 318 deletions(-) create mode 100644 test/fixtures/egg-revert/config/config.default.js create mode 100644 test/fixtures/egg-revert/node_modules/custom-framework/index.js create mode 100644 test/fixtures/egg-revert/node_modules/custom-framework/package.json create mode 100644 test/fixtures/egg-revert/package.json diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 5c216b8..648a735 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -12,7 +12,7 @@ on: jobs: Job: name: Node.js - uses: artusjs/github-actions/.github/workflows/node-test.yml@v1 + uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: os: 'ubuntu-latest, macos-latest, windows-latest' - version: '14, 16, 18' + version: '16, 18, 20' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1612587..58f7b94 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ on: jobs: release: name: Node.js - uses: artusjs/github-actions/.github/workflows/node-release.yml@v1 + uses: eggjs/github-actions/.github/workflows/node-release.yml@master secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GIT_TOKEN: ${{ secrets.GIT_TOKEN }} diff --git a/.gitignore b/.gitignore index 0c5a36f..03934de 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ run/ test/fixtures/ts/app/controller/home.js test/fixtures/ts-pkg/app/controller/home.js !test/fixtures/**/node_modules +package-lock.json diff --git a/lib/cmd/start.js b/lib/cmd/start.js index add1e2a..57d2fa2 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -76,7 +76,7 @@ class StartCommand extends Command { return 'Start server at prod mode'; } - * run(context) { + async run(context) { context.execArgvObj = context.execArgvObj || {}; const { argv, env, cwd, execArgvObj } = context; const HOME = homedir(); @@ -91,12 +91,12 @@ class StartCommand extends Command { const isDaemon = argv.daemon; - argv.framework = yield this.getFrameworkPath({ + argv.framework = await this.getFrameworkPath({ framework: argv.framework, baseDir, }); - this.frameworkName = yield this.getFrameworkName(argv.framework); + this.frameworkName = await this.getFrameworkName(argv.framework); const pkgInfo = require(path.join(baseDir, 'package.json')); argv.title = argv.title || `egg-server-${pkgInfo.name}`; @@ -121,7 +121,7 @@ class StartCommand extends Command { // for alinode env.ENABLE_NODE_LOG = 'YES'; env.NODE_LOG_DIR = env.NODE_LOG_DIR || path.join(logDir, 'alinode'); - yield mkdirp(env.NODE_LOG_DIR); + await mkdirp(env.NODE_LOG_DIR); // cli argv -> process.env.EGG_SERVER_ENV -> `undefined` then egg will use `prod` if (argv.env) { @@ -132,6 +132,14 @@ class StartCommand extends Command { // additional execArgv execArgvObj.deprecation = false; // --no-deprecation execArgvObj.traceWarnings = true; // --trace-warnings + const eggInfo = pkgInfo.egg || {}; + if (eggInfo.revert) { + context.execArgvObj['security-revert'] = context.execArgvObj['security-revert'] || []; + const reverts = Array.isArray(eggInfo.revert) ? eggInfo.revert : [ eggInfo.revert ]; + for (const revert of reverts) { + context.execArgvObj['security-revert'].push(revert); + } + } const command = argv.node || 'node'; @@ -154,7 +162,10 @@ class StartCommand extends Command { // whether run in the background. if (isDaemon) { this.logger.info(`Save log file to ${logDir}`); - const [ stdout, stderr ] = yield [ getRotatelog(argv.stdout), getRotatelog(argv.stderr) ]; + const [ stdout, stderr ] = await Promise.all([ + getRotatelog(argv.stdout), + getRotatelog(argv.stderr), + ]); options.stdio = [ 'ignore', stdout, stderr, 'ipc' ]; options.detached = true; @@ -173,7 +184,7 @@ class StartCommand extends Command { }); // check start status - yield this.checkStatus(argv); + await this.checkStatus(argv); } else { options.stdio = [ 'inherit', 'inherit', 'inherit', 'ipc' ]; debug('Run spawn `%s %s`', command, eggArgs.join(' ')); @@ -194,11 +205,24 @@ class StartCommand extends Command { } } - * getFrameworkPath(params) { + async getFrameworkPath(params) { return utils.getFrameworkPath(params); } - * getFrameworkName(framework) { + async getFrameworkName(framework) { + const pkgPath = path.join(framework, 'package.json'); + let name = 'egg'; + try { + const pkg = require(pkgPath); + /* istanbul ignore else */ + if (pkg.name) name = pkg.name; + } catch (_) { + /* istanbul next */ + } + return name; + } + + async getRevert(framework) { const pkgPath = path.join(framework, 'package.json'); let name = 'egg'; try { @@ -211,14 +235,14 @@ class StartCommand extends Command { return name; } - * checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) { + async checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) { let count = 0; let hasError = false; let isSuccess = true; timeout = timeout / 1000; while (!this.isReady) { try { - const stat = yield fs.stat(stderr); + const stat = await fs.stat(stderr); if (stat && stat.size > 0) { hasError = true; break; @@ -233,7 +257,7 @@ class StartCommand extends Command { break; } - yield sleep(1000); + await sleep(1000); this.logger.log('Wait Start: %d...', ++count); } @@ -241,7 +265,7 @@ class StartCommand extends Command { try { const args = [ '-n', '100', stderr ]; this.logger.error('tail %s', args.join(' ')); - const [ stdout ] = yield execFile('tail', args); + const [ stdout ] = await execFile('tail', args); this.logger.error('Got error when startup: '); this.logger.error(stdout); } catch (err) { @@ -254,23 +278,23 @@ class StartCommand extends Command { if (!isSuccess) { this.child.kill('SIGTERM'); - yield sleep(1000); + await sleep(1000); this.exit(1); } } } -function* getRotatelog(logfile) { - yield mkdirp(path.dirname(logfile)); +async function getRotatelog(logfile) { + await mkdirp(path.dirname(logfile)); - if (yield fs.exists(logfile)) { + if (await fs.exists(logfile)) { // format style: .20150602.193100 const timestamp = moment().format('.YYYYMMDD.HHmmss'); // Note: rename last log to next start time, not when last log file created - yield fs.rename(logfile, logfile + timestamp); + await fs.rename(logfile, logfile + timestamp); } - return yield fs.open(logfile, 'a'); + return await fs.open(logfile, 'a'); } function stringify(obj, ignore) { diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js index a15fc0e..40d4607 100644 --- a/lib/cmd/stop.js +++ b/lib/cmd/stop.js @@ -29,13 +29,13 @@ class StopCommand extends Command { return 'Stop server'; } - * run(context) { + async run(context) { const { argv } = context; this.logger.info(`stopping egg application ${argv.title ? `with --title=${argv.title}` : ''}`); // node /Users/tz/Workspaces/eggjs/egg-scripts/lib/start-cluster {"title":"egg-server","workers":4,"port":7001,"baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg"} - let processList = yield this.helper.findNodeProcess(item => { + let processList = await this.helper.findNodeProcess(item => { const cmd = item.cmd; return argv.title ? cmd.includes('start-cluster') && cmd.includes(util.format(osRelated.titleTemplate, argv.title)) : @@ -47,7 +47,7 @@ class StopCommand extends Command { this.logger.info('got master pid %j', pids); this.helper.kill(pids); // wait for 5s to confirm whether any worker process did not kill by master - yield sleep(argv.timeout || '5s'); + await sleep(argv.timeout || '5s'); } else { this.logger.warn('can\'t detect any running egg process'); } @@ -55,7 +55,7 @@ class StopCommand extends Command { // node --debug-port=5856 /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/agent_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} - processList = yield this.helper.findNodeProcess(item => { + processList = await this.helper.findNodeProcess(item => { const cmd = item.cmd; return argv.title ? (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)) && cmd.includes(util.format(osRelated.titleTemplate, argv.title)) : diff --git a/lib/helper.js b/lib/helper.js index d9de722..fbbbc03 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -4,12 +4,12 @@ const runScript = require('runscript'); const isWin = process.platform === 'win32'; const REGEX = isWin ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/; -exports.findNodeProcess = function* (filterFn) { +exports.findNodeProcess = async function(filterFn) { const command = isWin ? 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' : // command, cmd are alias of args, not POSIX standard, so we use args 'ps -wweo "pid,args"'; - const stdio = yield runScript(command, { stdio: 'pipe' }); + const stdio = await runScript(command, { stdio: 'pipe' }); const processList = stdio.stdout.toString().split('\n') .reduce((arr, line) => { if (!!line && !line.includes('/bin/sh') && line.includes('node')) { diff --git a/package.json b/package.json index b9dcbd7..dcb79cb 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "await-event": "^2.1.0", - "common-bin": "^2.8.0", + "common-bin": "^3.0.1", "debug": "^4.1.0", "egg-utils": "^2.4.1", "moment": "^2.23.0", @@ -36,7 +36,7 @@ "node": ">=6.0.0" }, "ci": { - "version": "14, 16, 18" + "version": "16, 18, 20" }, "scripts": { "contributor": "git-contributor", diff --git a/test/fixtures/egg-revert/config/config.default.js b/test/fixtures/egg-revert/config/config.default.js new file mode 100644 index 0000000..98de4f0 --- /dev/null +++ b/test/fixtures/egg-revert/config/config.default.js @@ -0,0 +1,8 @@ +'use strict'; + +exports.keys = '123456'; + +exports.logger = { + level: 'WARN', + consoleLevel: 'WARN', +}; diff --git a/test/fixtures/egg-revert/node_modules/custom-framework/index.js b/test/fixtures/egg-revert/node_modules/custom-framework/index.js new file mode 100644 index 0000000..071acea --- /dev/null +++ b/test/fixtures/egg-revert/node_modules/custom-framework/index.js @@ -0,0 +1,21 @@ +'use strict'; + +const egg = require('../../../../../node_modules/egg'); + +const originStartCluster = egg.startCluster; + +module.exports = Object.assign(egg, { + Application: class CustomApplication extends egg.Application { + get [Symbol.for('egg#eggPath')]() { + return __dirname; + } + }, + startCluster(...args) { + if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { + console.log('## EGG_SERVER_ENV is not pass'); + console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); + process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; + } + return originStartCluster(...args); + }, +}); diff --git a/test/fixtures/egg-revert/node_modules/custom-framework/package.json b/test/fixtures/egg-revert/node_modules/custom-framework/package.json new file mode 100644 index 0000000..a9328f7 --- /dev/null +++ b/test/fixtures/egg-revert/node_modules/custom-framework/package.json @@ -0,0 +1,7 @@ +{ + "name": "custom-framework", + "version": "1.0.0", + "dependencies": { + "egg": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/egg-revert/package.json b/test/fixtures/egg-revert/package.json new file mode 100644 index 0000000..71801ee --- /dev/null +++ b/test/fixtures/egg-revert/package.json @@ -0,0 +1,11 @@ +{ + "name": "example", + "version": "1.0.0", + "dependencies": { + "egg": "^1.0.0" + }, + "egg": { + "framework": "custom-framework", + "revert": "CVE-2023-46809" + } +} diff --git a/test/start.test.js b/test/start.test.js index e0aa759..1989315 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -12,6 +12,7 @@ const mm = require('mm'); const utils = require('./utils'); const awaitEvent = require('await-event'); const isWin = process.platform === 'win32'; +const version = Number(process.version.substring(1, 3)); describe('test/start.test.js', () => { const eggBin = require.resolve('../bin/egg-scripts.js'); @@ -20,11 +21,11 @@ describe('test/start.test.js', () => { const logDir = path.join(homePath, 'logs'); const waitTime = '10s'; - before(function* () { - yield mkdirp(homePath); + before(async () => { + await mkdirp(homePath); }); - after(function* () { - yield rimraf(homePath); + after(async () => { + await rimraf(homePath); }); beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); afterEach(mm.restore); @@ -34,22 +35,22 @@ describe('test/start.test.js', () => { let app; let fixturePath; - before(function* () { + before(async () => { fixturePath = path.join(__dirname, 'fixtures/pkg-config'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should --require', function* () { + it('should --require', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2.js' ], { cwd: fixturePath }); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/@@@ inject script/)); @@ -57,13 +58,13 @@ describe('test/start.test.js', () => { assert(app.stdout.match(/@@@ inject script2/)); }); - it('inject incorrect script', function* () { + it('inject incorrect script', async () => { const script = './inject3.js'; app = coffee.fork(eggBin, [ 'start', '--workers=1', `--require=${script}` ], { cwd: fixturePath }); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr.includes(`Cannot find module '${path.join(fixturePath, script)}'`)); }); @@ -73,22 +74,22 @@ describe('test/start.test.js', () => { let app; let fixturePath; - before(function* () { + before(async () => { fixturePath = path.join(__dirname, 'fixtures/pkg-config-sourcemap'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should not enable sourcemap-support', function* () { + it('should not enable sourcemap-support', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1' ], { cwd: fixturePath }); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(!/--require .*\/node_modules\/.*source-map-support/.test(app.stdout)); }); }); @@ -96,21 +97,21 @@ describe('test/start.test.js', () => { describe('full path', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - afterEach(function* () { + afterEach(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(!app.stdout.includes('DeprecationWarning:')); @@ -119,23 +120,23 @@ describe('test/start.test.js', () => { assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); assert(app.stdout.includes('app_worker#2:')); assert(!app.stdout.includes('app_worker#3:')); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - it('should start --trace-warnings work', function* () { + it('should start --trace-warnings work', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', path.join(__dirname, 'fixtures/trace-warnings') ]); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr.includes('MaxListenersExceededWarning:')); assert(app.stderr.includes('app.js:10:9')); // should had trace assert(!app.stdout.includes('DeprecationWarning:')); }); - it.skip('should get ready', function* () { + it.skip('should get ready', async () => { app = coffee.fork(path.join(__dirname, './fixtures/ipc-bin/start.js'), [], { env: { BASE_DIR: fixturePath, @@ -145,7 +146,7 @@ describe('test/start.test.js', () => { app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.includes('READY!!!')); @@ -160,22 +161,22 @@ describe('test/start.test.js', () => { describe('child exit with 1', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should emit spawn error', function* () { + it('should emit spawn error', async () => { const srv = require('http').createServer(() => {}); srv.listen(7007); app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); - yield sleep(waitTime); + await sleep(waitTime); srv.close(); assert(app.code === 1); }); @@ -184,25 +185,25 @@ describe('test/start.test.js', () => { describe('relative path', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', path.relative(process.cwd(), fixturePath) ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -210,25 +211,25 @@ describe('test/start.test.js', () => { describe('without baseDir', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2' ], { cwd: fixturePath }); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -236,25 +237,25 @@ describe('test/start.test.js', () => { describe('--framework', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, yadan'); }); }); @@ -262,21 +263,21 @@ describe('test/start.test.js', () => { describe('--title', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=egg-test', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.includes('--title=egg-test')); @@ -284,7 +285,7 @@ describe('test/start.test.js', () => { assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); assert(app.stdout.includes('app_worker#2:')); assert(!app.stdout.includes('app_worker#3:')); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -292,25 +293,25 @@ describe('test/start.test.js', () => { describe('--port', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--port=7002', '--workers=2', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); - const result = yield httpclient.request('http://127.0.0.1:7002'); + const result = await httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -318,25 +319,25 @@ describe('test/start.test.js', () => { describe('process.env.PORT', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ], { env: Object.assign({}, process.env, { PORT: 7002 }) }); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); - const result = yield httpclient.request('http://127.0.0.1:7002'); + const result = await httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -344,25 +345,25 @@ describe('test/start.test.js', () => { describe('--env', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', '--env=pre', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001/env'); + const result = await httpclient.request('http://127.0.0.1:7001/env'); assert(result.data.toString() === 'pre, true'); }); }); @@ -370,30 +371,30 @@ describe('test/start.test.js', () => { describe('custom env', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { mm(process.env, 'CUSTOM_ENV', 'pre'); app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.includes('## EGG_SERVER_ENV is not pass')); assert(app.stdout.includes('## CUSTOM_ENV: pre')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - let result = yield httpclient.request('http://127.0.0.1:7001/env'); + let result = await httpclient.request('http://127.0.0.1:7001/env'); assert(result.data.toString() === 'pre, true'); - result = yield httpclient.request('http://127.0.0.1:7001/path'); + result = await httpclient.request('http://127.0.0.1:7001/path'); const appBinPath = path.join(fixturePath, 'node_modules/.bin'); assert(result.data.toString().startsWith(`${appBinPath}${path.delimiter}`)); }); @@ -402,38 +403,38 @@ describe('test/start.test.js', () => { describe('--stdout --stderr', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); - yield rimraf(logDir); - yield rimraf(path.join(fixturePath, 'start-fail')); - yield mkdirp(logDir); + before(async () => { + await utils.cleanup(fixturePath); + await rimraf(logDir); + await rimraf(path.join(fixturePath, 'start-fail')); + await mkdirp(logDir); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); - yield rimraf(path.join(fixturePath, 'stdout.log')); - yield rimraf(path.join(fixturePath, 'stderr.log')); - yield rimraf(path.join(fixturePath, 'start-fail')); + await utils.cleanup(fixturePath); + await rimraf(path.join(fixturePath, 'stdout.log')); + await rimraf(path.join(fixturePath, 'stderr.log')); + await rimraf(path.join(fixturePath, 'start-fail')); }); - it('should start', function* () { + it('should start', async () => { const stdout = path.join(fixturePath, 'stdout.log'); const stderr = path.join(fixturePath, 'stderr.log'); app = coffee.fork(eggBin, [ 'start', '--workers=1', '--daemon', `--stdout=${stdout}`, `--stderr=${stderr}`, fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); - let content = yield fs.readFile(stdout, 'utf-8'); + let content = await fs.readFile(stdout, 'utf-8'); assert(content.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - content = yield fs.readFile(stderr, 'utf-8'); + content = await fs.readFile(stderr, 'utf-8'); assert(content === ''); }); - it('should start with insecurity --stderr argument', function* () { + it('should start with insecurity --stderr argument', async () => { const cwd = path.join(__dirname, 'fixtures/status'); mm(process.env, 'ERROR', 'error message'); @@ -447,13 +448,13 @@ describe('test/start.test.js', () => { ]); // app.debug(); - yield sleep(waitTime); + await sleep(waitTime); - const content = yield fs.readFile(stdout, 'utf-8'); + const content = await fs.readFile(stdout, 'utf-8'); assert(!content.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - let exists = yield fs.exists(stderr); + let exists = await fs.exists(stderr); assert(!exists); - exists = yield fs.exists(malicious); + exists = await fs.exists(malicious); assert(!exists); }); }); @@ -461,59 +462,59 @@ describe('test/start.test.js', () => { describe('--node', () => { let app; - beforeEach(function* () { - yield utils.cleanup(fixturePath); + beforeEach(async () => { + await utils.cleanup(fixturePath); }); - beforeEach(function* () { + beforeEach(async () => { app && app.proc && app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); describe('daemon', () => { - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--daemon', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, yadan'); }); - it('should error if node path invalid', function* () { + it('should error if node path invalid', async () => { app = coffee.fork(eggBin, [ 'start', '--daemon', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath ]); // app.debug(); app.expect('code', 1); - yield sleep(3000); + await sleep(3000); assert(app.stderr.includes('spawn invalid ENOENT')); }); }); describe('not daemon', () => { - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, yadan'); }); - it('should error if node path invalid', function* () { + it('should error if node path invalid', async () => { app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath ]); // app.debug(); app.expect('code', 1); - yield sleep(3000); + await sleep(3000); assert(app.stderr.includes('spawn invalid ENOENT')); }); }); @@ -523,27 +524,27 @@ describe('test/start.test.js', () => { let app; let fixturePath; - before(function* () { + before(async () => { fixturePath = path.join(__dirname, 'fixtures/cluster-config'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:8000/)); assert(!app.stdout.includes('app_worker#3:')); - const result = yield httpclient.request('http://127.0.0.1:8000'); + const result = await httpclient.request('http://127.0.0.1:8000'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -552,52 +553,80 @@ describe('test/start.test.js', () => { let app; let fixturePath; - before(function* () { + before(async () => { fixturePath = path.join(__dirname, 'fixtures/egg-scripts-node-options'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/maxHeaderSize: 20000/)); }); }); + describe('read egg.revert', () => { + if (version < 18) return; + if (isWin) return; + let app; + let fixturePath; + + before(async () => { + fixturePath = path.join(__dirname, 'fixtures/egg-revert'); + await utils.cleanup(fixturePath); + }); + + after(async () => { + app.proc.kill('SIGTERM'); + await utils.cleanup(fixturePath); + }); + + it('should start', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); + app.debug(); + app.expect('code', 0); + + await sleep(waitTime); + + assert(app.stderr === ''); + assert(app.stdout.match(/SECURITY WARNING: Reverting CVE-2023-46809: Marvin attack on PKCS#1 padding/)); + }); + }); + describe('subDir as baseDir', () => { let app; const rootDir = path.join(__dirname, '..'); const subDir = path.join(__dirname, 'fixtures/subdir-as-basedir/base-dir'); - before(function* () { - yield utils.cleanup(rootDir); + before(async () => { + await utils.cleanup(rootDir); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(rootDir); + await utils.cleanup(rootDir); }); - it('should start', function* () { + it('should start', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=2', subDir ], { cwd: rootDir }); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); }); @@ -606,17 +635,17 @@ describe('test/start.test.js', () => { let app; let fixturePath; - before(function* () { + before(async () => { fixturePath = path.join(__dirname, 'fixtures/custom-node-dir'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - after(function* () { + after(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should start', function* () { + it('should start', async () => { const expectPATH = [ path.join(fixturePath, 'node_modules/.bin'), path.join(fixturePath, '.node/bin'), @@ -625,12 +654,12 @@ describe('test/start.test.js', () => { // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7002/)); assert(!app.stdout.includes('app_worker#3:')); - const result = yield httpclient.request('http://127.0.0.1:7002'); + const result = await httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString().startsWith(`hi, ${expectPATH}`)); }); }); @@ -638,20 +667,20 @@ describe('test/start.test.js', () => { describe('kill command', () => { let app; - before(function* () { - yield utils.cleanup(fixturePath); + before(async () => { + await utils.cleanup(fixturePath); }); - after(function* () { - yield utils.cleanup(fixturePath); + after(async () => { + await utils.cleanup(fixturePath); }); - it('should wait child process exit', function* () { + it('should wait child process exit', async () => { app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); - yield sleep(waitTime); + await sleep(waitTime); const exitEvent = awaitEvent(app.proc, 'exit'); app.proc.kill('SIGTERM'); - const code = yield exitEvent; + const code = await exitEvent; if (isWin) { assert(code === null); } else { @@ -663,23 +692,23 @@ describe('test/start.test.js', () => { describe('start with daemon', () => { let cwd; - beforeEach(function* () { - if (cwd) yield utils.cleanup(cwd); - yield rimraf(logDir); - yield mkdirp(logDir); - yield fs.writeFile(path.join(logDir, 'master-stdout.log'), 'just for test'); - yield fs.writeFile(path.join(logDir, 'master-stderr.log'), 'just for test'); + beforeEach(async () => { + if (cwd) await utils.cleanup(cwd); + await rimraf(logDir); + await mkdirp(logDir); + await fs.writeFile(path.join(logDir, 'master-stdout.log'), 'just for test'); + await fs.writeFile(path.join(logDir, 'master-stderr.log'), 'just for test'); }); - afterEach(function* () { - yield coffee.fork(eggBin, [ 'stop', cwd ]) + afterEach(async () => { + await coffee.fork(eggBin, [ 'stop', cwd ]) // .debug() .end(); - yield utils.cleanup(cwd); + await utils.cleanup(cwd); }); - it('should start custom-framework', function* () { + it('should start custom-framework', async () => { cwd = fixturePath; - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', '--port=7002', cwd ]) + await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', '--port=7002', cwd ]) // .debug() .expect('stdout', /Starting custom-framework application/) .expect('stdout', /custom-framework started on http:\/\/127\.0\.0\.1:7002/) @@ -687,23 +716,23 @@ describe('test/start.test.js', () => { .end(); // master log - const stdout = yield fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); - const stderr = yield fs.readFile(path.join(logDir, 'master-stderr.log'), 'utf-8'); + const stdout = await fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); + const stderr = await fs.readFile(path.join(logDir, 'master-stderr.log'), 'utf-8'); assert(stderr === ''); assert(stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); // should rotate log - const fileList = yield fs.readdir(logDir); + const fileList = await fs.readdir(logDir); assert(fileList.some(name => name.match(/master-stdout\.log\.\d+\.\d+/))); assert(fileList.some(name => name.match(/master-stderr\.log\.\d+\.\d+/))); - const result = yield httpclient.request('http://127.0.0.1:7002'); + const result = await httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString() === 'hi, egg'); }); - it('should start default egg', function* () { + it('should start default egg', async () => { cwd = path.join(__dirname, 'fixtures/egg-app'); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', cwd ]) + await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', cwd ]) // .debug() .expect('stdout', /Starting egg application/) .expect('stdout', /egg started on http:\/\/127\.0\.0\.1:7001/) @@ -718,16 +747,16 @@ describe('test/start.test.js', () => { cwd = path.join(__dirname, 'fixtures/status'); }); - after(function* () { - yield coffee.fork(eggBin, [ 'stop', cwd ]) + after(async () => { + await coffee.fork(eggBin, [ 'stop', cwd ]) // .debug() .end(); - yield utils.cleanup(cwd); + await utils.cleanup(cwd); }); - it('should status check success, exit with 0', function* () { + it('should status check success, exit with 0', async () => { mm(process.env, 'WAIT_TIME', 5000); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) + await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) // .debug() .expect('stdout', /Wait Start: 5.../) .expect('stdout', /custom-framework started/) @@ -735,7 +764,7 @@ describe('test/start.test.js', () => { .end(); }); - it('should status check fail `--ignore-stderr`, exit with 0', function* () { + it('should status check fail `--ignore-stderr`, exit with 0', async () => { mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); @@ -746,12 +775,12 @@ describe('test/start.test.js', () => { // app.debug(); // TODO: find a windows replacement for tail command if (!isWin) app.expect('stderr', /nodejs.Error: error message/); - yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + await app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) .expect('code', 0) .end(); }); - it('should status check fail `--ignore-stderr` in package.json, exit with 0', function* () { + it('should status check fail `--ignore-stderr` in package.json, exit with 0', async () => { cwd = path.join(__dirname, 'fixtures/egg-scripts-config'); mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); @@ -763,12 +792,12 @@ describe('test/start.test.js', () => { // app.debug(); // TODO: find a windows replacement for tail command if (!isWin) app.expect('stderr', /nodejs.Error: error message/); - yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + await app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) .expect('code', 0) .end(); }); - it('should status check fail, exit with 1', function* () { + it('should status check fail, exit with 1', async () => { mm(process.env, 'WAIT_TIME', 5000); mm(process.env, 'ERROR', 'error message'); @@ -779,16 +808,16 @@ describe('test/start.test.js', () => { // app.debug(); // TODO: find a windows replacement for tail command if (!isWin) app.expect('stderr', /nodejs.Error: error message/); - yield app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + await app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) .expect('stderr', /Got error when startup/) .expect('code', 1) .end(); }); - it('should status check timeout and exit with code 1', function* () { + it('should status check timeout and exit with code 1', async () => { mm(process.env, 'WAIT_TIME', 10000); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--timeout=5000' ], { cwd }) + await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--timeout=5000' ], { cwd }) // .debug() .expect('stdout', /Wait Start: 1.../) .expect('stderr', /Start failed, 5s timeout/) diff --git a/test/stop.test.js b/test/stop.test.js index f15560c..dc72121 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -20,11 +20,11 @@ describe('test/stop.test.js', () => { const logDir = path.join(homePath, 'logs'); const waitTime = '15s'; - before(function* () { - yield mkdirp(homePath); + before(async () => { + await mkdirp(homePath); }); - after(function* () { - yield rimraf(homePath); + after(async () => { + await rimraf(homePath); }); beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); afterEach(() => mm.restore); @@ -33,31 +33,31 @@ describe('test/stop.test.js', () => { let app; let killer; - beforeEach(function* () { - yield utils.cleanup(fixturePath); + beforeEach(async () => { + await utils.cleanup(fixturePath); app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - afterEach(function* () { + afterEach(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should stop', function* () { + it('should stop', async () => { killer = coffee.fork(eggBin, [ 'stop', fixturePath ]); killer.debug(); killer.expect('code', 0); - // yield killer.end(); - yield sleep(waitTime); + // await killer.end(); + await sleep(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); @@ -76,33 +76,33 @@ describe('test/stop.test.js', () => { }); describe('stop with daemon', () => { - beforeEach(function* () { - yield utils.cleanup(fixturePath); - yield rimraf(logDir); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', fixturePath ]) + beforeEach(async () => { + await utils.cleanup(fixturePath); + await rimraf(logDir); + await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', fixturePath ]) .debug() .expect('code', 0) .end(); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - afterEach(function* () { - yield utils.cleanup(fixturePath); + afterEach(async () => { + await utils.cleanup(fixturePath); }); - it('should stop', function* () { - yield coffee.fork(eggBin, [ 'stop', fixturePath ]) + it('should stop', async () => { + await coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() .expect('stdout', /\[egg-scripts] stopping egg application/) .expect('stdout', /got master pid \["\d+\"\]/i) .expect('code', 0) .end(); - yield sleep(waitTime); + await sleep(waitTime); // master log - const stdout = yield fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); + const stdout = await fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); // no way to handle the SIGTERM signal in windows ? if (!isWin) { @@ -111,7 +111,7 @@ describe('test/stop.test.js', () => { assert(stdout.includes('[app_worker] exit with code:0')); } - yield coffee.fork(eggBin, [ 'stop', fixturePath ]) + await coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() .expect('stderr', /can't detect any running egg process/) .expect('code', 0) @@ -120,9 +120,9 @@ describe('test/stop.test.js', () => { }); describe('stop with not exist', () => { - it('should work', function* () { - yield utils.cleanup(fixturePath); - yield coffee.fork(eggBin, [ 'stop', fixturePath ]) + it('should work', async () => { + await utils.cleanup(fixturePath); + await coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() .expect('stdout', /\[egg-scripts] stopping egg application/) .expect('stderr', /can't detect any running egg process/) @@ -135,27 +135,27 @@ describe('test/stop.test.js', () => { let app; let killer; - beforeEach(function* () { - yield utils.cleanup(fixturePath); + beforeEach(async () => { + await utils.cleanup(fixturePath); app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - afterEach(function* () { + afterEach(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('shoud stop only if the title matches exactly', function* () { + it('shoud stop only if the title matches exactly', async () => { // Because of'exmaple'.inclues('exmap') === true,if egg-scripts <= 2.1.0 and you run `.. stop --title=exmap`,the process with 'title:example' will also be killed unexpectedly - yield coffee.fork(eggBin, [ 'stop', '--title=examp', fixturePath ]) + await coffee.fork(eggBin, [ 'stop', '--title=examp', fixturePath ]) .debug() .expect('stdout', /\[egg-scripts] stopping egg application with --title=examp/) .expect('stderr', /can't detect any running egg process/) @@ -163,7 +163,7 @@ describe('test/stop.test.js', () => { .end(); // stop only if the title matches exactly - yield coffee.fork(eggBin, [ 'stop', '--title=example', fixturePath ]) + await coffee.fork(eggBin, [ 'stop', '--title=example', fixturePath ]) .debug() .expect('stdout', /\[egg-scripts] stopping egg application with --title=example/) .expect('stdout', /\[egg-scripts\] got master pid \[/) @@ -171,8 +171,8 @@ describe('test/stop.test.js', () => { .end(); }); - it('should stop', function* () { - yield coffee.fork(eggBin, [ 'stop', '--title=random', fixturePath ]) + it('should stop', async () => { + await coffee.fork(eggBin, [ 'stop', '--title=random', fixturePath ]) .debug() .expect('stdout', /\[egg-scripts] stopping egg application with --title=random/) .expect('stderr', /can't detect any running egg process/) @@ -183,8 +183,8 @@ describe('test/stop.test.js', () => { killer.debug(); killer.expect('code', 0); - // yield killer.end(); - yield sleep(waitTime); + // await killer.end(); + await sleep(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); @@ -207,8 +207,8 @@ describe('test/stop.test.js', () => { let app2; let killer; - beforeEach(function* () { - yield utils.cleanup(fixturePath); + beforeEach(async () => { + await utils.cleanup(fixturePath); app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]); // app.debug(); app.expect('code', 0); @@ -216,32 +216,32 @@ describe('test/stop.test.js', () => { app2 = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=test', '--port=7002', fixturePath ]); app2.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); assert(app2.stderr === ''); assert(app2.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); - const result2 = yield httpclient.request('http://127.0.0.1:7002'); + const result2 = await httpclient.request('http://127.0.0.1:7002'); assert(result2.data.toString() === 'hi, egg'); }); - afterEach(function* () { + afterEach(async () => { app.proc.kill('SIGTERM'); app2.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should stop', function* () { + it('should stop', async () => { killer = coffee.fork(eggBin, [ 'stop' ], { cwd: fixturePath }); killer.debug(); killer.expect('code', 0); - // yield killer.end(); - yield sleep(waitTime); + // await killer.end(); + await sleep(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); @@ -272,32 +272,32 @@ describe('test/stop.test.js', () => { let app; let killer; this.timeout(17000); - beforeEach(function* () { - yield utils.cleanup(timeoutPath); + beforeEach(async () => { + await utils.cleanup(timeoutPath); app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=stop-timeout', timeoutPath ]); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001'); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - afterEach(function* () { + afterEach(async () => { app.proc.kill('SIGTERM'); - yield utils.cleanup(timeoutPath); + await utils.cleanup(timeoutPath); }); - it('should stop error without timeout', function* () { + it('should stop error without timeout', async () => { killer = coffee.fork(eggBin, [ 'stop' ], { cwd: timeoutPath }); killer.debug(); killer.expect('code', 0); - // yield killer.end(); - yield sleep(waitTime); + // await killer.end(); + await sleep(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); @@ -313,13 +313,13 @@ describe('test/stop.test.js', () => { assert(killer.stdout.match(/got master pid \["\d+\"]/i)); }); - it('should stop success', function* () { + it('should stop success', async () => { killer = coffee.fork(eggBin, [ 'stop', '--timeout=10s' ], { cwd: timeoutPath }); killer.debug(); killer.expect('code', 0); - // yield killer.end(); - yield sleep(waitTime); + // await killer.end(); + await sleep(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); @@ -339,10 +339,10 @@ describe('test/stop.test.js', () => { describe('stop with symlink', () => { const baseDir = path.join(__dirname, 'fixtures/tmp'); - beforeEach(function* () { + beforeEach(async () => { // if we can't create a symlink, skip the test try { - yield fs.symlink(fixturePath, baseDir, 'dir'); + await fs.symlink(fixturePath, baseDir, 'dir'); } catch (err) { // may get Error: EPERM: operation not permitted on windows console.log(`test skiped, can't create symlink: ${err}`); @@ -352,28 +352,28 @@ describe('test/stop.test.js', () => { // *unix get the real path of symlink, but windows wouldn't const appPathInRegexp = isWin ? baseDir.replace(/\\/g, '\\\\') : fixturePath; - yield utils.cleanup(fixturePath); - yield rimraf(logDir); - yield coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2' ], { cwd: baseDir }) + await utils.cleanup(fixturePath); + await rimraf(logDir); + await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2' ], { cwd: baseDir }) .debug() .expect('stdout', new RegExp(`Starting custom-framework application at ${appPathInRegexp}`)) .expect('code', 0) .end(); - yield rimraf(baseDir); - const result = yield httpclient.request('http://127.0.0.1:7001'); + await rimraf(baseDir); + const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); - afterEach(function* () { - yield utils.cleanup(fixturePath); - yield rimraf(baseDir); + afterEach(async () => { + await utils.cleanup(fixturePath); + await rimraf(baseDir); }); - it('should stop', function* () { - yield rimraf(baseDir); - yield fs.symlink(path.join(__dirname, 'fixtures/status'), baseDir); + it('should stop', async () => { + await rimraf(baseDir); + await fs.symlink(path.join(__dirname, 'fixtures/status'), baseDir); - yield coffee.fork(eggBin, [ 'stop', baseDir ]) + await coffee.fork(eggBin, [ 'stop', baseDir ]) .debug() .expect('stdout', /\[egg-scripts] stopping egg application/) .expect('stdout', /got master pid \["\d+\"\]/i) diff --git a/test/ts.test.js b/test/ts.test.js index ca0ad96..9d2cfdd 100644 --- a/test/ts.test.js +++ b/test/ts.test.js @@ -26,56 +26,56 @@ describe('test/ts.test.js', () => { describe('should display correct stack traces', () => { let app; - beforeEach(function* () { + beforeEach(async () => { fixturePath = path.join(__dirname, 'fixtures/ts'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); const result = cp.spawnSync('npm', [ 'run', isWin ? 'windows-build' : 'build' ], { cwd: fixturePath, shell: isWin }); assert(!result.stderr.toString()); }); - afterEach(function* () { + afterEach(async () => { app && app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('--ts', function* () { + it('--ts', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', '--ts', fixturePath ]); app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); - it('--typescript', function* () { + it('--typescript', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', '--typescript', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); - it('--sourcemap', function* () { + it('--sourcemap', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', '--sourcemap', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); @@ -83,28 +83,28 @@ describe('test/ts.test.js', () => { describe('pkg.egg.typescript', () => { let app; - beforeEach(function* () { + beforeEach(async () => { fixturePath = path.join(__dirname, 'fixtures/ts-pkg'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); const result = cp.spawnSync('npm', [ 'run', isWin ? 'windows-build' : 'build' ], { cwd: fixturePath, shell: isWin }); assert(!result.stderr.toString()); }); - afterEach(function* () { + afterEach(async () => { app && app.proc.kill('SIGTERM'); - yield utils.cleanup(fixturePath); + await utils.cleanup(fixturePath); }); - it('should got correct stack', function* () { + it('should got correct stack', async () => { app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); // app.debug(); app.expect('code', 0); - yield sleep(waitTime); + await sleep(waitTime); assert(app.stderr === ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = yield httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); + const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); }); diff --git a/test/utils.js b/test/utils.js index 7e21f75..51bde7a 100644 --- a/test/utils.js +++ b/test/utils.js @@ -4,8 +4,8 @@ const helper = require('../lib/helper'); const sleep = require('mz-modules/sleep'); const isWin = process.platform === 'win32'; -exports.cleanup = function* (baseDir) { - const processList = yield helper.findNodeProcess(x => { +exports.cleanup = async function(baseDir) { + const processList = await helper.findNodeProcess(x => { const dir = isWin ? baseDir.replace(/\\/g, '\\\\') : baseDir; const prefix = isWin ? '\\"baseDir\\":\\"' : '"baseDir":"'; return x.cmd.includes(`${prefix}${dir}`); @@ -36,6 +36,6 @@ exports.cleanup = function* (baseDir) { } } - yield sleep('5s'); + await sleep('5s'); } }; From 35fd6aaebb53ed8f1f3b2eaf68a2ed790e37bf51 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 19 Feb 2024 14:00:06 +0000 Subject: [PATCH 66/72] Release 3.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] ## [3.0.0](https://github.com/eggjs/egg-scripts/compare/v2.17.0...v3.0.0) (2024-02-19) ### ⚠ BREAKING CHANGES * drop Node.js 14 support ### Features * support configure egg.revert in package.json ([#58](https://github.com/eggjs/egg-scripts/issues/58)) ([a294691](https://github.com/eggjs/egg-scripts/commit/a29469134293a9dec3a7dd5cf6ce71810e913498)) --- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..470ed97 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +## [3.0.0](https://github.com/eggjs/egg-scripts/compare/v2.17.0...v3.0.0) (2024-02-19) + + +### ⚠ BREAKING CHANGES + +* drop Node.js 14 support + +### Features + +* support configure egg.revert in package.json ([#58](https://github.com/eggjs/egg-scripts/issues/58)) ([a294691](https://github.com/eggjs/egg-scripts/commit/a29469134293a9dec3a7dd5cf6ce71810e913498)) diff --git a/package.json b/package.json index dcb79cb..02aa134 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "2.17.0", + "version": "3.0.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From 7f2cecfeb68f07e9b69871f77b66f8a221c51b90 Mon Sep 17 00:00:00 2001 From: Gxkl Date: Sat, 11 May 2024 15:53:09 +0800 Subject: [PATCH 67/72] fix: head 100 stderr when startup failed (#59) --- lib/cmd/start.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 57d2fa2..041600a 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -265,9 +265,12 @@ class StartCommand extends Command { try { const args = [ '-n', '100', stderr ]; this.logger.error('tail %s', args.join(' ')); - const [ stdout ] = await execFile('tail', args); + const [ headStdout ] = await execFile('head', args); + const [ tailStdout ] = await execFile('tail', args); this.logger.error('Got error when startup: '); - this.logger.error(stdout); + this.logger.error(headStdout); + this.logger.error('...'); + this.logger.error(tailStdout); } catch (err) { this.logger.error('ignore tail error: %s', err); } From 52f2dbc25fa543af9fa20af7dfb8d599cc0f27de Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 11 May 2024 07:54:09 +0000 Subject: [PATCH 68/72] Release 3.0.1 [skip ci] ## [3.0.1](https://github.com/eggjs/egg-scripts/compare/v3.0.0...v3.0.1) (2024-05-11) ### Bug Fixes * head 100 stderr when startup failed ([#59](https://github.com/eggjs/egg-scripts/issues/59)) ([7f2cecf](https://github.com/eggjs/egg-scripts/commit/7f2cecfeb68f07e9b69871f77b66f8a221c51b90)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 470ed97..7d0206a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [3.0.1](https://github.com/eggjs/egg-scripts/compare/v3.0.0...v3.0.1) (2024-05-11) + + +### Bug Fixes + +* head 100 stderr when startup failed ([#59](https://github.com/eggjs/egg-scripts/issues/59)) ([7f2cecf](https://github.com/eggjs/egg-scripts/commit/7f2cecfeb68f07e9b69871f77b66f8a221c51b90)) + ## [3.0.0](https://github.com/eggjs/egg-scripts/compare/v2.17.0...v3.0.0) (2024-02-19) diff --git a/package.json b/package.json index 02aa134..7a2496f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "3.0.0", + "version": "3.0.1", "description": "deploy tool for egg project", "main": "index.js", "bin": { From ebbb7f60446a2bf5ec8eaac40c85c6224dd91c9d Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Tue, 10 Dec 2024 20:16:02 +0800 Subject: [PATCH 69/72] feat: use runscript v2 (#61) ## Summary by CodeRabbit - **Chores** - Removed the CodeQL analysis workflow. - Updated Node.js CI workflow to include an additional version. - Modified release workflow to remove manual trigger. - Added `.package-lock.json` to `.gitignore`. - **Documentation** - Updated contributors section in `README.md` to use a dynamic contributors' graph. - Updated CHANGELOG.md to reflect recent version changes and bug fixes. - **Dependencies** - Updated various dependencies in `package.json` and adjusted Node.js version requirement. - Removed the `contributor` script and updated test scripts to include flags. - **Tests** - Enhanced assertion checks in multiple test files for more robust error handling. - Added a new utility function to sanitize error messages in tests. --- .github/workflows/codeql-analysis.yml | 74 --------- .github/workflows/nodejs.yml | 6 +- .github/workflows/release.yml | 4 - .gitignore | 1 + CHANGELOG.md | 215 ++++++++++++++++++++++++++ History.md | 211 ------------------------- README.md | 11 +- lib/cmd/start.js | 14 +- lib/helper.js | 4 +- package.json | 24 ++- test/start.test.js | 41 ++--- test/stop.test.js | 10 +- test/ts.test.js | 8 +- test/utils.js | 10 +- 14 files changed, 273 insertions(+), 360 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml delete mode 100644 History.md diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 4b7e366..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,74 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ "master" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "master" ] - schedule: - - cron: '24 20 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 648a735..0dba04e 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -3,16 +3,12 @@ name: CI on: push: branches: [ master ] - pull_request: branches: [ master ] - workflow_dispatch: {} - jobs: Job: name: Node.js uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: - os: 'ubuntu-latest, macos-latest, windows-latest' - version: '16, 18, 20' + version: '16, 18, 20, 22' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 58f7b94..a2bf04a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,8 +4,6 @@ on: push: branches: [ master ] - workflow_dispatch: {} - jobs: release: name: Node.js @@ -13,5 +11,3 @@ jobs: secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GIT_TOKEN: ${{ secrets.GIT_TOKEN }} - with: - checkTest: false diff --git a/.gitignore b/.gitignore index 03934de..472d43c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ test/fixtures/ts/app/controller/home.js test/fixtures/ts-pkg/app/controller/home.js !test/fixtures/**/node_modules package-lock.json +.package-lock.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d0206a..a03d991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,218 @@ ### Features * support configure egg.revert in package.json ([#58](https://github.com/eggjs/egg-scripts/issues/58)) ([a294691](https://github.com/eggjs/egg-scripts/commit/a29469134293a9dec3a7dd5cf6ce71810e913498)) + + +--- + + +2.17.0 / 2022-04-28 +================== + +**features** + * [[`47f8e82`](http://github.com/eggjs/egg-scripts/commit/47f8e823e01b74028bf8dee7123fc3f9469fb3b6)] - feat: eggScriptsConfig support node-options (#54) (TZ | 天猪 <>) + +2.16.0 / 2022-03-27 +================== + +**features** + * [[`bb1ba0a`](http://github.com/eggjs/egg-scripts/commit/bb1ba0a665cab9530639d98f38b76c3c72176f76)] - feat: --trace-warnings (#53) (mansonchor.github.com <>) + +2.15.3 / 2022-03-08 +================== + +**fixes** + * [[`ef5496d`](http://github.com/eggjs/egg-scripts/commit/ef5496d1838a508a859cd5d77886098d7de8fec5)] - fix: ps-cmd result may be truncated (#52) (W <>) + +**others** + * [[`be89f9d`](http://github.com/eggjs/egg-scripts/commit/be89f9d6bb88810ffa3237deab9e4e0d9c4000c2)] - docs(doc): 修改readme文档中的stop脚本处的描述,并增加示例. (#51) (shuidian <<18842643145@163.com>>) + +2.15.2 / 2021-11-17 +================== + +**fixes** + * [[`b122d86`](http://github.com/eggjs/egg-scripts/commit/b122d86d300df4018291d8f8d8e98ab813048f67)] - fix: sourcemap default value should respect eggScriptConfig (#50) (killa <>) + +**others** + * [[`78c3284`](http://github.com/eggjs/egg-scripts/commit/78c3284cb68748f4487141f5481d6e44288c9e47)] - test: case for injecting incorrect script (#49) (hyj1991 <>) + +2.15.1 / 2021-09-15 +================== + +**features** + * [[`1a7f09c`](http://github.com/eggjs/egg-scripts/commit/1a7f09c707becaca42522ee415da0fe5961a6ad5)] - feat: support pkgInfo.eggScriptsConfig.require (#47) (hyj1991 <>) + +**others** + * [[`a68ac67`](http://github.com/eggjs/egg-scripts/commit/a68ac679b0eee4eff19c9e5d40ca80409ddf02eb)] - Revert "feat: support pkgInfo.egg.require (#45)" (#48) (hyj1991 <>) + +2.15.0 / 2021-09-13 +================== + +**features** + * [[`fe179fd`](http://github.com/eggjs/egg-scripts/commit/fe179fda909cd7eb5b6497357202185a4ecf5ec6)] - feat: support pkgInfo.egg.require (#45) (TZ | 天猪 <>) + +2.14.0 / 2021-06-11 +================== + +**features** + * [[`f0a342f`](http://github.com/eggjs/egg-scripts/commit/f0a342ffcd3ec1823eb2d42a9dd96c075cea3754)] - feat: --no-deprecation (#44) (TZ | 天猪 <>) + +2.13.0 / 2020-02-25 +================== + +**features** + * [[`c0ba739`](http://github.com/eggjs/egg-scripts/commit/c0ba73900642e488b0e6306ea028ef547ceedfae)] - feat: support stop timeout (#43) (hui <>) + +2.12.0 / 2019-12-16 +================== + +**features** + * [[`20483fd`](http://github.com/eggjs/egg-scripts/commit/20483fd56ce51238431fb095ede1c768a99470f2)] - feat: support eggScriptsConfig in package.json (#41) (Yiyu He <>) + +2.11.1 / 2019-10-10 +================== + +**fixes** + * [[`de61980`](http://github.com/eggjs/egg-scripts/commit/de61980f772c8a24010d3f078658f8c55b072067)] - fix: start command should exit after child process exit when no daemon mode (#39) (killa <>) + +**others** + * [[`7ae9cb0`](http://github.com/eggjs/egg-scripts/commit/7ae9cb054cb91ea7ac1e615e1e3a7fcdaba5f980)] - test: add egg@1 and egg@2 with travis (#36) (Maledong <>) + +2.11.0 / 2018-12-17 +=================== + + * feat(stop): only sleep when master process exists (#34) + * fix: stop process only if the title matches exactly (#35) + +2.10.0 / 2018-10-10 +================== + +**fixes** + * [[`4768950`](http://github.com/eggjs/egg-scripts/commit/4768950d29398031fd6ae129a981c60e308bff0a)] - fix: replace command by args in ps (#29) (Baffin Lee <>) + +**others** + * [[`f31efb9`](http://github.com/eggjs/egg-scripts/commit/f31efb9133c5edc6176371ca725198f1b43b9aab)] - feat: support customize node path (#32) (Yiyu He <>) + * [[`c2479dc`](http://github.com/eggjs/egg-scripts/commit/c2479dc6416386b654fc6e918a4dbd575cc0639e)] - chore: update version (TZ <>) + +2.9.1 / 2018-08-24 +================== + + * fix: replace command by args in ps (#29) + +2.9.0 / 2018-08-23 +================== + +**features** + * [[`1367883`](http://github.com/eggjs/egg-scripts/commit/1367883804e5ab1ece88831ea4d1a934ee757f81)] - feat: add ipc channel in nonDaemon mode (#28) (Khaidi Chu <>) + +**others** + * [[`262ef4c`](http://github.com/eggjs/egg-scripts/commit/262ef4c97179dbf6f8de2eb0547eef4cbc56bf92)] - chore: add license and issues link (#27) (Haoliang Gao <>) + +2.8.1 / 2018-08-19 +================== + +**fixes** + * [[`b98fd03`](http://github.com/eggjs/egg-scripts/commit/b98fd03d1e3aaed68004b881f0b3d42fe47341dd)] - fix: use execFile instead of exec for security reason (#26) (fengmk2 <>) + +2.8.0 / 2018-08-10 +================== + +**others** + * [[`dac29f7`](http://github.com/eggjs/egg-scripts/commit/dac29f73ed2dfc18edc2e8743ffd509af8ab0f4a)] - refactor: add `this.exit` to instead of `process.exit` (#25) (Khaidi Chu <>) + +2.7.0 / 2018-08-10 +================== + +**features** + * [[`22faa4c`](http://github.com/eggjs/egg-scripts/commit/22faa4cfbb84cc5bc819d981dce962d8f95f8357)] - feat: stop command support windows (#22) (Baffin Lee <>) + +**others** + * [[`e07726c`](http://github.com/eggjs/egg-scripts/commit/e07726c176a89dd63482b588868fd1feaab1fba6)] - refactor: raw spawn call to instead of helper.spawn in start non-daemon mode (#23) (Khaidi Chu <>) + +2.6.0 / 2018-04-03 +================== + + * feat: provides source map support for stack traces (#19) + +2.5.1 / 2018-02-06 +================== + + * chore: add description for ignore-stderr (#18) + +2.5.0 / 2017-12-12 +================== + +**features** + * [[`b5559d5`](http://github.com/eggjs/egg-scripts/commit/b5559d54228543b5422047e6f056829df11f8c87)] - feat: support --ignore-error (#17) (TZ | 天猪 <>) + +2.4.0 / 2017-11-30 +================== + +**features** + * [[`8eda3d1`](https://github.com/eggjs/egg-scripts/commit/8eda3d10cfea5757f220fd82b562fd5fef433440)] - feat: add `${baseDir}/.node/bin` to PATH if exists (#14) (fengmk2 <>) + +**others** + * [[`4dd24a4`](https://github.com/eggjs/egg-scripts/commit/4dd24a45d92b2c2a8e1e450e0f13ba4143550ca9)] - test: add testcase for #12 (#13) (Haoliang Gao <>) + +2.3.0 / 2017-11-29 +================== + +**features** + * [[`4c41319`](http://github.com/eggjs/egg-scripts/commit/4c41319f9e309402b2ccb5c7afd5a6d3cda2453f)] - feat: support stop --title (#16) (TZ | 天猪 <>) + +2.2.0 / 2017-11-22 +================== + +**features** + * [[`ac58d00`](http://github.com/eggjs/egg-scripts/commit/ac58d00a974fdfff6b5c722743e4b32174963c52)] - feat: cwd maybe not baseDir (#15) (zhennann <>) + +2.1.1 / 2017-11-14 +================== + +**fixes** + * [[`7324d99`](http://github.com/eggjs/egg-scripts/commit/7324d99b504cac5fef7dbf280f7d9e6243c16bb7)] - fix: should stop app when baseDir is symlink (#12) (Haoliang Gao <>) + +2.1.0 / 2017-10-16 +================== + +**features** + * [[`ac40135`](http://github.com/eggjs/egg-scripts/commit/ac40135d5b9a3200ea1bdfdb19d0f7e12d0c511a)] - feat: add eggctl bin (#10) (Haoliang Gao <>) + +2.0.0 / 2017-10-13 +================== + +**features** + * [[`0f7ca50`](http://github.com/eggjs/egg-scripts/commit/0f7ca502999c06a9cb05d8e5617f6045704511df)] - feat: [BREAKING_CHANGE] check the status of app when start on daemon (#9) (Haoliang Gao <>) + +**others** + * [[`cfd0d2f`](http://github.com/eggjs/egg-scripts/commit/cfd0d2f67845fffb9d5974514b65e43b22ed8040)] - refactor: modify the directory of logDir (#8) (Haoliang Gao <>) + +1.2.0 / 2017-09-11 +================== + +**features** + * [[`c0300b8`](http://github.com/eggjs/egg-scripts/commit/c0300b8c657fe4f75ca388061f6cb3de9864a743)] - feat: log success at daemon mode (#7) (TZ | 天猪 <>) + +**others** + * [[`fdd273c`](http://github.com/eggjs/egg-scripts/commit/fdd273c2d6f15d104288fef4d699627a7cf701d9)] - test: add cluster-config fixture (#4) (TZ | 天猪 <>) + +1.1.2 / 2017-09-01 +================== + + * fix: should not pass undefined env (#6) + * docs: fix stop typo (#5) + +1.1.1 / 2017-08-29 +================== + + * fix: should set title correct (#3) + +1.1.0 / 2017-08-16 +================== + + * feat: remove env default value (#2) + +1.0.0 / 2017-08-02 +================== + + * feat: first implementation (#1) diff --git a/History.md b/History.md deleted file mode 100644 index bd715b9..0000000 --- a/History.md +++ /dev/null @@ -1,211 +0,0 @@ - -2.17.0 / 2022-04-28 -================== - -**features** - * [[`47f8e82`](http://github.com/eggjs/egg-scripts/commit/47f8e823e01b74028bf8dee7123fc3f9469fb3b6)] - feat: eggScriptsConfig support node-options (#54) (TZ | 天猪 <>) - -2.16.0 / 2022-03-27 -================== - -**features** - * [[`bb1ba0a`](http://github.com/eggjs/egg-scripts/commit/bb1ba0a665cab9530639d98f38b76c3c72176f76)] - feat: --trace-warnings (#53) (mansonchor.github.com <>) - -2.15.3 / 2022-03-08 -================== - -**fixes** - * [[`ef5496d`](http://github.com/eggjs/egg-scripts/commit/ef5496d1838a508a859cd5d77886098d7de8fec5)] - fix: ps-cmd result may be truncated (#52) (W <>) - -**others** - * [[`be89f9d`](http://github.com/eggjs/egg-scripts/commit/be89f9d6bb88810ffa3237deab9e4e0d9c4000c2)] - docs(doc): 修改readme文档中的stop脚本处的描述,并增加示例. (#51) (shuidian <<18842643145@163.com>>) - -2.15.2 / 2021-11-17 -================== - -**fixes** - * [[`b122d86`](http://github.com/eggjs/egg-scripts/commit/b122d86d300df4018291d8f8d8e98ab813048f67)] - fix: sourcemap default value should respect eggScriptConfig (#50) (killa <>) - -**others** - * [[`78c3284`](http://github.com/eggjs/egg-scripts/commit/78c3284cb68748f4487141f5481d6e44288c9e47)] - test: case for injecting incorrect script (#49) (hyj1991 <>) - -2.15.1 / 2021-09-15 -================== - -**features** - * [[`1a7f09c`](http://github.com/eggjs/egg-scripts/commit/1a7f09c707becaca42522ee415da0fe5961a6ad5)] - feat: support pkgInfo.eggScriptsConfig.require (#47) (hyj1991 <>) - -**others** - * [[`a68ac67`](http://github.com/eggjs/egg-scripts/commit/a68ac679b0eee4eff19c9e5d40ca80409ddf02eb)] - Revert "feat: support pkgInfo.egg.require (#45)" (#48) (hyj1991 <>) - -2.15.0 / 2021-09-13 -================== - -**features** - * [[`fe179fd`](http://github.com/eggjs/egg-scripts/commit/fe179fda909cd7eb5b6497357202185a4ecf5ec6)] - feat: support pkgInfo.egg.require (#45) (TZ | 天猪 <>) - -2.14.0 / 2021-06-11 -================== - -**features** - * [[`f0a342f`](http://github.com/eggjs/egg-scripts/commit/f0a342ffcd3ec1823eb2d42a9dd96c075cea3754)] - feat: --no-deprecation (#44) (TZ | 天猪 <>) - -2.13.0 / 2020-02-25 -================== - -**features** - * [[`c0ba739`](http://github.com/eggjs/egg-scripts/commit/c0ba73900642e488b0e6306ea028ef547ceedfae)] - feat: support stop timeout (#43) (hui <>) - -2.12.0 / 2019-12-16 -================== - -**features** - * [[`20483fd`](http://github.com/eggjs/egg-scripts/commit/20483fd56ce51238431fb095ede1c768a99470f2)] - feat: support eggScriptsConfig in package.json (#41) (Yiyu He <>) - -2.11.1 / 2019-10-10 -================== - -**fixes** - * [[`de61980`](http://github.com/eggjs/egg-scripts/commit/de61980f772c8a24010d3f078658f8c55b072067)] - fix: start command should exit after child process exit when no daemon mode (#39) (killa <>) - -**others** - * [[`7ae9cb0`](http://github.com/eggjs/egg-scripts/commit/7ae9cb054cb91ea7ac1e615e1e3a7fcdaba5f980)] - test: add egg@1 and egg@2 with travis (#36) (Maledong <>) - -2.11.0 / 2018-12-17 -=================== - - * feat(stop): only sleep when master process exists (#34) - * fix: stop process only if the title matches exactly (#35) - -2.10.0 / 2018-10-10 -================== - -**fixes** - * [[`4768950`](http://github.com/eggjs/egg-scripts/commit/4768950d29398031fd6ae129a981c60e308bff0a)] - fix: replace command by args in ps (#29) (Baffin Lee <>) - -**others** - * [[`f31efb9`](http://github.com/eggjs/egg-scripts/commit/f31efb9133c5edc6176371ca725198f1b43b9aab)] - feat: support customize node path (#32) (Yiyu He <>) - * [[`c2479dc`](http://github.com/eggjs/egg-scripts/commit/c2479dc6416386b654fc6e918a4dbd575cc0639e)] - chore: update version (TZ <>) - -2.9.1 / 2018-08-24 -================== - - * fix: replace command by args in ps (#29) - -2.9.0 / 2018-08-23 -================== - -**features** - * [[`1367883`](http://github.com/eggjs/egg-scripts/commit/1367883804e5ab1ece88831ea4d1a934ee757f81)] - feat: add ipc channel in nonDaemon mode (#28) (Khaidi Chu <>) - -**others** - * [[`262ef4c`](http://github.com/eggjs/egg-scripts/commit/262ef4c97179dbf6f8de2eb0547eef4cbc56bf92)] - chore: add license and issues link (#27) (Haoliang Gao <>) - -2.8.1 / 2018-08-19 -================== - -**fixes** - * [[`b98fd03`](http://github.com/eggjs/egg-scripts/commit/b98fd03d1e3aaed68004b881f0b3d42fe47341dd)] - fix: use execFile instead of exec for security reason (#26) (fengmk2 <>) - -2.8.0 / 2018-08-10 -================== - -**others** - * [[`dac29f7`](http://github.com/eggjs/egg-scripts/commit/dac29f73ed2dfc18edc2e8743ffd509af8ab0f4a)] - refactor: add `this.exit` to instead of `process.exit` (#25) (Khaidi Chu <>) - -2.7.0 / 2018-08-10 -================== - -**features** - * [[`22faa4c`](http://github.com/eggjs/egg-scripts/commit/22faa4cfbb84cc5bc819d981dce962d8f95f8357)] - feat: stop command support windows (#22) (Baffin Lee <>) - -**others** - * [[`e07726c`](http://github.com/eggjs/egg-scripts/commit/e07726c176a89dd63482b588868fd1feaab1fba6)] - refactor: raw spawn call to instead of helper.spawn in start non-daemon mode (#23) (Khaidi Chu <>) - -2.6.0 / 2018-04-03 -================== - - * feat: provides source map support for stack traces (#19) - -2.5.1 / 2018-02-06 -================== - - * chore: add description for ignore-stderr (#18) - -2.5.0 / 2017-12-12 -================== - -**features** - * [[`b5559d5`](http://github.com/eggjs/egg-scripts/commit/b5559d54228543b5422047e6f056829df11f8c87)] - feat: support --ignore-error (#17) (TZ | 天猪 <>) - -2.4.0 / 2017-11-30 -================== - -**features** - * [[`8eda3d1`](https://github.com/eggjs/egg-scripts/commit/8eda3d10cfea5757f220fd82b562fd5fef433440)] - feat: add `${baseDir}/.node/bin` to PATH if exists (#14) (fengmk2 <>) - -**others** - * [[`4dd24a4`](https://github.com/eggjs/egg-scripts/commit/4dd24a45d92b2c2a8e1e450e0f13ba4143550ca9)] - test: add testcase for #12 (#13) (Haoliang Gao <>) - -2.3.0 / 2017-11-29 -================== - -**features** - * [[`4c41319`](http://github.com/eggjs/egg-scripts/commit/4c41319f9e309402b2ccb5c7afd5a6d3cda2453f)] - feat: support stop --title (#16) (TZ | 天猪 <>) - -2.2.0 / 2017-11-22 -================== - -**features** - * [[`ac58d00`](http://github.com/eggjs/egg-scripts/commit/ac58d00a974fdfff6b5c722743e4b32174963c52)] - feat: cwd maybe not baseDir (#15) (zhennann <>) - -2.1.1 / 2017-11-14 -================== - -**fixes** - * [[`7324d99`](http://github.com/eggjs/egg-scripts/commit/7324d99b504cac5fef7dbf280f7d9e6243c16bb7)] - fix: should stop app when baseDir is symlink (#12) (Haoliang Gao <>) - -2.1.0 / 2017-10-16 -================== - -**features** - * [[`ac40135`](http://github.com/eggjs/egg-scripts/commit/ac40135d5b9a3200ea1bdfdb19d0f7e12d0c511a)] - feat: add eggctl bin (#10) (Haoliang Gao <>) - -2.0.0 / 2017-10-13 -================== - -**features** - * [[`0f7ca50`](http://github.com/eggjs/egg-scripts/commit/0f7ca502999c06a9cb05d8e5617f6045704511df)] - feat: [BREAKING_CHANGE] check the status of app when start on daemon (#9) (Haoliang Gao <>) - -**others** - * [[`cfd0d2f`](http://github.com/eggjs/egg-scripts/commit/cfd0d2f67845fffb9d5974514b65e43b22ed8040)] - refactor: modify the directory of logDir (#8) (Haoliang Gao <>) - -1.2.0 / 2017-09-11 -================== - -**features** - * [[`c0300b8`](http://github.com/eggjs/egg-scripts/commit/c0300b8c657fe4f75ca388061f6cb3de9864a743)] - feat: log success at daemon mode (#7) (TZ | 天猪 <>) - -**others** - * [[`fdd273c`](http://github.com/eggjs/egg-scripts/commit/fdd273c2d6f15d104288fef4d699627a7cf701d9)] - test: add cluster-config fixture (#4) (TZ | 天猪 <>) - -1.1.2 / 2017-09-01 -================== - - * fix: should not pass undefined env (#6) - * docs: fix stop typo (#5) - -1.1.1 / 2017-08-29 -================== - - * fix: should set title correct (#3) - -1.1.0 / 2017-08-16 -================== - - * feat: remove env default value (#2) - -1.0.0 / 2017-08-02 -================== - - * feat: first implementation (#1) diff --git a/README.md b/README.md index 31d7c29..9e62754 100644 --- a/README.md +++ b/README.md @@ -99,15 +99,8 @@ Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is% [MIT](LICENSE) - - ## Contributors -|[
atian25](https://github.com/atian25)
|[
popomore](https://github.com/popomore)
|[
fengmk2](https://github.com/fengmk2)
|[
dead-horse](https://github.com/dead-horse)
|[
XadillaX](https://github.com/XadillaX)
|[
hyj1991](https://github.com/hyj1991)
| -| :---: | :---: | :---: | :---: | :---: | :---: | -|[
killagu](https://github.com/killagu)
|[
BaffinLee](https://github.com/BaffinLee)
|[
leoner](https://github.com/leoner)
|[
plusmancn](https://github.com/plusmancn)
|[
shuidian](https://github.com/shuidian)
|[
zhennann](https://github.com/zhennann)
| -[
liyanlong](https://github.com/liyanlong)
- -This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Tue Mar 08 2022 09:52:13 GMT+0800`. +[![Contributors](https://contrib.rocks/image?repo=eggjs/egg-scripts)](https://github.com/eggjs/egg-scripts/graphs/contributors) - +Made with [contributors-img](https://contrib.rocks). diff --git a/lib/cmd/start.js b/lib/cmd/start.js index 041600a..427ef42 100644 --- a/lib/cmd/start.js +++ b/lib/cmd/start.js @@ -1,17 +1,14 @@ -'use strict'; - const path = require('path'); - -const Command = require('../command'); -const debug = require('debug')('egg-script:start'); +const debug = require('util').debuglog('egg-script:start'); +const spawn = require('child_process').spawn; const { execFile } = require('mz/child_process'); const fs = require('mz/fs'); const homedir = require('node-homedir'); const mkdirp = require('mz-modules/mkdirp'); -const moment = require('moment'); const sleep = require('mz-modules/sleep'); -const spawn = require('child_process').spawn; const utils = require('egg-utils'); +const { getDateStringParts } = require('utility'); +const Command = require('../command'); class StartCommand extends Command { constructor(rawArgv) { @@ -292,7 +289,8 @@ async function getRotatelog(logfile) { if (await fs.exists(logfile)) { // format style: .20150602.193100 - const timestamp = moment().format('.YYYYMMDD.HHmmss'); + const [ YYYY, MM, DD, HH, mm, ss ] = getDateStringParts(); + const timestamp = `.${YYYY}${MM}${DD}.${HH}${mm}${ss}`; // Note: rename last log to next start time, not when last log file created await fs.rename(logfile, logfile + timestamp); } diff --git a/lib/helper.js b/lib/helper.js index fbbbc03..4fe853b 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -1,6 +1,4 @@ -'use strict'; - -const runScript = require('runscript'); +const { runScript } = require('runscript'); const isWin = process.platform === 'win32'; const REGEX = isWin ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/; diff --git a/package.json b/package.json index 7a2496f..8c90cca 100644 --- a/package.json +++ b/package.json @@ -10,39 +10,33 @@ "dependencies": { "await-event": "^2.1.0", "common-bin": "^3.0.1", - "debug": "^4.1.0", - "egg-utils": "^2.4.1", - "moment": "^2.23.0", + "egg-utils": "^2.5.0", "mz": "^2.7.0", "mz-modules": "^2.1.0", "node-homedir": "^1.1.1", - "runscript": "^1.3.0", + "runscript": "^2.0.1", "source-map-support": "^0.5.9", + "utility": "^2.2.0", "zlogger": "^1.1.0" }, "devDependencies": { "co": "^4.6.0", "coffee": "^5.1.1", "egg": "^3.9.0", - "egg-bin": "^5.6.1", + "egg-bin": "^6.12.0", "eslint": "^8.30.0", - "eslint-config-egg": "^12.1.0", - "git-contributor": "^1.0.10", + "eslint-config-egg": "13", "mm": "^3.2.1", "typescript": "^4.9.4", - "urllib": "^3.9.0" + "urllib": "^4.6.6" }, "engines": { - "node": ">=6.0.0" - }, - "ci": { - "version": "16, 18, 20" + "node": ">=16.0.0" }, "scripts": { - "contributor": "git-contributor", "test": "npm run lint -- --fix && npm run test-local", - "test-local": "egg-bin test", - "cov": "egg-bin cov", + "test-local": "egg-bin test --ts false", + "cov": "egg-bin test --ts false", "lint": "eslint .", "ci": "npm run lint && npm run cov" }, diff --git a/test/start.test.js b/test/start.test.js index 1989315..d071a23 100644 --- a/test/start.test.js +++ b/test/start.test.js @@ -52,7 +52,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/@@@ inject script/)); assert(app.stdout.match(/@@@ inject script1/)); assert(app.stdout.match(/@@@ inject script2/)); @@ -113,7 +113,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(!app.stdout.includes('DeprecationWarning:')); assert(app.stdout.includes('--title=egg-server-example')); assert(app.stdout.includes('"title":"egg-server-example"')); @@ -148,7 +148,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.includes('READY!!!')); assert(app.stdout.includes('--title=egg-server-example')); assert(app.stdout.includes('"title":"egg-server-example"')); @@ -201,7 +201,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); @@ -227,7 +227,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); @@ -253,7 +253,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, yadan'); @@ -279,7 +279,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.includes('--title=egg-test')); assert(app.stdout.includes('"title":"egg-test"')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); @@ -309,7 +309,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); const result = await httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString() === 'hi, egg'); @@ -335,7 +335,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); const result = await httpclient.request('http://127.0.0.1:7002'); assert(result.data.toString() === 'hi, egg'); @@ -361,7 +361,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001/env'); assert(result.data.toString() === 'pre, true'); @@ -388,7 +388,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.includes('## EGG_SERVER_ENV is not pass')); assert(app.stdout.includes('## CUSTOM_ENV: pre')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); @@ -479,7 +479,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, yadan'); @@ -503,7 +503,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, yadan'); @@ -541,7 +541,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:8000/)); assert(!app.stdout.includes('app_worker#3:')); const result = await httpclient.request('http://127.0.0.1:8000'); @@ -570,13 +570,13 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/maxHeaderSize: 20000/)); }); }); describe('read egg.revert', () => { - if (version < 18) return; + if (version < 18 || version > 20) return; if (isWin) return; let app; let fixturePath; @@ -598,7 +598,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/SECURITY WARNING: Reverting CVE-2023-46809: Marvin attack on PKCS#1 padding/)); }); }); @@ -624,10 +624,10 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); @@ -656,7 +656,7 @@ describe('test/start.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7002/)); assert(!app.stdout.includes('app_worker#3:')); const result = await httpclient.request('http://127.0.0.1:7002'); @@ -723,6 +723,7 @@ describe('test/start.test.js', () => { // should rotate log const fileList = await fs.readdir(logDir); + // console.log(fileList); assert(fileList.some(name => name.match(/master-stdout\.log\.\d+\.\d+/))); assert(fileList.some(name => name.match(/master-stderr\.log\.\d+\.\d+/))); diff --git a/test/stop.test.js b/test/stop.test.js index dc72121..4ae4f0c 100644 --- a/test/stop.test.js +++ b/test/stop.test.js @@ -40,7 +40,7 @@ describe('test/stop.test.js', () => { app.expect('code', 0); await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); @@ -142,7 +142,7 @@ describe('test/stop.test.js', () => { app.expect('code', 0); await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); @@ -218,12 +218,12 @@ describe('test/stop.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); - assert(app2.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app2.stderr), ''); assert(app2.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); const result2 = await httpclient.request('http://127.0.0.1:7002'); assert(result2.data.toString() === 'hi, egg'); @@ -280,7 +280,7 @@ describe('test/stop.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); diff --git a/test/ts.test.js b/test/ts.test.js index 9d2cfdd..40de990 100644 --- a/test/ts.test.js +++ b/test/ts.test.js @@ -45,7 +45,7 @@ describe('test/ts.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); @@ -59,7 +59,7 @@ describe('test/ts.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); @@ -73,7 +73,7 @@ describe('test/ts.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); @@ -102,7 +102,7 @@ describe('test/ts.test.js', () => { await sleep(waitTime); - assert(app.stderr === ''); + assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); // console.log(result.data); diff --git a/test/utils.js b/test/utils.js index 51bde7a..4aa9840 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,5 +1,3 @@ -'use strict'; - const helper = require('../lib/helper'); const sleep = require('mz-modules/sleep'); const isWin = process.platform === 'win32'; @@ -39,3 +37,11 @@ exports.cleanup = async function(baseDir) { await sleep('5s'); } }; + +exports.replaceWeakRefMessage = function(stderr) { + // Using compatibility WeakRef and FinalizationRegistry\r\n + if (stderr.includes('Using compatibility WeakRef and FinalizationRegistry')) { + stderr = stderr.replace(/Using compatibility WeakRef and FinalizationRegistry[\r\n]*/g, ''); + } + return stderr; +}; From 16d468e9c8039ad48a0e603734570259e4d238b3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 10 Dec 2024 12:17:00 +0000 Subject: [PATCH 70/72] Release 3.1.0 [skip ci] ## [3.1.0](https://github.com/eggjs/egg-scripts/compare/v3.0.1...v3.1.0) (2024-12-10) ### Features * use runscript v2 ([#61](https://github.com/eggjs/egg-scripts/issues/61)) ([ebbb7f6](https://github.com/eggjs/egg-scripts/commit/ebbb7f60446a2bf5ec8eaac40c85c6224dd91c9d)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a03d991..1f6a541 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [3.1.0](https://github.com/eggjs/egg-scripts/compare/v3.0.1...v3.1.0) (2024-12-10) + + +### Features + +* use runscript v2 ([#61](https://github.com/eggjs/egg-scripts/issues/61)) ([ebbb7f6](https://github.com/eggjs/egg-scripts/commit/ebbb7f60446a2bf5ec8eaac40c85c6224dd91c9d)) + ## [3.0.1](https://github.com/eggjs/egg-scripts/compare/v3.0.0...v3.0.1) (2024-05-11) diff --git a/package.json b/package.json index 8c90cca..ebc6107 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-scripts", - "version": "3.0.1", + "version": "3.1.0", "description": "deploy tool for egg project", "main": "index.js", "bin": { From d9d0bc65aefd1d73be2c40b86366af566cf471c1 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Tue, 31 Dec 2024 21:31:13 +0800 Subject: [PATCH 71/72] feat: support cjs and esm both by tshy (#63) BREAKING CHANGE: drop Node.js < 18.19.0 support part of https://github.com/eggjs/egg/issues/3644 https://github.com/eggjs/egg/issues/5257 ## Summary by CodeRabbit ## Release Notes - **New Features** - Added support for ECMAScript modules (ESM). - Enhanced CLI with more robust start and stop commands. - Improved TypeScript integration and type safety. - Introduced new commands for stopping an Egg.js server application. - Added new configuration options for logging and process management. - **Improvements** - Updated package configuration for better modularity. - Modernized test infrastructure with TypeScript support. - Refined error handling and logging mechanisms. - Enhanced process management capabilities. - Improved documentation with updated installation instructions and usage examples. - **Breaking Changes** - Renamed package from `egg-scripts` to `@eggjs/scripts`. - Requires Node.js version 18.19.0 or higher. - Significant changes to project structure and module exports. - **Bug Fixes** - Improved process management for server start and stop operations. - Enhanced cross-platform compatibility. - Fixed issues with asynchronous route handlers in various applications. --- .eslintrc | 5 +- .github/PULL_REQUEST_TEMPLATE.md | 24 - .github/workflows/nodejs.yml | 5 +- .github/workflows/pkg.pr.new.yml | 23 + .gitignore | 3 + README.md | 27 +- bin/dev.cmd | 3 + bin/dev.js | 5 + bin/egg-scripts.js | 7 - bin/run.cmd | 3 + bin/run.js | 5 + index.js | 19 - lib/cmd/start.js | 311 --------- lib/cmd/stop.js | 75 --- lib/command.js | 116 ---- lib/helper.js | 38 -- lib/start-cluster | 6 - package.json | 115 ++-- scripts/start-cluster.cjs | 15 + scripts/start-cluster.mjs | 14 + src/baseCommand.ts | 68 ++ src/commands/start.ts | 384 ++++++++++++ src/commands/stop.ts | 105 ++++ src/helper.ts | 62 ++ src/index.ts | 8 + src/types.ts | 9 + test/egg-scripts.test.js | 17 - test/egg-scripts.test.ts | 26 + test/fixtures/cluster-config/app/router.js | 4 +- .../cluster-config/config/config.default.js | 2 - .../cluster-config/config/config.prod.js | 2 - test/fixtures/custom-node-dir/app/router.js | 4 +- .../custom-node-dir/config/config.default.js | 2 - .../node_modules/custom-framework/index.js | 39 +- test/fixtures/egg-scripts-config/app.js | 8 +- .../node_modules/custom-framework/index.js | 39 +- test/fixtures/example/app.js | 2 - test/fixtures/example/app/router.js | 8 +- .../node_modules/custom-framework/index.js | 13 +- .../example/node_modules/yadan/index.js | 12 +- .../pkg-config-esm/config/config.default.js | 7 + test/fixtures/pkg-config-esm/config/plugin.js | 146 +++++ test/fixtures/pkg-config-esm/inject1.js | 1 + test/fixtures/pkg-config-esm/inject2.js | 1 + .../node_modules/custom-framework/index.js | 19 + .../custom-framework/package.json | 11 + .../node_modules/inject/index.js | 1 + .../node_modules/inject/package.json | 4 + test/fixtures/pkg-config-esm/package.json | 14 + .../node_modules/custom-framework/index.js | 12 +- .../node_modules/inject/index.js | 4 +- .../node_modules/custom-framework/index.js | 12 +- .../pkg-config/node_modules/inject/index.js | 4 +- test/fixtures/status/app.js | 8 +- test/fixtures/status/config/config.default.js | 2 - .../node_modules/custom-framework/index.js | 39 +- test/fixtures/stop-timeout/app/router.js | 8 +- .../subdir-as-basedir/base-dir/app/router.js | 8 +- test/fixtures/trace-warnings/app.js | 10 +- test/fixtures/ts-pkg/app/controller/home.ts | 2 +- test/fixtures/ts-pkg/package.json | 2 +- test/fixtures/ts/app/controller/home.ts | 2 +- test/fixtures/ts/package.json | 2 +- test/fixtures/ts/tsconfig.json | 3 +- test/{start.test.js => start.test.ts} | 592 ++++++++++-------- test/{stop.test.js => stop.test.ts} | 272 ++++---- test/ts.test.js | 113 ---- test/ts.test.ts | 121 ++++ test/{utils.js => utils.ts} | 27 +- tsconfig.json | 10 + 70 files changed, 1765 insertions(+), 1325 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/pkg.pr.new.yml create mode 100644 bin/dev.cmd create mode 100755 bin/dev.js delete mode 100755 bin/egg-scripts.js create mode 100644 bin/run.cmd create mode 100755 bin/run.js delete mode 100644 index.js delete mode 100644 lib/cmd/start.js delete mode 100644 lib/cmd/stop.js delete mode 100644 lib/command.js delete mode 100644 lib/helper.js delete mode 100644 lib/start-cluster create mode 100755 scripts/start-cluster.cjs create mode 100755 scripts/start-cluster.mjs create mode 100644 src/baseCommand.ts create mode 100644 src/commands/start.ts create mode 100644 src/commands/stop.ts create mode 100644 src/helper.ts create mode 100644 src/index.ts create mode 100644 src/types.ts delete mode 100644 test/egg-scripts.test.js create mode 100644 test/egg-scripts.test.ts create mode 100644 test/fixtures/pkg-config-esm/config/config.default.js create mode 100644 test/fixtures/pkg-config-esm/config/plugin.js create mode 100644 test/fixtures/pkg-config-esm/inject1.js create mode 100644 test/fixtures/pkg-config-esm/inject2.js create mode 100644 test/fixtures/pkg-config-esm/node_modules/custom-framework/index.js create mode 100644 test/fixtures/pkg-config-esm/node_modules/custom-framework/package.json create mode 100644 test/fixtures/pkg-config-esm/node_modules/inject/index.js create mode 100644 test/fixtures/pkg-config-esm/node_modules/inject/package.json create mode 100644 test/fixtures/pkg-config-esm/package.json rename test/{start.test.js => start.test.ts} (53%) rename test/{stop.test.js => stop.test.ts} (56%) delete mode 100644 test/ts.test.js create mode 100644 test/ts.test.ts rename test/{utils.js => utils.ts} (61%) create mode 100644 tsconfig.json diff --git a/.eslintrc b/.eslintrc index c799fe5..9bcdb46 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,6 @@ { - "extends": "eslint-config-egg" + "extends": [ + "eslint-config-egg/typescript", + "eslint-config-egg/lib/rules/enforce-node-prefix" + ] } diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 48f9944..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,24 +0,0 @@ - - -##### Checklist - - -- [ ] `npm test` passes -- [ ] tests and/or benchmarks are included -- [ ] documentation is changed or added -- [ ] commit message follows commit guidelines - -##### Affected core subsystem(s) - - - -##### Description of change - diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 0dba04e..65e67b0 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -11,4 +11,7 @@ jobs: name: Node.js uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: - version: '16, 18, 20, 22' + version: '18.19.0, 18, 20, 22' + os: 'ubuntu-latest, macos-latest' + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml new file mode 100644 index 0000000..bac3fac --- /dev/null +++ b/.github/workflows/pkg.pr.new.yml @@ -0,0 +1,23 @@ +name: Publish Any Commit +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run prepublishOnly --if-present + + - run: npx pkg-pr-new publish diff --git a/.gitignore b/.gitignore index 472d43c..8189f41 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ test/fixtures/ts-pkg/app/controller/home.js !test/fixtures/**/node_modules package-lock.json .package-lock.json +.tshy* +.eslintcache +dist diff --git a/README.md b/README.md index 9e62754..0badde0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,18 @@ -# egg-scripts +# @eggjs/scripts + +[![NPM version][npm-image]][npm-url] +[![Node.js CI](https://github.com/eggjs/scripts/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/scripts/actions/workflows/nodejs.yml) +[![Test coverage][codecov-image]][codecov-url] +[![npm download][download-image]][download-url] +[![Node.js Version](https://img.shields.io/node/v/@eggjs/scripts.svg?style=flat)](https://nodejs.org/en/download/) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) + +[npm-image]: https://img.shields.io/npm/v/@eggjs/scripts.svg?style=flat-square +[npm-url]: https://npmjs.org/package/@eggjs/scripts +[codecov-image]: https://codecov.io/github/eggjs/scripts/coverage.svg?branch=master +[codecov-url]: https://codecov.io/github/eggjs/scripts?branch=master +[download-image]: https://img.shields.io/npm/dm/@eggjs/scripts.svg?style=flat-square +[download-url]: https://npmjs.org/package/@eggjs/scripts deploy tool for egg project. @@ -7,7 +21,7 @@ deploy tool for egg project. ## Install ```bash -$ npm i egg-scripts --save +npm i @eggjs/scripts --save ``` ## Usage @@ -38,6 +52,7 @@ Start egg at prod mode. ```bash $ eggctl start [options] [baseDir] + # Usage # eggctl start --port=7001 # eggctl start ./server @@ -67,6 +82,7 @@ Stop egg gracefull. ```bash $ eggctl stop [options] + # Usage # eggctl stop --title=example ``` @@ -85,12 +101,13 @@ In addition to the command line specification, options can also be specified in "port": 1234, "ignore-stderr": true, // will pass as `node --max-http-header-size=20000` - "node-options--max-http-header-size": "20000" + "node-options--max-http-header-size": "20000", + // will pass as `node --allow-wasi` + "node-options--allow-wasi": true } } ``` - ## Questions & Suggestions Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). @@ -101,6 +118,6 @@ Please open an issue [here](https://github.com/eggjs/egg/issues?q=is%3Aissue+is% ## Contributors -[![Contributors](https://contrib.rocks/image?repo=eggjs/egg-scripts)](https://github.com/eggjs/egg-scripts/graphs/contributors) +[![Contributors](https://contrib.rocks/image?repo=eggjs/scripts)](https://github.com/eggjs/scripts/graphs/contributors) Made with [contributors-img](https://contrib.rocks). diff --git a/bin/dev.cmd b/bin/dev.cmd new file mode 100644 index 0000000..cec553b --- /dev/null +++ b/bin/dev.cmd @@ -0,0 +1,3 @@ +@echo off + +node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %* diff --git a/bin/dev.js b/bin/dev.js new file mode 100755 index 0000000..f0b6195 --- /dev/null +++ b/bin/dev.js @@ -0,0 +1,5 @@ +#!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning + +import { execute } from '@oclif/core'; + +await execute({ development: true, dir: import.meta.url }); diff --git a/bin/egg-scripts.js b/bin/egg-scripts.js deleted file mode 100755 index a77422c..0000000 --- a/bin/egg-scripts.js +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -const Command = require('..'); - -new Command().start(); diff --git a/bin/run.cmd b/bin/run.cmd new file mode 100644 index 0000000..968fc30 --- /dev/null +++ b/bin/run.cmd @@ -0,0 +1,3 @@ +@echo off + +node "%~dp0\run" %* diff --git a/bin/run.js b/bin/run.js new file mode 100755 index 0000000..176d2af --- /dev/null +++ b/bin/run.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import { execute } from '@oclif/core'; + +await execute({ dir: import.meta.url }); diff --git a/index.js b/index.js deleted file mode 100644 index 5fd74e0..0000000 --- a/index.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const path = require('path'); -const Command = require('./lib/command'); - -class EggScripts extends Command { - constructor(rawArgv) { - super(rawArgv); - this.usage = 'Usage: egg-scripts [command] [options]'; - - // load directory - this.load(path.join(__dirname, 'lib/cmd')); - } -} - -module.exports = exports = EggScripts; -exports.Command = Command; -exports.StartCommand = require('./lib/cmd/start'); -exports.StopCommand = require('./lib/cmd/stop'); diff --git a/lib/cmd/start.js b/lib/cmd/start.js deleted file mode 100644 index 427ef42..0000000 --- a/lib/cmd/start.js +++ /dev/null @@ -1,311 +0,0 @@ -const path = require('path'); -const debug = require('util').debuglog('egg-script:start'); -const spawn = require('child_process').spawn; -const { execFile } = require('mz/child_process'); -const fs = require('mz/fs'); -const homedir = require('node-homedir'); -const mkdirp = require('mz-modules/mkdirp'); -const sleep = require('mz-modules/sleep'); -const utils = require('egg-utils'); -const { getDateStringParts } = require('utility'); -const Command = require('../command'); - -class StartCommand extends Command { - constructor(rawArgv) { - super(rawArgv); - this.usage = 'Usage: egg-scripts start [options] [baseDir]'; - this.serverBin = path.join(__dirname, '../start-cluster'); - - this.options = { - title: { - description: 'process title description, use for kill grep, default to `egg-server-${APP_NAME}`', - type: 'string', - }, - workers: { - description: 'numbers of app workers, default to `os.cpus().length`', - type: 'number', - alias: [ 'c', 'cluster' ], - default: process.env.EGG_WORKERS, - }, - port: { - description: 'listening port, default to `process.env.PORT`', - type: 'number', - alias: 'p', - default: process.env.PORT, - }, - env: { - description: 'server env, default to `process.env.EGG_SERVER_ENV`', - default: process.env.EGG_SERVER_ENV, - }, - framework: { - description: 'specify framework that can be absolute path or npm package', - type: 'string', - }, - daemon: { - description: 'whether run at background daemon mode', - type: 'boolean', - }, - stdout: { - description: 'customize stdout file', - type: 'string', - }, - stderr: { - description: 'customize stderr file', - type: 'string', - }, - timeout: { - description: 'the maximum timeout when app starts', - type: 'number', - default: 300 * 1000, - }, - 'ignore-stderr': { - description: 'whether ignore stderr when app starts', - type: 'boolean', - }, - node: { - description: 'customize node command path', - type: 'string', - }, - }; - } - - get description() { - return 'Start server at prod mode'; - } - - async run(context) { - context.execArgvObj = context.execArgvObj || {}; - const { argv, env, cwd, execArgvObj } = context; - const HOME = homedir(); - const logDir = path.join(HOME, 'logs'); - - // egg-script start - // egg-script start ./server - // egg-script start /opt/app - let baseDir = argv._[0] || cwd; - if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); - argv.baseDir = baseDir; - - const isDaemon = argv.daemon; - - argv.framework = await this.getFrameworkPath({ - framework: argv.framework, - baseDir, - }); - - this.frameworkName = await this.getFrameworkName(argv.framework); - - const pkgInfo = require(path.join(baseDir, 'package.json')); - argv.title = argv.title || `egg-server-${pkgInfo.name}`; - - argv.stdout = argv.stdout || path.join(logDir, 'master-stdout.log'); - argv.stderr = argv.stderr || path.join(logDir, 'master-stderr.log'); - - // normalize env - env.HOME = HOME; - env.NODE_ENV = 'production'; - - // it makes env big but more robust - env.PATH = env.Path = [ - // for nodeinstall - path.join(baseDir, 'node_modules/.bin'), - // support `.node/bin`, due to npm5 will remove `node_modules/.bin` - path.join(baseDir, '.node/bin'), - // adjust env for win - env.PATH || env.Path, - ].filter(x => !!x).join(path.delimiter); - - // for alinode - env.ENABLE_NODE_LOG = 'YES'; - env.NODE_LOG_DIR = env.NODE_LOG_DIR || path.join(logDir, 'alinode'); - await mkdirp(env.NODE_LOG_DIR); - - // cli argv -> process.env.EGG_SERVER_ENV -> `undefined` then egg will use `prod` - if (argv.env) { - // if undefined, should not pass key due to `spwan`, https://github.com/nodejs/node/blob/master/lib/child_process.js#L470 - env.EGG_SERVER_ENV = argv.env; - } - - // additional execArgv - execArgvObj.deprecation = false; // --no-deprecation - execArgvObj.traceWarnings = true; // --trace-warnings - const eggInfo = pkgInfo.egg || {}; - if (eggInfo.revert) { - context.execArgvObj['security-revert'] = context.execArgvObj['security-revert'] || []; - const reverts = Array.isArray(eggInfo.revert) ? eggInfo.revert : [ eggInfo.revert ]; - for (const revert of reverts) { - context.execArgvObj['security-revert'].push(revert); - } - } - - const command = argv.node || 'node'; - - const options = { - execArgv: context.execArgv, // getter for execArgvObj, see https://github.com/node-modules/common-bin/blob/master/lib/command.js#L332 - env, - stdio: 'inherit', - detached: false, - }; - - this.logger.info('Starting %s application at %s', this.frameworkName, baseDir); - - // remove unused properties from stringify, alias had been remove by `removeAlias` - const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr', 'node' ]; - const clusterOptions = stringify(argv, ignoreKeys); - // Note: `spawn` is not like `fork`, had to pass `execArgv` youself - const eggArgs = [ ...(options.execArgv || []), this.serverBin, clusterOptions, `--title=${argv.title}` ]; - this.logger.info('Run node %s', eggArgs.join(' ')); - - // whether run in the background. - if (isDaemon) { - this.logger.info(`Save log file to ${logDir}`); - const [ stdout, stderr ] = await Promise.all([ - getRotatelog(argv.stdout), - getRotatelog(argv.stderr), - ]); - options.stdio = [ 'ignore', stdout, stderr, 'ipc' ]; - options.detached = true; - - debug('Run spawn `%s %s`', command, eggArgs.join(' ')); - const child = this.child = spawn(command, eggArgs, options); - this.isReady = false; - child.on('message', msg => { - /* istanbul ignore else */ - if (msg && msg.action === 'egg-ready') { - this.isReady = true; - this.logger.info('%s started on %s', this.frameworkName, msg.data.address); - child.unref(); - child.disconnect(); - this.exit(0); - } - }); - - // check start status - await this.checkStatus(argv); - } else { - options.stdio = [ 'inherit', 'inherit', 'inherit', 'ipc' ]; - debug('Run spawn `%s %s`', command, eggArgs.join(' ')); - const child = this.child = spawn(command, eggArgs, options); - child.once('exit', code => { - // command should exit after child process exit - this.exit(code); - }); - - // attach master signal to child - let signal; - [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ].forEach(event => { - process.once(event, () => { - debug('Kill child %s with %s', child.pid, signal); - child.kill(event); - }); - }); - } - } - - async getFrameworkPath(params) { - return utils.getFrameworkPath(params); - } - - async getFrameworkName(framework) { - const pkgPath = path.join(framework, 'package.json'); - let name = 'egg'; - try { - const pkg = require(pkgPath); - /* istanbul ignore else */ - if (pkg.name) name = pkg.name; - } catch (_) { - /* istanbul next */ - } - return name; - } - - async getRevert(framework) { - const pkgPath = path.join(framework, 'package.json'); - let name = 'egg'; - try { - const pkg = require(pkgPath); - /* istanbul ignore else */ - if (pkg.name) name = pkg.name; - } catch (_) { - /* istanbul next */ - } - return name; - } - - async checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) { - let count = 0; - let hasError = false; - let isSuccess = true; - timeout = timeout / 1000; - while (!this.isReady) { - try { - const stat = await fs.stat(stderr); - if (stat && stat.size > 0) { - hasError = true; - break; - } - } catch (_) { - // nothing - } - - if (count >= timeout) { - this.logger.error('Start failed, %ds timeout', timeout); - isSuccess = false; - break; - } - - await sleep(1000); - this.logger.log('Wait Start: %d...', ++count); - } - - if (hasError) { - try { - const args = [ '-n', '100', stderr ]; - this.logger.error('tail %s', args.join(' ')); - const [ headStdout ] = await execFile('head', args); - const [ tailStdout ] = await execFile('tail', args); - this.logger.error('Got error when startup: '); - this.logger.error(headStdout); - this.logger.error('...'); - this.logger.error(tailStdout); - } catch (err) { - this.logger.error('ignore tail error: %s', err); - } - isSuccess = ignoreStdErr; - this.logger.error('Start got error, see %s', stderr); - this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.'); - } - - if (!isSuccess) { - this.child.kill('SIGTERM'); - await sleep(1000); - this.exit(1); - } - } -} - -async function getRotatelog(logfile) { - await mkdirp(path.dirname(logfile)); - - if (await fs.exists(logfile)) { - // format style: .20150602.193100 - const [ YYYY, MM, DD, HH, mm, ss ] = getDateStringParts(); - const timestamp = `.${YYYY}${MM}${DD}.${HH}${mm}${ss}`; - // Note: rename last log to next start time, not when last log file created - await fs.rename(logfile, logfile + timestamp); - } - - return await fs.open(logfile, 'a'); -} - -function stringify(obj, ignore) { - const result = {}; - Object.keys(obj).forEach(key => { - if (!ignore.includes(key)) { - result[key] = obj[key]; - } - }); - return JSON.stringify(result); -} - -module.exports = StartCommand; diff --git a/lib/cmd/stop.js b/lib/cmd/stop.js deleted file mode 100644 index 40d4607..0000000 --- a/lib/cmd/stop.js +++ /dev/null @@ -1,75 +0,0 @@ -'use strict'; - -const path = require('path'); -const util = require('util'); -const sleep = require('mz-modules/sleep'); -const Command = require('../command'); -const isWin = process.platform === 'win32'; -const osRelated = { - titleTemplate: isWin ? '\\"title\\":\\"%s\\"' : '"title":"%s"', - appWorkerPath: isWin ? 'egg-cluster\\lib\\app_worker.js' : 'egg-cluster/lib/app_worker.js', - agentWorkerPath: isWin ? 'egg-cluster\\lib\\agent_worker.js' : 'egg-cluster/lib/agent_worker.js', -}; - -class StopCommand extends Command { - - constructor(rawArgv) { - super(rawArgv); - this.usage = 'Usage: egg-scripts stop [--title=example]'; - this.serverBin = path.join(__dirname, '../start-cluster'); - this.options = { - title: { - description: 'process title description, use for kill grep', - type: 'string', - }, - }; - } - - get description() { - return 'Stop server'; - } - - async run(context) { - const { argv } = context; - - this.logger.info(`stopping egg application ${argv.title ? `with --title=${argv.title}` : ''}`); - - // node /Users/tz/Workspaces/eggjs/egg-scripts/lib/start-cluster {"title":"egg-server","workers":4,"port":7001,"baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg"} - let processList = await this.helper.findNodeProcess(item => { - const cmd = item.cmd; - return argv.title ? - cmd.includes('start-cluster') && cmd.includes(util.format(osRelated.titleTemplate, argv.title)) : - cmd.includes('start-cluster'); - }); - let pids = processList.map(x => x.pid); - - if (pids.length) { - this.logger.info('got master pid %j', pids); - this.helper.kill(pids); - // wait for 5s to confirm whether any worker process did not kill by master - await sleep(argv.timeout || '5s'); - } else { - this.logger.warn('can\'t detect any running egg process'); - } - - - // node --debug-port=5856 /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/agent_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} - // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} - processList = await this.helper.findNodeProcess(item => { - const cmd = item.cmd; - return argv.title ? - (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)) && cmd.includes(util.format(osRelated.titleTemplate, argv.title)) : - (cmd.includes(osRelated.appWorkerPath) || cmd.includes(osRelated.agentWorkerPath)); - }); - pids = processList.map(x => x.pid); - - if (pids.length) { - this.logger.info('got worker/agent pids %j that is not killed by master', pids); - this.helper.kill(pids, 'SIGKILL'); - } - - this.logger.info('stopped'); - } -} - -module.exports = StopCommand; diff --git a/lib/command.js b/lib/command.js deleted file mode 100644 index 7944ae3..0000000 --- a/lib/command.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const BaseCommand = require('common-bin'); -const Logger = require('zlogger'); -const helper = require('./helper'); - -class Command extends BaseCommand { - constructor(rawArgv) { - super(rawArgv); - - Object.assign(this.helper, helper); - - this.parserOptions = { - removeAlias: true, - removeCamelCase: true, - execArgv: true, - }; - - // common-bin setter, don't care about override at sub class - // https://github.com/node-modules/common-bin/blob/master/lib/command.js#L158 - this.options = { - sourcemap: { - description: 'whether enable sourcemap support, will load `source-map-support` etc', - type: 'boolean', - alias: [ 'ts', 'typescript' ], - }, - - require: { - description: 'inject to execArgv --require', - type: 'array', - alias: 'r', - }, - }; - - this.logger = new Logger({ - prefix: '[egg-scripts] ', - time: false, - }); - } - - get context() { - const context = super.context; - const { argv, execArgvObj, cwd } = context; - - let baseDir = argv._[0] || cwd; - if (!path.isAbsolute(baseDir)) baseDir = path.join(cwd, baseDir); - const pkgFile = path.join(baseDir, 'package.json'); - if (fs.existsSync(pkgFile)) { - const pkgInfo = require(pkgFile); - const eggInfo = pkgInfo.egg; - - // read `eggScriptsConfig.require` from package.json - const eggScriptsConfig = pkgInfo.eggScriptsConfig; - let requireFiles = Array.isArray(argv.require) ? argv.require : []; - if (eggScriptsConfig && Array.isArray(eggScriptsConfig.require)) { - requireFiles = requireFiles.concat(eggScriptsConfig.require); - } - execArgvObj.require = execArgvObj.require || []; - requireFiles - .filter(injectScript => injectScript) - .forEach(injectScript => { - let requirePath = ''; - if (path.isAbsolute(injectScript) || injectScript.startsWith(`.${path.sep}`)) { - requirePath = path.resolve(baseDir, injectScript); - } else { - requirePath = injectScript; - } - execArgvObj.require.push(requirePath); - }); - - // read argv from eggScriptsConfig in package.json - if (eggScriptsConfig && typeof eggScriptsConfig === 'object') { - for (const key in pkgInfo.eggScriptsConfig) { - const v = pkgInfo.eggScriptsConfig[key]; - // like https://github.com/node-modules/common-bin/blob/master/lib/helper.js#L180 - if (key.startsWith('node-options--')) { - const newKey = key.replace('node-options--', ''); - if (execArgvObj[newKey] == null) { - execArgvObj[newKey] = v; - } - } else { - if (argv[key] == null) { - // only set if key is not pass from command line - argv[key] = v; - } - } - } - } - - // read `egg.typescript` from package.json - if (eggInfo && eggInfo.typescript && typeof argv.sourcemap === 'undefined') { - argv.sourcemap = true; - } - - delete argv.require; - } - - // execArgv - if (argv.sourcemap) { - execArgvObj.require = execArgvObj.require || []; - execArgvObj.require.push(require.resolve('source-map-support/register')); - } - - argv.sourcemap = argv.typescript = argv.ts = undefined; - - return context; - } - - exit(code) { - process.exit(code); - } -} - -module.exports = Command; diff --git a/lib/helper.js b/lib/helper.js deleted file mode 100644 index 4fe853b..0000000 --- a/lib/helper.js +++ /dev/null @@ -1,38 +0,0 @@ -const { runScript } = require('runscript'); -const isWin = process.platform === 'win32'; -const REGEX = isWin ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/; - -exports.findNodeProcess = async function(filterFn) { - const command = isWin ? - 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' : - // command, cmd are alias of args, not POSIX standard, so we use args - 'ps -wweo "pid,args"'; - const stdio = await runScript(command, { stdio: 'pipe' }); - const processList = stdio.stdout.toString().split('\n') - .reduce((arr, line) => { - if (!!line && !line.includes('/bin/sh') && line.includes('node')) { - const m = line.match(REGEX); - /* istanbul ignore else */ - if (m) { - const item = isWin ? { pid: m[2], cmd: m[1] } : { pid: m[1], cmd: m[2] }; - if (!filterFn || filterFn(item)) { - arr.push(item); - } - } - } - return arr; - }, []); - return processList; -}; - -exports.kill = function(pids, signal) { - pids.forEach(pid => { - try { - process.kill(pid, signal); - } catch (err) { /* istanbul ignore next */ - if (err.code !== 'ESRCH') { - throw err; - } - } - }); -}; diff --git a/lib/start-cluster b/lib/start-cluster deleted file mode 100644 index ebb1efe..0000000 --- a/lib/start-cluster +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -const options = JSON.parse(process.argv[2]); -require(options.framework).startCluster(options); diff --git a/package.json b/package.json index ebc6107..655fd81 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,103 @@ { - "name": "egg-scripts", + "name": "@eggjs/scripts", "version": "3.1.0", - "description": "deploy tool for egg project", - "main": "index.js", - "bin": { - "egg-scripts": "bin/egg-scripts.js", - "eggctl": "bin/egg-scripts.js" + "publishConfig": { + "access": "public" }, + "description": "deploy tool for egg project", "dependencies": { - "await-event": "^2.1.0", + "@eggjs/utils": "^4.2.1", + "@oclif/core": "^4.2.0", "common-bin": "^3.0.1", - "egg-utils": "^2.5.0", "mz": "^2.7.0", "mz-modules": "^2.1.0", - "node-homedir": "^1.1.1", + "node-homedir": "^2.0.0", "runscript": "^2.0.1", - "source-map-support": "^0.5.9", - "utility": "^2.2.0", - "zlogger": "^1.1.0" + "source-map-support": "^0.5.21", + "utility": "^2.4.0" }, "devDependencies": { - "co": "^4.6.0", - "coffee": "^5.1.1", - "egg": "^3.9.0", - "egg-bin": "^6.12.0", - "eslint": "^8.30.0", - "eslint-config-egg": "13", - "mm": "^3.2.1", - "typescript": "^4.9.4", - "urllib": "^4.6.6" + "@arethetypeswrong/cli": "^0.17.1", + "@eggjs/bin": "^7.0.1", + "@eggjs/tsconfig": "1", + "@types/mocha": "10", + "@types/node": "22", + "coffee": "^5.5.1", + "egg": "beta", + "eslint": "8", + "eslint-config-egg": "14", + "mm": "^4.0.1", + "rimraf": "6", + "ts-node": "^10.9.2", + "tshy": "3", + "tshy-after": "1", + "typescript": "5", + "urllib": "4" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.19.0" }, "scripts": { - "test": "npm run lint -- --fix && npm run test-local", - "test-local": "egg-bin test --ts false", - "cov": "egg-bin test --ts false", - "lint": "eslint .", - "ci": "npm run lint && npm run cov" + "lint": "eslint --cache src test --ext .ts", + "pretest": "npm run clean && npm run lint -- --fix && npm run prepublishOnly", + "test": "egg-bin test", + "posttest": "npm run clean", + "preci": "npm run clean && npm run lint && npm run prepublishOnly", + "ci": "egg-bin test", + "postci": "npm run clean", + "clean": "rimraf dist", + "prepublishOnly": "tshy && tshy-after && attw --pack" }, - "files": [ - "index.js", - "lib", - "bin" - ], "bug": { "url": "https://github.com/eggjs/egg/issues" }, - "homepage": "https://github.com/eggjs/egg-scripts", + "homepage": "https://github.com/eggjs/scripts", "repository": { "type": "git", - "url": "git@github.com:eggjs/egg-scripts.git" + "url": "git@github.com:eggjs/scripts.git" }, "author": "TZ ", - "license": "MIT" + "license": "MIT", + "oclif": { + "bin": "eggctl", + "commands": "./dist/esm/commands", + "dirname": "eggctl", + "topicSeparator": " ", + "additionalHelpFlags": [ + "-h" + ] + }, + "bin": { + "egg-scripts": "./bin/run.js", + "eggctl": "./bin/run.js" + }, + "type": "module", + "tshy": { + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + } + }, + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + }, + "./package.json": "./package.json" + }, + "files": [ + "bin", + "dist", + "src", + "scripts" + ], + "types": "./dist/commonjs/index.d.ts", + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js" } diff --git a/scripts/start-cluster.cjs b/scripts/start-cluster.cjs new file mode 100755 index 0000000..a399f75 --- /dev/null +++ b/scripts/start-cluster.cjs @@ -0,0 +1,15 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { debuglog } = require('node:util'); +const { importModule } = require('@eggjs/utils'); + +const debug = debuglog('@eggjs/scripts/scripts/start-cluster'); + +async function main() { + debug('argv: %o', process.argv); + const options = JSON.parse(process.argv[2]); + debug('start cluster options: %o', options); + const { startCluster } = await importModule(options.framework); + await startCluster(options); +} + +main(); diff --git a/scripts/start-cluster.mjs b/scripts/start-cluster.mjs new file mode 100755 index 0000000..5792705 --- /dev/null +++ b/scripts/start-cluster.mjs @@ -0,0 +1,14 @@ +import { debuglog } from 'node:util'; +import { importModule } from '@eggjs/utils'; + +const debug = debuglog('@eggjs/scripts/scripts/start-cluster'); + +async function main() { + debug('argv: %o', process.argv); + const options = JSON.parse(process.argv[2]); + debug('start cluster options: %o', options); + const { startCluster } = await importModule(options.framework); + await startCluster(options); +} + +main(); diff --git a/src/baseCommand.ts b/src/baseCommand.ts new file mode 100644 index 0000000..ec76132 --- /dev/null +++ b/src/baseCommand.ts @@ -0,0 +1,68 @@ +import { debuglog } from 'node:util'; +import { Command, Flags, Interfaces } from '@oclif/core'; +import { PackageEgg } from './types.js'; +import { readJSON } from 'utility'; +import path from 'node:path'; + +const debug = debuglog('@eggjs/scripts/baseCommand'); + +type Flags = Interfaces.InferredFlags; +type Args = Interfaces.InferredArgs; + +export abstract class BaseCommand extends Command { + // add the --json flag + static enableJsonFlag = false; + + // define flags that can be inherited by any command that extends BaseCommand + static baseFlags = { + // 'log-level': Flags.option({ + // default: 'info', + // helpGroup: 'GLOBAL', + // options: ['debug', 'warn', 'error', 'info', 'trace'] as const, + // summary: 'Specify level for logging.', + // })(), + }; + + protected flags!: Flags; + protected args!: Args; + + protected env = { ...process.env }; + protected pkg: Record; + protected isESM: boolean; + protected pkgEgg: PackageEgg; + protected globalExecArgv: string[] = []; + + public async init(): Promise { + await super.init(); + debug('[init] raw args: %o, NODE_ENV: %o', this.argv, this.env.NODE_ENV); + const { args, flags } = await this.parse({ + flags: this.ctor.flags, + baseFlags: (super.ctor as typeof BaseCommand).baseFlags, + enableJsonFlag: this.ctor.enableJsonFlag, + args: this.ctor.args, + strict: this.ctor.strict, + }); + this.flags = flags as Flags; + this.args = args as Args; + } + + protected async initBaseInfo(baseDir: string) { + const pkg = await readJSON(path.join(baseDir, 'package.json')); + this.pkg = pkg; + this.pkgEgg = pkg.egg ?? {}; + this.isESM = pkg.type === 'module'; + debug('[initBaseInfo] baseDir: %o, pkgEgg: %o, isESM: %o', baseDir, this.pkgEgg, this.isESM); + } + + protected async catch(err: Error & {exitCode?: number}): Promise { + // add any custom logic to handle errors from the command + // or simply return the parent class error handling + return super.catch(err); + } + + protected async finally(_: Error | undefined): Promise { + // called after run and catch regardless of whether or not the command errored + return super.finally(_); + } +} + diff --git a/src/commands/start.ts b/src/commands/start.ts new file mode 100644 index 0000000..2b62d1c --- /dev/null +++ b/src/commands/start.ts @@ -0,0 +1,384 @@ +import { debuglog, promisify } from 'node:util'; +import path from 'node:path'; +import { scheduler } from 'node:timers/promises'; +import { spawn, SpawnOptions, ChildProcess, execFile as _execFile } from 'node:child_process'; +import { mkdir, rename, stat, open } from 'node:fs/promises'; +import { homedir } from 'node-homedir'; +import { Args, Flags } from '@oclif/core'; +import { getFrameworkPath, importResolve } from '@eggjs/utils'; +import { readJSON, exists, getDateStringParts } from 'utility'; +import { BaseCommand } from '../baseCommand.js'; +import { getSourceDirname } from '../helper.js'; + +const debug = debuglog('@eggjs/scripts/commands/start'); + +const execFile = promisify(_execFile); + +export interface FrameworkOptions { + baseDir: string; + framework?: string; +} + +export default class Start extends BaseCommand { + static override description = 'Start server at prod mode'; + + static override examples = [ + '<%= config.bin %> <%= command.id %>', + ]; + + static override args = { + baseDir: Args.string({ + description: 'directory of application', + required: false, + }), + }; + + static override flags = { + title: Flags.string({ + description: 'process title description, use for kill grep, default to `egg-server-${APP_NAME}`', + }), + framework: Flags.string({ + description: 'specify framework that can be absolute path or npm package', + }), + port: Flags.integer({ + description: 'listening port, default to `process.env.PORT`', + char: 'p', + }), + workers: Flags.integer({ + char: 'c', + aliases: [ 'cluster' ], + description: 'numbers of app workers, default to `process.env.EGG_WORKERS` or `os.cpus().length`', + }), + env: Flags.string({ + description: 'server env, default to `process.env.EGG_SERVER_ENV`', + default: process.env.EGG_SERVER_ENV, + }), + daemon: Flags.boolean({ + description: 'whether run at background daemon mode', + }), + stdout: Flags.string({ + description: 'customize stdout file', + }), + stderr: Flags.string({ + description: 'customize stderr file', + }), + timeout: Flags.integer({ + description: 'the maximum timeout(ms) when app starts', + default: 300 * 1000, + }), + 'ignore-stderr': Flags.boolean({ + description: 'whether ignore stderr when app starts', + }), + node: Flags.string({ + description: 'customize node command path', + default: 'node', + }), + require: Flags.string({ + summary: 'require the given module', + char: 'r', + multiple: true, + }), + sourcemap: Flags.boolean({ + summary: 'whether enable sourcemap support, will load `source-map-support` etc', + aliases: [ 'ts', 'typescript' ], + }), + }; + + isReady = false; + #child: ChildProcess; + + protected async getFrameworkPath(options: FrameworkOptions) { + return getFrameworkPath(options); + } + + protected async getFrameworkName(frameworkPath: string) { + const pkgPath = path.join(frameworkPath, 'package.json'); + let name = 'egg'; + try { + const pkg = await readJSON(pkgPath); + if (pkg.name) { + name = pkg.name; + } + } catch { + // ignore + } + return name; + } + + protected async getServerBin() { + const serverBinName = this.isESM ? 'start-cluster.mjs' : 'start-cluster.cjs'; + // for src paths, `./src/commands/start.js` + let serverBin = path.join(getSourceDirname(), '../scripts', serverBinName); + if (!(await exists(serverBin))) { + // for dist paths, `./dist/esm/commands/start.js` + serverBin = path.join(getSourceDirname(), '../../scripts', serverBinName); + } + return serverBin; + } + + public async run(): Promise { + const { args, flags } = this; + // context.execArgvObj = context.execArgvObj || {}; + // const { argv, env, cwd, execArgvObj } = context; + const HOME = homedir(); + const logDir = path.join(HOME, 'logs'); + + // eggctl start + // eggctl start ./server + // eggctl start /opt/app + const cwd = process.cwd(); + let baseDir = args.baseDir || cwd; + if (!path.isAbsolute(baseDir)) { + baseDir = path.join(cwd, baseDir); + } + await this.initBaseInfo(baseDir); + + flags.framework = await this.getFrameworkPath({ + framework: flags.framework, + baseDir, + }); + + const frameworkName = await this.getFrameworkName(flags.framework); + + flags.title = flags.title || `egg-server-${this.pkg.name}`; + + flags.stdout = flags.stdout || path.join(logDir, 'master-stdout.log'); + flags.stderr = flags.stderr || path.join(logDir, 'master-stderr.log'); + + if (flags.workers === undefined && process.env.EGG_WORKERS) { + flags.workers = Number(process.env.EGG_WORKERS); + } + + // normalize env + this.env.HOME = HOME; + this.env.NODE_ENV = 'production'; + + // it makes env big but more robust + this.env.PATH = this.env.Path = [ + // for nodeinstall + path.join(baseDir, 'node_modules/.bin'), + // support `.node/bin`, due to npm5 will remove `node_modules/.bin` + path.join(baseDir, '.node/bin'), + // adjust env for win + this.env.PATH || this.env.Path, + ].filter(x => !!x).join(path.delimiter); + + // for alinode + this.env.ENABLE_NODE_LOG = 'YES'; + this.env.NODE_LOG_DIR = this.env.NODE_LOG_DIR || path.join(logDir, 'alinode'); + await mkdir(this.env.NODE_LOG_DIR, { recursive: true }); + + // cli argv -> process.env.EGG_SERVER_ENV -> `undefined` then egg will use `prod` + if (flags.env) { + // if undefined, should not pass key due to `spawn`, https://github.com/nodejs/node/blob/master/lib/child_process.js#L470 + this.env.EGG_SERVER_ENV = flags.env; + } + + // additional execArgv + const execArgv: string[] = [ + '--no-deprecation', + '--trace-warnings', + ]; + if (this.pkgEgg.revert) { + const reverts = Array.isArray(this.pkgEgg.revert) ? this.pkgEgg.revert : [ this.pkgEgg.revert ]; + for (const revert of reverts) { + execArgv.push(`--security-revert=${revert}`); + } + } + + // pkg.eggScriptsConfig.require + const scriptsConfig: Record = this.pkg.eggScriptsConfig; + if (scriptsConfig?.require) { + scriptsConfig.require = Array.isArray(scriptsConfig.require) ? scriptsConfig.require : [ scriptsConfig.require ]; + flags.require = [ ...scriptsConfig.require, ...(flags.require ?? []) ]; + } + + // read argv from eggScriptsConfig in package.json + if (scriptsConfig) { + for (const key in scriptsConfig) { + const v = scriptsConfig[key]; + if (key.startsWith('node-options--')) { + const newKey = key.replace('node-options--', ''); + if (v === true) { + // "node-options--allow-wasi": true + // => --allow-wasi + execArgv.push(`--${newKey}`); + } else { + // "node-options--max-http-header-size": "20000" + // => --max-http-header-size=20000 + execArgv.push(`--${newKey}=${v}`); + } + continue; + } + const existsValue = Reflect.get(flags, key); + if (existsValue === undefined) { + // only set if key is not pass from command line + Reflect.set(flags, key, v); + } + } + } + + // read `egg.typescript` from package.json + if (this.pkgEgg.typescript && flags.sourcemap === undefined) { + flags.sourcemap = true; + } + if (flags.sourcemap) { + const sourceMapSupport = importResolve('source-map-support/register.js', { + paths: [ getSourceDirname() ], + }); + if (this.isESM) { + execArgv.push('--import', sourceMapSupport); + } else { + execArgv.push('--require', sourceMapSupport); + } + } + + if (flags.port === undefined && process.env.PORT) { + flags.port = parseInt(process.env.PORT); + } + + debug('flags: %o, framework: %o, baseDir: %o, execArgv: %o', + flags, frameworkName, baseDir, execArgv); + + const command = flags.node; + const options: SpawnOptions = { + env: this.env, + stdio: 'inherit', + detached: false, + cwd: baseDir, + }; + + this.log('Starting %s application at %s', frameworkName, baseDir); + + // remove unused properties from stringify, alias had been remove by `removeAlias` + const ignoreKeys = [ 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr', 'node' ]; + const clusterOptions = stringify({ + ...flags, + baseDir, + }, ignoreKeys); + // Note: `spawn` is not like `fork`, had to pass `execArgv` yourself + const serverBin = await this.getServerBin(); + const eggArgs = [ ...execArgv, serverBin, clusterOptions, `--title=${flags.title}` ]; + const spawnScript = `${command} ${eggArgs.map(a => `'${a}'`).join(' ')}`; + this.log('Spawn %o', spawnScript); + + // whether run in the background. + if (flags.daemon) { + this.log(`Save log file to ${logDir}`); + const [ stdout, stderr ] = await Promise.all([ + getRotateLog(flags.stdout), + getRotateLog(flags.stderr), + ]); + options.stdio = [ 'ignore', stdout, stderr, 'ipc' ]; + options.detached = true; + const child = this.#child = spawn(command, eggArgs, options); + this.isReady = false; + child.on('message', (msg: any) => { + // https://github.com/eggjs/cluster/blob/master/src/master.ts#L119 + if (msg && msg.action === 'egg-ready') { + this.isReady = true; + this.log('%s started on %s', frameworkName, msg.data.address); + child.unref(); + child.disconnect(); + } + }); + + // check start status + await this.checkStatus(); + } else { + options.stdio = [ 'inherit', 'inherit', 'inherit', 'ipc' ]; + const child = this.#child = spawn(command, eggArgs, options); + child.once('exit', code => { + if (!code) return; + // command should exit after child process exit + this.exit(code); + }); + + // attach master signal to child + let signal; + const signals = [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ] as NodeJS.Signals[]; + signals.forEach(event => { + process.once(event, () => { + debug('Kill child %s with %s', child.pid, signal); + child.kill(event); + }); + }); + } + } + + protected async checkStatus() { + let count = 0; + let hasError = false; + let isSuccess = true; + const timeout = this.flags.timeout / 1000; + const stderrFile = this.flags.stderr!; + while (!this.isReady) { + try { + const stats = await stat(stderrFile); + if (stats && stats.size > 0) { + hasError = true; + break; + } + } catch (_) { + // nothing + } + + if (count >= timeout) { + this.logToStderr('Start failed, %ds timeout', timeout); + isSuccess = false; + break; + } + + await scheduler.wait(1000); + this.log('Wait Start: %d...', ++count); + } + + if (hasError) { + try { + const args = [ '-n', '100', stderrFile ]; + this.logToStderr('tail %s', args.join(' ')); + const { stdout: headStdout } = await execFile('head', args); + const { stdout: tailStdout } = await execFile('tail', args); + this.logToStderr('Got error when startup: '); + this.logToStderr(headStdout); + this.logToStderr('...'); + this.logToStderr(tailStdout); + } catch (err) { + this.logToStderr('ignore tail error: %s', err); + } + isSuccess = this.flags['ignore-stderr']; + this.logToStderr('Start got error, see %o', stderrFile); + this.logToStderr('Or use `--ignore-stderr` to ignore stderr at startup.'); + } + + if (!isSuccess) { + this.#child.kill('SIGTERM'); + await scheduler.wait(1000); + this.exit(1); + } + } +} + +function stringify(obj: Record, ignore: string[]) { + const result: Record = {}; + Object.keys(obj).forEach(key => { + if (!ignore.includes(key)) { + result[key] = obj[key]; + } + }); + return JSON.stringify(result); +} + +async function getRotateLog(logFile: string) { + await mkdir(path.dirname(logFile), { recursive: true }); + + if (await exists(logFile)) { + // format style: .20150602.193100 + const [ YYYY, MM, DD, HH, mm, ss ] = getDateStringParts(); + const timestamp = `.${YYYY}${MM}${DD}.${HH}${mm}${ss}`; + // Note: rename last log to next start time, not when last log file created + await rename(logFile, logFile + timestamp); + } + + return (await open(logFile, 'a')).fd; +} diff --git a/src/commands/stop.ts b/src/commands/stop.ts new file mode 100644 index 0000000..248ae1d --- /dev/null +++ b/src/commands/stop.ts @@ -0,0 +1,105 @@ +import { debuglog, format } from 'node:util'; +import { scheduler } from 'node:timers/promises'; +import { Args, Flags } from '@oclif/core'; +import { BaseCommand } from '../baseCommand.js'; +import { isWindows, findNodeProcess, NodeProcess, kill } from '../helper.js'; + +const debug = debuglog('@eggjs/scripts/commands/stop'); + +const osRelated = { + titleTemplate: isWindows ? '\\"title\\":\\"%s\\"' : '"title":"%s"', + // node_modules/@eggjs/cluster/dist/commonjs/app_worker.js + // node_modules/@eggjs/cluster/dist/esm/app_worker.js + appWorkerPath: /@eggjs[\/\\]cluster[\/\\]dist[\/\\](commonjs|esm)[\/\\]app_worker\.js/i, + // node_modules/@eggjs/cluster/dist/commonjs/agent_worker.js + // node_modules/@eggjs/cluster/dist/esm/agent_worker.js + agentWorkerPath: /@eggjs[\/\\]cluster[\/\\]dist[\/\\](commonjs|esm)[\/\\]agent_worker\.js/i, +}; + +export default class Stop extends BaseCommand { + static override description = 'Stop server'; + + static override examples = [ + '<%= config.bin %> <%= command.id %>', + ]; + + static override args = { + baseDir: Args.string({ + description: 'directory of application', + required: false, + }), + }; + + static override flags = { + title: Flags.string({ + description: 'process title description, use for kill grep', + }), + timeout: Flags.integer({ + description: 'the maximum timeout(ms) when app stop', + default: 5000, + }), + }; + + public async run(): Promise { + const { flags } = this; + + this.log(`stopping egg application${flags.title ? ` with --title=${flags.title}` : ''}`); + + // node ~/eggjs/scripts/scripts/start-cluster.cjs {"title":"egg-server","workers":4,"port":7001,"baseDir":"~/eggjs/test/showcase","framework":"~/eggjs/test/showcase/node_modules/egg"} + let processList = await this.findNodeProcesses(item => { + const cmd = item.cmd; + const matched = flags.title ? + cmd.includes('start-cluster') && cmd.includes(format(osRelated.titleTemplate, flags.title)) : + cmd.includes('start-cluster'); + if (matched) { + debug('find master process: %o', item); + } + return matched; + }); + let pids = processList.map(x => x.pid); + + if (pids.length) { + this.log('got master pid %j, list:', pids); + this.log(''); + for (const item of processList) { + this.log('- %s: %o', item.pid, item.cmd); + } + this.log(''); + this.killProcesses(pids); + // wait for 5s to confirm whether any worker process did not kill by master + await scheduler.wait(flags.timeout); + } else { + this.logToStderr('can\'t detect any running egg process'); + } + + // node --debug-port=5856 /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/agent_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} + // node /Users/tz/Workspaces/eggjs/test/showcase/node_modules/_egg-cluster@1.8.0@egg-cluster/lib/app_worker.js {"framework":"/Users/tz/Workspaces/eggjs/test/showcase/node_modules/egg","baseDir":"/Users/tz/Workspaces/eggjs/test/showcase","port":7001,"workers":2,"plugins":null,"https":false,"key":"","cert":"","title":"egg-server","clusterPort":52406} + // ~/bin/node --no-deprecation --trace-warnings ~/eggjs/examples/helloworld/node_modules/@eggjs/cluster/dist/commonjs/agent_worker.js {"baseDir":"~/eggjs/examples/helloworld","startMode":"process","framework":"~/eggjs/examples/helloworld/node_modules/egg","title":"egg-server-helloworld","workers":10,"clusterPort":58977} + processList = await this.findNodeProcesses(item => { + const cmd = item.cmd; + const matched = flags.title ? + (osRelated.appWorkerPath.test(cmd) || osRelated.agentWorkerPath.test(cmd)) && cmd.includes(format(osRelated.titleTemplate, flags.title)) : + (osRelated.appWorkerPath.test(cmd) || osRelated.agentWorkerPath.test(cmd)); + if (matched) { + debug('find app/agent worker process: %o', item); + } + return matched; + }); + pids = processList.map(x => x.pid); + + if (pids.length) { + this.log('got worker/agent pids %j that is not killed by master', pids); + this.killProcesses(pids); + } + + this.log('stopped'); + } + + protected async findNodeProcesses(filter: (item: NodeProcess) => boolean): Promise { + return findNodeProcess(filter); + } + + protected killProcesses(pids: number[], signal: NodeJS.Signals = 'SIGTERM') { + kill(pids, signal); + } +} diff --git a/src/helper.ts b/src/helper.ts new file mode 100644 index 0000000..7c57cdb --- /dev/null +++ b/src/helper.ts @@ -0,0 +1,62 @@ +import { runScript } from 'runscript'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export const isWindows = process.platform === 'win32'; + +const REGEX = isWindows ? /^(.*)\s+(\d+)\s*$/ : /^\s*(\d+)\s+(.*)/; + +export interface NodeProcess { + pid: number; + cmd: string; +} + +export type FilterFunction = (item: NodeProcess) => boolean; + +export async function findNodeProcess(filterFn?: FilterFunction): Promise { + const command = isWindows ? + 'wmic Path win32_process Where "Name = \'node.exe\'" Get CommandLine,ProcessId' : + // command, cmd are alias of args, not POSIX standard, so we use args + 'ps -wweo "pid,args"'; + const stdio = await runScript(command, { stdio: 'pipe' }); + const processList = stdio.stdout!.toString().split('\n') + .reduce((arr, line) => { + if (!!line && !line.includes('/bin/sh') && line.includes('node')) { + const m = line.match(REGEX); + if (m) { + const item: NodeProcess = isWindows ? { pid: parseInt(m[2]), cmd: m[1] } : { pid: parseInt(m[1]), cmd: m[2] }; + if (filterFn?.(item)) { + arr.push(item); + } + } + } + return arr; + }, []); + return processList; +} + +export function kill(pids: number[], signal?: string | number) { + pids.forEach(pid => { + try { + process.kill(pid, signal); + } catch (err: any) { + if (err.code !== 'ESRCH') { + throw err; + } + } + }); +} + +export function getSourceDirname() { + if (typeof __dirname === 'string') { + return __dirname; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const __filename = fileURLToPath(import.meta.url); + return path.dirname(__filename); +} + +export function getSourceFilename(filename: string) { + return path.join(getSourceDirname(), filename); +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..6d1c425 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,8 @@ +import Start from './commands/start.js'; + +// exports.StopCommand = require('./lib/cmd/stop'); + +export * from './baseCommand.js'; +export { + Start, Start as StartCommand, +}; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..b785f83 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,9 @@ +export interface PackageEgg { + framework?: boolean; + typescript?: boolean; + tscompiler?: string; + declarations?: boolean; + revert?: string | string[]; + require?: string | string[]; + import?: string | string[]; +} diff --git a/test/egg-scripts.test.js b/test/egg-scripts.test.js deleted file mode 100644 index 9fc38b5..0000000 --- a/test/egg-scripts.test.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -const coffee = require('coffee'); - -describe('test/egg-scripts.test.js', () => { - let app; - const eggBin = require.resolve('../bin/egg-scripts.js'); - - it('show help', done => { - app = coffee.fork(eggBin, [ '--help' ]); - app - // .debug() - .expect('stdout', /Usage: egg-scripts/) - .expect('code', 0) - .end(done); - }); -}); diff --git a/test/egg-scripts.test.ts b/test/egg-scripts.test.ts new file mode 100644 index 0000000..21e2323 --- /dev/null +++ b/test/egg-scripts.test.ts @@ -0,0 +1,26 @@ +import coffee from 'coffee'; +import { getSourceFilename } from '../src/helper.js'; + +describe('test/egg-scripts.test.ts', () => { + const eggBin = getSourceFilename('../bin/run.js'); + + it('show help', async () => { + await coffee.fork(eggBin, [ '--help' ]) + .debug() + .expect('stdout', /\$ eggctl \[COMMAND]/) + .expect('code', 0) + .end(); + + await coffee.fork(eggBin, [ 'start', '-h' ]) + .debug() + .expect('stdout', /\$ eggctl start \[BASEDIR] /) + .expect('code', 0) + .end(); + + await coffee.fork(eggBin, [ 'stop', '-h' ]) + .debug() + .expect('stdout', /\$ eggctl stop \[BASEDIR] /) + .expect('code', 0) + .end(); + }); +}); diff --git a/test/fixtures/cluster-config/app/router.js b/test/fixtures/cluster-config/app/router.js index 5a6c833..21c4989 100644 --- a/test/fixtures/cluster-config/app/router.js +++ b/test/fixtures/cluster-config/app/router.js @@ -1,7 +1,5 @@ -'use strict'; - module.exports = app => { - app.get('/', function* () { + app.get('/', async function() { this.body = `hi, ${app.config.framework || 'egg'}`; }); }; diff --git a/test/fixtures/cluster-config/config/config.default.js b/test/fixtures/cluster-config/config/config.default.js index 98de4f0..dad1a31 100644 --- a/test/fixtures/cluster-config/config/config.default.js +++ b/test/fixtures/cluster-config/config/config.default.js @@ -1,5 +1,3 @@ -'use strict'; - exports.keys = '123456'; exports.logger = { diff --git a/test/fixtures/cluster-config/config/config.prod.js b/test/fixtures/cluster-config/config/config.prod.js index e7523db..6c31593 100644 --- a/test/fixtures/cluster-config/config/config.prod.js +++ b/test/fixtures/cluster-config/config/config.prod.js @@ -1,5 +1,3 @@ -'use strict'; - exports.cluster = { listen: { port: 8000, diff --git a/test/fixtures/custom-node-dir/app/router.js b/test/fixtures/custom-node-dir/app/router.js index 20c9024..540d6f1 100644 --- a/test/fixtures/custom-node-dir/app/router.js +++ b/test/fixtures/custom-node-dir/app/router.js @@ -1,7 +1,5 @@ -'use strict'; - module.exports = app => { - app.get('/', function* () { + app.get('/', async function() { this.body = `hi, ${process.env.PATH}`; }); }; diff --git a/test/fixtures/custom-node-dir/config/config.default.js b/test/fixtures/custom-node-dir/config/config.default.js index c997e00..5f44376 100644 --- a/test/fixtures/custom-node-dir/config/config.default.js +++ b/test/fixtures/custom-node-dir/config/config.default.js @@ -1,3 +1 @@ -'use strict'; - exports.keys = '123456'; diff --git a/test/fixtures/egg-revert/node_modules/custom-framework/index.js b/test/fixtures/egg-revert/node_modules/custom-framework/index.js index 071acea..4dde6a1 100644 --- a/test/fixtures/egg-revert/node_modules/custom-framework/index.js +++ b/test/fixtures/egg-revert/node_modules/custom-framework/index.js @@ -1,21 +1,24 @@ -'use strict'; +const { Application: _Application, Agent, startCluster: originStartCluster } = require('egg'); -const egg = require('../../../../../node_modules/egg'); +const EGG_PATH = Symbol.for('egg#eggPath'); -const originStartCluster = egg.startCluster; +class Application extends _Application { + get [EGG_PATH]() { + return __dirname; + } +} -module.exports = Object.assign(egg, { - Application: class CustomApplication extends egg.Application { - get [Symbol.for('egg#eggPath')]() { - return __dirname; - } - }, - startCluster(...args) { - if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { - console.log('## EGG_SERVER_ENV is not pass'); - console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); - process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; - } - return originStartCluster(...args); - }, -}); +function startCluster(...args) { + if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { + console.log('## EGG_SERVER_ENV is not pass'); + console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); + process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; + } + return originStartCluster(...args); +} + +module.exports = { + Application, + Agent, + startCluster, +}; diff --git a/test/fixtures/egg-scripts-config/app.js b/test/fixtures/egg-scripts-config/app.js index 7ba4259..36e010e 100644 --- a/test/fixtures/egg-scripts-config/app.js +++ b/test/fixtures/egg-scripts-config/app.js @@ -1,13 +1,11 @@ -'use strict'; - -const sleep = require('mz-modules/sleep'); +const { scheduler } = require('node:timers/promises'); module.exports = app => { if (process.env.ERROR) { app.logger.error(new Error(process.env.ERROR)); } - app.beforeStart(function* () { - yield sleep(process.env.WAIT_TIME); + app.beforeStart(async () => { + await scheduler.wait(parseInt(process.env.WAIT_TIME)); }); }; diff --git a/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js b/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js index 071acea..4dde6a1 100644 --- a/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js +++ b/test/fixtures/egg-scripts-config/node_modules/custom-framework/index.js @@ -1,21 +1,24 @@ -'use strict'; +const { Application: _Application, Agent, startCluster: originStartCluster } = require('egg'); -const egg = require('../../../../../node_modules/egg'); +const EGG_PATH = Symbol.for('egg#eggPath'); -const originStartCluster = egg.startCluster; +class Application extends _Application { + get [EGG_PATH]() { + return __dirname; + } +} -module.exports = Object.assign(egg, { - Application: class CustomApplication extends egg.Application { - get [Symbol.for('egg#eggPath')]() { - return __dirname; - } - }, - startCluster(...args) { - if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { - console.log('## EGG_SERVER_ENV is not pass'); - console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); - process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; - } - return originStartCluster(...args); - }, -}); +function startCluster(...args) { + if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { + console.log('## EGG_SERVER_ENV is not pass'); + console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); + process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; + } + return originStartCluster(...args); +} + +module.exports = { + Application, + Agent, + startCluster, +}; diff --git a/test/fixtures/example/app.js b/test/fixtures/example/app.js index bbebd92..1da2776 100644 --- a/test/fixtures/example/app.js +++ b/test/fixtures/example/app.js @@ -1,5 +1,3 @@ -'use strict'; - module.exports = () => { // --no-deprecation new Buffer('aaa'); diff --git a/test/fixtures/example/app/router.js b/test/fixtures/example/app/router.js index cd29c09..2ca255f 100644 --- a/test/fixtures/example/app/router.js +++ b/test/fixtures/example/app/router.js @@ -1,15 +1,13 @@ -'use strict'; - module.exports = app => { - app.get('/', function* () { + app.get('/', async function() { this.body = `hi, ${app.config.framework || 'egg'}`; }); - app.get('/env', function* () { + app.get('/env', async function() { this.body = app.config.env + ', ' + app.config.pre; }); - app.get('/path', function* () { + app.get('/path', async function() { this.body = process.env.PATH; }); }; diff --git a/test/fixtures/example/node_modules/custom-framework/index.js b/test/fixtures/example/node_modules/custom-framework/index.js index 071acea..e153588 100644 --- a/test/fixtures/example/node_modules/custom-framework/index.js +++ b/test/fixtures/example/node_modules/custom-framework/index.js @@ -1,11 +1,8 @@ -'use strict'; +const { Application: _Application, Agent, startCluster: originStartCluster } = require('egg'); -const egg = require('../../../../../node_modules/egg'); - -const originStartCluster = egg.startCluster; - -module.exports = Object.assign(egg, { - Application: class CustomApplication extends egg.Application { +module.exports = { + Agent, + Application: class CustomApplication extends _Application { get [Symbol.for('egg#eggPath')]() { return __dirname; } @@ -18,4 +15,4 @@ module.exports = Object.assign(egg, { } return originStartCluster(...args); }, -}); +}; diff --git a/test/fixtures/example/node_modules/yadan/index.js b/test/fixtures/example/node_modules/yadan/index.js index 246811a..ddc49a7 100644 --- a/test/fixtures/example/node_modules/yadan/index.js +++ b/test/fixtures/example/node_modules/yadan/index.js @@ -1,11 +1,11 @@ -'use strict'; +const { Application: _Application, Agent, startCluster } = require('egg'); -const egg = require('../../../../../node_modules/egg'); - -module.exports = Object.assign(egg, { - Application: class CustomApplication extends egg.Application { +module.exports = { + Agent, + startCluster, + Application: class CustomApplication extends _Application { get [Symbol.for('egg#eggPath')]() { return __dirname; } }, -}); +}; diff --git a/test/fixtures/pkg-config-esm/config/config.default.js b/test/fixtures/pkg-config-esm/config/config.default.js new file mode 100644 index 0000000..45b1a89 --- /dev/null +++ b/test/fixtures/pkg-config-esm/config/config.default.js @@ -0,0 +1,7 @@ +export default { + keys: '123456', + logger: { + level: 'WARN', + consoleLevel: 'WARN', + }, +}; diff --git a/test/fixtures/pkg-config-esm/config/plugin.js b/test/fixtures/pkg-config-esm/config/plugin.js new file mode 100644 index 0000000..5f7239c --- /dev/null +++ b/test/fixtures/pkg-config-esm/config/plugin.js @@ -0,0 +1,146 @@ +export default { + // enable plugins + + /** + * app global Error Handling + * @member {Object} Plugin#onerror + * @property {Boolean} enable - `true` by default + */ + onerror: { + enable: false, + package: 'egg-onerror', + path: 'xxxxx', + }, + + /** + * session + * @member {Object} Plugin#session + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + session: { + enable: false, + package: 'egg-session', + path: 'xxxxx', + }, + + /** + * i18n + * @member {Object} Plugin#i18n + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + i18n: { + enable: false, + package: 'egg-i18n', + path: 'xxxxx', + }, + + /** + * file and dir watcher + * @member {Object} Plugin#watcher + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + watcher: { + enable: false, + package: 'egg-watcher', + path: 'xxxxx', + }, + + /** + * multipart + * @member {Object} Plugin#multipart + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + multipart: { + enable: false, + package: 'egg-multipart', + path: 'xxxxx', + }, + + /** + * security middlewares and extends + * @member {Object} Plugin#security + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + security: { + enable: false, + package: 'egg-security', + path: 'xxxxx', + }, + + /** + * local development helper + * @member {Object} Plugin#development + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + development: { + enable: false, + package: 'egg-development', + path: 'xxxxx', + }, + + /** + * logger file rotator + * @member {Object} Plugin#logrotator + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + logrotator: { + enable: false, + package: 'egg-logrotator', + path: 'xxxxx', + }, + + /** + * schedule tasks + * @member {Object} Plugin#schedule + * @property {Boolean} enable - `true` by default + * @since 2.7.0 + */ + schedule: { + enable: false, + package: 'egg-schedule', + path: 'xxxxx', + }, + + /** + * `app/public` dir static serve + * @member {Object} Plugin#static + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + static: { + enable: false, + package: 'egg-static', + path: 'xxxxx', + }, + + /** + * jsonp support for egg + * @member {Function} Plugin#jsonp + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + jsonp: { + enable: false, + package: 'egg-jsonp', + path: 'xxxxx', + }, + + /** + * view plugin + * @member {Function} Plugin#view + * @property {Boolean} enable - `true` by default + * @since 1.0.0 + */ + view: { + enable: false, + package: 'egg-view', + path: 'xxxxx', + }, +}; diff --git a/test/fixtures/pkg-config-esm/inject1.js b/test/fixtures/pkg-config-esm/inject1.js new file mode 100644 index 0000000..025593f --- /dev/null +++ b/test/fixtures/pkg-config-esm/inject1.js @@ -0,0 +1 @@ +console.log('@@@ inject script1'); diff --git a/test/fixtures/pkg-config-esm/inject2.js b/test/fixtures/pkg-config-esm/inject2.js new file mode 100644 index 0000000..ebb4122 --- /dev/null +++ b/test/fixtures/pkg-config-esm/inject2.js @@ -0,0 +1 @@ +console.log('@@@ inject script2'); diff --git a/test/fixtures/pkg-config-esm/node_modules/custom-framework/index.js b/test/fixtures/pkg-config-esm/node_modules/custom-framework/index.js new file mode 100644 index 0000000..28ee048 --- /dev/null +++ b/test/fixtures/pkg-config-esm/node_modules/custom-framework/index.js @@ -0,0 +1,19 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { Application as _Application, Agent, startCluster } from 'egg'; + +const EGG_PATH = Symbol.for('egg#eggPath'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +class Application extends _Application { + get [EGG_PATH]() { + return __dirname; + } +} + +export { + Application, + Agent, + startCluster, +}; diff --git a/test/fixtures/pkg-config-esm/node_modules/custom-framework/package.json b/test/fixtures/pkg-config-esm/node_modules/custom-framework/package.json new file mode 100644 index 0000000..04d2690 --- /dev/null +++ b/test/fixtures/pkg-config-esm/node_modules/custom-framework/package.json @@ -0,0 +1,11 @@ +{ + "name": "custom-framework-esm", + "version": "1.0.0", + "dependencies": { + "egg": "*" + }, + "type": "module", + "egg": { + "framework": true + } +} diff --git a/test/fixtures/pkg-config-esm/node_modules/inject/index.js b/test/fixtures/pkg-config-esm/node_modules/inject/index.js new file mode 100644 index 0000000..ae5a6c9 --- /dev/null +++ b/test/fixtures/pkg-config-esm/node_modules/inject/index.js @@ -0,0 +1 @@ +console.log('@@@ inject script!'); diff --git a/test/fixtures/pkg-config-esm/node_modules/inject/package.json b/test/fixtures/pkg-config-esm/node_modules/inject/package.json new file mode 100644 index 0000000..f751e13 --- /dev/null +++ b/test/fixtures/pkg-config-esm/node_modules/inject/package.json @@ -0,0 +1,4 @@ +{ + "name": "inject", + "type": "module" +} diff --git a/test/fixtures/pkg-config-esm/package.json b/test/fixtures/pkg-config-esm/package.json new file mode 100644 index 0000000..51b26db --- /dev/null +++ b/test/fixtures/pkg-config-esm/package.json @@ -0,0 +1,14 @@ +{ + "name": "example-esm", + "version": "1.0.0", + "egg": { + "framework": "custom-framework" + }, + "eggScriptsConfig": { + "require": [ + "./inject1.js", + "inject" + ] + }, + "type": "module" +} diff --git a/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js b/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js index 499901d..5da602c 100644 --- a/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js +++ b/test/fixtures/pkg-config-sourcemap/node_modules/custom-framework/index.js @@ -1,13 +1,15 @@ -'use strict'; - -const egg = require('../../../../../node_modules/egg'); +const { Application: _Application, Agent, startCluster } = require('egg'); const EGG_PATH = Symbol.for('egg#eggPath'); -class Application extends egg.Application { +class Application extends _Application { get [EGG_PATH]() { return __dirname; } } -module.exports = Object.assign(egg, { Application }); +module.exports = { + Application, + Agent, + startCluster, +}; diff --git a/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js b/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js index 638c7b9..ae5a6c9 100644 --- a/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js +++ b/test/fixtures/pkg-config-sourcemap/node_modules/inject/index.js @@ -1,3 +1 @@ -'use strict'; - -console.log('@@@ inject script'); +console.log('@@@ inject script!'); diff --git a/test/fixtures/pkg-config/node_modules/custom-framework/index.js b/test/fixtures/pkg-config/node_modules/custom-framework/index.js index 499901d..5da602c 100644 --- a/test/fixtures/pkg-config/node_modules/custom-framework/index.js +++ b/test/fixtures/pkg-config/node_modules/custom-framework/index.js @@ -1,13 +1,15 @@ -'use strict'; - -const egg = require('../../../../../node_modules/egg'); +const { Application: _Application, Agent, startCluster } = require('egg'); const EGG_PATH = Symbol.for('egg#eggPath'); -class Application extends egg.Application { +class Application extends _Application { get [EGG_PATH]() { return __dirname; } } -module.exports = Object.assign(egg, { Application }); +module.exports = { + Application, + Agent, + startCluster, +}; diff --git a/test/fixtures/pkg-config/node_modules/inject/index.js b/test/fixtures/pkg-config/node_modules/inject/index.js index 638c7b9..ae5a6c9 100644 --- a/test/fixtures/pkg-config/node_modules/inject/index.js +++ b/test/fixtures/pkg-config/node_modules/inject/index.js @@ -1,3 +1 @@ -'use strict'; - -console.log('@@@ inject script'); +console.log('@@@ inject script!'); diff --git a/test/fixtures/status/app.js b/test/fixtures/status/app.js index 7ba4259..36e010e 100644 --- a/test/fixtures/status/app.js +++ b/test/fixtures/status/app.js @@ -1,13 +1,11 @@ -'use strict'; - -const sleep = require('mz-modules/sleep'); +const { scheduler } = require('node:timers/promises'); module.exports = app => { if (process.env.ERROR) { app.logger.error(new Error(process.env.ERROR)); } - app.beforeStart(function* () { - yield sleep(process.env.WAIT_TIME); + app.beforeStart(async () => { + await scheduler.wait(parseInt(process.env.WAIT_TIME)); }); }; diff --git a/test/fixtures/status/config/config.default.js b/test/fixtures/status/config/config.default.js index 98de4f0..dad1a31 100644 --- a/test/fixtures/status/config/config.default.js +++ b/test/fixtures/status/config/config.default.js @@ -1,5 +1,3 @@ -'use strict'; - exports.keys = '123456'; exports.logger = { diff --git a/test/fixtures/status/node_modules/custom-framework/index.js b/test/fixtures/status/node_modules/custom-framework/index.js index 071acea..4dde6a1 100644 --- a/test/fixtures/status/node_modules/custom-framework/index.js +++ b/test/fixtures/status/node_modules/custom-framework/index.js @@ -1,21 +1,24 @@ -'use strict'; +const { Application: _Application, Agent, startCluster: originStartCluster } = require('egg'); -const egg = require('../../../../../node_modules/egg'); +const EGG_PATH = Symbol.for('egg#eggPath'); -const originStartCluster = egg.startCluster; +class Application extends _Application { + get [EGG_PATH]() { + return __dirname; + } +} -module.exports = Object.assign(egg, { - Application: class CustomApplication extends egg.Application { - get [Symbol.for('egg#eggPath')]() { - return __dirname; - } - }, - startCluster(...args) { - if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { - console.log('## EGG_SERVER_ENV is not pass'); - console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); - process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; - } - return originStartCluster(...args); - }, -}); +function startCluster(...args) { + if (process.env.CUSTOM_ENV && !process.env.EGG_SERVER_ENV) { + console.log('## EGG_SERVER_ENV is not pass'); + console.log('## CUSTOM_ENV:', process.env.CUSTOM_ENV); + process.env.EGG_SERVER_ENV = process.env.CUSTOM_ENV; + } + return originStartCluster(...args); +} + +module.exports = { + Application, + Agent, + startCluster, +}; diff --git a/test/fixtures/stop-timeout/app/router.js b/test/fixtures/stop-timeout/app/router.js index cd29c09..2ca255f 100644 --- a/test/fixtures/stop-timeout/app/router.js +++ b/test/fixtures/stop-timeout/app/router.js @@ -1,15 +1,13 @@ -'use strict'; - module.exports = app => { - app.get('/', function* () { + app.get('/', async function() { this.body = `hi, ${app.config.framework || 'egg'}`; }); - app.get('/env', function* () { + app.get('/env', async function() { this.body = app.config.env + ', ' + app.config.pre; }); - app.get('/path', function* () { + app.get('/path', async function() { this.body = process.env.PATH; }); }; diff --git a/test/fixtures/subdir-as-basedir/base-dir/app/router.js b/test/fixtures/subdir-as-basedir/base-dir/app/router.js index cd29c09..2ca255f 100644 --- a/test/fixtures/subdir-as-basedir/base-dir/app/router.js +++ b/test/fixtures/subdir-as-basedir/base-dir/app/router.js @@ -1,15 +1,13 @@ -'use strict'; - module.exports = app => { - app.get('/', function* () { + app.get('/', async function() { this.body = `hi, ${app.config.framework || 'egg'}`; }); - app.get('/env', function* () { + app.get('/env', async function() { this.body = app.config.env + ', ' + app.config.pre; }); - app.get('/path', function* () { + app.get('/path', async function() { this.body = process.env.PATH; }); }; diff --git a/test/fixtures/trace-warnings/app.js b/test/fixtures/trace-warnings/app.js index 9eee040..3925891 100644 --- a/test/fixtures/trace-warnings/app.js +++ b/test/fixtures/trace-warnings/app.js @@ -1,10 +1,10 @@ -'use strict'; - -const Event = require('events'); -const event = new Event(); -event.setMaxListeners(1); +const EventEmitter = require('events'); module.exports = () => { + console.log('app loaded'); + const event = new EventEmitter(); + event.setMaxListeners(1); + // --trace-warnings test about MaxListenersExceededWarning event.on('xx', () => {}); event.on('xx', () => {}); diff --git a/test/fixtures/ts-pkg/app/controller/home.ts b/test/fixtures/ts-pkg/app/controller/home.ts index bfb11be..5424538 100644 --- a/test/fixtures/ts-pkg/app/controller/home.ts +++ b/test/fixtures/ts-pkg/app/controller/home.ts @@ -12,4 +12,4 @@ export default class AppController extends Controller { }; } } -}; +} diff --git a/test/fixtures/ts-pkg/package.json b/test/fixtures/ts-pkg/package.json index c2c929d..cd48b79 100644 --- a/test/fixtures/ts-pkg/package.json +++ b/test/fixtures/ts-pkg/package.json @@ -8,7 +8,7 @@ "typescript": true }, "scripts": { - "build": "node ../../../node_modules/.bin/tsc", + "build": "./../../../node_modules/.bin/tsc", "windows-build": "call ../../../node_modules/.bin/tsc.cmd" } } diff --git a/test/fixtures/ts/app/controller/home.ts b/test/fixtures/ts/app/controller/home.ts index bfb11be..5424538 100644 --- a/test/fixtures/ts/app/controller/home.ts +++ b/test/fixtures/ts/app/controller/home.ts @@ -12,4 +12,4 @@ export default class AppController extends Controller { }; } } -}; +} diff --git a/test/fixtures/ts/package.json b/test/fixtures/ts/package.json index 183b153..26b2e6f 100644 --- a/test/fixtures/ts/package.json +++ b/test/fixtures/ts/package.json @@ -5,7 +5,7 @@ "egg": "^1.0.0" }, "scripts": { - "build": "node ../../../node_modules/.bin/tsc", + "build": "./../../../node_modules/.bin/tsc", "windows-build": "call ../../../node_modules/.bin/tsc.cmd" } } diff --git a/test/fixtures/ts/tsconfig.json b/test/fixtures/ts/tsconfig.json index f5bd4ba..2b11d3f 100644 --- a/test/fixtures/ts/tsconfig.json +++ b/test/fixtures/ts/tsconfig.json @@ -7,7 +7,6 @@ "noImplicitAny": false, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "charset": "utf8", "allowJs": false, "pretty": true, "noEmitOnError": false, @@ -26,4 +25,4 @@ "app/public", "app/views" ] -} \ No newline at end of file +} diff --git a/test/start.test.js b/test/start.test.ts similarity index 53% rename from test/start.test.js rename to test/start.test.ts index d071a23..395586e 100644 --- a/test/start.test.js +++ b/test/start.test.ts @@ -1,139 +1,184 @@ -'use strict'; - -const path = require('path'); -const assert = require('assert'); -const fs = require('mz/fs'); -const sleep = require('mz-modules/sleep'); -const rimraf = require('mz-modules/rimraf'); -const mkdirp = require('mz-modules/mkdirp'); -const coffee = require('coffee'); -const httpclient = require('urllib'); -const mm = require('mm'); -const utils = require('./utils'); -const awaitEvent = require('await-event'); -const isWin = process.platform === 'win32'; -const version = Number(process.version.substring(1, 3)); - -describe('test/start.test.js', () => { - const eggBin = require.resolve('../bin/egg-scripts.js'); +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { strict as assert } from 'node:assert'; +import fs from 'node:fs/promises'; +import { scheduler } from 'node:timers/promises'; +import { createServer } from 'node:http'; +import { once } from 'node:events'; +import coffee from 'coffee'; +import { request } from 'urllib'; +import { mm, restore } from 'mm'; +import { exists } from 'utility'; +import { cleanup, replaceWeakRefMessage, Coffee } from './utils.js'; +import { isWindows, getSourceFilename } from '../src/helper.js'; + +const version = parseInt(process.version.split('.')[0].substring(1)); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +describe('test/start.test.ts', () => { + const eggBin = getSourceFilename('../bin/run.js'); const fixturePath = path.join(__dirname, 'fixtures/example'); const homePath = path.join(__dirname, 'fixtures/home'); const logDir = path.join(homePath, 'logs'); - const waitTime = '10s'; + const waitTime = 10000; before(async () => { - await mkdirp(homePath); + await fs.mkdir(homePath, { recursive: true }); }); after(async () => { - await rimraf(homePath); + await fs.rm(homePath, { force: true, recursive: true }); }); beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); - afterEach(mm.restore); + afterEach(restore); describe('start without daemon', () => { - describe('read pkgInfo', () => { - let app; - let fixturePath; + describe('read pkgInfo on CommonJS', () => { + let app: Coffee; + let fixturePath: string; before(async () => { fixturePath = path.join(__dirname, 'fixtures/pkg-config'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); - it('should --require', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2.js' ], { cwd: fixturePath }); - app.debug(); + it('should --require work', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2.js' ], { + cwd: fixturePath, + }) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/@@@ inject script/)); - assert(app.stdout.match(/@@@ inject script1/)); - assert(app.stdout.match(/@@@ inject script2/)); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /@@@ inject script\!/); + assert.match(app.stdout, /@@@ inject script1/); + assert.match(app.stdout, /@@@ inject script2/); }); it('inject incorrect script', async () => { const script = './inject3.js'; - app = coffee.fork(eggBin, [ 'start', '--workers=1', `--require=${script}` ], { cwd: fixturePath }); - app.debug(); + app = coffee.fork(eggBin, [ 'start', '--workers=1', `--require=${script}` ], { + cwd: fixturePath, + }) as Coffee; + // app.debug(); + await scheduler.wait(waitTime); + assert.match(app.stderr, /Cannot find module/); + app.expect('code', 1); + }); + }); + + describe('read pkgInfo on ESM', () => { + let app: Coffee; + let fixturePath: string; + + before(async () => { + fixturePath = path.join(__dirname, 'fixtures/pkg-config-esm'); + await cleanup(fixturePath); + }); + + after(async () => { + app.proc.kill('SIGTERM'); + await cleanup(fixturePath); + }); + + it('should --require work', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--require=./inject2.js' ], { + cwd: fixturePath, + }) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert(app.stderr.includes(`Cannot find module '${path.join(fixturePath, script)}'`)); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /@@@ inject script\!/); + assert.match(app.stdout, /@@@ inject script1/); + assert.match(app.stdout, /@@@ inject script2/); + }); + + it('inject incorrect script', async () => { + const script = './inject3.js'; + app = coffee.fork(eggBin, [ 'start', '--workers=1', `--require=${script}` ], { cwd: fixturePath }) as Coffee; + // app.debug(); + await scheduler.wait(waitTime); + assert.match(app.stderr, /Cannot find module/); + app.expect('code', 1); }); }); describe('sourcemap default value should respect eggScriptConfig', () => { - let app; - let fixturePath; + let app: Coffee; + let fixturePath: string; before(async () => { fixturePath = path.join(__dirname, 'fixtures/pkg-config-sourcemap'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should not enable sourcemap-support', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1' ], { cwd: fixturePath }); - app.debug(); + app = coffee.fork(eggBin, [ 'start', '--workers=1' ], { cwd: fixturePath }) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); - assert(!/--require .*\/node_modules\/.*source-map-support/.test(app.stdout)); + await scheduler.wait(waitTime); + assert.doesNotMatch(app.stdout, /--require .*\/node_modules\/.*source-map-support/); }); }); describe('full path', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); afterEach(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]) as Coffee; app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(!app.stdout.includes('DeprecationWarning:')); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + // assert(!app.stdout.includes('DeprecationWarning:')); assert(app.stdout.includes('--title=egg-server-example')); assert(app.stdout.includes('"title":"egg-server-example"')); - assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - assert(app.stdout.includes('app_worker#2:')); - assert(!app.stdout.includes('app_worker#3:')); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + assert.match(app.stdout, /custom-framework started on http:\/\/127\.0\.0\.1:7001/); + assert.match(app.stdout, /app_worker#2:/); + assert.doesNotMatch(app.stdout, /app_worker#3:/); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, egg'); }); it('should start --trace-warnings work', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', path.join(__dirname, 'fixtures/trace-warnings') ]); - app.debug(); + app = coffee.fork(eggBin, [ + 'start', '--workers=1', path.join(__dirname, 'fixtures/trace-warnings'), + ]) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert(app.stderr.includes('MaxListenersExceededWarning:')); - assert(app.stderr.includes('app.js:10:9')); // should had trace - assert(!app.stdout.includes('DeprecationWarning:')); + // assert.match(app.stderr, /MaxListenersExceededWarning:/); + // assert.match(app.stderr, /app.js:10:9/); // should had trace + assert.doesNotMatch(app.stdout, /DeprecationWarning:/); }); it.skip('should get ready', async () => { @@ -142,13 +187,13 @@ describe('test/start.test.js', () => { BASE_DIR: fixturePath, PATH: process.env.PATH, }, - }); - app.debug(); + }) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.includes('READY!!!')); assert(app.stdout.includes('--title=egg-server-example')); assert(app.stdout.includes('"title":"egg-server-example"')); @@ -159,279 +204,283 @@ describe('test/start.test.js', () => { }); describe('child exit with 1', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should emit spawn error', async () => { - const srv = require('http').createServer(() => {}); - srv.listen(7007); + const server = createServer(() => {}); + server.listen(7007); - app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]) as Coffee; - await sleep(waitTime); - srv.close(); - assert(app.code === 1); + await scheduler.wait(waitTime); + server.close(); + assert.equal(app.code, 1); }); }); describe('relative path', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', path.relative(process.cwd(), fixturePath) ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', path.relative(process.cwd(), fixturePath) ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('without baseDir', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2' ], { cwd: fixturePath }); + app = coffee.fork(eggBin, [ 'start', '--workers=2' ], { cwd: fixturePath }) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('--framework', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, yadan'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, yadan'); }); }); describe('--title', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=egg-test', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=egg-test', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.includes('--title=egg-test')); assert(app.stdout.includes('"title":"egg-test"')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); assert(app.stdout.includes('app_worker#2:')); assert(!app.stdout.includes('app_worker#3:')); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('--port', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--port=7002', '--workers=2', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--port=7002', '--workers=2', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); - const result = await httpclient.request('http://127.0.0.1:7002'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:7002'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('process.env.PORT', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ], { env: Object.assign({}, process.env, { PORT: 7002 }) }); + app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ], { + env: Object.assign({}, process.env, { PORT: 7002 }), + }) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); - const result = await httpclient.request('http://127.0.0.1:7002'); - assert(result.data.toString() === 'hi, egg'); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /custom-framework started on http:\/\/127\.0\.0\.1:7002/); + const result = await request('http://127.0.0.1:7002'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('--env', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', '--env=pre', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--env=pre', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001/env'); - assert(result.data.toString() === 'pre, true'); + const result = await request('http://127.0.0.1:7001/env'); + assert.equal(result.data.toString(), 'pre, true'); }); }); describe('custom env', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { mm(process.env, 'CUSTOM_ENV', 'pre'); - app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.includes('## EGG_SERVER_ENV is not pass')); assert(app.stdout.includes('## CUSTOM_ENV: pre')); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - let result = await httpclient.request('http://127.0.0.1:7001/env'); - assert(result.data.toString() === 'pre, true'); - result = await httpclient.request('http://127.0.0.1:7001/path'); + let result = await request('http://127.0.0.1:7001/env'); + assert.equal(result.data.toString(), 'pre, true'); + result = await request('http://127.0.0.1:7001/path'); const appBinPath = path.join(fixturePath, 'node_modules/.bin'); assert(result.data.toString().startsWith(`${appBinPath}${path.delimiter}`)); }); }); describe('--stdout --stderr', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); - await rimraf(logDir); - await rimraf(path.join(fixturePath, 'start-fail')); - await mkdirp(logDir); + await cleanup(fixturePath); + await fs.rm(logDir, { force: true, recursive: true }); + await fs.rm(path.join(fixturePath, 'start-fail'), { force: true, recursive: true }); + await fs.mkdir(logDir, { recursive: true }); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); - await rimraf(path.join(fixturePath, 'stdout.log')); - await rimraf(path.join(fixturePath, 'stderr.log')); - await rimraf(path.join(fixturePath, 'start-fail')); + await cleanup(fixturePath); + await fs.rm(path.join(fixturePath, 'stdout.log'), { force: true }); + await fs.rm(path.join(fixturePath, 'stderr.log'), { force: true }); + await fs.rm(path.join(fixturePath, 'start-fail'), { force: true, recursive: true }); }); it('should start', async () => { const stdout = path.join(fixturePath, 'stdout.log'); const stderr = path.join(fixturePath, 'stderr.log'); - app = coffee.fork(eggBin, [ 'start', '--workers=1', '--daemon', `--stdout=${stdout}`, `--stderr=${stderr}`, fixturePath ]); + app = coffee.fork(eggBin, [ + 'start', '--workers=1', '--daemon', `--stdout=${stdout}`, `--stderr=${stderr}`, fixturePath, + ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); let content = await fs.readFile(stdout, 'utf-8'); - assert(content.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); + assert.match(content, /custom-framework started on http:\/\/127\.0\.0\.1:7001/); content = await fs.readFile(stderr, 'utf-8'); - assert(content === ''); + assert.equal(content, ''); }); it('should start with insecurity --stderr argument', async () => { @@ -445,204 +494,212 @@ describe('test/start.test.js', () => { 'start', '--workers=1', '--daemon', `--stdout=${stdout}`, `--stderr=${stderr}; touch ${malicious}`, cwd, - ]); + ]) as Coffee; // app.debug(); - await sleep(waitTime); + await scheduler.wait(waitTime); const content = await fs.readFile(stdout, 'utf-8'); assert(!content.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - let exists = await fs.exists(stderr); - assert(!exists); - exists = await fs.exists(malicious); - assert(!exists); + let stats = await exists(stderr); + assert(!stats); + stats = await exists(malicious); + assert(!stats); }); }); describe('--node', () => { - let app; + let app: Coffee; beforeEach(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); beforeEach(async () => { app && app.proc && app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); describe('daemon', () => { it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--daemon', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath ]); + app = coffee.fork(eggBin, [ + 'start', '--daemon', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath, + ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, yadan'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, yadan'); }); it('should error if node path invalid', async () => { - app = coffee.fork(eggBin, [ 'start', '--daemon', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath ]); + app = coffee.fork(eggBin, [ + 'start', '--daemon', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath, + ]) as Coffee; // app.debug(); app.expect('code', 1); - await sleep(3000); - assert(app.stderr.includes('spawn invalid ENOENT')); + await scheduler.wait(3000); + assert.match(app.stderr, /spawn invalid ENOENT/); }); }); describe('not daemon', () => { it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath ]); + app = coffee.fork(eggBin, [ + 'start', '--framework=yadan', '--workers=2', `--node=${process.execPath}`, fixturePath, + ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/yadan started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, yadan'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, yadan'); }); it('should error if node path invalid', async () => { - app = coffee.fork(eggBin, [ 'start', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath ]); + app = coffee.fork(eggBin, [ + 'start', '--framework=yadan', '--workers=2', '--node=invalid', fixturePath, + ]) as Coffee; // app.debug(); app.expect('code', 1); - await sleep(3000); - assert(app.stderr.includes('spawn invalid ENOENT')); + await scheduler.wait(3000); + assert.match(app.stderr, /spawn invalid ENOENT/); }); }); }); describe('read cluster config', () => { - let app; - let fixturePath; + let app: Coffee; + let fixturePath: string; before(async () => { fixturePath = path.join(__dirname, 'fixtures/cluster-config'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:8000/)); assert(!app.stdout.includes('app_worker#3:')); - const result = await httpclient.request('http://127.0.0.1:8000'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:8000'); + assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('read eggScriptsConfig', () => { - let app; - let fixturePath; + let app: Coffee; + let fixturePath: string; before(async () => { fixturePath = path.join(__dirname, 'fixtures/egg-scripts-node-options'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]) as Coffee; app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/maxHeaderSize: 20000/)); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /maxHeaderSize: 20000/); }); }); describe('read egg.revert', () => { - if (version < 18 || version > 20) return; - if (isWin) return; - let app; - let fixturePath; + if (version !== 20) return; + if (isWindows) return; + let app: Coffee; + let fixturePath: string; before(async () => { fixturePath = path.join(__dirname, 'fixtures/egg-revert'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); - app.debug(); + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/SECURITY WARNING: Reverting CVE-2023-46809: Marvin attack on PKCS#1 padding/)); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /SECURITY WARNING: Reverting CVE-2023-46809: Marvin attack on PKCS#1 padding/); }); }); describe('subDir as baseDir', () => { - let app; + let app: Coffee; const rootDir = path.join(__dirname, '..'); const subDir = path.join(__dirname, 'fixtures/subdir-as-basedir/base-dir'); before(async () => { - await utils.cleanup(rootDir); + await cleanup(rootDir); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(rootDir); + await cleanup(rootDir); }); it('should start', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=2', subDir ], { cwd: rootDir }); + app = coffee.fork(eggBin, [ 'start', '--workers=2', subDir ], { cwd: rootDir }) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); + const result = await request('http://127.0.0.1:7001'); assert.equal(result.data.toString(), 'hi, egg'); }); }); describe('auto set custom node dir to PATH', () => { - let app; - let fixturePath; + let app: Coffee; + let fixturePath: string; before(async () => { fixturePath = path.join(__dirname, 'fixtures/custom-node-dir'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should start', async () => { @@ -650,60 +707,63 @@ describe('test/start.test.js', () => { path.join(fixturePath, 'node_modules/.bin'), path.join(fixturePath, '.node/bin'), ].join(path.delimiter) + path.delimiter; - app = coffee.fork(eggBin, [ 'start', '--workers=2', '--port=7002', fixturePath ]); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--port=7002', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7002/)); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /egg started on http:\/\/127\.0\.0\.1:7002/); assert(!app.stdout.includes('app_worker#3:')); - const result = await httpclient.request('http://127.0.0.1:7002'); + const result = await request('http://127.0.0.1:7002'); assert(result.data.toString().startsWith(`hi, ${expectPATH}`)); }); }); describe('kill command', () => { - let app; + let app: Coffee; before(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); after(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should wait child process exit', async () => { - app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]); - await sleep(waitTime); - const exitEvent = awaitEvent(app.proc, 'exit'); + app = coffee.fork(eggBin, [ 'start', '--port=7007', '--workers=2', fixturePath ]) as Coffee; + await scheduler.wait(waitTime); + const exitEvent = once(app.proc, 'exit'); app.proc.kill('SIGTERM'); - const code = await exitEvent; - if (isWin) { + const [ code ] = await exitEvent; + if (isWindows) { assert(code === null); } else { - assert(code === 0); + assert.equal(code, 0); } }); }); }); describe('start with daemon', () => { - let cwd; + let cwd: string; beforeEach(async () => { - if (cwd) await utils.cleanup(cwd); - await rimraf(logDir); - await mkdirp(logDir); + if (cwd) { + await cleanup(cwd); + } + await fs.rm(logDir, { force: true, recursive: true }); + await fs.mkdir(logDir, { recursive: true }); await fs.writeFile(path.join(logDir, 'master-stdout.log'), 'just for test'); await fs.writeFile(path.join(logDir, 'master-stderr.log'), 'just for test'); }); + afterEach(async () => { await coffee.fork(eggBin, [ 'stop', cwd ]) // .debug() .end(); - await utils.cleanup(cwd); + await cleanup(cwd); }); it('should start custom-framework', async () => { @@ -719,7 +779,7 @@ describe('test/start.test.js', () => { const stdout = await fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); const stderr = await fs.readFile(path.join(logDir, 'master-stderr.log'), 'utf-8'); assert(stderr === ''); - assert(stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); + assert.match(stdout, /custom-framework started on http:\/\/127\.0\.0\.1:7002/); // should rotate log const fileList = await fs.readdir(logDir); @@ -727,8 +787,8 @@ describe('test/start.test.js', () => { assert(fileList.some(name => name.match(/master-stdout\.log\.\d+\.\d+/))); assert(fileList.some(name => name.match(/master-stderr\.log\.\d+\.\d+/))); - const result = await httpclient.request('http://127.0.0.1:7002'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:7002'); + assert.equal(result.data.toString(), 'hi, egg'); }); it('should start default egg', async () => { @@ -743,7 +803,7 @@ describe('test/start.test.js', () => { }); describe('check status', () => { - let cwd; + let cwd: string; beforeEach(() => { cwd = path.join(__dirname, 'fixtures/status'); }); @@ -752,64 +812,60 @@ describe('test/start.test.js', () => { await coffee.fork(eggBin, [ 'stop', cwd ]) // .debug() .end(); - await utils.cleanup(cwd); + await cleanup(cwd); }); it('should status check success, exit with 0', async () => { - mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'WAIT_TIME', 3000); await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }) - // .debug() - .expect('stdout', /Wait Start: 5.../) + // .debug() + .expect('stdout', /Wait Start: 2.../) .expect('stdout', /custom-framework started/) .expect('code', 0) .end(); }); it('should status check fail `--ignore-stderr`, exit with 0', async () => { - mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'WAIT_TIME', 3000); mm(process.env, 'ERROR', 'error message'); - - let stderr = path.join(homePath, 'logs/master-stderr.log'); - if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); - const app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--ignore-stderr' ], { cwd }); // app.debug(); // TODO: find a windows replacement for tail command - if (!isWin) app.expect('stderr', /nodejs.Error: error message/); - await app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + if (!isWindows) { + app.expect('stderr', /nodejs.Error: error message/); + } + await app.expect('stderr', /Start got error, see /) .expect('code', 0) .end(); }); it('should status check fail `--ignore-stderr` in package.json, exit with 0', async () => { cwd = path.join(__dirname, 'fixtures/egg-scripts-config'); - mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'WAIT_TIME', 3000); mm(process.env, 'ERROR', 'error message'); - let stderr = path.join(homePath, 'logs/master-stderr.log'); - if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); - const app = coffee.fork(eggBin, [ 'start' ], { cwd }); // app.debug(); // TODO: find a windows replacement for tail command - if (!isWin) app.expect('stderr', /nodejs.Error: error message/); - await app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + if (!isWindows) { + app.expect('stderr', /nodejs.Error: error message/); + } + await app.expect('stderr', /Start got error, see /) .expect('code', 0) .end(); }); it('should status check fail, exit with 1', async () => { - mm(process.env, 'WAIT_TIME', 5000); + mm(process.env, 'WAIT_TIME', 3000); mm(process.env, 'ERROR', 'error message'); - let stderr = path.join(homePath, 'logs/master-stderr.log'); - if (isWin) stderr = stderr.replace(/\\/g, '\\\\'); - const app = coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1' ], { cwd }); // app.debug(); // TODO: find a windows replacement for tail command - if (!isWin) app.expect('stderr', /nodejs.Error: error message/); - await app.expect('stderr', new RegExp(`Start got error, see ${stderr}`)) + if (!isWindows) { + app.expect('stderr', /nodejs.Error: error message/); + } + await app.expect('stderr', /Start got error, see /) .expect('stderr', /Got error when startup/) .expect('code', 1) .end(); @@ -819,7 +875,7 @@ describe('test/start.test.js', () => { mm(process.env, 'WAIT_TIME', 10000); await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=1', '--timeout=5000' ], { cwd }) - // .debug() + // .debug() .expect('stdout', /Wait Start: 1.../) .expect('stderr', /Start failed, 5s timeout/) .expect('code', 1) diff --git a/test/stop.test.js b/test/stop.test.ts similarity index 56% rename from test/stop.test.js rename to test/stop.test.ts index 4ae4f0c..4896b0a 100644 --- a/test/stop.test.js +++ b/test/stop.test.ts @@ -1,114 +1,110 @@ -'use strict'; - -const path = require('path'); -const assert = require('assert'); -const fs = require('mz/fs'); -const sleep = require('mz-modules/sleep'); -const rimraf = require('mz-modules/rimraf'); -const mkdirp = require('mz-modules/mkdirp'); -const coffee = require('coffee'); -const httpclient = require('urllib'); -const mm = require('mm'); -const utils = require('./utils'); -const isWin = process.platform === 'win32'; - -describe('test/stop.test.js', () => { - const eggBin = require.resolve('../bin/egg-scripts.js'); +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { strict as assert } from 'node:assert'; +import fs from 'node:fs/promises'; +import { scheduler } from 'node:timers/promises'; +import coffee from 'coffee'; +import { request } from 'urllib'; +import { mm, restore } from 'mm'; +import { cleanup, replaceWeakRefMessage, Coffee } from './utils.js'; +import { isWindows, getSourceFilename } from '../src/helper.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +describe('test/stop.test.ts', () => { + const eggBin = getSourceFilename('../bin/run.js'); const fixturePath = path.join(__dirname, 'fixtures/example'); const timeoutPath = path.join(__dirname, 'fixtures/stop-timeout'); const homePath = path.join(__dirname, 'fixtures/home'); const logDir = path.join(homePath, 'logs'); - const waitTime = '15s'; + const waitTime = 10000; before(async () => { - await mkdirp(homePath); + await fs.mkdir(homePath, { recursive: true }); }); after(async () => { - await rimraf(homePath); + await fs.rm(homePath, { force: true, recursive: true }); }); beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); - afterEach(() => mm.restore); + afterEach(restore); describe('stop without daemon', () => { - let app; - let killer; + let app: Coffee; + let killer: Coffee; beforeEach(async () => { - await utils.cleanup(fixturePath); - app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]); + await cleanup(fixturePath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, egg'); }); afterEach(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should stop', async () => { - killer = coffee.fork(eggBin, [ 'stop', fixturePath ]); - killer.debug(); + killer = coffee.fork(eggBin, [ 'stop', fixturePath ]) as Coffee; + // killer.debug(); killer.expect('code', 0); - - // await killer.end(); - await sleep(waitTime); + await killer.end(); // make sure is kill not auto exist - assert(!app.stdout.includes('exist by env')); + assert.doesNotMatch(app.stdout, /exist by env/); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { - assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); - assert(app.stdout.includes('[master] exit with code:0')); - assert(app.stdout.includes('[app_worker] exit with code:0')); + if (!isWindows) { + assert.match(app.stdout, /\[master] master is killed by signal SIGTERM, closing/); + assert.match(app.stdout, /\[master] exit with code:0/); + assert.match(app.stdout, /\[app_worker] exit with code:0/); // assert(app.stdout.includes('[agent_worker] exit with code:0')); } - assert(killer.stdout.includes('[egg-scripts] stopping egg application')); - assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); + assert.match(killer.stdout, /stopping egg application/); + assert.match(killer.stdout, /got master pid \[\d+\]/); }); }); describe('stop with daemon', () => { beforeEach(async () => { - await utils.cleanup(fixturePath); - await rimraf(logDir); + await cleanup(fixturePath); + await fs.rm(logDir, { force: true, recursive: true }); await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2', fixturePath ]) - .debug() + // .debug() .expect('code', 0) .end(); - const result = await httpclient.request('http://127.0.0.1:7001'); + const result = await request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); afterEach(async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should stop', async () => { await coffee.fork(eggBin, [ 'stop', fixturePath ]) .debug() - .expect('stdout', /\[egg-scripts] stopping egg application/) - .expect('stdout', /got master pid \["\d+\"\]/i) + .expect('stdout', /stopping egg application/) + .expect('stdout', /got master pid \[\d+\]/i) .expect('code', 0) .end(); - await sleep(waitTime); - // master log const stdout = await fs.readFile(path.join(logDir, 'master-stdout.log'), 'utf-8'); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { - assert(stdout.includes('[master] master is killed by signal SIGTERM, closing')); - assert(stdout.includes('[master] exit with code:0')); - assert(stdout.includes('[app_worker] exit with code:0')); + if (!isWindows) { + assert.match(stdout, /\[master] master is killed by signal SIGTERM, closing/); + assert.match(stdout, /\[master] exit with code:0/); + assert.match(stdout, /\[app_worker] exit with code:0/); } await coffee.fork(eggBin, [ 'stop', fixturePath ]) @@ -121,10 +117,10 @@ describe('test/stop.test.js', () => { describe('stop with not exist', () => { it('should work', async () => { - await utils.cleanup(fixturePath); + await cleanup(fixturePath); await coffee.fork(eggBin, [ 'stop', fixturePath ]) - .debug() - .expect('stdout', /\[egg-scripts] stopping egg application/) + // .debug() + .expect('stdout', /stopping egg application/) .expect('stderr', /can't detect any running egg process/) .expect('code', 0) .end(); @@ -132,41 +128,41 @@ describe('test/stop.test.js', () => { }); describe('stop --title', () => { - let app; - let killer; + let app: Coffee; + let killer: Coffee; beforeEach(async () => { - await utils.cleanup(fixturePath); - app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]); + await cleanup(fixturePath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]) as Coffee; // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /custom-framework started on http:\/\/127\.0\.0\.1:7001/); + const result = await request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); afterEach(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); - it('shoud stop only if the title matches exactly', async () => { + it('should stop only if the title matches exactly', async () => { // Because of'exmaple'.inclues('exmap') === true,if egg-scripts <= 2.1.0 and you run `.. stop --title=exmap`,the process with 'title:example' will also be killed unexpectedly await coffee.fork(eggBin, [ 'stop', '--title=examp', fixturePath ]) - .debug() - .expect('stdout', /\[egg-scripts] stopping egg application with --title=examp/) + // .debug() + .expect('stdout', /stopping egg application with --title=examp/) .expect('stderr', /can't detect any running egg process/) .expect('code', 0) .end(); // stop only if the title matches exactly await coffee.fork(eggBin, [ 'stop', '--title=example', fixturePath ]) - .debug() - .expect('stdout', /\[egg-scripts] stopping egg application with --title=example/) - .expect('stdout', /\[egg-scripts\] got master pid \[/) + // .debug() + .expect('stdout', /stopping egg application with --title=example/) + .expect('stdout', /got master pid \[/) .expect('code', 0) .end(); }); @@ -174,93 +170,89 @@ describe('test/stop.test.js', () => { it('should stop', async () => { await coffee.fork(eggBin, [ 'stop', '--title=random', fixturePath ]) .debug() - .expect('stdout', /\[egg-scripts] stopping egg application with --title=random/) + .expect('stdout', /stopping egg application with --title=random/) .expect('stderr', /can't detect any running egg process/) .expect('code', 0) .end(); - killer = coffee.fork(eggBin, [ 'stop', '--title=example' ], { cwd: fixturePath }); + killer = coffee.fork(eggBin, [ 'stop', '--title=example' ], { cwd: fixturePath }) as Coffee; killer.debug(); - killer.expect('code', 0); - - // await killer.end(); - await sleep(waitTime); + // killer.expect('code', 0); + await killer.end(); // make sure is kill not auto exist - assert(!app.stdout.includes('exist by env')); + assert.doesNotMatch(app.stdout, /exist by env/); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { + if (!isWindows) { assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[app_worker] exit with code:0')); // assert(app.stdout.includes('[agent_worker] exit with code:0')); } - assert(killer.stdout.includes('[egg-scripts] stopping egg application with --title=example')); - assert(killer.stdout.match(/got master pid \["\d+\"\]/i)); + assert(killer.stdout.includes('stopping egg application with --title=example')); + assert(killer.stdout.match(/got master pid \[\d+\]/i)); }); }); describe('stop all', () => { - let app; - let app2; - let killer; + let app: Coffee; + let app2: Coffee; + let killer: Coffee; beforeEach(async () => { - await utils.cleanup(fixturePath); - app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]); - // app.debug(); + await cleanup(fixturePath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=example', fixturePath ]) as Coffee; + app.debug(); app.expect('code', 0); - app2 = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=test', '--port=7002', fixturePath ]); + app2 = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=test', '--port=7002', fixturePath ]) as Coffee; app2.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(10000); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); - assert(result.data.toString() === 'hi, egg'); + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /custom-framework started on http:\/\/127\.0\.0\.1:7001/); + const result = await request('http://127.0.0.1:7001'); + assert.equal(result.data.toString(), 'hi, egg'); - assert.equal(utils.replaceWeakRefMessage(app2.stderr), ''); - assert(app2.stdout.match(/custom-framework started on http:\/\/127\.0\.0\.1:7002/)); - const result2 = await httpclient.request('http://127.0.0.1:7002'); - assert(result2.data.toString() === 'hi, egg'); + assert.equal(replaceWeakRefMessage(app2.stderr), ''); + assert.match(app2.stdout, /custom-framework started on http:\/\/127\.0\.0\.1:7002/); + const result2 = await request('http://127.0.0.1:7002'); + assert.equal(result2.data.toString(), 'hi, egg'); }); afterEach(async () => { app.proc.kill('SIGTERM'); app2.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); + await cleanup(fixturePath); }); it('should stop', async () => { - killer = coffee.fork(eggBin, [ 'stop' ], { cwd: fixturePath }); + killer = coffee.fork(eggBin, [ 'stop' ], { cwd: fixturePath }) as Coffee; killer.debug(); - killer.expect('code', 0); - - // await killer.end(); - await sleep(waitTime); + // killer.expect('code', 0); + await killer.end(); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { + if (!isWindows) { assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[app_worker] exit with code:0')); // assert(app.stdout.includes('[agent_worker] exit with code:0')); } - assert(killer.stdout.includes('[egg-scripts] stopping egg application')); - assert(killer.stdout.match(/got master pid \["\d+\","\d+\"\]/i)); + assert(killer.stdout.includes('stopping egg application')); + assert(killer.stdout.match(/got master pid \[\d+,\d+\]/i)); assert(!app2.stdout.includes('exist by env')); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { + if (!isWindows) { assert(app2.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app2.stdout.includes('[master] exit with code:0')); assert(app2.stdout.includes('[app_worker] exit with code:0')); @@ -269,77 +261,76 @@ describe('test/stop.test.js', () => { }); describe('stop all with timeout', function() { - let app; - let killer; + let app: Coffee; + let killer: Coffee; this.timeout(17000); beforeEach(async () => { - await utils.cleanup(timeoutPath); - app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=stop-timeout', timeoutPath ]); - app.debug(); + await cleanup(timeoutPath); + app = coffee.fork(eggBin, [ 'start', '--workers=2', '--title=stop-timeout', timeoutPath ]) as Coffee; + // app.debug(); app.expect('code', 0); - await sleep(waitTime); + await scheduler.wait(waitTime); - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); + // assert.equal(replaceWeakRefMessage(app.stderr), ''); assert(app.stdout.match(/http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001'); + const result = await request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); afterEach(async () => { app.proc.kill('SIGTERM'); - await utils.cleanup(timeoutPath); + await cleanup(timeoutPath); }); it('should stop error without timeout', async () => { - killer = coffee.fork(eggBin, [ 'stop' ], { cwd: timeoutPath }); + killer = coffee.fork(eggBin, [ 'stop' ], { cwd: timeoutPath }) as Coffee; killer.debug(); killer.expect('code', 0); - - // await killer.end(); - await sleep(waitTime); + await killer.end(); + await scheduler.wait(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { + if (!isWindows) { assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.match(/app_worker#\d+:\d+ disconnect/)); assert(app.stdout.match(/don't fork, because worker:\d+ will be kill soon/)); } - assert(killer.stdout.includes('[egg-scripts] stopping egg application')); - assert(killer.stdout.match(/got master pid \["\d+\"]/i)); + assert(killer.stdout.includes('stopping egg application')); + assert(killer.stdout.match(/got master pid \[\d+\]/i)); }); it('should stop success', async () => { - killer = coffee.fork(eggBin, [ 'stop', '--timeout=10s' ], { cwd: timeoutPath }); + killer = coffee.fork(eggBin, [ 'stop', '--timeout=10000' ], { cwd: timeoutPath }) as Coffee; killer.debug(); killer.expect('code', 0); // await killer.end(); - await sleep(waitTime); + await scheduler.wait(waitTime); // make sure is kill not auto exist assert(!app.stdout.includes('exist by env')); // no way to handle the SIGTERM signal in windows ? - if (!isWin) { + if (!isWindows) { assert(app.stdout.includes('[master] master is killed by signal SIGTERM, closing')); assert(app.stdout.includes('[master] exit with code:0')); assert(app.stdout.includes('[agent_worker] exit with code:0')); } - assert(killer.stdout.includes('[egg-scripts] stopping egg application')); - assert(killer.stdout.match(/got master pid \["\d+\"]/i)); + assert(killer.stdout.includes('stopping egg application')); + assert(killer.stdout.match(/got master pid \[\d+\]/i)); }); }); describe('stop with symlink', () => { const baseDir = path.join(__dirname, 'fixtures/tmp'); - beforeEach(async () => { + beforeEach(async function() { // if we can't create a symlink, skip the test try { await fs.symlink(fixturePath, baseDir, 'dir'); @@ -350,36 +341,35 @@ describe('test/stop.test.js', () => { } // *unix get the real path of symlink, but windows wouldn't - const appPathInRegexp = isWin ? baseDir.replace(/\\/g, '\\\\') : fixturePath; + const appPathInRegexp = isWindows ? baseDir.replace(/\\/g, '\\\\') : fixturePath; - await utils.cleanup(fixturePath); - await rimraf(logDir); + await cleanup(fixturePath); + await fs.rm(logDir, { force: true, recursive: true }); await coffee.fork(eggBin, [ 'start', '--daemon', '--workers=2' ], { cwd: baseDir }) .debug() .expect('stdout', new RegExp(`Starting custom-framework application at ${appPathInRegexp}`)) .expect('code', 0) .end(); - await rimraf(baseDir); - const result = await httpclient.request('http://127.0.0.1:7001'); + await fs.rm(baseDir, { force: true, recursive: true }); + const result = await request('http://127.0.0.1:7001'); assert(result.data.toString() === 'hi, egg'); }); afterEach(async () => { - await utils.cleanup(fixturePath); - await rimraf(baseDir); + await cleanup(fixturePath); + await fs.rm(baseDir, { force: true, recursive: true }); }); it('should stop', async () => { - await rimraf(baseDir); + await fs.rm(baseDir, { force: true, recursive: true }); await fs.symlink(path.join(__dirname, 'fixtures/status'), baseDir); await coffee.fork(eggBin, [ 'stop', baseDir ]) .debug() - .expect('stdout', /\[egg-scripts] stopping egg application/) - .expect('stdout', /got master pid \["\d+\"\]/i) + .expect('stdout', /stopping egg application/) + .expect('stdout', /got master pid \[\d+\]/i) .expect('code', 0) .end(); }); }); - }); diff --git a/test/ts.test.js b/test/ts.test.js deleted file mode 100644 index 40de990..0000000 --- a/test/ts.test.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -const path = require('path'); -const assert = require('assert'); -const cp = require('child_process'); -const sleep = require('mz-modules/sleep'); -const rimraf = require('mz-modules/rimraf'); -const mkdirp = require('mz-modules/mkdirp'); -const coffee = require('coffee'); -const httpclient = require('urllib'); -const mm = require('mm'); -const utils = require('./utils'); -const isWin = process.platform === 'win32'; - -describe('test/ts.test.js', () => { - const eggBin = require.resolve('../bin/egg-scripts.js'); - const homePath = path.join(__dirname, 'fixtures/home'); - const waitTime = '10s'; - let fixturePath; - - beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); - afterEach(mm.restore); - - before(() => mkdirp(homePath)); - after(() => rimraf(homePath)); - - describe('should display correct stack traces', () => { - let app; - beforeEach(async () => { - fixturePath = path.join(__dirname, 'fixtures/ts'); - await utils.cleanup(fixturePath); - const result = cp.spawnSync('npm', [ 'run', isWin ? 'windows-build' : 'build' ], { cwd: fixturePath, shell: isWin }); - assert(!result.stderr.toString()); - }); - - afterEach(async () => { - app && app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); - }); - - it('--ts', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', '--ts', fixturePath ]); - app.debug(); - app.expect('code', 0); - - await sleep(waitTime); - - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); - // console.log(result.data); - assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); - }); - - it('--typescript', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', '--typescript', fixturePath ]); - // app.debug(); - app.expect('code', 0); - - await sleep(waitTime); - - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); - // console.log(result.data); - assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); - }); - - it('--sourcemap', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', '--sourcemap', fixturePath ]); - // app.debug(); - app.expect('code', 0); - - await sleep(waitTime); - - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); - // console.log(result.data); - assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); - }); - }); - - describe('pkg.egg.typescript', () => { - let app; - beforeEach(async () => { - fixturePath = path.join(__dirname, 'fixtures/ts-pkg'); - await utils.cleanup(fixturePath); - const result = cp.spawnSync('npm', [ 'run', isWin ? 'windows-build' : 'build' ], { cwd: fixturePath, shell: isWin }); - assert(!result.stderr.toString()); - }); - - afterEach(async () => { - app && app.proc.kill('SIGTERM'); - await utils.cleanup(fixturePath); - }); - - it('should got correct stack', async () => { - app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]); - // app.debug(); - app.expect('code', 0); - - await sleep(waitTime); - - assert.equal(utils.replaceWeakRefMessage(app.stderr), ''); - assert(app.stdout.match(/egg started on http:\/\/127\.0\.0\.1:7001/)); - const result = await httpclient.request('http://127.0.0.1:7001', { dataType: 'json' }); - // console.log(result.data); - assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); - }); - }); -}); - diff --git a/test/ts.test.ts b/test/ts.test.ts new file mode 100644 index 0000000..771cc3a --- /dev/null +++ b/test/ts.test.ts @@ -0,0 +1,121 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { strict as assert } from 'node:assert'; +import fs from 'node:fs/promises'; +import cp from 'node:child_process'; +import { scheduler } from 'node:timers/promises'; +import coffee from 'coffee'; +import { request } from 'urllib'; +import { mm, restore } from 'mm'; +import { cleanup, replaceWeakRefMessage, Coffee } from './utils.js'; +import { isWindows, getSourceFilename } from '../src/helper.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +describe('test/ts.test.ts', () => { + const eggBin = getSourceFilename('../bin/run.js'); + const homePath = path.join(__dirname, 'fixtures/home'); + const waitTime = 5000; + let fixturePath: string; + + beforeEach(() => mm(process.env, 'MOCK_HOME_DIR', homePath)); + afterEach(restore); + + before(() => fs.mkdir(homePath, { recursive: true })); + after(() => fs.rm(homePath, { recursive: true, force: true })); + + describe('should display correct stack traces', () => { + let app: Coffee; + beforeEach(async () => { + fixturePath = path.join(__dirname, 'fixtures/ts'); + await cleanup(fixturePath); + const result = cp.spawnSync('npm', [ 'run', isWindows ? 'windows-build' : 'build' ], { + cwd: fixturePath, + shell: isWindows, + }); + assert.equal(result.stderr.toString(), ''); + }); + + afterEach(async () => { + app && app.proc.kill('SIGTERM'); + await cleanup(fixturePath); + }); + + it('--ts', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--ts', fixturePath ]) as Coffee; + // app.debug(); + app.expect('code', 0); + + await scheduler.wait(waitTime); + + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /egg started on http:\/\/127\.0\.0\.1:7001/); + const result = await request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); + }); + + it('--typescript', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--typescript', fixturePath ]) as Coffee; + // app.debug(); + app.expect('code', 0); + + await scheduler.wait(waitTime); + + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /egg started on http:\/\/127\.0\.0\.1:7001/); + const result = await request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); + }); + + it('--sourcemap', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', '--sourcemap', fixturePath ]) as Coffee; + // app.debug(); + app.expect('code', 0); + + await scheduler.wait(waitTime); + + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /egg started on http:\/\/127\.0\.0\.1:7001/); + const result = await request('http://127.0.0.1:7001', { dataType: 'json' }); + // console.log(result.data); + assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); + }); + }); + + describe('pkg.egg.typescript', () => { + let app: Coffee; + beforeEach(async () => { + fixturePath = path.join(__dirname, 'fixtures/ts-pkg'); + await cleanup(fixturePath); + const result = cp.spawnSync('npm', [ 'run', isWindows ? 'windows-build' : 'build' ], { + cwd: fixturePath, + shell: isWindows, + }); + assert.equal(result.stderr.toString(), ''); + }); + + afterEach(async () => { + app && app.proc.kill('SIGTERM'); + await cleanup(fixturePath); + }); + + it('should got correct stack', async () => { + app = coffee.fork(eggBin, [ 'start', '--workers=1', fixturePath ]) as Coffee; + // app.debug(); + app.expect('code', 0); + + await scheduler.wait(waitTime); + + assert.equal(replaceWeakRefMessage(app.stderr), ''); + assert.match(app.stdout, /egg started on http:\/\/127\.0\.0\.1:7001/); + const result = await request('http://127.0.0.1:7001', { dataType: 'json' }); + console.log(result.data); + assert.match(result.data.stack, /home\.ts:6:13/); + // assert(result.data.stack.includes(path.normalize('app/controller/home.ts:6:13'))); + }); + }); +}); + diff --git a/test/utils.js b/test/utils.ts similarity index 61% rename from test/utils.js rename to test/utils.ts index 4aa9840..60f1673 100644 --- a/test/utils.js +++ b/test/utils.ts @@ -1,11 +1,14 @@ -const helper = require('../lib/helper'); -const sleep = require('mz-modules/sleep'); -const isWin = process.platform === 'win32'; +import { scheduler } from 'node:timers/promises'; +import { ChildProcess } from 'node:child_process'; +import { Coffee as _Coffee } from 'coffee'; +import { isWindows, findNodeProcess } from '../src/helper.js'; -exports.cleanup = async function(baseDir) { - const processList = await helper.findNodeProcess(x => { - const dir = isWin ? baseDir.replace(/\\/g, '\\\\') : baseDir; - const prefix = isWin ? '\\"baseDir\\":\\"' : '"baseDir":"'; +export type Coffee = _Coffee & { proc: ChildProcess, stderr: string, stdout: string, code?: number }; + +export async function cleanup(baseDir: string) { + const processList = await findNodeProcess(x => { + const dir = isWindows ? baseDir.replace(/\\/g, '\\\\') : baseDir; + const prefix = isWindows ? '\\"baseDir\\":\\"' : '"baseDir":"'; return x.cmd.includes(`${prefix}${dir}`); }); @@ -26,7 +29,7 @@ exports.cleanup = async function(baseDir) { try { process.kill(pid, type === 'master' ? '' : 'SIGKILL'); console.log(`cleanup ${type} ${pid}`); - } catch (err) { + } catch (err: any) { console.log(`cleanup ${type} ${pid} got error ${err.code || err.message || err}`); if (err.code !== 'ESRCH') { throw err; @@ -34,14 +37,14 @@ exports.cleanup = async function(baseDir) { } } - await sleep('5s'); + await scheduler.wait(5000); } -}; +} -exports.replaceWeakRefMessage = function(stderr) { +export function replaceWeakRefMessage(stderr: string) { // Using compatibility WeakRef and FinalizationRegistry\r\n if (stderr.includes('Using compatibility WeakRef and FinalizationRegistry')) { stderr = stderr.replace(/Using compatibility WeakRef and FinalizationRegistry[\r\n]*/g, ''); } return stderr; -}; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ff41b73 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@eggjs/tsconfig", + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext" + } +} From 74605f7e21525c94deded87a7f949801530bdf05 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 31 Dec 2024 13:31:55 +0000 Subject: [PATCH 72/72] Release 4.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] ## [4.0.0](https://github.com/eggjs/scripts/compare/v3.1.0...v4.0.0) (2024-12-31) ### ⚠ BREAKING CHANGES * drop Node.js < 18.19.0 support part of https://github.com/eggjs/egg/issues/3644 https://github.com/eggjs/egg/issues/5257 ## Summary by CodeRabbit ## Release Notes - **New Features** - Added support for ECMAScript modules (ESM). - Enhanced CLI with more robust start and stop commands. - Improved TypeScript integration and type safety. - Introduced new commands for stopping an Egg.js server application. - Added new configuration options for logging and process management. - **Improvements** - Updated package configuration for better modularity. - Modernized test infrastructure with TypeScript support. - Refined error handling and logging mechanisms. - Enhanced process management capabilities. - Improved documentation with updated installation instructions and usage examples. - **Breaking Changes** - Renamed package from `egg-scripts` to `@eggjs/scripts`. - Requires Node.js version 18.19.0 or higher. - Significant changes to project structure and module exports. - **Bug Fixes** - Improved process management for server start and stop operations. - Enhanced cross-platform compatibility. - Fixed issues with asynchronous route handlers in various applications. ### Features * support cjs and esm both by tshy ([#63](https://github.com/eggjs/scripts/issues/63)) ([d9d0bc6](https://github.com/eggjs/scripts/commit/d9d0bc65aefd1d73be2c40b86366af566cf471c1)) --- CHANGELOG.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f6a541..4ed0672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## [4.0.0](https://github.com/eggjs/scripts/compare/v3.1.0...v4.0.0) (2024-12-31) + + +### ⚠ BREAKING CHANGES + +* drop Node.js < 18.19.0 support + +part of https://github.com/eggjs/egg/issues/3644 + +https://github.com/eggjs/egg/issues/5257 + + + +## Summary by CodeRabbit + +## Release Notes + +- **New Features** + - Added support for ECMAScript modules (ESM). + - Enhanced CLI with more robust start and stop commands. + - Improved TypeScript integration and type safety. + - Introduced new commands for stopping an Egg.js server application. + - Added new configuration options for logging and process management. + +- **Improvements** + - Updated package configuration for better modularity. + - Modernized test infrastructure with TypeScript support. + - Refined error handling and logging mechanisms. + - Enhanced process management capabilities. +- Improved documentation with updated installation instructions and +usage examples. + +- **Breaking Changes** + - Renamed package from `egg-scripts` to `@eggjs/scripts`. + - Requires Node.js version 18.19.0 or higher. + - Significant changes to project structure and module exports. + +- **Bug Fixes** + - Improved process management for server start and stop operations. + - Enhanced cross-platform compatibility. +- Fixed issues with asynchronous route handlers in various applications. + + +### Features + +* support cjs and esm both by tshy ([#63](https://github.com/eggjs/scripts/issues/63)) ([d9d0bc6](https://github.com/eggjs/scripts/commit/d9d0bc65aefd1d73be2c40b86366af566cf471c1)) + ## [3.1.0](https://github.com/eggjs/egg-scripts/compare/v3.0.1...v3.1.0) (2024-12-10) diff --git a/package.json b/package.json index 655fd81..e197530 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/scripts", - "version": "3.1.0", + "version": "4.0.0", "publishConfig": { "access": "public" },