From 550261b107cd87416244057da16d1958dda49cbf Mon Sep 17 00:00:00 2001 From: Noor Eldeen Salah Date: Tue, 5 Jul 2022 14:18:30 +0200 Subject: [PATCH] feat: add support for configuration file (#522) * Add support for `--config` command-line argument * Add unit-tests for `--config` command-line argument * Update documentation with configuration file details * Add an alias for `--verbose-watch` to fix regression Fix a regression that was caused by removing `default` from `yargs-parser` --- README.md | 5 +-- args.js | 43 ++++++++++++++--------- test/args.test.js | 71 ++++++++++++++++++++++++++++++++++++++ test/data/custom-config.js | 9 +++++ 4 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 test/data/custom-config.js diff --git a/README.md b/README.md index 086c730c..040f3232 100644 --- a/README.md +++ b/README.md @@ -127,10 +127,11 @@ This works with a `.js` extension if you are using Node.js >= 14 and the nearest If your `package.json` does not have `"type": "module"`, use `.mjs` for the extension (`plugin.mjs` in the above example). #### Options -You can pass the following options via CLI arguments. Every option has a corresponding environment variable: +You can pass the following options via CLI arguments. You can also use `--config` or `-c` flag to pass a configuration file that exports all the properties listed below in camelCase convention. In case of collision (i.e., An argument existing in both the configuration file and as a command-line argument, the command-line argument is given the priority). Every option has a corresponding environment variable: | Description | Short command | Full command | Environment variable | | --------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------ | ------------------------ | +| Path to configuration file that can be used to manage the options listed below | `-c` | `--config` | `FASTIFY_CONFIG or CONFIG` | | Port to listen on (default to 3000) | `-p` | `--port` | `FASTIFY_PORT or PORT` | | Address to listen on | `-a` | `--address` | `FASTIFY_ADDRESS` | | Socket to listen on | `-s` | `--socket` | `FASTIFY_SOCKET` | @@ -143,7 +144,7 @@ You can pass the following options via CLI arguments. Every option has a corresp | Prints pretty logs | `-P` | `--pretty-logs` | `FASTIFY_PRETTY_LOGS` | | Watch process.cwd() directory for changes, recursively; when that happens, the process will auto reload | `-w` | `--watch` | `FASTIFY_WATCH` | | Ignore changes to the specified files or directories when watch is enabled. (e.g. `--ignore-watch='node_modules .git logs/error.log'` ) | | `--ignore-watch` | `FASTIFY_IGNORE_WATCH` | -| Prints events triggered by watch listener (useful to debug unexpected reload when using `--watch` ) | | `--verbose-watch` | `FASTIFY_VERBOSE_WATCH` | +| Prints events triggered by watch listener (useful to debug unexpected reload when using `--watch` ) | `-V` | `--verbose-watch` | `FASTIFY_VERBOSE_WATCH` | | Use custom options | `-o` | `--options` | `FASTIFY_OPTIONS` | | Set the prefix | `-x` | `--prefix` | `FASTIFY_PREFIX` | | Set the plugin timeout | `-T` | `--plugin-timeout` | `FASTIFY_PLUGIN_TIMEOUT` | diff --git a/args.js b/args.js index 7c8a0a4d..23032928 100644 --- a/args.js +++ b/args.js @@ -2,23 +2,38 @@ const argv = require('yargs-parser') const dotenv = require('dotenv') +const { requireModule } = require('./util') const DEFAULT_IGNORE = 'node_modules build dist .git bower_components logs .swp .nyc_output' +const DEFAULT_ARGUMENTS = { + logLevel: 'fatal', + prettyLogs: false, + watch: false, + verboseWatch: false, + debug: false, + debugPort: 9320, + options: false, + pluginTimeout: 10 * 1000, // everything should load in 10 seconds + lang: 'js', + standardlint: false +} + module.exports = function parseArgs (args) { dotenv.config() - const parsedArgs = argv(args, { + const commandLineArguments = argv(args, { configuration: { 'populate--': true }, number: ['port', 'inspect-port', 'body-limit', 'plugin-timeout'], - string: ['log-level', 'address', 'socket', 'prefix', 'ignore-watch', 'logging-module', 'debug-host', 'lang', 'require'], + string: ['log-level', 'address', 'socket', 'prefix', 'ignore-watch', 'logging-module', 'debug-host', 'lang', 'require', 'config'], boolean: ['pretty-logs', 'options', 'watch', 'verbose-watch', 'debug', 'standardlint'], envPrefix: 'FASTIFY_', alias: { port: ['p'], socket: ['s'], help: ['h'], + config: ['c'], options: ['o'], address: ['a'], watch: ['w'], @@ -29,31 +44,25 @@ module.exports = function parseArgs (args) { 'log-level': ['l'], 'pretty-logs': ['P'], 'plugin-timeout': ['T'], - 'logging-module': ['L'] - }, - default: { - 'log-level': 'fatal', - 'pretty-logs': false, - watch: false, - verboseWatch: false, - debug: false, - debugPort: 9320, - options: false, - 'plugin-timeout': 10 * 1000, // everything should load in 10 seconds - lang: 'js', - standardlint: false + 'logging-module': ['L'], + 'verbose-watch': ['V'] } }) - const additionalArgs = parsedArgs['--'] || [] + const configFileOptions = commandLineArguments.config ? requireModule(commandLineArguments.config) : undefined + + const additionalArgs = commandLineArguments['--'] || [] const { _, ...pluginOptions } = argv(additionalArgs) - const ignoreWatchArg = parsedArgs.ignoreWatch || '' + const ignoreWatchArg = commandLineArguments.ignoreWatch || configFileOptions?.ignoreWatch || '' let ignoreWatch = `${DEFAULT_IGNORE} ${ignoreWatchArg}`.trim() if (ignoreWatchArg.includes('.ts$')) { ignoreWatch = ignoreWatch.replace('dist', '') } + // Merge objects from lower to higher priority + const parsedArgs = { ...DEFAULT_ARGUMENTS, ...configFileOptions, ...commandLineArguments } + return { _: parsedArgs._, '--': additionalArgs, diff --git a/test/args.test.js b/test/args.test.js index e72a197b..408ab810 100644 --- a/test/args.test.js +++ b/test/args.test.js @@ -253,3 +253,74 @@ test('should parse custom plugin options', t => { lang: 'js' }) }) + +test('should parse config file correctly and prefer config values over default ones', t => { + t.plan(1) + + const argv = [ + '--config', './test/data/custom-config.js', + 'app.js' + ] + const parsedArgs = parseArgs(argv) + + t.strictSame(parsedArgs, { + _: ['app.js'], + '--': [], + port: 5000, + bodyLimit: undefined, + pluginTimeout: 9000, + pluginOptions: {}, + prettyLogs: true, + options: false, + watch: true, + debug: false, + debugPort: 4000, + debugHost: '1.1.1.1', + ignoreWatch: 'node_modules build dist .git bower_components logs .swp .nyc_output', + verboseWatch: false, + logLevel: 'fatal', + address: 'fastify.io:9999', + socket: undefined, + require: undefined, + prefix: 'FASTIFY_', + loggingModule: undefined, + lang: 'js' + }) +}) + +test('should prefer command line args over config file options', t => { + t.plan(1) + + const argv = [ + '--config', './test/data/custom-config.js', + '--port', '4000', + '--debugPort', '9320', + '--plugin-timeout', '10000', + 'app.js' + ] + const parsedArgs = parseArgs(argv) + + t.strictSame(parsedArgs, { + _: ['app.js'], + '--': [], + port: 4000, + bodyLimit: undefined, + pluginTimeout: 10000, + pluginOptions: {}, + prettyLogs: true, + options: false, + watch: true, + debug: false, + debugPort: 9320, + debugHost: '1.1.1.1', + ignoreWatch: 'node_modules build dist .git bower_components logs .swp .nyc_output', + verboseWatch: false, + logLevel: 'fatal', + address: 'fastify.io:9999', + socket: undefined, + require: undefined, + prefix: 'FASTIFY_', + loggingModule: undefined, + lang: 'js' + }) +}) diff --git a/test/data/custom-config.js b/test/data/custom-config.js new file mode 100644 index 00000000..5a073f6e --- /dev/null +++ b/test/data/custom-config.js @@ -0,0 +1,9 @@ +module.exports = { + port: 5000, + address: 'fastify.io:9999', + prefix: 'FASTIFY_', + watch: true, + prettyLogs: true, + debugPort: 4000, + pluginTimeout: 9 * 1000 +}