Skip to content

Commit

Permalink
feat(cli): allow default command options to be specified in .diezrc (#84
Browse files Browse the repository at this point in the history
)
  • Loading branch information
stristr committed May 11, 2019
1 parent 63a2b48 commit 0e8a1bb
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 8 deletions.
8 changes: 8 additions & 0 deletions packages/cli-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ export interface TargetBinding {
[targetName: string]: string;
}

/**
* Config-style default command options for `.diezrc`.
*/
export interface CliDefaultOptions {
[command: string]: any;
}

/**
* The full Diez configuration.
*/
Expand All @@ -108,6 +115,7 @@ export interface FullDiezConfiguration {
extensions: Iterable<string>;
targets: Iterable<string>;
}>;
commandOptions: CliDefaultOptions;
}

/**
Expand Down
25 changes: 19 additions & 6 deletions packages/cli-core/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
import {args, command, help, on, parse, version} from 'commander';
import packageJson from 'package-json';
import semver from 'semver';
import {CliCommandExtension, CliCommandOption, CliCommandProvider, CliOptionValidator, ValidatedCommand} from './api';
import {
CliCommandExtension,
CliCommandOption,
CliCommandProvider,
CliDefaultOptions,
CliOptionValidator,
ValidatedCommand,
} from './api';
import {fatalError, warning} from './reporting';
import {cliRequire, diezVersion, findPlugins} from './utils';

Expand Down Expand Up @@ -35,7 +42,7 @@ const registerOptions = (validatedCommand: ValidatedCommand, options?: CliComman
* Registers a command from its provider.
* @internal
*/
const registerWithProvider = async (provider: CliCommandProvider) => {
const registerWithProvider = async (provider: CliCommandProvider, defaultOptions?: any) => {
if (provider.preinstall) {
await provider.preinstall();
}
Expand All @@ -44,10 +51,11 @@ const registerWithProvider = async (provider: CliCommandProvider) => {

const registeredCommand = command(provider.name).action(async (...options: any[]) => {
try {
const commandWithDefaults = Object.assign({}, defaultOptions, registeredCommand);
for (const validator of validators) {
await validator(registeredCommand);
await validator(commandWithDefaults);
}
await provider.action.call(undefined, registeredCommand, ...options);
await provider.action.call(undefined, commandWithDefaults, ...options);
} catch (error) {
fatalError(error.message);
}
Expand All @@ -74,6 +82,7 @@ const registerWithProvider = async (provider: CliCommandProvider) => {
const registerWithProviders = async (
registry: Map<string, ValidatedCommand>,
plugin: string,
options: CliDefaultOptions,
providers?: Iterable<string>,
) => {
if (!providers) {
Expand All @@ -88,7 +97,7 @@ const registerWithProviders = async (
continue;
}

registry.set(provider.name, await registerWithProvider(provider));
registry.set(provider.name, await registerWithProvider(provider, options[provider.name]));
} catch (error) {
warning(`An invalid command provider was specified at ${path}.`);
}
Expand All @@ -112,12 +121,16 @@ export const bootstrap = async (rootPackageName = global.process.cwd(), bootstra
const plugins = await findPlugins(rootPackageName, bootstrapRoot);
const registeredCommands = new Map<string, ValidatedCommand>();
const deferredExtensions: CliCommandExtension[] = [];
const options: CliDefaultOptions = {};
if (plugins.has('.')) {
Object.assign(options, plugins.get('.')!.commandOptions);
}
for (const [plugin, {providers}] of plugins) {
if (!providers) {
continue;
}

await registerWithProviders(registeredCommands, plugin, providers.commands);
await registerWithProviders(registeredCommands, plugin, options, providers.commands);

if (!providers.extensions) {
continue;
Expand Down
4 changes: 3 additions & 1 deletion packages/cli-core/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ describe('cli', () => {
});

test('command e2e', async () => {
process.argv = ['node', 'diez', 'foobar', '--stringParam', 'foo', '--booleanParam'];
// "booleanParam": true is provided in `.diezrc` of ./fixtures/starting-point
// "stringParam": "baz" is provided in `.diezrc`, but overridden at calltime
process.argv = ['node', 'diez', 'foobar', '--stringParam', 'foo'];
mockAction.mockRejectedValueOnce('<fake error>');
await run();
expect(mockAction).toHaveBeenCalled();
Expand Down
6 changes: 6 additions & 0 deletions packages/cli-core/test/fixtures/starting-point/.diezrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,11 @@
"extensions": [
"./does/not/exist"
]
},
"commandOptions": {
"foobar": {
"booleanParam": true,
"stringParam": "baz"
}
}
}
4 changes: 3 additions & 1 deletion packages/cli-core/test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {cleanupMockOsData, mockOsData} from '@diez/test-utils';
import {join} from 'path';
import {execAsync, findPlugins, isMacOS} from '../src/utils';
import {canRunCommand, execAsync, findPlugins, isMacOS} from '../src/utils';

jest.mock('os');
jest.unmock('fs-extra');
Expand All @@ -17,7 +17,9 @@ describe('utils', () => {

test('execAsync', async () => {
await expect(execAsync('nonexistentcommand')).rejects.toThrow();
expect(await canRunCommand('nonexistentcommand')).toBe(false);
expect(await execAsync('echo " foobar "')).toBe('foobar');
expect(await canRunCommand('echo " foobar "')).toBe(true);
});

test('isMacOS', async () => {
Expand Down

0 comments on commit 0e8a1bb

Please sign in to comment.