cli: added support for dynamically discovering create options

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2021-11-12 11:22:30 +01:00
parent e607456dbc
commit 2ca3f5ff4c
3 changed files with 56 additions and 18 deletions
@@ -53,24 +53,36 @@ export class FactoryRegistry {
factory: AnyFactory,
provided: Record<string, string>,
): Promise<Record<string, string>> {
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<string, string>),
};
}
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;
}
}
@@ -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<Options>({
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<Options>({
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(
+2 -1
View File
@@ -21,7 +21,8 @@ export type AnyOptions = Record<string, string>;
export interface Factory<Options extends AnyOptions> {
name: string;
description: string;
options: ReadonlyArray<DistinctQuestion<Options> & { name: string }>;
optionsDiscovery?(): Promise<Partial<Options>>;
optionsPrompts?: ReadonlyArray<DistinctQuestion<Options> & { name: string }>;
create(options: Options): Promise<void>;
}