From ca4ecd14090db4c153655cc0b33528aa6a9a80cc Mon Sep 17 00:00:00 2001 From: Wil Wilsman Date: Mon, 7 Oct 2019 16:44:09 -0500 Subject: [PATCH] fix: :bug: Default config overrides (#394) * :white_check_mark: Add configuration utiliy tests * fix: :bug: Remove requirement for static snapshot and upload arg This arg is allowed to be specified via a config file. It seems it was always meant to be this way as there are defaults specified for these args. * fix: :bug: Remove oclif defaults Percy defaults are handled seperately from oclif due to allowing specifying some flags and args within a configuration file. --- src/commands/exec.ts | 12 ++-- src/commands/health-check.ts | 6 +- src/commands/snapshot.ts | 40 ++++++++----- src/commands/start.ts | 12 ++-- src/commands/stop.ts | 6 +- src/commands/upload.ts | 18 ++++-- src/utils/configuration.ts | 3 +- test/utils/configuration.test.ts | 99 ++++++++++++++++++++++++++++++++ 8 files changed, 163 insertions(+), 33 deletions(-) create mode 100644 test/utils/configuration.test.ts diff --git a/src/commands/exec.ts b/src/commands/exec.ts index aeca454f..da79a1ff 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -22,13 +22,17 @@ export default class Exec extends PercyCommand { }), 'network-idle-timeout': flags.integer({ char: 't', - default: DEFAULT_CONFIGURATION.agent['asset-discovery']['network-idle-timeout'], - description: 'asset discovery network idle timeout (in milliseconds)', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent['asset-discovery']['network-idle-timeout']}]`, + 'Asset discovery network idle timeout (in milliseconds)', + ].join(' '), }), 'port': flags.integer({ char: 'p', - default: DEFAULT_CONFIGURATION.agent.port, - description: 'port', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent.port}]`, + 'Port', + ].join(' '), }), 'config': flags.string({ char: 'c', diff --git a/src/commands/health-check.ts b/src/commands/health-check.ts index 110d980e..e8429088 100644 --- a/src/commands/health-check.ts +++ b/src/commands/health-check.ts @@ -9,8 +9,10 @@ export default class HealthCheck extends Command { static flags = { port: flags.integer({ char: 'p', - default: DEFAULT_CONFIGURATION.agent.port, - description: 'port', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent.port}]`, + 'Port', + ].join(' '), }), } diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index d9c801cc..19c42da0 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -12,8 +12,10 @@ export default class Snapshot extends PercyCommand { static args = [{ name: 'snapshotDirectory', - description: 'A path to the directory you would like to snapshot', - required: true, + description: [ + `[default: ${DEFAULT_CONFIGURATION['static-snapshots'].path}]`, + 'A path to the directory you would like to snapshot', + ].join(' '), }] static examples = [ @@ -25,35 +27,45 @@ export default class Snapshot extends PercyCommand { static flags = { 'snapshot-files': flags.string({ char: 's', - description: 'Glob or comma-seperated string of globs for matching the files and directories to snapshot.', - default: DEFAULT_CONFIGURATION['static-snapshots']['snapshot-files'], + description: [ + `[default: ${DEFAULT_CONFIGURATION['static-snapshots']['snapshot-files']}]`, + 'Glob or comma-seperated string of globs for matching the files and directories to snapshot.', + ].join(' '), }), 'ignore-files': flags.string({ char: 'i', - description: 'Glob or comma-seperated string of globs for matching the files and directories to ignore.', - default: DEFAULT_CONFIGURATION['static-snapshots']['ignore-files'], + description: [ + `[default: ${DEFAULT_CONFIGURATION['static-snapshots']['ignore-files']}]`, + 'Glob or comma-seperated string of globs for matching the files and directories to ignore.', + ].join(' '), }), 'base-url': flags.string({ char: 'b', - description: 'If your static files will be hosted in a subdirectory, instead \n' + - 'of the webserver\'s root path, set that subdirectory with this flag.', - default: DEFAULT_CONFIGURATION['static-snapshots']['base-url'], + description: [ + `[default: ${DEFAULT_CONFIGURATION['static-snapshots']['base-url']}]`, + 'If your static files will be hosted in a subdirectory, instead', + 'of the webserver\'s root path, set that subdirectory with this flag.', + ].join(' '), }), + // from exec command. needed to start the agent service. 'allowed-hostname': flags.string({ char: 'h', description: 'Allowable hostname(s) to capture assets from', multiple: true, }), - // from exec command. needed to start the agent service. 'network-idle-timeout': flags.integer({ char: 't', - default: DEFAULT_CONFIGURATION.agent['asset-discovery']['network-idle-timeout'], - description: 'Asset discovery network idle timeout (in milliseconds)', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent['asset-discovery']['network-idle-timeout']}]`, + 'Asset discovery network idle timeout (in milliseconds)', + ].join(' '), }), 'port': flags.integer({ char: 'p', - default: DEFAULT_CONFIGURATION.agent.port, - description: 'Port', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent.port}]`, + 'Port', + ].join(' '), }), 'config': flags.string({ char: 'c', diff --git a/src/commands/start.ts b/src/commands/start.ts index dd596e1f..33e83900 100644 --- a/src/commands/start.ts +++ b/src/commands/start.ts @@ -26,13 +26,17 @@ export default class Start extends PercyCommand { }), 'network-idle-timeout': flags.integer({ char: 't', - default: DEFAULT_CONFIGURATION.agent['asset-discovery']['network-idle-timeout'], - description: 'asset discovery network idle timeout (in milliseconds)', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent['asset-discovery']['network-idle-timeout']}]`, + 'Asset discovery network idle timeout (in milliseconds)', + ].join(' '), }), 'port': flags.integer({ char: 'p', - default: DEFAULT_CONFIGURATION.agent.port, - description: 'port', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent.port}]`, + 'Port', + ].join(' '), }), 'config': flags.string({ char: 'c', diff --git a/src/commands/stop.ts b/src/commands/stop.ts index 91c09bff..f27ac501 100644 --- a/src/commands/stop.ts +++ b/src/commands/stop.ts @@ -18,8 +18,10 @@ export default class Stop extends PercyCommand { static flags = { port: flags.integer({ char: 'p', - default: DEFAULT_CONFIGURATION.agent.port, - description: 'port', + description: [ + `[default: ${DEFAULT_CONFIGURATION.agent.port}]`, + 'Port', + ].join(' '), }), } diff --git a/src/commands/upload.ts b/src/commands/upload.ts index f3483ff1..66c48fa9 100644 --- a/src/commands/upload.ts +++ b/src/commands/upload.ts @@ -9,8 +9,10 @@ export default class Upload extends Command { static args = [{ name: 'uploadDirectory', - description: 'A path to the directory containing static snapshot images', - required: true, + description: [ + `[default: ${DEFAULT_CONFIGURATION['static-snapshots'].path}]`, + 'A path to the directory containing static snapshot images', + ].join(' '), }] static examples = [ @@ -21,13 +23,17 @@ export default class Upload extends Command { static flags = { files: flags.string({ char: 'f', - description: 'Glob or comma-seperated string of globs for matching the files and directories to snapshot.', - default: DEFAULT_CONFIGURATION['image-snapshots'].files, + description: [ + `[default: ${DEFAULT_CONFIGURATION['image-snapshots'].files}]`, + 'Glob or comma-seperated string of globs for matching the files and directories to snapshot.', + ].join(' '), }), ignore: flags.string({ char: 'i', - description: 'Glob or comma-seperated string of globs for matching the files and directories to ignore.', - default: DEFAULT_CONFIGURATION['image-snapshots'].ignore, + description: [ + `[default: ${DEFAULT_CONFIGURATION['image-snapshots'].ignore}]`, + 'Glob or comma-seperated string of globs for matching the files and directories to ignore.', + ].join(' '), }), config: flags.string({ char: 'c', diff --git a/src/utils/configuration.ts b/src/utils/configuration.ts index 0bd39c3d..85a5844b 100644 --- a/src/utils/configuration.ts +++ b/src/utils/configuration.ts @@ -7,7 +7,8 @@ import logger from './logger' const { isArray } = Array const { assign, keys } = Object -const explorer = cosmiconfig('percy', { + +export const explorer = cosmiconfig('percy', { searchPlaces: [ 'package.json', '.percyrc', diff --git a/test/utils/configuration.test.ts b/test/utils/configuration.test.ts new file mode 100644 index 00000000..37c6cac5 --- /dev/null +++ b/test/utils/configuration.test.ts @@ -0,0 +1,99 @@ +import { expect } from 'chai' +import * as fs from 'fs' +import * as path from 'path' +import { DEFAULT_CONFIGURATION } from '../../src/configuration/configuration' +import config, { explorer } from '../../src/utils/configuration' + +function dedent(str: string) { + const indent = str.match(/ +/g)![0].length + return str.replace(new RegExp(`\n {${indent}}`, 'g'), '\n').trim() +} + +describe('configuration', () => { + let configfiles: string[] + + // helper to create a config files and cleanup on `afterEach` + function mkconfig(filename: string, contents: string) { + const filepath = path.join(process.cwd(), filename) + fs.writeFileSync(filepath, dedent(contents)) + configfiles.push(filepath) + } + + beforeEach(() => { + // clear caches for creating & removing files during testing + explorer.clearCaches() + configfiles = [] + }) + + afterEach(() => { + // clean up any created config files + configfiles.forEach((file) => { + fs.unlinkSync(file) + }) + }) + + it('returns the default configuration', () => { + expect(config({})).to.deep.equal(DEFAULT_CONFIGURATION) + }) + + it('automatically loads overrides from a `.percy.yml` config file', () => { + mkconfig('.percy.yml', ` + version: 1 + snapshot: + widths: [320, 1200] + enable-javascript: true + agent: + asset-discovery: + request-headers: + Authorization: 'Basic abc123=' + `) + + expect(config({})).to.deep.equal({ + ...DEFAULT_CONFIGURATION, + snapshot: { + ...DEFAULT_CONFIGURATION.snapshot, + 'widths': [320, 1200], + 'enable-javascript': true, + }, + agent: { + ...DEFAULT_CONFIGURATION.agent, + 'asset-discovery': { + ...DEFAULT_CONFIGURATION.agent['asset-discovery'], + 'request-headers': { + Authorization: 'Basic abc123=', + }, + }, + }, + }) + }) + + it('overrides defaults and config file options with flags and args', () => { + mkconfig('.percy.json', `{ + "version": 1, + "snapshot": { + "widths": [800] + }, + "static-snapshots": { + "path": "_wrong/", + "ignore-files": "**/*.ignore.*" + } + }`) + + const flags = { 'snapshot-files': '**/*.snapshot.html' } + const args = { snapshotDirectory: '_site/' } + + expect(config(flags, args)).to.deep.equal({ + ...DEFAULT_CONFIGURATION, + 'snapshot': { + ...DEFAULT_CONFIGURATION.snapshot, + widths: [800], + }, + 'static-snapshots': { + ...DEFAULT_CONFIGURATION['static-snapshots'], + 'path': '_site/', + 'ignore-files': '**/*.ignore.*', + 'snapshot-files': '**/*.snapshot.html', + }, + }) + }) +})