feat(core, medusa, cli): Enable migration scripts (#10960)

* feat(core, medusa): Enable migration scripts

* spacing

* rm unnecessary import

* Allow to skip script migration

* fix missing options

* add options

* add tests and small changes

* update

* add checks

* add lock mechanism to be extra safe

* Create six-bears-vanish.md

* update queries

* fix tests

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2025-01-15 12:51:37 -05:00
committed by GitHub
co-authored by Oli Juhl
parent 62d543e691
commit 0924164e86
11 changed files with 589 additions and 1 deletions
@@ -11,6 +11,7 @@ import { syncLinks } from "./sync-links"
import { ensureDbExists } from "../utils"
import { initializeContainer } from "../../loaders"
import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins"
import { runMigrationScripts } from "./run-scripts"
const TERMINAL_SIZE = process.stdout.columns
@@ -21,11 +22,13 @@ const TERMINAL_SIZE = process.stdout.columns
export async function migrate({
directory,
skipLinks,
skipScripts,
executeAllLinks,
executeSafeLinks,
}: {
directory: string
skipLinks: boolean
skipScripts: boolean
executeAllLinks: boolean
executeSafeLinks: boolean
}): Promise<boolean> {
@@ -69,12 +72,24 @@ export async function migrate({
})
}
if (!skipScripts) {
/**
* Run migration scripts
*/
console.log(new Array(TERMINAL_SIZE).join("-"))
await runMigrationScripts({
directory,
container,
})
}
return true
}
const main = async function ({
directory,
skipLinks,
skipScripts,
executeAllLinks,
executeSafeLinks,
}) {
@@ -82,6 +97,7 @@ const main = async function ({
const migrated = await migrate({
directory,
skipLinks,
skipScripts,
executeAllLinks,
executeSafeLinks,
})
@@ -0,0 +1,112 @@
import { MedusaAppLoader } from "@medusajs/framework"
import { LinkLoader } from "@medusajs/framework/links"
import { logger } from "@medusajs/framework/logger"
import { MigrationScriptsMigrator } from "@medusajs/framework/migrations"
import {
ContainerRegistrationKeys,
mergePluginModules,
} from "@medusajs/framework/utils"
import { dirname, join } from "path"
import { MedusaModule } from "@medusajs/framework/modules-sdk"
import { MedusaContainer } from "@medusajs/types"
import { initializeContainer } from "../../loaders"
import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins"
import { ensureDbExists } from "../utils"
const TERMINAL_SIZE = process.stdout.columns
/**
* A low-level utility to migrate the migration scripts. This util should
* never exit the process implicitly.
*/
export async function runMigrationScripts({
directory,
container,
}: {
directory: string
container?: MedusaContainer
}): Promise<boolean> {
/**
* Clear all module instances to prevent cache from kicking in
*/
MedusaModule.clearInstances()
let container_: MedusaContainer = container!
let onApplicationPrepareShutdown: () => Promise<void> = async () =>
Promise.resolve()
let onApplicationShutdown: () => Promise<void> = async () => Promise.resolve()
try {
/**
* Setup
*/
container_ ??= await initializeContainer(directory)
await ensureDbExists(container_)
const configModule = container_.resolve(
ContainerRegistrationKeys.CONFIG_MODULE
)
const plugins = await getResolvedPlugins(directory, configModule, true)
mergePluginModules(configModule, plugins)
const linksSourcePaths = plugins.map((plugin) =>
join(plugin.resolve, "links")
)
await new LinkLoader(linksSourcePaths).load()
const medusaAppResources = await new MedusaAppLoader().load()
onApplicationPrepareShutdown =
medusaAppResources.onApplicationPrepareShutdown
onApplicationShutdown = medusaAppResources.onApplicationShutdown
await medusaAppResources.onApplicationStart()
const scriptsSourcePaths = [
join(dirname(require.resolve("@medusajs/medusa")), "migration-scripts"),
...plugins.map((plugin) => join(plugin.resolve, "migration-scripts")),
]
const migrator = new MigrationScriptsMigrator({ container: container_ })
await migrator.ensureMigrationsTable()
const pendingScripts = await migrator.getPendingMigrations(
scriptsSourcePaths
)
if (!pendingScripts?.length) {
logger.info("No pending migration scripts to execute")
return true
}
console.log(new Array(TERMINAL_SIZE).join("-"))
logger.info("Pending migration scripts to execute")
logger.info(`${pendingScripts.join("\n")}`)
console.log(new Array(TERMINAL_SIZE).join("-"))
logger.info("Running migration scripts...")
await migrator.run(scriptsSourcePaths)
console.log(new Array(TERMINAL_SIZE).join("-"))
logger.info("Migration scripts completed")
return true
} finally {
await onApplicationPrepareShutdown()
await onApplicationShutdown()
}
}
const main = async function ({ directory }: { directory: string }) {
try {
const migrated = await runMigrationScripts({
directory,
})
process.exit(migrated ? 0 : 1)
} catch (error) {
logger.error(error)
process.exit(1)
}
}
export default main
+2
View File
@@ -7,6 +7,7 @@ const main = async function ({
interactive,
db,
skipLinks,
skipScripts,
executeAllLinks,
executeSafeLinks,
}) {
@@ -19,6 +20,7 @@ const main = async function ({
const migrated = await migrate({
directory,
skipLinks,
skipScripts,
executeAllLinks,
executeSafeLinks,
})