diff --git a/packages/cli-config/README.md b/packages/cli-config/README.md index 4a083447a..a3068ae69 100644 --- a/packages/cli-config/README.md +++ b/packages/cli-config/README.md @@ -5,29 +5,35 @@ Percy configuration files. ## Commands -* [`percy config:create [FILEPATH]`](#percy-configcreate-filepath) -* [`percy config:migrate [FILEPATH] [OUTPUT]`](#percy-configmigrate-filepath-output) -* [`percy config:validate [FILEPATH]`](#percy-configvalidate-filepath) +* [`percy config:create`](#percy-configcreate) +* [`percy config:validate`](#percy-configvalidate) +* [`percy config:migrate`](#percy-configmigrate) -## `percy config:create [FILEPATH]` +### `percy config:create` Create a Percy config file ``` -USAGE - $ percy config:create [FILEPATH] - -ARGUMENTS - FILEPATH config filepath - -OPTIONS - --js create a .percy.js file - --json create a .percy.json file - --rc create a .percyrc file - --yaml create a .percy.yaml file - --yml create a .percy.yml file - -EXAMPLES +Usage: + $ percy config:create [options] [filepath] + +Arguments: + filepath Optional config filepath + +Options: + --rc Create a .percyrc file + --yaml Create a .percy.yaml file + --yml Create a .percy.yml file + --json Create a .percy.json file + --js Create a .percy.js file + +Global options: + -v, --verbose Log everything + -q, --quiet Log errors only + -s, --silent Log nothing + -h, --help Display command help + +Examples: $ percy config:create $ percy config:create --yaml $ percy config:create --json @@ -36,41 +42,53 @@ EXAMPLES $ percy config:create ./config/percy.yml ``` -## `percy config:migrate [FILEPATH] [OUTPUT]` +### `percy config:validate` -Migrate a Percy config file to the latest version +Validate a Percy config file ``` -USAGE - $ percy config:migrate [FILEPATH] [OUTPUT] +Usage: + $ percy config:validate [options] [filepath] -ARGUMENTS - FILEPATH current config filepath, detected by default - OUTPUT new config filepath to write to, defaults to FILEPATH +Arguments: + filepath Config filepath, detected by default -OPTIONS - -d, --dry-run prints the new config rather than writing it +Global options: + -v, --verbose Log everything + -q, --quiet Log errors only + -s, --silent Log nothing + -h, --help Display command help -EXAMPLES - $ percy config:migrate - $ percy config:migrate --dry-run - $ percy config:migrate ./config/percy.yml - $ percy config:migrate .percy.yml .percy.js +Examples: + $ percy config:validate + $ percy config:validate ./config/percy.yml ``` -## `percy config:validate [FILEPATH]` +### `percy config:migrate` -Validate a Percy config file +Migrate a Percy config file to the latest version ``` -USAGE - $ percy config:validate [FILEPATH] +Usage: + $ percy config:migrate [options] [filepath] [output] -ARGUMENTS - FILEPATH config filepath, detected by default +Arguments: + filepath Current config filepath, detected by default + output New config filepath to write to, defaults to 'filepath' -EXAMPLES - $ percy config:validate - $ percy config:validate ./config/percy.yml +Options: + -d, --dry-run Print the new config without writing it + +Global options: + -v, --verbose Log everything + -q, --quiet Log errors only + -s, --silent Log nothing + -h, --help Display command help + +Examples: + $ percy config:migrate + $ percy config:migrate --dry-run + $ percy config:migrate ./config/percy.yml + $ percy config:migrate .percy.yml .percy.js ``` diff --git a/packages/cli-config/package.json b/packages/cli-config/package.json index 5c67be6ac..21b50c4f4 100644 --- a/packages/cli-config/package.json +++ b/packages/cli-config/package.json @@ -2,10 +2,17 @@ "name": "@percy/cli-config", "version": "1.0.0-beta.71", "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/percy/cli", + "directory": "packages/cli-config" + }, + "publishConfig": { + "access": "public" + }, "main": "dist/index.js", "files": [ - "dist", - "oclif.manifest.json" + "dist" ], "engines": { "node": ">=12" @@ -13,32 +20,17 @@ "scripts": { "build": "node ../../scripts/build", "lint": "eslint --ignore-path ../../.gitignore .", - "postbuild": "oclif-dev manifest", - "readme": "oclif-dev readme", + "readme": "percy-cli-readme", "test": "node ../../scripts/test", "test:coverage": "yarn test --coverage" }, - "publishConfig": { - "access": "public" - }, - "oclif": { - "bin": "percy", - "commands": "./dist/commands", - "topics": { - "config": { - "description": "manage Percy config files" - } - } + "@percy/cli": { + "commands": [ + "./dist/config.js" + ] }, "dependencies": { - "@oclif/command": "^1.8.0", - "@oclif/config": "^1.17.0", - "@percy/config": "1.0.0-beta.71", - "@percy/logger": "1.0.0-beta.71" - }, - "repository": { - "type": "git", - "url": "https://github.com/percy/cli", - "directory": "packages/cli-config" + "@percy/cli-command": "1.0.0-beta.71", + "@percy/config": "1.0.0-beta.71" } } diff --git a/packages/cli-config/src/commands/config/create.js b/packages/cli-config/src/commands/config/create.js deleted file mode 100644 index 13d56ab3f..000000000 --- a/packages/cli-config/src/commands/config/create.js +++ /dev/null @@ -1,88 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import Command, { flags } from '@oclif/command'; -import PercyConfig from '@percy/config'; -import logger from '@percy/logger'; - -const FILETYPES = ['rc', 'yaml', 'yml', 'json', 'js']; - -export class Create extends Command { - static description = 'Create a Percy config file'; - - static flags = { - rc: flags.boolean({ - description: 'create a .percyrc file', - exclusive: FILETYPES.filter(t => t !== 'rc') - }), - yaml: flags.boolean({ - description: 'create a .percy.yaml file', - exclusive: FILETYPES.filter(t => t !== 'yaml') - }), - yml: flags.boolean({ - description: 'create a .percy.yml file', - exclusive: FILETYPES.filter(t => t !== 'yml') - }), - json: flags.boolean({ - description: 'create a .percy.json file', - exclusive: FILETYPES.filter(t => t !== 'json') - }), - js: flags.boolean({ - description: 'create a .percy.js file', - exclusive: FILETYPES.filter(t => t !== 'js') - }) - }; - - static args = [{ - name: 'filepath', - description: 'config filepath' - }]; - - static examples = [ - '$ percy config:create', - '$ percy config:create --yaml', - '$ percy config:create --json', - '$ percy config:create --js', - '$ percy config:create --rc', - '$ percy config:create ./config/percy.yml' - ]; - - log = logger('cli:config:create'); - - async run() { - let { flags, args } = this.parse(); - logger.loglevel('info'); - - // discern the filetype - let filetype = args.filepath - ? path.extname(args.filepath).replace(/^./, '') - : FILETYPES.find(t => flags[t]) ?? 'yml'; - - // validate the filetype for filepaths - if (!FILETYPES.includes(filetype)) { - this.log.error(`Unsupported filetype: ${filetype}`); - return this.exit(1); - } - - // discern the appropriate filename - let filepath = args.filepath || ({ - rc: '.percyrc', - yaml: '.percy.yaml', - yml: '.percy.yml', - json: '.percy.json', - js: '.percy.js' - })[filetype]; - - // validate the file does not already exist - if (fs.existsSync(filepath)) { - this.log.error(`Percy config already exists: ${filepath}`); - return this.exit(1); - } - - // discern the file format - let format = ['rc', 'yaml', 'yml'].includes(filetype) ? 'yaml' : filetype; - - // write stringified default config options to the filepath - fs.writeFileSync(filepath, PercyConfig.stringify(format)); - this.log.info(`Created Percy config: ${filepath}`); - } -} diff --git a/packages/cli-config/src/commands/config/migrate.js b/packages/cli-config/src/commands/config/migrate.js deleted file mode 100644 index a063a12ae..000000000 --- a/packages/cli-config/src/commands/config/migrate.js +++ /dev/null @@ -1,100 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import Command, { flags } from '@oclif/command'; -import PercyConfig from '@percy/config'; -import logger from '@percy/logger'; - -export class Migrate extends Command { - static description = 'Migrate a Percy config file to the latest version'; - - static args = [{ - name: 'filepath', - description: 'current config filepath, detected by default' - }, { - name: 'output', - description: 'new config filepath to write to, defaults to FILEPATH' - }]; - - static flags = { - 'dry-run': flags.boolean({ - char: 'd', - description: 'prints the new config rather than writing it' - }) - }; - - static examples = [ - '$ percy config:migrate', - '$ percy config:migrate --dry-run', - '$ percy config:migrate ./config/percy.yml', - '$ percy config:migrate .percy.yml .percy.js' - ]; - - log = logger('cli:config:migrate'); - - async run() { - let config; - - let { - args: { filepath: input, output }, - flags: { 'dry-run': dry } - } = this.parse(); - - try { - ({ config, filepath: input } = PercyConfig.search(input)); - } catch (error) { - this.log.error(error); - this.exit(1); - } - - if (config) { - this.log.info(`Found config file: ${path.relative('', input)}`); - output = output ? path.resolve(output) : input; - } else { - this.log.error('Config file not found'); - this.exit(1); - } - - // if migrating versions, warn when latest - if (input === output && config.version === 2) { - this.log.warn('Config is already the latest version'); - return; - } - - // migrate config - this.log.info('Migrating config file...'); - let format = path.extname(output).replace(/^./, '') || 'yaml'; - let migrated = PercyConfig.migrate(config); - - // prefer kebab-case for yaml - if (/^ya?ml$/.test(format)) { - migrated = PercyConfig.normalize(migrated, { - schema: '/config', - kebab: true - }); - } - - // stringify to the desired format - let body = PercyConfig.stringify(format, migrated); - - if (!dry) { - let content = body; - - // update the package.json entry by requiring it and modifying it - if (path.basename(output) === 'package.json') { - let pkg = JSON.parse(fs.readFileSync(output)); - content = PercyConfig.stringify(format, { ...pkg, percy: migrated }); - // rename input if it is the output - } else if (input === output) { - let old = input.replace(path.extname(input), '.old$&'); - fs.renameSync(input, old); - } - - // write to output - fs.writeFileSync(output, content); - } - - this.log.info('Config file migrated!'); - // when dry-running, print config to stdout when finished - if (dry) logger.stdout.write('\n' + body); - } -} diff --git a/packages/cli-config/src/commands/config/validate.js b/packages/cli-config/src/commands/config/validate.js deleted file mode 100644 index c7b4d4e14..000000000 --- a/packages/cli-config/src/commands/config/validate.js +++ /dev/null @@ -1,26 +0,0 @@ -import Command from '@oclif/command'; -import PercyConfig from '@percy/config'; -import logger from '@percy/logger'; - -export class Validate extends Command { - static description = 'Validate a Percy config file'; - - static args = [{ - name: 'filepath', - description: 'config filepath, detected by default' - }]; - - static examples = [ - '$ percy config:validate', - '$ percy config:validate ./config/percy.yml' - ]; - - log = logger('cli:config:validate'); - - async run() { - let { args: { filepath: path } } = this.parse(); - // when `bail` is true, #load() returns undefined on validation warnings - let config = PercyConfig.load({ path, bail: true, print: true }); - if (!config) this.exit(1); - } -} diff --git a/packages/cli-config/src/config.js b/packages/cli-config/src/config.js new file mode 100644 index 000000000..5ebcd91b8 --- /dev/null +++ b/packages/cli-config/src/config.js @@ -0,0 +1,12 @@ +import command from '@percy/cli-command'; + +import create from './create'; +import validate from './validate'; +import migrate from './migrate'; + +export const config = command('config', { + description: 'Manage Percy config files', + commands: [create, validate, migrate] +}); + +export default config; diff --git a/packages/cli-config/src/create.js b/packages/cli-config/src/create.js new file mode 100644 index 000000000..467ea0c8e --- /dev/null +++ b/packages/cli-config/src/create.js @@ -0,0 +1,87 @@ +import fs from 'fs'; +import path from 'path'; +import command from '@percy/cli-command'; + +const DEFAULT_FILES = { + rc: '.percyrc', + yaml: '.percy.yaml', + yml: '.percy.yml', + json: '.percy.json', + js: '.percy.js' +}; + +const FILETYPES = Object.keys( + DEFAULT_FILES +); + +export const create = command('create', { + description: 'Create a Percy config file', + + args: [{ + name: 'filepath', + description: 'Optional config filepath' + }], + + flags: [{ + name: 'rc', + description: 'Create a .percyrc file', + conflicts: FILETYPES.filter(t => t !== 'rc'), + type: 'boolean' + }, { + name: 'yaml', + description: 'Create a .percy.yaml file', + conflicts: FILETYPES.filter(t => t !== 'yaml'), + type: 'boolean' + }, { + name: 'yml', + description: 'Create a .percy.yml file', + conflicts: FILETYPES.filter(t => t !== 'yml'), + type: 'boolean' + }, { + name: 'json', + description: 'Create a .percy.json file', + conflicts: FILETYPES.filter(t => t !== 'json'), + type: 'boolean' + }, { + name: 'js', + description: 'Create a .percy.js file', + conflicts: FILETYPES.filter(t => t !== 'js'), + type: 'boolean' + }], + + examples: [ + '$0', + '$0 --yaml', + '$0 --json', + '$0 --js', + '$0 --rc', + '$0 ./config/percy.yml' + ] +}, async ({ flags, args, log, exit }) => { + let PercyConfig = await import('@percy/config'); + + // discern the filetype + let filetype = args.filepath + ? path.extname(args.filepath).replace(/^./, '') + : FILETYPES.find(t => flags[t]) ?? 'yml'; + + // verify the filetype is supported + if (!DEFAULT_FILES[filetype]) { + exit(1, `Unsupported filetype: ${filetype}`); + } + + // default filepath based on filetype + let filepath = args.filepath || DEFAULT_FILES[filetype]; + + // verify the file does not already exist + if (fs.existsSync(filepath)) { + exit(1, `Percy config already exists: ${filepath}`); + } + + // write stringified default config options to the filepath + let format = ['rc', 'yaml', 'yml'].includes(filetype) ? 'yaml' : filetype; + fs.writeFileSync(filepath, PercyConfig.stringify(format)); + log.info(`Created Percy config: ${filepath}`); +}); + +export default create; diff --git a/packages/cli-config/src/index.js b/packages/cli-config/src/index.js index 1c53e4adf..db08333ce 100644 --- a/packages/cli-config/src/index.js +++ b/packages/cli-config/src/index.js @@ -1,5 +1,4 @@ -const { Create } = require('./commands/config/create'); -const { Migrate } = require('./commands/config/migrate'); -const { Validate } = require('./commands/config/validate'); - -module.exports = { Create, Migrate, Validate }; +export { default, config } from './config'; +export { create } from './create'; +export { validate } from './validate'; +export { migrate } from './migrate'; diff --git a/packages/cli-config/src/migrate.js b/packages/cli-config/src/migrate.js new file mode 100644 index 000000000..c352c4d68 --- /dev/null +++ b/packages/cli-config/src/migrate.js @@ -0,0 +1,83 @@ +import fs from 'fs'; +import path from 'path'; +import command from '@percy/cli-command'; + +export const migrate = command('migrate', { + description: 'Migrate a Percy config file to the latest version', + + args: [{ + name: 'filepath', + description: 'Current config filepath, detected by default' + }, { + name: 'output', + description: 'New config filepath to write to, defaults to \'filepath\'' + }], + + flags: [{ + name: 'dry-run', + description: 'Print the new config without writing it', + short: 'd' + }], + + examples: [ + '$0', + '$0 --dry-run', + '$0 ./config/percy.yml', + '$0 .percy.yml .percy.js' + ] +}, async ({ args, flags, log, exit }) => { + let PercyConfig = await import('@percy/config'); + + let { config, filepath: input } = PercyConfig.search(args.filepath); + let output = args.output ? path.resolve(args.output) : input; + + if (!config) exit(1, 'Config file not found'); + log.info(`Found config file: ${path.relative('', input)}`); + + // if migrating versions, warn when latest + if (input === output && config.version === 2) { + exit(0, 'Config is already the latest version'); + } + + // migrate config + log.info('Migrating config file...'); + let format = path.extname(output).replace(/^./, '') || 'yaml'; + let migrated = PercyConfig.migrate(config); + + // prefer kebab-case for yaml + if (/^ya?ml$/.test(format)) { + migrated = PercyConfig.normalize(migrated, { + schema: '/config', + kebab: true + }); + } + + // stringify to the desired format + let body = PercyConfig.stringify(format, migrated); + + if (!flags.dryRun) { + let content = body; + + if (path.basename(output) === 'package.json') { + // update the package.json entry by reading and modifying it + let pkg = JSON.parse(fs.readFileSync(output)); + content = PercyConfig.stringify(format, { ...pkg, percy: migrated }); + } else if (input === output) { + // rename input if it is the output + let old = input.replace(path.extname(input), '.old$&'); + fs.renameSync(input, old); + } + + // write to output + fs.writeFileSync(output, content); + } + + log.info('Config file migrated!'); + + // when dry-running, print config to stdout when finished + if (flags.dryRun) { + log.stdout.write('\n' + body); + } +}); + +export default migrate; diff --git a/packages/cli-config/src/validate.js b/packages/cli-config/src/validate.js new file mode 100644 index 000000000..11bf44ead --- /dev/null +++ b/packages/cli-config/src/validate.js @@ -0,0 +1,33 @@ +import command from '@percy/cli-command'; + +export const validate = command('validate', { + description: 'Validate a Percy config file', + + args: [{ + name: 'filepath', + description: 'Config filepath, detected by default' + }], + + examples: [ + '$0', + '$0 ./config/percy.yml' + ] +}, async ({ args, log, exit }) => { + let PercyConfig = await import('@percy/config'); + + // verify a config file can be located + let { config, filepath } = PercyConfig.search(args.filepath); + if (!config) exit(1, 'Config file not found'); + + // when `bail` is true, .load() returns undefined when validation fails + let result = PercyConfig.load({ + path: filepath, + print: true, + bail: true + }); + + // exit 1 when config is empty + if (!result) exit(1); +}); + +export default validate; diff --git a/packages/cli-config/test/create.test.js b/packages/cli-config/test/create.test.js index 4019f9e13..0957d3d7a 100644 --- a/packages/cli-config/test/create.test.js +++ b/packages/cli-config/test/create.test.js @@ -1,46 +1,46 @@ import path from 'path'; import { logger, getMockConfig } from './helpers'; -import { Create } from '../src/commands/config/create'; import PercyConfig from '@percy/config'; +import create from '../src/create'; describe('percy config:create', () => { it('creates a .percy.yml config file by default', async () => { - await Create.run([]); + await create(); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual(['[percy] Created Percy config: .percy.yml']); expect(getMockConfig('.percy.yml')).toBe(PercyConfig.stringify('yaml')); }); it('can create a .percyrc config file', async () => { - await Create.run(['--rc']); + await create(['--rc']); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual(['[percy] Created Percy config: .percyrc']); expect(getMockConfig('.percyrc')).toBe(PercyConfig.stringify('yaml')); }); it('can create a .percy.yaml config file', async () => { - await Create.run(['--yaml']); + await create(['--yaml']); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual(['[percy] Created Percy config: .percy.yaml']); expect(getMockConfig('.percy.yaml')).toBe(PercyConfig.stringify('yaml')); }); it('can create a .percy.yml config file', async () => { - await Create.run(['--yml']); + await create(['--yml']); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual(['[percy] Created Percy config: .percy.yml']); expect(getMockConfig('.percy.yml')).toBe(PercyConfig.stringify('yaml')); }); it('can create a .percy.json config file', async () => { - await Create.run(['--json']); + await create(['--json']); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual(['[percy] Created Percy config: .percy.json']); expect(getMockConfig('.percy.json')).toBe(PercyConfig.stringify('json')); }); it('can create a .percy.js config file', async () => { - await Create.run(['--js']); + await create(['--js']); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual(['[percy] Created Percy config: .percy.js']); expect(getMockConfig('.percy.js')).toBe(PercyConfig.stringify('js')); @@ -48,25 +48,29 @@ describe('percy config:create', () => { it('can create specific config files', async () => { let filename = path.join('.config', 'percy.config.js'); - await Create.run([filename]); + await create([filename]); + expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual([`[percy] Created Percy config: ${filename}`]); expect(getMockConfig(filename)).toBe(PercyConfig.stringify('js')); }); - it('logs an error and exits when the filetype is unsupported', async () => { - await expectAsync(Create.run([path.join('.config', 'percy.config.php')])).toBeRejectedWithError('EEXIT: 1'); + it('errors when the filetype is unsupported', async () => { + await expectAsync( + create([path.join('.config', 'percy.config.php')]) + ).toBeRejected(); + expect(logger.stdout).toEqual([]); - expect(logger.stderr).toEqual(['[percy] Unsupported filetype: php']); + expect(logger.stderr).toEqual(['[percy] Error: Unsupported filetype: php']); }); - it('logs an error and exits when the config file already exists', async () => { - await Create.run(['.percy.yml']); + it('errors when the config file already exists', async () => { + await create(['.percy.yml']); logger.reset(); - await expectAsync(Create.run(['.percy.yml'])).toBeRejectedWithError('EEXIT: 1'); + await expectAsync(create(['.percy.yml'])).toBeRejected(); expect(logger.stdout).toEqual([]); - expect(logger.stderr).toEqual(['[percy] Percy config already exists: .percy.yml']); + expect(logger.stderr).toEqual(['[percy] Error: Percy config already exists: .percy.yml']); }); }); diff --git a/packages/cli-config/test/helpers.js b/packages/cli-config/test/helpers.js index fc0c4def7..9651d9a1c 100644 --- a/packages/cli-config/test/helpers.js +++ b/packages/cli-config/test/helpers.js @@ -1,5 +1,4 @@ // required before fs is mocked by the config helper -import '@oclif/command'; import logger from '@percy/logger/test/helpers'; beforeEach(() => { diff --git a/packages/cli-config/test/migrate.test.js b/packages/cli-config/test/migrate.test.js index 6f9f21e24..c54075b57 100644 --- a/packages/cli-config/test/migrate.test.js +++ b/packages/cli-config/test/migrate.test.js @@ -1,10 +1,10 @@ import path from 'path'; -import PercyConfig from '@percy/config'; import { logger, mockConfig, getMockConfig } from './helpers'; -import { Migrate } from '../src/commands/config/migrate'; +import PercyConfig from '@percy/config'; +import migrate from '../src/migrate'; describe('percy config:migrate', () => { - beforeEach(() => { + beforeEach(async () => { mockConfig('.percy.yml', 'version: 1\n'); PercyConfig.addMigration((config, util) => { if (config.migrate) util.map('migrate', 'migrated', v => v.replace('old', 'new')); @@ -16,7 +16,7 @@ describe('percy config:migrate', () => { }); it('by default, renames the config before writing', async () => { - await Migrate.run([]); + await migrate(); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual([ @@ -30,7 +30,8 @@ describe('percy config:migrate', () => { }); it('prints config with the --dry-run flag', async () => { - await Migrate.run(['--dry-run']); + await migrate(['--dry-run']); + expect(getMockConfig('.percy.yml')).toContain('version: 1'); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual([ @@ -43,7 +44,8 @@ describe('percy config:migrate', () => { it('works with rc configs', async () => { mockConfig('.percyrc', 'version: 1\n'); - await Migrate.run(['.percyrc']); + await migrate(['.percyrc']); + expect(getMockConfig('.percyrc')).toEqual('version: 2\n'); }); @@ -62,7 +64,7 @@ describe('percy config:migrate', () => { // this is mocked and reflected in `getMockConfig` require('fs').writeFileSync('package.json', json(pkg)); - await Migrate.run(['package.json']); + await migrate(['package.json']); expect(getMockConfig('package.json')).toEqual( json({ ...pkg, percy: { version: 2 } }) @@ -70,28 +72,28 @@ describe('percy config:migrate', () => { }); it('can convert between config types', async () => { - await Migrate.run(['.percy.yml', '.percy.js']); + await migrate(['.percy.yml', '.percy.js']); + expect(getMockConfig('.percy.js')) .toEqual('module.exports = {\n version: 2\n}\n'); }); - it('errors and exits when a config cannot be found', async () => { - await expectAsync(Migrate.run([path.join('.config', 'percy.yml')])).toBeRejectedWithError('EEXIT: 1'); + it('errors when a config cannot be found', async () => { + await expectAsync( + migrate([path.join('.config', 'percy.yml')]) + ).toBeRejected(); expect(logger.stdout).toEqual([]); expect(logger.stderr).toEqual([ - '[percy] Config file not found' + '[percy] Error: Config file not found' ]); }); - it('errors and exits when a config cannot be parsed', async () => { + it('errors when a config cannot be parsed', async () => { let filename = path.join('.config', 'percy.yml'); + mockConfig(filename, () => { throw new Error('test'); }); - mockConfig(filename, () => { - throw new Error('test'); - }); - - await expectAsync(Migrate.run([filename])).toBeRejectedWithError('EEXIT: 1'); + await expectAsync(migrate([filename])).toBeRejected(); expect(logger.stdout).toEqual([]); expect(logger.stderr).toEqual([ @@ -101,7 +103,7 @@ describe('percy config:migrate', () => { it('warns when a config is already the latest version', async () => { mockConfig('.percy.yml', 'version: 2\n'); - await Migrate.run([]); + await migrate(); expect(logger.stdout).toEqual([ '[percy] Found config file: .percy.yml' @@ -119,7 +121,7 @@ describe('percy config:migrate', () => { 'migrate: old-value' ].join('\n')); - await Migrate.run([]); + await migrate(); expect(getMockConfig('.percy.yml')).toEqual([ 'version: 2', diff --git a/packages/cli-config/test/validate.test.js b/packages/cli-config/test/validate.test.js index 45bd79554..64edf07a5 100644 --- a/packages/cli-config/test/validate.test.js +++ b/packages/cli-config/test/validate.test.js @@ -1,7 +1,7 @@ import path from 'path'; import { logger, mockConfig } from './helpers'; -import { Validate } from '../src/commands/config/validate'; import PercyConfig from '@percy/config'; +import validate from '../src/validate'; describe('percy config:validate', () => { beforeEach(() => { @@ -26,7 +26,7 @@ describe('percy config:validate', () => { it('logs debug info for a valid config file', async () => { mockConfig('.percy.yml', 'version: 2\ntest:\n value: percy'); - await Validate.run([]); + await validate(); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual([ @@ -45,7 +45,7 @@ describe('percy config:validate', () => { it('logs debug info for a provided valid config file', async () => { let filename = path.join('.config', 'percy.yml'); mockConfig(filename, 'version: 2\ntest:\n value: config'); - await Validate.run([filename]); + await validate([filename]); expect(logger.stderr).toEqual([]); expect(logger.stdout).toEqual([ @@ -61,9 +61,9 @@ describe('percy config:validate', () => { ]); }); - it('logs an error and exits for invalid or unkown config options', async () => { + it('errors with invalid or unkown config options', async () => { mockConfig('.invalid.yml', 'version: 2\ntest:\n value: false\nbar: baz'); - await expectAsync(Validate.run(['.invalid.yml'])).toBeRejectedWithError('EEXIT: 1'); + await expectAsync(validate(['.invalid.yml'])).toBeRejected(); expect(logger.stdout).toEqual([ '[percy] Found config file: .invalid.yml' @@ -74,4 +74,13 @@ describe('percy config:validate', () => { '[percy] - test.value: must be a string, received a boolean' ]); }); + + it('errors when a config cannot be found', async () => { + await expectAsync(validate(['.404.yml'])).toBeRejected(); + + expect(logger.stdout).toEqual([]); + expect(logger.stderr).toEqual([ + '[percy] Error: Config file not found' + ]); + }); });