From ede3fa866c6658c84ee88e14bbbf2ad92e97f5cb Mon Sep 17 00:00:00 2001 From: ehmicky Date: Tue, 1 Oct 2019 14:59:50 +0200 Subject: [PATCH] Normalize configuration --- .../@netlify-build/src/build/instructions.js | 28 ++++--------- packages/@netlify-build/src/build/main.js | 6 --- packages/@netlify-config/index.js | 6 ++- packages/@netlify-config/normalize.js | 40 +++++++++++++++++++ packages/@netlify-config/package-lock.json | 40 ++++++++++++++++--- packages/@netlify-config/package.json | 2 + packages/@netlify-config/tests/config.test.js | 12 ++++-- packages/@netlify-config/validate.js | 14 +++++++ 8 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 packages/@netlify-config/normalize.js create mode 100644 packages/@netlify-config/validate.js diff --git a/packages/@netlify-build/src/build/instructions.js b/packages/@netlify-build/src/build/instructions.js index 62b9d977c6..b0071fd35f 100644 --- a/packages/@netlify-build/src/build/instructions.js +++ b/packages/@netlify-build/src/build/instructions.js @@ -35,36 +35,22 @@ const getHookInstructions = function({ hook, pluginsHooks, netlifyConfig: { - build: { command: configCommand, lifecycle: configLifecycle } + build: { + lifecycle: { [hook]: lifecycleCommands } + } }, redactedKeys }) { return [ - // Support for old command. Add build.command to execution - configCommand && hook === 'build' - ? { - name: `config.build.command`, - hook: 'build', - pluginConfig: {}, - async method() { - await execCommand(configCommand, 'build.command', redactedKeys) - }, - override: {} - } - : undefined, - // Merge in config lifecycle events first - configLifecycle && configLifecycle[hook] + lifecycleCommands ? { name: `config.build.lifecycle.${hook}`, hook, pluginConfig: {}, async method() { - const commands = Array.isArray(configLifecycle[hook]) - ? configLifecycle[hook] - : configLifecycle[hook].split('\n') - // TODO pass in env vars if not available - // TODO return stdout? - await pMapSeries(commands, command => execCommand(command, `build.lifecycle.${hook}`, redactedKeys)) + await pMapSeries(lifecycleCommands, command => + execCommand(command, `build.lifecycle.${hook}`, redactedKeys) + ) }, override: {} } diff --git a/packages/@netlify-build/src/build/main.js b/packages/@netlify-build/src/build/main.js index 1afbd20d19..6c1f9fa2bd 100644 --- a/packages/@netlify-build/src/build/main.js +++ b/packages/@netlify-build/src/build/main.js @@ -39,12 +39,6 @@ module.exports = async function build(options = {}) { redactedKeys }) - if (netlifyConfig.build.lifecycle && netlifyConfig.build.command) { - throw new Error( - `build.command && build.lifecycle are both defined in config file. Please move build.command to build.lifecycle.build` - ) - } - doDryRun({ buildInstructions, netlifyConfigPath, options }) logLifeCycleStart() diff --git a/packages/@netlify-config/index.js b/packages/@netlify-config/index.js index b29d3d16df..23475a47ab 100644 --- a/packages/@netlify-config/index.js +++ b/packages/@netlify-config/index.js @@ -5,6 +5,8 @@ const configorama = require('configorama') const pathExists = require('path-exists') const getConfigPath = require('./path') +const { validateConfig } = require('./validate') +const { normalizeConfig } = require('./normalize') async function netlifyConfig(configFile, options) { const configPath = resolve(cwd(), configFile) @@ -35,7 +37,9 @@ async function netlifyConfig(configFile, options) { ] }) - const configA = Object.assign({ build: {} }, config) + validateConfig(config) + + const configA = normalizeConfig(config) return configA } diff --git a/packages/@netlify-config/normalize.js b/packages/@netlify-config/normalize.js new file mode 100644 index 0000000000..f9b4dac348 --- /dev/null +++ b/packages/@netlify-config/normalize.js @@ -0,0 +1,40 @@ +const mapObj = require('map-obj') +const omit = require('omit.js') + +// Normalize configuration object +const normalizeConfig = function(config) { + const configA = Object.assign({ build: {} }, config) + const configB = normalizeLifecycles(configA) + return configB +} + +const normalizeLifecycles = function(config) { + const { + build, + build: { command, lifecycle = {} } + } = config + const buildA = omit(build, ['command']) + const lifecycleA = normalizeCommand(lifecycle, command) + + const lifecycleB = mapObj(lifecycleA, normalizeLifecycle) + + return Object.assign({}, config, { + build: Object.assign({}, buildA, { lifecycle: lifecycleB }) + }) +} + +// `build.lifecycle.build` was previously called `build.command` +const normalizeCommand = function(lifecycle, command) { + if (command === undefined) { + return lifecycle + } + + return { ...lifecycle, build: command } +} + +const normalizeLifecycle = function(hook, value) { + const valueA = typeof value === 'string' ? value.trim().split('\n') : value + return [hook, valueA] +} + +module.exports = { normalizeConfig } diff --git a/packages/@netlify-config/package-lock.json b/packages/@netlify-config/package-lock.json index e5e5806aa5..22d4017299 100644 --- a/packages/@netlify-config/package-lock.json +++ b/packages/@netlify-config/package-lock.json @@ -706,6 +706,15 @@ "estraverse": "^4.1.1" } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -873,6 +882,14 @@ "camelcase": "^4.1.0", "map-obj": "^2.0.0", "quick-lru": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + } } }, "chalk": { @@ -1195,8 +1212,7 @@ "core-js": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", - "dev": true + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" }, "cross-spawn": { "version": "5.1.0", @@ -2266,10 +2282,9 @@ } }, "map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==" }, "matcher": { "version": "2.0.0", @@ -2483,6 +2498,14 @@ "symbol-observable": "^1.0.4" } }, + "omit.js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-1.0.2.tgz", + "integrity": "sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ==", + "requires": { + "babel-runtime": "^6.23.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3042,6 +3065,11 @@ "regenerate": "^1.4.0" } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, "regexp.prototype.flags": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", diff --git a/packages/@netlify-config/package.json b/packages/@netlify-config/package.json index fd23f21b37..35c1836c2f 100644 --- a/packages/@netlify-config/package.json +++ b/packages/@netlify-config/package.json @@ -19,7 +19,9 @@ "dependencies": { "configorama": "0.3.4", "find-up": "^4.1.0", + "map-obj": "^4.1.0", "minimist": "^1.2.0", + "omit.js": "^1.0.2", "path-exists": "^4.0.0" }, "devDependencies": { diff --git a/packages/@netlify-config/tests/config.test.js b/packages/@netlify-config/tests/config.test.js index 63ac1cb687..d7662e73b9 100644 --- a/packages/@netlify-config/tests/config.test.js +++ b/packages/@netlify-config/tests/config.test.js @@ -10,7 +10,9 @@ test('Test TOML', async t => { t.deepEqual(config, { build: { publish: 'dist', - command: 'npm run build', + lifecycle: { + build: ['npm run build'] + }, functions: 'functions' } }) @@ -22,7 +24,9 @@ test('Test YAML', async t => { t.deepEqual(config, { build: { publish: 'dist', - command: 'npm run build', + lifecycle: { + build: ['npm run build'] + }, functions: 'functions' } }) @@ -34,7 +38,9 @@ test('Test JSON', async t => { t.deepEqual(config, { build: { publish: 'dist', - command: 'npm run build', + lifecycle: { + build: ['npm run build'] + }, functions: 'functions' } }) diff --git a/packages/@netlify-config/validate.js b/packages/@netlify-config/validate.js new file mode 100644 index 0000000000..8310a0bc7a --- /dev/null +++ b/packages/@netlify-config/validate.js @@ -0,0 +1,14 @@ +// Validate the configuration object +const validateConfig = function(config) { + validateOldCommand(config) +} + +const validateOldCommand = function({ build: { command, lifecycle } = {} }) { + if (command !== undefined && lifecycle !== undefined) { + throw new Error( + `'build.command' and 'build.lifecycle' are both defined in the configuration. Please rename 'build.command' to 'build.lifecycle.build'` + ) + } +} + +module.exports = { validateConfig }