From 95d134bdfda223e0f09dc408d3c6ca95f1e9fc50 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Wed, 22 May 2019 07:50:14 +0200 Subject: [PATCH] feat: parse YAML/JSON/JS config file (#1258) * Parse JSON/YAML config file. * fix missing export * fix: typos * test(config): remove JSON test * feat: better config error handling, tests * fix: detect YAML config file via extension * docs: https://github.com/verdaccio/website/pull/99 --- src/lib/utils.js | 29 +++++++++-- test/unit/modules/config/config.spec.js | 7 ++- test/unit/modules/utils/config-utils.spec.js | 47 ++++++++++++++++- test/unit/partials/config/js/default.js | 15 ++++++ test/unit/partials/config/js/invalid.js | 1 + test/unit/partials/config/json/default.json | 55 ++++++++++++++++++++ test/unit/partials/config/json/invalid.json | 1 + 7 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 test/unit/partials/config/js/default.js create mode 100644 test/unit/partials/config/js/invalid.js create mode 100644 test/unit/partials/config/json/default.json create mode 100644 test/unit/partials/config/json/invalid.json diff --git a/src/lib/utils.js b/src/lib/utils.js index 2b9d43067..78caa87d8 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -13,7 +13,18 @@ import createError from 'http-errors'; // $FlowFixMe import sanitizyReadme from '@verdaccio/readme'; -import { HTTP_STATUS, API_ERROR, DEFAULT_PORT, DEFAULT_DOMAIN, DEFAULT_PROTOCOL, CHARACTER_ENCODING, HEADERS, DIST_TAGS, DEFAULT_USER } from './constants'; +import { + HTTP_STATUS, + API_ERROR, + APP_ERROR, + DEFAULT_PORT, + DEFAULT_DOMAIN, + DEFAULT_PROTOCOL, + CHARACTER_ENCODING, + HEADERS, + DIST_TAGS, + DEFAULT_USER, +} from './constants'; import { generateGravatarUrl, GENERIC_AVATAR } from '../utils/user'; import type { Package } from '@verdaccio/types'; @@ -381,8 +392,20 @@ export const ErrorCode = { }, }; -export function parseConfigFile(configPath: string): Object { - return YAML.safeLoad(fs.readFileSync(configPath, CHARACTER_ENCODING.UTF8)); +export function parseConfigFile(configPath: string) { + try { + if (/\.ya?ml$/i.test(configPath)) { + return YAML.safeLoad(fs.readFileSync(configPath, CHARACTER_ENCODING.UTF8)); + } else { + return require(configPath); + } + } catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') { + e.message = APP_ERROR.CONFIG_NOT_VALID; + } + + throw new Error(e); + } } /** diff --git a/test/unit/modules/config/config.spec.js b/test/unit/modules/config/config.spec.js index 128b0cb81..342dabbca 100644 --- a/test/unit/modules/config/config.spec.js +++ b/test/unit/modules/config/config.spec.js @@ -5,7 +5,12 @@ import Config from '../../../../src/lib/config'; import {parseConfigFile} from '../../../../src/lib/utils'; import {DEFAULT_REGISTRY, DEFAULT_UPLINK, ROLES, WEB_TITLE} from '../../../../src/lib/constants'; -const resolveConf = (conf) => path.join(__dirname, `../../../../conf/${conf}.yaml`); +const resolveConf = (conf) => { + const { name, ext } = path.parse(conf); + + return path.join(__dirname, `../../../../conf/${name}${ext.startsWith('.') ? ext : '.yaml'}`); +}; + require('../../../../src/lib/logger').setup([]); const checkDefaultUplink = (config) => { diff --git a/test/unit/modules/utils/config-utils.spec.js b/test/unit/modules/utils/config-utils.spec.js index d21a3f7b2..ff1d48f6d 100644 --- a/test/unit/modules/utils/config-utils.spec.js +++ b/test/unit/modules/utils/config-utils.spec.js @@ -14,8 +14,11 @@ import {PACKAGE_ACCESS, ROLES} from '../../../../src/lib/constants'; describe('Config Utilities', () => { - const parseConfigurationFile = (name) => { - return path.join(__dirname, `../../partials/config/yaml/${name}.yaml`); + const parseConfigurationFile = (conf) => { + const { name, ext } = path.parse(conf); + const format = ext.startsWith('.') ? ext.substring(1) : 'yaml'; + + return path.join(__dirname, `../../partials/config/${format}/${name}.${format}`); }; describe('uplinkSanityCheck', () => { @@ -265,4 +268,44 @@ describe('Config Utilities', () => { expect(url).toMatch('/-/static/logo.png'); }); }); + + describe('JSON', () => { + test('parse default.json', () => { + const config = parseConfigFile(parseConfigurationFile('default.json')); + + expect(config.storage).toBeDefined(); + }); + + test('parse invalid.json', () => { + expect(function ( ) { + parseConfigFile(parseConfigurationFile('invalid.json')); + }).toThrow(/Error/); + }); + + test('parse not-exists.json', () => { + expect(function ( ) { + parseConfigFile(parseConfigurationFile('not-exists.json')); + }).toThrow(/Error/); + }); + }); + + describe('JavaScript', () => { + test('parse default.js', () => { + const config = parseConfigFile(parseConfigurationFile('default.js')); + + expect(config.storage).toBeDefined(); + }); + + test('parse invalid.js', () => { + expect(function ( ) { + parseConfigFile(parseConfigurationFile('invalid.js')); + }).toThrow(/Error/); + }); + + test('parse not-exists.js', () => { + expect(function ( ) { + parseConfigFile(parseConfigurationFile('not-exists.js')); + }).toThrow(/Error/); + }); + }); }); diff --git a/test/unit/partials/config/js/default.js b/test/unit/partials/config/js/default.js new file mode 100644 index 000000000..599754cf3 --- /dev/null +++ b/test/unit/partials/config/js/default.js @@ -0,0 +1,15 @@ +module.exports = { storage: './storage_default_storage', + uplinks: { npmjs: { url: 'http://localhost:4873/' } }, + packages: + { '@*/*': { access: '$all', publish: '$all', proxy: 'npmjs' }, + 'forbidden-place': { access: 'nobody', publish: '$all' }, + react: { access: '$all', publish: '$all', proxy: 'npmjs' }, + 'corrupted-package': { access: '$all', publish: '$all', proxy: 'npmjs' }, + jquery: { access: '$all', publish: '$all', proxy: 'npmjs' }, + 'auth-package': { access: '$authenticated', publish: '$authenticated' }, + vue: + { access: '$authenticated', + publish: '$authenticated', + proxy: 'npmjs' }, + '*': { access: '$all', publish: '$all', proxy: 'npmjs' } }, + logs: [ { type: 'stdout', format: 'pretty', level: 'warn' } ] }; diff --git a/test/unit/partials/config/js/invalid.js b/test/unit/partials/config/js/invalid.js new file mode 100644 index 000000000..3407ebe0d --- /dev/null +++ b/test/unit/partials/config/js/invalid.js @@ -0,0 +1 @@ +module.exports = {; diff --git a/test/unit/partials/config/json/default.json b/test/unit/partials/config/json/default.json new file mode 100644 index 000000000..843920610 --- /dev/null +++ b/test/unit/partials/config/json/default.json @@ -0,0 +1,55 @@ +{ + "storage": "./storage_default_storage", + "uplinks": { + "npmjs": { + "url": "http://localhost:4873/" + } + }, + "packages": { + "@*/*": { + "access": "$all", + "publish": "$all", + "proxy": "npmjs" + }, + "forbidden-place": { + "access": "nobody", + "publish": "$all" + }, + "react": { + "access": "$all", + "publish": "$all", + "proxy": "npmjs" + }, + "corrupted-package": { + "access": "$all", + "publish": "$all", + "proxy": "npmjs" + }, + "jquery": { + "access": "$all", + "publish": "$all", + "proxy": "npmjs" + }, + "auth-package": { + "access": "$authenticated", + "publish": "$authenticated" + }, + "vue": { + "access": "$authenticated", + "publish": "$authenticated", + "proxy": "npmjs" + }, + "*": { + "access": "$all", + "publish": "$all", + "proxy": "npmjs" + } + }, + "logs": [ + { + "type": "stdout", + "format": "pretty", + "level": "warn" + } + ] +} diff --git a/test/unit/partials/config/json/invalid.json b/test/unit/partials/config/json/invalid.json new file mode 100644 index 000000000..98232c64f --- /dev/null +++ b/test/unit/partials/config/json/invalid.json @@ -0,0 +1 @@ +{