这是indexloc提供的服务,不要输入任何密码
Skip to content

Commit b08ab63

Browse files
authored
Merge 5d92865 into f52a071
2 parents f52a071 + 5d92865 commit b08ab63

File tree

5 files changed

+193
-60
lines changed

5 files changed

+193
-60
lines changed

lib/cli.js

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const fs = require('graceful-fs')
77
const Server = require('./server')
88
const helper = require('./helper')
99
const constant = require('./constants')
10+
const cfg = require('./config')
1011

1112
function processArgs (argv, options, fs, path) {
1213
Object.getOwnPropertyNames(argv).forEach(function (name) {
@@ -278,26 +279,47 @@ exports.process = () => {
278279
}
279280

280281
exports.run = () => {
281-
const config = exports.process()
282-
283-
switch (config.cmd) {
284-
case 'start':
285-
new Server(config).start()
286-
break
287-
case 'run':
288-
require('./runner')
289-
.run(config)
290-
.on('progress', printRunnerProgress)
291-
break
292-
case 'stop':
293-
require('./stopper').stop(config)
294-
break
295-
case 'init':
296-
require('./init').init(config)
297-
break
298-
case 'completion':
299-
require('./completion').completion(config)
300-
break
282+
const cliOptions = exports.process()
283+
const cmd = cliOptions.cmd // prevent config from changing the command
284+
const cmdNeedsConfig = cmd === 'start' || cmd === 'run' || cmd === 'stop'
285+
if (cmdNeedsConfig) {
286+
cfg.parseConfig(
287+
cliOptions.configFile,
288+
cliOptions,
289+
{
290+
promiseConfig: true,
291+
throwErrors: true
292+
}
293+
).then(function onKarmaConfigFulfilled (config) {
294+
switch (cmd) {
295+
case 'start':
296+
new Server(config).start()
297+
break
298+
case 'run':
299+
require('./runner')
300+
.run(config)
301+
.on('progress', printRunnerProgress)
302+
break
303+
case 'stop':
304+
require('./stopper').stop(config)
305+
break
306+
}
307+
}, function onKarmaConfigRejected (reason) {
308+
console.error(reason) // TODO: configure a CLI Logger?
309+
310+
// The `run` function is a private application, not a public API. We don't
311+
// need to worry about process.exit vs throw vs promise rejection here.
312+
process.exit(1)
313+
})
314+
} else {
315+
switch (cmd) {
316+
case 'init':
317+
require('./init').init(cliOptions)
318+
break
319+
case 'completion':
320+
require('./completion').completion(cliOptions)
321+
break
322+
}
301323
}
302324
}
303325

lib/config.js

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,17 @@ const CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' +
352352
' };\n'
353353

354354
function parseConfig (configFilePath, cliOptions, parseOptions) {
355+
const promiseConfig = parseOptions && parseOptions.promiseConfig === true
356+
const throwErrors = parseOptions && parseOptions.throwErrors === true
355357
function fail () {
356358
log.error(...arguments)
357-
if (parseOptions && parseOptions.throwErrors === true) {
359+
if (throwErrors) {
358360
const errorMessage = Array.from(arguments).join(' ')
359-
throw new Error(errorMessage)
361+
const err = new Error(errorMessage)
362+
if (promiseConfig) {
363+
return Promise.reject(err)
364+
}
365+
throw err
360366
} else {
361367
const warningMessage =
362368
'The `parseConfig()` function historically called `process.exit(1)`' +
@@ -411,34 +417,59 @@ function parseConfig (configFilePath, cliOptions, parseOptions) {
411417
// add the user's configuration in
412418
config.set(cliOptions)
413419

420+
let configModuleReturn
414421
try {
415-
configModule(config)
422+
configModuleReturn = configModule(config)
416423
} catch (e) {
417424
return fail('Error in config file!\n', e)
418425
}
426+
function finalizeConfig (config) {
427+
// merge the config from config file and cliOptions (precedence)
428+
config.set(cliOptions)
419429

420-
// merge the config from config file and cliOptions (precedence)
421-
config.set(cliOptions)
422-
423-
// if the user changed listenAddress, but didn't set a hostname, warn them
424-
if (config.hostname === null && config.listenAddress !== null) {
425-
log.warn(`ListenAddress was set to ${config.listenAddress} but hostname was left as the default: ` +
430+
// if the user changed listenAddress, but didn't set a hostname, warn them
431+
if (config.hostname === null && config.listenAddress !== null) {
432+
log.warn(`ListenAddress was set to ${config.listenAddress} but hostname was left as the default: ` +
426433
`${defaultHostname}. If your browsers fail to connect, consider changing the hostname option.`)
427-
}
428-
// restore values that weren't overwritten by the user
429-
if (config.hostname === null) {
430-
config.hostname = defaultHostname
431-
}
432-
if (config.listenAddress === null) {
433-
config.listenAddress = defaultListenAddress
434-
}
434+
}
435+
// restore values that weren't overwritten by the user
436+
if (config.hostname === null) {
437+
config.hostname = defaultHostname
438+
}
439+
if (config.listenAddress === null) {
440+
config.listenAddress = defaultListenAddress
441+
}
435442

436-
// configure the logger as soon as we can
437-
logger.setup(config.logLevel, config.colors, config.loggers)
443+
// configure the logger as soon as we can
444+
logger.setup(config.logLevel, config.colors, config.loggers)
438445

439-
log.debug(configFilePath ? `Loading config ${configFilePath}` : 'No config file specified.')
446+
log.debug(configFilePath ? `Loading config ${configFilePath}` : 'No config file specified.')
440447

441-
return normalizeConfig(config, configFilePath)
448+
return normalizeConfig(config, configFilePath)
449+
}
450+
const returnIsThenable = configModuleReturn != null && typeof configModuleReturn === 'object' && typeof configModuleReturn.then === 'function'
451+
if (returnIsThenable) {
452+
if (promiseConfig !== true) {
453+
const errorMessage =
454+
'The `parseOptions.promiseConfig` option must be set to `true` to ' +
455+
'enable promise return values from configuration files. ' +
456+
'Example: `parseConfig(path, cliOptions, { promiseConfig: true })`'
457+
return fail(errorMessage)
458+
}
459+
return configModuleReturn.then(function onKarmaConfigModuleFulfilled (/* ignoredResolutionValue */) {
460+
return finalizeConfig(config)
461+
})
462+
} else {
463+
if (promiseConfig) {
464+
try {
465+
return Promise.resolve(finalizeConfig(config))
466+
} catch (exception) {
467+
return Promise.reject(exception)
468+
}
469+
} else {
470+
return finalizeConfig(config)
471+
}
472+
}
442473
}
443474

444475
// PUBLIC API

lib/runner.js

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,44 @@ function parseExitCode (buffer, defaultExitCode, failOnEmptyTestSuite) {
3232
}
3333

3434
// TODO(vojta): read config file (port, host, urlRoot)
35-
function run (config, done) {
36-
config = config || {}
37-
38-
logger.setupFromConfig(config)
35+
function run (cliOptionsOrConfig, done) {
36+
cliOptionsOrConfig = cliOptionsOrConfig || {}
37+
38+
// TODO: Should `const log = logger.create('runner')` be moved into the
39+
// : function for consistency with server.js and stopper.js? or the
40+
// : reverse (make server and stopper consistent with runner?)
41+
logger.setupFromConfig({
42+
colors: cliOptionsOrConfig.colors,
43+
logLevel: cliOptionsOrConfig.logLevel
44+
})
3945

4046
done = helper.isFunction(done) ? done : process.exit
41-
config = cfg.parseConfig(config.configFile, config)
4247

48+
let config
49+
if (cliOptionsOrConfig instanceof cfg.Config) {
50+
config = cliOptionsOrConfig
51+
} else {
52+
const deprecatedCliOptionsMessage =
53+
'Passing raw CLI options to `runner(config, done)` is deprecated. Use ' +
54+
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
55+
'to prepare a processed `Config` instance and pass that as the ' +
56+
'`config` argument instead.'
57+
log.warn(deprecatedCliOptionsMessage)
58+
try {
59+
config = cfg.parseConfig(
60+
cliOptionsOrConfig.configFile,
61+
cliOptionsOrConfig,
62+
{
63+
promiseConfig: false,
64+
throwErrors: true
65+
}
66+
)
67+
} catch (parseConfigError) {
68+
// TODO: change how `done` falls back to exit in next major version
69+
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
70+
done(1)
71+
}
72+
}
4373
let exitCode = 1
4474
const emitter = new EventEmitter()
4575
const options = {

lib/server.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,43 @@ function createSocketIoServer (webServer, executor, config) {
5555
}
5656

5757
class Server extends KarmaEventEmitter {
58-
constructor (cliOptions, done) {
58+
constructor (cliOptionsOrConfig, done) {
5959
super()
60-
logger.setupFromConfig(cliOptions)
61-
60+
cliOptionsOrConfig = cliOptionsOrConfig || {}
61+
logger.setupFromConfig({
62+
colors: cliOptionsOrConfig.colors,
63+
logLevel: cliOptionsOrConfig.logLevel
64+
})
6265
this.log = logger.create('karma-server')
63-
66+
done = helper.isFunction(done) ? done : process.exit
6467
this.loadErrors = []
6568

6669
let config
67-
try {
68-
config = cfg.parseConfig(cliOptions.configFile, cliOptions, { throwErrors: true })
69-
} catch (parseConfigError) {
70-
// TODO: change how `done` falls back to exit in next major version
71-
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
72-
(done || process.exit)(1)
73-
return
70+
if (cliOptionsOrConfig instanceof cfg.Config) {
71+
config = cliOptionsOrConfig
72+
} else {
73+
const deprecatedCliOptionsMessage =
74+
'Passing raw CLI options to `new Server(config, done)` is ' +
75+
'deprecated. Use ' +
76+
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
77+
'to prepare a processed `Config` instance and pass that as the ' +
78+
'`config` argument instead.'
79+
this.log.warn(deprecatedCliOptionsMessage)
80+
try {
81+
config = cfg.parseConfig(
82+
cliOptionsOrConfig.configFile,
83+
cliOptionsOrConfig,
84+
{
85+
promiseConfig: false,
86+
throwErrors: true
87+
}
88+
)
89+
} catch (parseConfigError) {
90+
// TODO: change how `done` falls back to exit in next major version
91+
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
92+
done(1)
93+
return
94+
}
7495
}
7596

7697
this.log.debug('Final config', util.inspect(config, false, /** depth **/ null))

lib/stopper.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,40 @@ const cfg = require('./config')
33
const logger = require('./logger')
44
const helper = require('./helper')
55

6-
exports.stop = function (config, done) {
7-
config = config || {}
8-
logger.setupFromConfig(config)
6+
exports.stop = function (cliOptionsOrConfig, done) {
7+
cliOptionsOrConfig = cliOptionsOrConfig || {}
8+
logger.setupFromConfig({
9+
colors: cliOptionsOrConfig.colors,
10+
logLevel: cliOptionsOrConfig.logLevel
11+
})
912
const log = logger.create('stopper')
1013
done = helper.isFunction(done) ? done : process.exit
14+
15+
let config
16+
if (cliOptionsOrConfig instanceof cfg.Config) {
17+
config = cliOptionsOrConfig
18+
} else {
19+
const deprecatedCliOptionsMessage =
20+
'Passing raw CLI options to `stopper(config, done)` is deprecated. Use ' +
21+
'`parseConfig(configFilePath, cliOptions, {promiseConfig: true, throwErrors: true})` ' +
22+
'to prepare a processed `Config` instance and pass that as the ' +
23+
'`config` argument instead.'
24+
log.warn(deprecatedCliOptionsMessage)
25+
try {
26+
config = cfg.parseConfig(
27+
cliOptionsOrConfig.configFile,
28+
cliOptionsOrConfig,
29+
{
30+
promiseConfig: false,
31+
throwErrors: true
32+
}
33+
)
34+
} catch (parseConfigError) {
35+
// TODO: change how `done` falls back to exit in next major version
36+
// SEE: https://github.com/karma-runner/karma/pull/3635#discussion_r565399378
37+
done(1)
38+
}
39+
}
1140
config = cfg.parseConfig(config.configFile, config)
1241

1342
const request = http.request({

0 commit comments

Comments
 (0)