124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
import process from 'node:process';
|
|
import { getOrLoadReporter, getOrLoadStorage } from '@emigrate/plugin-tools';
|
|
import { type MigrationHistoryEntry, type MigrationMetadataFinished } from '@emigrate/plugin-tools/types';
|
|
import {
|
|
BadOptionError,
|
|
MigrationNotRunError,
|
|
MissingArgumentsError,
|
|
MissingOptionError,
|
|
OptionNeededError,
|
|
StorageInitError,
|
|
} from '../errors.js';
|
|
import { type Config } from '../types.js';
|
|
import { getMigration } from '../get-migration.js';
|
|
import { getDuration } from '../get-duration.js';
|
|
import { exec } from '../exec.js';
|
|
import { version } from '../get-package-info.js';
|
|
|
|
type ExtraFlags = {
|
|
force?: boolean;
|
|
};
|
|
|
|
const lazyDefaultReporter = async () => import('../reporters/default.js');
|
|
|
|
export default async function removeCommand(
|
|
{ directory, reporter: reporterConfig, storage: storageConfig, force }: Config & ExtraFlags,
|
|
name: string,
|
|
) {
|
|
if (!directory) {
|
|
throw new MissingOptionError('directory');
|
|
}
|
|
|
|
if (!name) {
|
|
throw new MissingArgumentsError('name');
|
|
}
|
|
|
|
const cwd = process.cwd();
|
|
const storagePlugin = await getOrLoadStorage([storageConfig]);
|
|
|
|
if (!storagePlugin) {
|
|
throw new BadOptionError('storage', 'No storage found, please specify a storage using the storage option');
|
|
}
|
|
|
|
const reporter = await getOrLoadReporter([reporterConfig ?? lazyDefaultReporter]);
|
|
|
|
if (!reporter) {
|
|
throw new BadOptionError(
|
|
'reporter',
|
|
'No reporter found, please specify an existing reporter using the reporter option',
|
|
);
|
|
}
|
|
|
|
const [storage, storageError] = await exec(async () => storagePlugin.initializeStorage());
|
|
|
|
if (storageError) {
|
|
await reporter.onFinished?.([], new StorageInitError('Could not initialize storage', { cause: storageError }));
|
|
|
|
return 1;
|
|
}
|
|
|
|
await reporter.onInit?.({ command: 'remove', version, cwd, dry: false, directory });
|
|
|
|
const migrationFile = await getMigration(cwd, directory, name, !force);
|
|
|
|
const finishedMigrations: MigrationMetadataFinished[] = [];
|
|
let historyEntry: MigrationHistoryEntry | undefined;
|
|
let removalError: Error | undefined;
|
|
|
|
for await (const migrationHistoryEntry of storage.getHistory()) {
|
|
if (migrationHistoryEntry.name !== migrationFile.name) {
|
|
continue;
|
|
}
|
|
|
|
if (migrationHistoryEntry.status === 'done' && !force) {
|
|
removalError = new OptionNeededError(
|
|
'force',
|
|
`The migration "${migrationFile.name}" is not in a failed state. Use the "force" option to force its removal`,
|
|
);
|
|
} else {
|
|
historyEntry = migrationHistoryEntry;
|
|
}
|
|
}
|
|
|
|
await reporter.onMigrationRemoveStart?.(migrationFile);
|
|
|
|
const start = process.hrtime();
|
|
|
|
if (historyEntry) {
|
|
try {
|
|
await storage.remove(migrationFile);
|
|
|
|
const duration = getDuration(start);
|
|
const finishedMigration: MigrationMetadataFinished = { ...migrationFile, status: 'done', duration };
|
|
|
|
await reporter.onMigrationRemoveSuccess?.(finishedMigration);
|
|
|
|
finishedMigrations.push(finishedMigration);
|
|
} catch (error) {
|
|
removalError = error instanceof Error ? error : new Error(String(error));
|
|
}
|
|
} else if (!removalError) {
|
|
removalError = new MigrationNotRunError(
|
|
`Migration "${migrationFile.name}" is not in the migration history`,
|
|
migrationFile,
|
|
);
|
|
}
|
|
|
|
if (removalError) {
|
|
const duration = getDuration(start);
|
|
const finishedMigration: MigrationMetadataFinished = {
|
|
...migrationFile,
|
|
status: 'failed',
|
|
error: removalError,
|
|
duration,
|
|
};
|
|
await reporter.onMigrationRemoveError?.(finishedMigration, removalError);
|
|
finishedMigrations.push(finishedMigration);
|
|
}
|
|
|
|
await reporter.onFinished?.(finishedMigrations, removalError);
|
|
|
|
await storage.end();
|
|
|
|
return removalError ? 1 : 0;
|
|
}
|