From c6745ab292005bfd330d001ee51e8ea4357fd550 Mon Sep 17 00:00:00 2001 From: Espen Hovlandsdal Date: Thu, 1 Feb 2024 16:05:06 -0800 Subject: [PATCH] fix(migration): make `sanity migration list` also include file-only migrations --- .../migration/listMigrationsCommand.ts | 60 ++++++++++++------- .../commands/migration/runMigrationCommand.ts | 2 +- .../_internal/cli/commands/migration/utils.ts | 43 ++++++++++++- 3 files changed, 80 insertions(+), 25 deletions(-) diff --git a/packages/sanity/src/_internal/cli/commands/migration/listMigrationsCommand.ts b/packages/sanity/src/_internal/cli/commands/migration/listMigrationsCommand.ts index 6d2f0721d36..8733f603f67 100644 --- a/packages/sanity/src/_internal/cli/commands/migration/listMigrationsCommand.ts +++ b/packages/sanity/src/_internal/cli/commands/migration/listMigrationsCommand.ts @@ -5,7 +5,7 @@ import type {Migration} from '@sanity/migrate' import chalk from 'chalk' import {Table} from 'console-table-printer' import {register} from 'esbuild-register/dist/node' -import {MIGRATIONS_DIRECTORY} from './constants' +import {MIGRATIONS_DIRECTORY, MIGRATION_SCRIPT_EXTENSIONS} from './constants' import {resolveMigrationScript} from './utils' const helpText = `` @@ -38,7 +38,7 @@ const listMigrationCommand: CliCommandDefinition = { }) migrations.forEach((definedMigration) => { - table.addRow({id: definedMigration.dirname, title: definedMigration.migration.title}) + table.addRow({id: definedMigration.id, title: definedMigration.migration.title}) }) table.printTable() output.print('\nRun `sanity migration run ` to run a migration') @@ -55,6 +55,16 @@ const listMigrationCommand: CliCommandDefinition = { }, } +/** + * A resolved migration, where you are guaranteed that the migration file exists + * + * @internal + */ +export interface ResolvedMigration { + id: string + migration: Migration +} + /** * Resolves all migrations in the studio working directory * @@ -62,9 +72,7 @@ const listMigrationCommand: CliCommandDefinition = { * @returns Array of migrations and their respective paths * @internal */ -export async function resolveMigrations( - workDir: string, -): Promise<{dirname: string; migration: Migration}[]> { +export async function resolveMigrations(workDir: string): Promise { let unregister if (!__DEV__) { unregister = register({ @@ -72,29 +80,39 @@ export async function resolveMigrations( }).unregister } - const directories = ( - await readdir(path.join(workDir, MIGRATIONS_DIRECTORY), {withFileTypes: true}) - ).filter((ent) => ent.isDirectory()) + const migrationsDir = path.join(workDir, MIGRATIONS_DIRECTORY) + const migrationEntries = await readdir(migrationsDir, {withFileTypes: true}) - const entries = directories - .map((ent) => { - const candidates = resolveMigrationScript(workDir, ent.name) - const found = candidates.find((candidate) => candidate.mod?.default) - if (!found) { - return null - } - return { - dirname: ent.name, - migration: found.mod.default as Migration, + const migrations: ResolvedMigration[] = [] + for (const entry of migrationEntries) { + const entryName = entry.isDirectory() ? entry.name : removeMigrationScriptExtension(entry.name) + const candidates = resolveMigrationScript(workDir, entryName) + + for (const candidate of candidates) { + if (!candidate.mod?.default) { + continue } - }) - .filter(Boolean) as {dirname: string; migration: Migration}[] + + migrations.push({ + id: entryName, + migration: candidate.mod.default, + }) + } + } if (unregister) { unregister() } - return entries + return migrations +} + +function removeMigrationScriptExtension(fileName: string) { + // Remove `.ts`, `.js` etc from the end of a filename + return MIGRATION_SCRIPT_EXTENSIONS.reduce( + (name, ext) => (name.endsWith(`.${ext}`) ? path.basename(name, `.${ext}`) : name), + fileName, + ) } export default listMigrationCommand diff --git a/packages/sanity/src/_internal/cli/commands/migration/runMigrationCommand.ts b/packages/sanity/src/_internal/cli/commands/migration/runMigrationCommand.ts index 22bcab1ec3c..e1f13ffef2b 100644 --- a/packages/sanity/src/_internal/cli/commands/migration/runMigrationCommand.ts +++ b/packages/sanity/src/_internal/cli/commands/migration/runMigrationCommand.ts @@ -108,7 +108,7 @@ const runMigrationCommand: CliCommandDefinition = { }) migrations.forEach((definedMigration) => { - table.addRow({id: definedMigration.dirname, title: definedMigration.migration.title}) + table.addRow({id: definedMigration.id, title: definedMigration.migration.title}) }) table.printTable() output.print('\nRun `sanity migration run ` to run a migration') diff --git a/packages/sanity/src/_internal/cli/commands/migration/utils.ts b/packages/sanity/src/_internal/cli/commands/migration/utils.ts index 03a480cd4b4..c9da64cc60c 100644 --- a/packages/sanity/src/_internal/cli/commands/migration/utils.ts +++ b/packages/sanity/src/_internal/cli/commands/migration/utils.ts @@ -1,8 +1,43 @@ import path from 'path' - +import type {Migration} from '@sanity/migrate' import {MIGRATION_SCRIPT_EXTENSIONS, MIGRATIONS_DIRECTORY} from './constants' -export function resolveMigrationScript(workDir: string, migrationName: string) { +interface ResolvedMigrationScript { + /** + * Relative path from the working directory to the migration script + */ + relativePath: string + + /** + * Absolute path to the migration script + */ + absolutePath: string + + /** + * The migration module, if it could be resolved - otherwise `undefined` + */ + mod?: {default: Migration} +} + +/** + * Resolves the potential paths to a migration script. + * Considers the following paths (where `` is 'mjs', 'js', 'ts' or 'cjs'): + * + * - `/.` + * - `//index.` + * + * Note that all possible paths are returned, even if the files do not exist. + * Check the `mod` property to see if a module could actually be loaded. + * + * @param workDir - Working directory of the studio + * @param migrationName - The name of the migration directory to resolve + * @returns An array of potential migration scripts + * @internal + */ +export function resolveMigrationScript( + workDir: string, + migrationName: string, +): ResolvedMigrationScript[] { return [migrationName, path.join(migrationName, 'index')].flatMap((location) => MIGRATION_SCRIPT_EXTENSIONS.map((ext) => { const relativePath = path.join(MIGRATIONS_DIRECTORY, `${location}.${ext}`) @@ -12,7 +47,9 @@ export function resolveMigrationScript(workDir: string, migrationName: string) { // eslint-disable-next-line import/no-dynamic-require mod = require(absolutePath) } catch (err) { - // console.error(err) + if (err.code !== 'MODULE_NOT_FOUND') { + throw new Error(`Error: ${err.message}"`) + } } return {relativePath, absolutePath, mod} }),