diff --git a/packages/cli/src/commands/create/FactoryRegistry.ts b/packages/cli/src/commands/create/FactoryRegistry.ts index 0f48acc337..a959896bd0 100644 --- a/packages/cli/src/commands/create/FactoryRegistry.ts +++ b/packages/cli/src/commands/create/FactoryRegistry.ts @@ -53,24 +53,36 @@ export class FactoryRegistry { factory: AnyFactory, provided: Record, ): Promise> { - const [hasAnswers, needsAnswers] = partition( - factory.options, - option => option.name in provided, - ); + let currentOptions = provided; - for (const option of hasAnswers) { - const value = provided[option.name]; - - if (option.validate) { - const result = option.validate(value); - if (result !== true) { - throw new Error(`Invalid option '${option.name}'. ${result}`); - } - } + if (factory.optionsDiscovery) { + const discoveredOptions = await factory.optionsDiscovery(); + currentOptions = { + ...currentOptions, + ...(discoveredOptions as Record), + }; } - const answers = await inquirer.prompt(needsAnswers); + if (factory.optionsPrompts) { + const [hasAnswers, needsAnswers] = partition( + factory.optionsPrompts, + option => option.name in currentOptions, + ); - return { ...provided, ...answers }; + for (const option of hasAnswers) { + const value = provided[option.name]; + + if (option.validate) { + const result = option.validate(value); + if (result !== true) { + throw new Error(`Invalid option '${option.name}'. ${result}`); + } + } + } + + currentOptions = await inquirer.prompt(needsAnswers, currentOptions); + } + + return currentOptions; } } diff --git a/packages/cli/src/commands/create/factories/frontendPlugin.ts b/packages/cli/src/commands/create/factories/frontendPlugin.ts index 195953e780..35e18b9e09 100644 --- a/packages/cli/src/commands/create/factories/frontendPlugin.ts +++ b/packages/cli/src/commands/create/factories/frontendPlugin.ts @@ -14,20 +14,27 @@ * limitations under the License. */ +import { paths } from '../../../lib/paths'; +import { getCodeownersFilePath, parseOwnerIds } from '../../../lib/codeowners'; import { createFactory } from '../types'; type Options = { id: string; + owner?: string; + codeOwnersPath?: string; }; export const frontendPlugin = createFactory({ name: 'plugin', description: 'A new frontend plugin', - options: [ + optionsDiscovery: async () => ({ + codeOwnersPath: await getCodeownersFilePath(paths.targetRoot), + }), + optionsPrompts: [ { type: 'input', name: 'id', - message: 'Enter an ID for the plugin', + message: 'Enter an ID for the plugin [required]', validate: (value: string) => { if (!value) { return 'Please enter an ID for the plugin'; @@ -37,6 +44,24 @@ export const frontendPlugin = createFactory({ return true; }, }, + { + type: 'input', + name: 'owner', + message: 'Enter an owner of the plugin to add to CODEOWNERS [optional]', + when: opts => Boolean(opts.codeOwnersPath), + validate: (value: string) => { + if (!value) { + return true; + } + + const ownerIds = parseOwnerIds(value); + if (!ownerIds) { + return 'The owner must be a space separated list of team names (e.g. @org/team-name), usernames (e.g. @username), or the email addresses (e.g. user@example.com).'; + } + + return true; + }, + }, ], async create(options: Options) { console.log( diff --git a/packages/cli/src/commands/create/types.ts b/packages/cli/src/commands/create/types.ts index e5252df6bc..a797664e37 100644 --- a/packages/cli/src/commands/create/types.ts +++ b/packages/cli/src/commands/create/types.ts @@ -21,7 +21,8 @@ export type AnyOptions = Record; export interface Factory { name: string; description: string; - options: ReadonlyArray & { name: string }>; + optionsDiscovery?(): Promise>; + optionsPrompts?: ReadonlyArray & { name: string }>; create(options: Options): Promise; }