feat(reporters): add built-in "json" reporter and rename "default" to "pretty"
This commit is contained in:
parent
4e8ac5294d
commit
18382ce961
11 changed files with 102 additions and 16 deletions
5
.changeset/famous-elephants-fail.md
Normal file
5
.changeset/famous-elephants-fail.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@emigrate/cli': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add a built-in "json" reporter for outputting a single JSON object
|
||||||
5
.changeset/slimy-tomatoes-taste.md
Normal file
5
.changeset/slimy-tomatoes-taste.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@emigrate/cli': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Rename the "default" reporter to "pretty" and make it possible to specify it using the `--reporter` CLI option or in the configuration file
|
||||||
|
|
@ -104,7 +104,7 @@ Options:
|
||||||
|
|
||||||
-p, --plugin <name> The plugin(s) to use (can be specified multiple times)
|
-p, --plugin <name> The plugin(s) to use (can be specified multiple times)
|
||||||
|
|
||||||
-r, --reporter <name> The reporter to use for reporting the migration progress
|
-r, --reporter <name> The reporter to use for reporting the migration progress (default: pretty)
|
||||||
|
|
||||||
-l, --limit <count> Limit the number of migrations to run
|
-l, --limit <count> Limit the number of migrations to run
|
||||||
|
|
||||||
|
|
@ -261,7 +261,7 @@ Options:
|
||||||
|
|
||||||
-h, --help Show this help message and exit
|
-h, --help Show this help message and exit
|
||||||
-d, --directory <path> The directory where the migration files are located (required)
|
-d, --directory <path> The directory where the migration files are located (required)
|
||||||
-r, --reporter <name> The reporter to use for reporting the migration file creation progress
|
-r, --reporter <name> The reporter to use for reporting the migration file creation progress (default: pretty)
|
||||||
-p, --plugin <name> The plugin(s) to use (can be specified multiple times)
|
-p, --plugin <name> The plugin(s) to use (can be specified multiple times)
|
||||||
-t, --template <path> A template file to use as contents for the new migration file
|
-t, --template <path> A template file to use as contents for the new migration file
|
||||||
(if the extension option is not provided the template file's extension will be used)
|
(if the extension option is not provided the template file's extension will be used)
|
||||||
|
|
@ -358,7 +358,7 @@ Options:
|
||||||
-d, --directory <path> The directory where the migration files are located (required)
|
-d, --directory <path> The directory where the migration files are located (required)
|
||||||
-i, --import <module> Additional modules/packages to import before listing the migrations (can be specified multiple times)
|
-i, --import <module> Additional modules/packages to import before listing the migrations (can be specified multiple times)
|
||||||
For example if you want to use Dotenv to load environment variables
|
For example if you want to use Dotenv to load environment variables
|
||||||
-r, --reporter <name> The reporter to use for reporting the migrations
|
-r, --reporter <name> The reporter to use for reporting the migrations (default: pretty)
|
||||||
-s, --storage <name> The storage to use to get the migration history (required)
|
-s, --storage <name> The storage to use to get the migration history (required)
|
||||||
--color Force color output (this option is passed to the reporter)
|
--color Force color output (this option is passed to the reporter)
|
||||||
--no-color Disable color output (this option is passed to the reporter)
|
--no-color Disable color output (this option is passed to the reporter)
|
||||||
|
|
@ -456,7 +456,7 @@ Options:
|
||||||
-d, --directory <path> The directory where the migration files are located (required)
|
-d, --directory <path> The directory where the migration files are located (required)
|
||||||
-i, --import <module> Additional modules/packages to import before removing the migration (can be specified multiple times)
|
-i, --import <module> Additional modules/packages to import before removing the migration (can be specified multiple times)
|
||||||
For example if you want to use Dotenv to load environment variables
|
For example if you want to use Dotenv to load environment variables
|
||||||
-r, --reporter <name> The reporter to use for reporting the removal process
|
-r, --reporter <name> The reporter to use for reporting the removal process (default: pretty)
|
||||||
-s, --storage <name> The storage to use to get the migration history (required)
|
-s, --storage <name> The storage to use to get the migration history (required)
|
||||||
-f, --force Force removal of the migration history entry even if the migration is not in a failed state
|
-f, --force Force removal of the migration history entry even if the migration is not in a failed state
|
||||||
--color Force color output (this option is passed to the reporter)
|
--color Force color output (this option is passed to the reporter)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ import { exec } from '../exec.js';
|
||||||
import { migrationRunner } from '../migration-runner.js';
|
import { migrationRunner } from '../migration-runner.js';
|
||||||
import { collectMigrations } from '../collect-migrations.js';
|
import { collectMigrations } from '../collect-migrations.js';
|
||||||
import { version } from '../get-package-info.js';
|
import { version } from '../get-package-info.js';
|
||||||
|
import { getStandardReporter } from '../reporters/get.js';
|
||||||
const lazyDefaultReporter = async () => import('../reporters/default.js');
|
|
||||||
|
|
||||||
type ExtraFlags = {
|
type ExtraFlags = {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
|
@ -29,7 +28,7 @@ export default async function listCommand({
|
||||||
throw BadOptionError.fromOption('storage', 'No storage found, please specify a storage using the storage option');
|
throw BadOptionError.fromOption('storage', 'No storage found, please specify a storage using the storage option');
|
||||||
}
|
}
|
||||||
|
|
||||||
const reporter = await getOrLoadReporter([reporterConfig ?? lazyDefaultReporter]);
|
const reporter = getStandardReporter(reporterConfig) ?? (await getOrLoadReporter([reporterConfig]));
|
||||||
|
|
||||||
if (!reporter) {
|
if (!reporter) {
|
||||||
throw BadOptionError.fromOption(
|
throw BadOptionError.fromOption(
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,7 @@ import { type Config } from '../types.js';
|
||||||
import { withLeadingPeriod } from '../with-leading-period.js';
|
import { withLeadingPeriod } from '../with-leading-period.js';
|
||||||
import { version } from '../get-package-info.js';
|
import { version } from '../get-package-info.js';
|
||||||
import { getDuration } from '../get-duration.js';
|
import { getDuration } from '../get-duration.js';
|
||||||
|
import { getStandardReporter } from '../reporters/get.js';
|
||||||
const lazyDefaultReporter = async () => import('../reporters/default.js');
|
|
||||||
|
|
||||||
type ExtraFlags = {
|
type ExtraFlags = {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
|
@ -38,7 +37,7 @@ export default async function newCommand(
|
||||||
throw MissingOptionError.fromOption(['extension', 'template', 'plugin']);
|
throw MissingOptionError.fromOption(['extension', 'template', 'plugin']);
|
||||||
}
|
}
|
||||||
|
|
||||||
const reporter = await getOrLoadReporter([reporterConfig ?? lazyDefaultReporter]);
|
const reporter = getStandardReporter(reporterConfig) ?? (await getOrLoadReporter([reporterConfig]));
|
||||||
|
|
||||||
if (!reporter) {
|
if (!reporter) {
|
||||||
throw BadOptionError.fromOption(
|
throw BadOptionError.fromOption(
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { collectMigrations } from '../collect-migrations.js';
|
||||||
import { migrationRunner } from '../migration-runner.js';
|
import { migrationRunner } from '../migration-runner.js';
|
||||||
import { arrayMapAsync } from '../array-map-async.js';
|
import { arrayMapAsync } from '../array-map-async.js';
|
||||||
import { type GetMigrationsFunction } from '../get-migrations.js';
|
import { type GetMigrationsFunction } from '../get-migrations.js';
|
||||||
|
import { getStandardReporter } from '../reporters/get.js';
|
||||||
|
|
||||||
type ExtraFlags = {
|
type ExtraFlags = {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
|
@ -27,8 +28,6 @@ type ExtraFlags = {
|
||||||
|
|
||||||
type RemovableMigrationMetadata = MigrationMetadata & { originalStatus?: 'done' | 'failed' };
|
type RemovableMigrationMetadata = MigrationMetadata & { originalStatus?: 'done' | 'failed' };
|
||||||
|
|
||||||
const lazyDefaultReporter = async () => import('../reporters/default.js');
|
|
||||||
|
|
||||||
export default async function removeCommand(
|
export default async function removeCommand(
|
||||||
{
|
{
|
||||||
directory,
|
directory,
|
||||||
|
|
@ -55,7 +54,7 @@ export default async function removeCommand(
|
||||||
throw BadOptionError.fromOption('storage', 'No storage found, please specify a storage using the storage option');
|
throw BadOptionError.fromOption('storage', 'No storage found, please specify a storage using the storage option');
|
||||||
}
|
}
|
||||||
|
|
||||||
const reporter = await getOrLoadReporter([reporterConfig ?? lazyDefaultReporter]);
|
const reporter = getStandardReporter(reporterConfig) ?? (await getOrLoadReporter([reporterConfig]));
|
||||||
|
|
||||||
if (!reporter) {
|
if (!reporter) {
|
||||||
throw BadOptionError.fromOption(
|
throw BadOptionError.fromOption(
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { exec } from '../exec.js';
|
||||||
import { migrationRunner } from '../migration-runner.js';
|
import { migrationRunner } from '../migration-runner.js';
|
||||||
import { collectMigrations } from '../collect-migrations.js';
|
import { collectMigrations } from '../collect-migrations.js';
|
||||||
import { version } from '../get-package-info.js';
|
import { version } from '../get-package-info.js';
|
||||||
|
import { getStandardReporter } from '../reporters/get.js';
|
||||||
|
|
||||||
type ExtraFlags = {
|
type ExtraFlags = {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
|
|
@ -29,7 +30,6 @@ type ExtraFlags = {
|
||||||
abortRespite?: number;
|
abortRespite?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const lazyDefaultReporter = async () => import('../reporters/default.js');
|
|
||||||
const lazyPluginLoaderJs = async () => import('../plugin-loader-js.js');
|
const lazyPluginLoaderJs = async () => import('../plugin-loader-js.js');
|
||||||
|
|
||||||
export default async function upCommand({
|
export default async function upCommand({
|
||||||
|
|
@ -58,7 +58,7 @@ export default async function upCommand({
|
||||||
throw BadOptionError.fromOption('storage', 'No storage found, please specify a storage using the storage option');
|
throw BadOptionError.fromOption('storage', 'No storage found, please specify a storage using the storage option');
|
||||||
}
|
}
|
||||||
|
|
||||||
const reporter = await getOrLoadReporter([reporterConfig ?? lazyDefaultReporter]);
|
const reporter = getStandardReporter(reporterConfig) ?? (await getOrLoadReporter([reporterConfig]));
|
||||||
|
|
||||||
if (!reporter) {
|
if (!reporter) {
|
||||||
throw BadOptionError.fromOption(
|
throw BadOptionError.fromOption(
|
||||||
|
|
|
||||||
14
packages/cli/src/reporters/get.ts
Normal file
14
packages/cli/src/reporters/get.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { type Config } from '../types.js';
|
||||||
|
import * as reporters from './index.js';
|
||||||
|
|
||||||
|
export const getStandardReporter = (reporter?: Config['reporter']) => {
|
||||||
|
if (!reporter) {
|
||||||
|
return reporters.pretty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reporter === 'string' && reporter in reporters) {
|
||||||
|
return reporters[reporter as keyof typeof reporters];
|
||||||
|
}
|
||||||
|
|
||||||
|
return; // eslint-disable-line no-useless-return
|
||||||
|
};
|
||||||
2
packages/cli/src/reporters/index.ts
Normal file
2
packages/cli/src/reporters/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default as pretty } from './default.js';
|
||||||
|
export { default as json } from './json.js';
|
||||||
60
packages/cli/src/reporters/json.ts
Normal file
60
packages/cli/src/reporters/json.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { type ReporterInitParameters, type EmigrateReporter, type MigrationMetadataFinished } from '@emigrate/types';
|
||||||
|
import { toSerializedError } from '../errors.js';
|
||||||
|
|
||||||
|
class JsonReporter implements EmigrateReporter {
|
||||||
|
#parameters!: ReporterInitParameters;
|
||||||
|
#startTime!: number;
|
||||||
|
|
||||||
|
onInit(parameters: ReporterInitParameters): void {
|
||||||
|
this.#startTime = Date.now();
|
||||||
|
this.#parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFinished(migrations: MigrationMetadataFinished[], error?: Error | undefined): void {
|
||||||
|
const { command, version } = this.#parameters;
|
||||||
|
|
||||||
|
let numberDoneMigrations = 0;
|
||||||
|
let numberSkippedMigrations = 0;
|
||||||
|
let numberFailedMigrations = 0;
|
||||||
|
let numberPendingMigrations = 0;
|
||||||
|
|
||||||
|
for (const migration of migrations) {
|
||||||
|
// eslint-disable-next-line unicorn/prefer-switch
|
||||||
|
if (migration.status === 'done') {
|
||||||
|
numberDoneMigrations++;
|
||||||
|
} else if (migration.status === 'skipped') {
|
||||||
|
numberSkippedMigrations++;
|
||||||
|
} else if (migration.status === 'failed') {
|
||||||
|
numberFailedMigrations++;
|
||||||
|
} else {
|
||||||
|
numberPendingMigrations++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
command,
|
||||||
|
version,
|
||||||
|
numberTotalMigrations: migrations.length,
|
||||||
|
numberDoneMigrations,
|
||||||
|
numberSkippedMigrations,
|
||||||
|
numberFailedMigrations,
|
||||||
|
numberPendingMigrations,
|
||||||
|
success: !error,
|
||||||
|
startTime: this.#startTime,
|
||||||
|
endTime: Date.now(),
|
||||||
|
error: error ? toSerializedError(error) : undefined,
|
||||||
|
migrations: migrations.map((migration) => ({
|
||||||
|
name: migration.filePath,
|
||||||
|
status: migration.status,
|
||||||
|
duration: 'duration' in migration ? migration.duration : 0,
|
||||||
|
error: 'error' in migration ? toSerializedError(migration.error) : undefined,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(JSON.stringify(result, undefined, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonReporter = new JsonReporter() as EmigrateReporter;
|
||||||
|
|
||||||
|
export default jsonReporter;
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
import { type EmigrateStorage, type Awaitable, type Plugin, type EmigrateReporter } from '@emigrate/types';
|
import { type EmigrateStorage, type Awaitable, type Plugin, type EmigrateReporter } from '@emigrate/types';
|
||||||
|
import type * as reporters from './reporters/index.js';
|
||||||
|
|
||||||
|
export type StandardReporter = keyof typeof reporters;
|
||||||
|
|
||||||
export type EmigratePlugin = Plugin;
|
export type EmigratePlugin = Plugin;
|
||||||
|
|
||||||
|
|
@ -6,7 +9,7 @@ type StringOrModule<T> = string | T | (() => Awaitable<T>) | (() => Awaitable<{
|
||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
storage?: StringOrModule<EmigrateStorage>;
|
storage?: StringOrModule<EmigrateStorage>;
|
||||||
reporter?: StringOrModule<EmigrateReporter>;
|
reporter?: StandardReporter | StringOrModule<EmigrateReporter>;
|
||||||
plugins?: Array<StringOrModule<EmigratePlugin>>;
|
plugins?: Array<StringOrModule<EmigratePlugin>>;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
template?: string;
|
template?: string;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue