feat(cli): storage and reporter are now their own options
Instead of mixing storages and reporters with other plugins in the plugin option they now have their own separate options. This is for increased future flexibility and to be more similar to other CLI tools. BREAKING CHANGE: the storage to use must now be specified using the "storage" configuration option or the "--storage" CLI option instead of having it among other plugins.
This commit is contained in:
parent
509cd41663
commit
8e87ade5c0
9 changed files with 150 additions and 95 deletions
|
|
@ -19,6 +19,14 @@ const up: Action = async (args) => {
|
|||
type: 'string',
|
||||
short: 'd',
|
||||
},
|
||||
reporter: {
|
||||
type: 'string',
|
||||
short: 'r',
|
||||
},
|
||||
storage: {
|
||||
type: 'string',
|
||||
short: 's',
|
||||
},
|
||||
dry: {
|
||||
type: 'boolean',
|
||||
},
|
||||
|
|
@ -40,14 +48,16 @@ Options:
|
|||
|
||||
-h, --help Show this help message and exit
|
||||
-d, --directory The directory where the migration files are located (required)
|
||||
-s, --storage The storage to use for where to store the migration history (required)
|
||||
-p, --plugin The plugin(s) to use (can be specified multiple times)
|
||||
-r, --reporter The reporter to use for reporting the migration progress
|
||||
--dry List the pending migrations that would be run without actually running them
|
||||
|
||||
Examples:
|
||||
|
||||
emigrate up --directory src/migrations
|
||||
emigrate up -d ./migrations --plugin @emigrate/plugin-storage-mysql
|
||||
emigrate up -d src/migrations --dry
|
||||
emigrate up --directory src/migrations -s fs
|
||||
emigrate up -d ./migrations --storage @emigrate/storage-mysql
|
||||
emigrate up -d src/migrations -s postgres -r json --dry
|
||||
`;
|
||||
|
||||
if (values.help) {
|
||||
|
|
@ -56,12 +66,12 @@ Examples:
|
|||
return;
|
||||
}
|
||||
|
||||
const { directory = config.directory, dry } = values;
|
||||
const { directory = config.directory, storage = config.storage, reporter = config.reporter, dry } = values;
|
||||
const plugins = [...(config.plugins ?? []), ...(values.plugin ?? [])];
|
||||
|
||||
try {
|
||||
const { default: upCommand } = await import('./up-command.js');
|
||||
await upCommand({ directory, plugins, dry });
|
||||
await upCommand({ storage, reporter, directory, plugins, dry });
|
||||
} catch (error) {
|
||||
if (error instanceof ShowUsageError) {
|
||||
console.error(error.message, '\n');
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { cosmiconfig } from 'cosmiconfig';
|
||||
import { type Config, type EmigrateConfig } from './types.js';
|
||||
|
||||
export const getConfig = async (command: 'up' | 'list' | 'new'): Promise<Config> => {
|
||||
const commands = ['up', 'list', 'new'] as const;
|
||||
type Command = (typeof commands)[number];
|
||||
|
||||
export const getConfig = async (command: Command): Promise<Config> => {
|
||||
const explorer = cosmiconfig('emigrate');
|
||||
|
||||
const result = await explorer.search();
|
||||
|
|
@ -10,11 +13,14 @@ export const getConfig = async (command: 'up' | 'list' | 'new'): Promise<Config>
|
|||
return {};
|
||||
}
|
||||
|
||||
const { plugins, directory, template, ...commandsConfig } = result.config as EmigrateConfig;
|
||||
const config = result.config as EmigrateConfig;
|
||||
|
||||
if (commandsConfig[command]) {
|
||||
return { plugins, directory, template, ...commandsConfig[command] };
|
||||
const commandConfig = config[command];
|
||||
|
||||
for (const command of commands) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete config[command];
|
||||
}
|
||||
|
||||
return { plugins, directory, template };
|
||||
return { ...config, ...commandConfig };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import prettyMs from 'pretty-ms';
|
|||
import {
|
||||
type MigrationMetadata,
|
||||
type MigrationMetadataFinished,
|
||||
type ReporterPlugin,
|
||||
type EmigrateReporter,
|
||||
} from '@emigrate/plugin-tools/types';
|
||||
|
||||
type Status = ReturnType<typeof getMigrationStatus>;
|
||||
|
|
@ -202,7 +202,7 @@ const getHeaderMessage = (migrations?: MigrationMetadata[], lockedMigrations?: M
|
|||
)} ${ansis.yellow(`(${migrations.length - lockedMigrations.length} locked)`)}`;
|
||||
};
|
||||
|
||||
class DefaultFancyReporter implements Required<ReporterPlugin> {
|
||||
class DefaultFancyReporter implements Required<EmigrateReporter> {
|
||||
#migrations: Array<MigrationMetadata | MigrationMetadataFinished> | undefined;
|
||||
#lockedMigrations: MigrationMetadata[] | undefined;
|
||||
#activeMigration: MigrationMetadata | undefined;
|
||||
|
|
@ -290,7 +290,7 @@ class DefaultFancyReporter implements Required<ReporterPlugin> {
|
|||
}
|
||||
}
|
||||
|
||||
class DefaultReporter implements Required<ReporterPlugin> {
|
||||
class DefaultReporter implements Required<EmigrateReporter> {
|
||||
#migrations?: MigrationMetadata[];
|
||||
#lockedMigrations?: MigrationMetadata[];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
import { type Plugin } from '@emigrate/plugin-tools/types';
|
||||
import { type EmigrateStorage, type Awaitable, type Plugin, type EmigrateReporter } from '@emigrate/plugin-tools/types';
|
||||
|
||||
export type EmigratePlugin = Plugin;
|
||||
|
||||
type StringOrModule<T> = string | T | (() => Awaitable<T>) | (() => Awaitable<{ default: T }>);
|
||||
|
||||
export type Config = {
|
||||
plugins?: Array<string | EmigratePlugin>;
|
||||
storage?: StringOrModule<EmigrateStorage>;
|
||||
reporter?: StringOrModule<EmigrateReporter>;
|
||||
plugins?: Array<StringOrModule<EmigratePlugin>>;
|
||||
directory?: string;
|
||||
template?: string;
|
||||
extension?: string;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
import process from 'node:process';
|
||||
import { getOrLoadPlugin, getOrLoadPlugins } from '@emigrate/plugin-tools';
|
||||
import { getOrLoadPlugins, getOrLoadReporter, getOrLoadStorage } from '@emigrate/plugin-tools';
|
||||
import {
|
||||
type LoaderPlugin,
|
||||
type MigrationFunction,
|
||||
type Plugin,
|
||||
type PluginType,
|
||||
type PluginFromType,
|
||||
type MigrationMetadata,
|
||||
type MigrationMetadataFinished,
|
||||
} from '@emigrate/plugin-tools/types';
|
||||
|
|
@ -20,42 +17,42 @@ import {
|
|||
import { type Config } from './types.js';
|
||||
import { withLeadingPeriod } from './with-leading-period.js';
|
||||
import pluginLoaderJs from './plugin-loader-js.js';
|
||||
import pluginReporterDefault from './plugin-reporter-default.js';
|
||||
|
||||
type ExtraFlags = {
|
||||
dry?: boolean;
|
||||
};
|
||||
|
||||
const requirePlugin = async <T extends PluginType>(
|
||||
type: T,
|
||||
plugins: Array<Plugin | string>,
|
||||
): Promise<PluginFromType<T>> => {
|
||||
const plugin = await getOrLoadPlugin(type, plugins);
|
||||
|
||||
if (!plugin) {
|
||||
throw new BadOptionError(
|
||||
'plugin',
|
||||
`No ${type} plugin found, please specify a ${type} plugin using the plugin option`,
|
||||
);
|
||||
}
|
||||
|
||||
return plugin;
|
||||
};
|
||||
|
||||
const getDuration = (start: [number, number]) => {
|
||||
const [seconds, nanoseconds] = process.hrtime(start);
|
||||
return seconds * 1000 + nanoseconds / 1_000_000;
|
||||
};
|
||||
|
||||
export default async function upCommand({ directory, dry = false, plugins = [] }: Config & ExtraFlags) {
|
||||
const lazyDefaultReporter = async () => import('./plugin-reporter-default.js');
|
||||
|
||||
export default async function upCommand({
|
||||
storage: storageConfig,
|
||||
reporter: reporterConfig,
|
||||
directory,
|
||||
dry = false,
|
||||
plugins = [],
|
||||
}: Config & ExtraFlags) {
|
||||
if (!directory) {
|
||||
throw new MissingOptionError('directory');
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
const storagePlugin = await requirePlugin('storage', plugins);
|
||||
const storagePlugin = await getOrLoadStorage([storageConfig]);
|
||||
|
||||
if (!storagePlugin) {
|
||||
throw new BadOptionError('storage', 'No storage found, please specify a storage using the storage option');
|
||||
}
|
||||
|
||||
const storage = await storagePlugin.initializeStorage();
|
||||
const reporter = await requirePlugin('reporter', [pluginReporterDefault, ...plugins]);
|
||||
const reporter = await getOrLoadReporter([lazyDefaultReporter, reporterConfig]);
|
||||
|
||||
if (!reporter) {
|
||||
throw new BadOptionError('reporter', 'No reporter found, please specify a reporter using the reporter option');
|
||||
}
|
||||
|
||||
await reporter.onInit?.({ cwd, dry, directory });
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue