Skip to content

Commit

Permalink
feat(app-builder): allow passing custom root command via command line
Browse files Browse the repository at this point in the history
  • Loading branch information
EdieLemoine committed Oct 16, 2023
1 parent c5bf728 commit 44689f6
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 26 deletions.
5 changes: 4 additions & 1 deletion apps/app-builder/src/commands/upgrade/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export type UpgradeCommandArgs = CommandArgs & {
lockfile?: string;
};

export type InputUpgradeCommandArgs = MakeOptional<UpgradeCommandArgs, 'composerCommand' | 'yarnCommand'>;
export type InputUpgradeCommandArgs = MakeOptional<
UpgradeCommandArgs,
'composerCommand' | 'yarnCommand' | 'rootCommand'
>;

export interface UpgradeSubContext {
args: UpgradeCommandArgs;
Expand Down
39 changes: 26 additions & 13 deletions apps/app-builder/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ const ALL_BULK_COMMANDS = [
[COMMAND_BUILD_NAME, BUILD_COMMANDS],
] as const;

const BULK_COMMAND_OPTIONS = [OPTION_DRY_RUN, OPTION_PARALLEL, OPTION_VERBOSITY, OPTION_QUIET, OPTION_VERSION] as const;

const CONFIG_OPTIONS = [['--root-command <command>', 'Root command', '']] as const;

// eslint-disable-next-line max-lines-per-function
export const run = (env: LiftoffEnv, argv: string[]): void => {
const withContext = createWithContext(env, argv);
Expand All @@ -141,22 +145,30 @@ export const run = (env: LiftoffEnv, argv: string[]): void => {

WITHOUT_CONFIG_COMMANDS.forEach((definition) => registerCommand(definition, withContext));

CONFIG_COMMANDS.forEach((definition) => registerCommand(definition, withConfig));
CONFIG_COMMANDS.forEach((definition) => {
registerCommand(
{
...definition,
options: [...CONFIG_OPTIONS, ...(definition.options ?? [])],
},
withConfig,
);
});

ALL_BULK_COMMANDS.forEach(([commandName, commands]) => {
program
const command = program
.command(commandName)
.description(`Run ${commands.map(({name}) => name).join(', ')} in sequence. ${REQUIRES_CONFIG_FILE}`)
.option(...OPTION_DRY_RUN)
.option(...OPTION_PARALLEL)
.option(...OPTION_VERBOSITY)
.option(...OPTION_QUIET)
.option(...OPTION_VERSION)
.action(async (...args) => {
for (const command of commands) {
await withConfig(command)(...args);
}
});
.description(`Run ${commands.map(({name}) => name).join(', ')} in sequence. ${REQUIRES_CONFIG_FILE}`);

// @ts-expect-error todo
BULK_COMMAND_OPTIONS.forEach((option) => command.option(...option));
CONFIG_OPTIONS.forEach((option) => command.option(...option));

command.action(async (...args) => {
for (const command of commands) {
await withConfig(command)(...args);
}
});
});

void (async () => {
Expand All @@ -166,6 +178,7 @@ export const run = (env: LiftoffEnv, argv: string[]): void => {
config.additionalCommands?.forEach((definition) => {
const resolvedDefinition = {
...definition,
options: [...CONFIG_OPTIONS, ...(definition.options ?? [])],
action: () => Promise.resolve({default: definition.action}),
};

Expand Down
2 changes: 0 additions & 2 deletions apps/app-builder/src/types/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ export type WithContextParams = <A extends AnyCommandArgs>(
context: Omit<PdkBuilderContext<A>, 'config'>,
) => Promise<void> | void;

export type WithConfigParams = <A extends AnyCommandArgs>(context: PdkBuilderContext<A>) => Promise<void> | void;

export type CommandCb = (...args: CommandArguments) => void | Promise<void>;

export type CreateHook<A = PdkBuilderContext> = (
Expand Down
5 changes: 5 additions & 0 deletions apps/app-builder/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ export type PdkBuilderConfig = {
*/
composerCommand?: OneOrMore<string>;

/**
* Command to prepend to all commands.
*/
rootCommand?: OneOrMore<string>;

/**
* Translations configuration.
*/
Expand Down
9 changes: 9 additions & 0 deletions apps/app-builder/src/utils/createCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {type OneOrMore, toArray} from '@myparcel/ts-utils';
import {type PdkBuilderConfig} from '../types';

export const createCommand = (config: PdkBuilderConfig, command: OneOrMore<string>): string => {
const resolvedRootCommand = toArray(config.rootCommand ?? []);
const resolvedCommand = toArray(command ?? []);

return [...resolvedRootCommand, ...resolvedCommand].filter(Boolean).join(' ');
};
2 changes: 1 addition & 1 deletion apps/app-builder/src/utils/createWithConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {mergeDefaultConfig} from './mergeDefaultConfig';
export const createWithConfig: CreateHook = (env) => {
return (definition) => {
return async (...args) => {
const config = await resolveConfig(env);
const {command, context} = await parseCommandInput(definition, args, env);
const config = await resolveConfig(env, context.args);

const commandName = definition.name;

Expand Down
11 changes: 8 additions & 3 deletions apps/app-builder/src/utils/executeCommand.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {spawnSync, type SpawnSyncOptions, type SpawnSyncOptionsWithStringEncoding} from 'child_process';
import {type OneOrMore, toArray} from '@myparcel/ts-utils';
import {type ExecuteCommandContext} from '../types';
import {isOfType, type OneOrMore, toArray} from '@myparcel/ts-utils';
import {type ExecuteCommandContext, type PdkBuilderContext} from '../types';
import {VerbosityLevel} from '../constants';
import {createCommand} from './createCommand';

export const executeCommand = async (
context: ExecuteCommandContext,
Expand All @@ -16,7 +17,11 @@ export const executeCommand = async (
};

return new Promise((resolve, reject) => {
const splitCommand = toArray(command).reduce((acc, command) => [...acc, ...command.split(' ')], [] as string[]);
const resolvedCommand = isOfType<PdkBuilderContext>(context, 'config')
? toArray(createCommand(context.config, command))
: toArray(command);

const splitCommand = resolvedCommand.reduce((acc, command) => [...acc, ...command.split(' ')], [] as string[]);
const allArgs = [...splitCommand, ...(args ?? [])];

const [commandName, ...commandArgs] = allArgs;
Expand Down
1 change: 1 addition & 0 deletions apps/app-builder/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './createArchive';
export * from './createCommand';
export * from './createDebugger';
export * from './createWithConfig';
export * from './createWithContext';
Expand Down
1 change: 1 addition & 0 deletions apps/app-builder/src/utils/mergeDefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const mergeDefaultConfig = (config: PdkBuilderConfig): ResolvedPdkBuilder
nodePackageManagerCommand: undefined,
outDir: 'dist',
platformFolderName: '{{platform}}-{{name}}',
rootCommand: '',
version: '0.0.0',
yarnCommand: undefined,
...config,
Expand Down
2 changes: 1 addition & 1 deletion apps/app-builder/src/utils/registerCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {type CommandCb, type CommandDefinition} from '../types';
export const registerCommand = (
definition: CommandDefinition,
callback: (definition: CommandDefinition) => CommandCb,
) => {
): void => {
const command = program.command(definition.name).description(definition.description);

if (definition.options) {
Expand Down
19 changes: 14 additions & 5 deletions apps/app-builder/src/utils/resolveConfig.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import {type LiftoffEnv} from 'liftoff';
import {type PdkBuilderConfig, type ResolvedPdkBuilderConfig} from '../types';
import {type AnyCommandArgs, type PdkBuilderConfig, type ResolvedPdkBuilderConfig} from '../types';
import {type ParsedCommand} from './parseCommand';

const configCache = new Map<string, PdkBuilderConfig>();

export async function resolveConfig(env: LiftoffEnv): Promise<ResolvedPdkBuilderConfig> {
export async function resolveConfig(
env: LiftoffEnv,
args?: ParsedCommand<AnyCommandArgs>,
): Promise<ResolvedPdkBuilderConfig> {
if (!env.configPath) {
throw new Error('No config file found.');
}

if (configCache.has(env.configPath)) {
return configCache.get(env.configPath) as ResolvedPdkBuilderConfig;
return {...configCache.get(env.configPath), ...args} as ResolvedPdkBuilderConfig;
}

const imported = await import(env.configPath);

configCache.set(env.configPath, imported.default);
const resolvedConfig = {
...imported.default,
...args,
};

return imported.default;
configCache.set(env.configPath, resolvedConfig);

return resolvedConfig;
}

0 comments on commit 44689f6

Please sign in to comment.