From 18fce175430e5c23df0b34af13433631f24fc0f9 Mon Sep 17 00:00:00 2001 From: Wil Wilsman Date: Mon, 28 Mar 2022 15:53:21 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Automatically=20include=20package?= =?UTF-8?q?=20information=20with=20CLI=20commands=20(#850)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cli-command/src/command.js | 3 +++ packages/cli-command/src/parse.js | 13 ++++++++++--- packages/cli-command/test/command.test.js | 22 ++++++++++++++-------- packages/cli/src/commands.js | 1 + packages/cli/test/commands.test.js | 7 +++++++ 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/packages/cli-command/src/command.js b/packages/cli-command/src/command.js index 2c2c31e04..22524fa95 100644 --- a/packages/cli-command/src/command.js +++ b/packages/cli-command/src/command.js @@ -104,6 +104,7 @@ async function runCommandWithContext(parsed) { // include flags, args, argv, logger, exit helper, and env info let context = { flags, args, argv, log, exit }; let env = context.env = process.env; + let pkg = command.packageInformation; let def = command.definition; // automatically include a preconfigured percy instance @@ -112,6 +113,8 @@ async function runCommandWithContext(parsed) { // set defaults and prune preconfiguraton options let conf = del({ server: false, ...def.percy }, 'discoveryFlags'); + if (pkg) conf.clientInfo ||= `${pkg.name}/${pkg.version}`; + conf.environmentInfo ||= `node/${process.version}`; Object.defineProperty(context, 'percy', { configurable: true, diff --git a/packages/cli-command/src/parse.js b/packages/cli-command/src/parse.js index ef211743b..4a42d1ed7 100644 --- a/packages/cli-command/src/parse.js +++ b/packages/cli-command/src/parse.js @@ -75,7 +75,7 @@ async function maybeParseCommand(input, parsed) { // Parses input to identify a flag option. Consumes input and adds to parsed output as needed, // returning true if any defined flag was found. If a found flag is missing a required argument, the // next input option will be consumed as that argument. Boolean flags support negation if their -// default value is true, integer flags are automaticaly parsed, and flags that can be provided +// default value is true, integer flags are automatically parsed, and flags that can be provided // multiple times will be concatenated together. Implicit help and version flags are also supported. async function maybeParseFlag(input, parsed) { if (!isFlag(input[0])) return; @@ -323,8 +323,15 @@ async function normalizeCommand(command, properties) { definition.commands = await definition.commands(); } - // return shallow copy with additional properties - return { ...command, ...properties, definition }; + // create a shallow copy with additional properties + let normalized = { ...command, ...properties, definition }; + + // inherit parent package information by default + normalized.packageInformation ||= ( + properties?.parent || command.parent + )?.packageInformation; + + return normalized; } // Parses and validates command-line arguments according to a command definition. diff --git a/packages/cli-command/test/command.test.js b/packages/cli-command/test/command.test.js index 8ae14f245..43a806f9f 100644 --- a/packages/cli-command/test/command.test.js +++ b/packages/cli-command/test/command.test.js @@ -112,21 +112,27 @@ describe('Command', () => { it('initializes the percy instance with provided percy options', async () => { let test = command('foo', { flags: [{ - name: 'client', - type: 'info', - percyrc: 'clientInfo' + name: 'dry', + percyrc: 'dryRun' }], percy: { - environmentInfo: 'env/456' + environmentInfo: 'env/4.5.6' } }, ({ percy }) => { - test.client = percy.client; + test.percy = percy; }); - await test(['--client', 'client/123']); + // automatic client info from package.json + test.packageInformation = { + name: 'percy-cli-sdk', + version: '1.2.3' + }; + + await test(['--dry']); - expect(test.client.clientInfo).toEqual(new Set(['client/123'])); - expect(test.client.environmentInfo).toEqual(new Set(['env/456'])); + expect(test.percy.dryRun).toBe(true); + expect(test.percy.client.clientInfo).toEqual(new Set(['percy-cli-sdk/1.2.3'])); + expect(test.percy.client.environmentInfo).toEqual(new Set(['env/4.5.6'])); }); it('handles logging unhandled action errors', async () => { diff --git a/packages/cli/src/commands.js b/packages/cli/src/commands.js index 0e85998d3..fdf8e13e1 100644 --- a/packages/cli/src/commands.js +++ b/packages/cli/src/commands.js @@ -136,6 +136,7 @@ export async function importCommands() { pkgs.set(pkg.name, () => Promise.all( pkg['@percy/cli'].commands.map(async cmdPath => { let module = await import(path.join(pkgPath, cmdPath)); + module.default.packageInformation ||= pkg; return module.default; }) )); diff --git a/packages/cli/test/commands.test.js b/packages/cli/test/commands.test.js index 5bc5e062a..0a77da352 100644 --- a/packages/cli/test/commands.test.js +++ b/packages/cli/test/commands.test.js @@ -50,6 +50,13 @@ describe('CLI commands', () => { expect(logger.stderr).toEqual([]); }); + it('automatically includes package information', async () => { + mockModuleCommands(path.resolve('.'), mockCmds); + let cmds = await importCommands(); + + expect(cmds[0].packageInformation.name).toEqual('@percy/cli-config'); + }); + it('handles errors and logs debug info', async () => { fs.$vol.fromJSON({ './node_modules': null }); fs.readdirSync.and.throwError(new Error('EACCES'));