diff --git a/packages/cli/medusa-cli/src/create-cli.ts b/packages/cli/medusa-cli/src/create-cli.ts index e43be85783..3f65750e00 100644 --- a/packages/cli/medusa-cli/src/create-cli.ts +++ b/packages/cli/medusa-cli/src/create-cli.ts @@ -120,6 +120,42 @@ function buildLocalCommands(cli, isLocalProject) { desc: `Create a new Medusa project.`, handler: handlerP(newStarter), }) + .command({ + command: "db:setup", + desc: "Create the database, run migrations and sync links", + builder: (builder) => { + builder.option("db", { + type: "string", + describe: "Specify the name of the database you want to create", + }) + builder.option("interactive", { + type: "boolean", + default: true, + describe: + "Display prompts. Use --no-interactive flag to run the command without prompts", + }) + builder.option("skip-links", { + type: "boolean", + describe: "Do not sync links", + }) + builder.option("execute-all-links", { + type: "boolean", + describe: + "Skip prompts and execute all (including unsafe) actions from sync links", + }) + builder.option("execute-safe-links", { + type: "boolean", + describe: + "Skip prompts and execute only safe actions from sync links", + }) + }, + handler: handlerP( + getCommandHandler("db/setup", (args, cmd) => { + process.env.NODE_ENV = process.env.NODE_ENV || `development` + return cmd(args) + }) + ), + }) .command({ command: "db:create", desc: "Create the database used by your application", diff --git a/packages/medusa/src/commands/db/create.ts b/packages/medusa/src/commands/db/create.ts index 9d7d02b649..c3c46dd356 100644 --- a/packages/medusa/src/commands/db/create.ts +++ b/packages/medusa/src/commands/db/create.ts @@ -10,7 +10,19 @@ import { parseConnectionString, } from "@medusajs/utils" -const main = async function ({ directory, interactive, db }) { +/** + * A low-level utility to create the database. This util should + * never exit the process implicitly. + */ +export async function dbCreate({ + db, + directory, + interactive, +}: { + db: string | undefined + directory: string + interactive: boolean +}): Promise { let dbName = db /** @@ -33,8 +45,7 @@ const main = async function ({ directory, interactive, db }) { logger.error( `Missing "DATABASE_URL" inside the .env file. The value is required to connect to the PostgreSQL server` ) - process.exitCode = 1 - return + return false } /** @@ -45,18 +56,11 @@ const main = async function ({ directory, interactive, db }) { const defaultValue = envEditor.get("DB_NAME") ?? `medusa-${slugify(basename(directory))}` if (interactive) { - try { - dbName = await input({ - message: "Enter the database name", - default: defaultValue, - required: true, - }) - } catch (error) { - if (error.name === "ExitPromptError") { - process.exit() - } - throw error - } + dbName = await input({ + message: "Enter the database name", + default: defaultValue, + required: true, + }) } else { dbName = defaultValue } @@ -82,12 +86,11 @@ const main = async function ({ directory, interactive, db }) { await client.connect() logger.info(`Connection established with the database "${dbName}"`) } catch (error) { - process.exitCode = 1 logger.error( "Unable to establish database connection because of the following error" ) logger.error(error) - return + return false } if (await dbExists(client, dbName)) { @@ -97,7 +100,7 @@ const main = async function ({ directory, interactive, db }) { await envEditor.save() logger.info(`Updated .env file with "DB_NAME=${dbName}"`) - return + return true } await createDb(client, dbName) @@ -106,6 +109,20 @@ const main = async function ({ directory, interactive, db }) { envEditor.set("DB_NAME", dbName) await envEditor.save() logger.info(`Updated .env file with "DB_NAME=${dbName}"`) + return true +} + +const main = async function ({ directory, interactive, db }) { + try { + const created = await dbCreate({ directory, interactive, db }) + process.exit(created ? 0 : 1) + } catch (error) { + if (error.name === "ExitPromptError") { + process.exit() + } + logger.error(error) + process.exit(1) + } } export default main diff --git a/packages/medusa/src/commands/db/migrate.ts b/packages/medusa/src/commands/db/migrate.ts index 677af52eea..945a7c0ff3 100644 --- a/packages/medusa/src/commands/db/migrate.ts +++ b/packages/medusa/src/commands/db/migrate.ts @@ -9,6 +9,62 @@ import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins" const TERMINAL_SIZE = process.stdout.columns +/** + * A low-level utility to migrate the database. This util should + * never exit the process implicitly. + */ +export async function migrate({ + directory, + skipLinks, + executeAllLinks, + executeSafeLinks, +}: { + directory: string + skipLinks: boolean + executeAllLinks: boolean + executeSafeLinks: boolean +}): Promise { + /** + * Setup + */ + const container = await initializeContainer(directory) + await ensureDbExists(container) + + const medusaAppLoader = new MedusaAppLoader() + const configModule = container.resolve( + ContainerRegistrationKeys.CONFIG_MODULE + ) + + const plugins = getResolvedPlugins(directory, configModule, true) || [] + const linksSourcePaths = plugins.map((plugin) => + join(plugin.resolve, "links") + ) + await new LinkLoader(linksSourcePaths).load() + + /** + * Run migrations + */ + logger.info("Running migrations...") + await medusaAppLoader.runModulesMigrations({ + action: "run", + }) + console.log(new Array(TERMINAL_SIZE).join("-")) + logger.info("Migrations completed") + + /** + * Sync links + */ + if (!skipLinks) { + console.log(new Array(TERMINAL_SIZE).join("-")) + await syncLinks(medusaAppLoader, { + executeAll: executeAllLinks, + executeSafe: executeSafeLinks, + }) + } + + return true +} + const main = async function ({ directory, skipLinks, @@ -16,45 +72,13 @@ const main = async function ({ executeSafeLinks, }) { try { - /** - * Setup - */ - const container = await initializeContainer(directory) - await ensureDbExists(container) - - const medusaAppLoader = new MedusaAppLoader() - const configModule = container.resolve( - ContainerRegistrationKeys.CONFIG_MODULE - ) - - const plugins = getResolvedPlugins(directory, configModule, true) || [] - const linksSourcePaths = plugins.map((plugin) => - join(plugin.resolve, "links") - ) - await new LinkLoader(linksSourcePaths).load() - - /** - * Run migrations - */ - logger.info("Running migrations...") - await medusaAppLoader.runModulesMigrations({ - action: "run", + const migrated = await migrate({ + directory, + skipLinks, + executeAllLinks, + executeSafeLinks, }) - console.log(new Array(TERMINAL_SIZE).join("-")) - logger.info("Migrations completed") - - /** - * Sync links - */ - if (!skipLinks) { - console.log(new Array(TERMINAL_SIZE).join("-")) - await syncLinks(medusaAppLoader, { - executeAll: executeAllLinks, - executeSafe: executeSafeLinks, - }) - } - - process.exit() + process.exit(migrated ? 0 : 1) } catch (error) { logger.error(error) process.exit(1) diff --git a/packages/medusa/src/commands/db/setup.ts b/packages/medusa/src/commands/db/setup.ts new file mode 100644 index 0000000000..1427aac061 --- /dev/null +++ b/packages/medusa/src/commands/db/setup.ts @@ -0,0 +1,36 @@ +import { logger } from "@medusajs/framework" +import { dbCreate } from "./create" +import { migrate } from "./migrate" + +const main = async function ({ + directory, + interactive, + db, + skipLinks, + executeAllLinks, + executeSafeLinks, +}) { + try { + const created = await dbCreate({ directory, interactive, db }) + if (!created) { + process.exit(1) + } + + const migrated = await migrate({ + directory, + skipLinks, + executeAllLinks, + executeSafeLinks, + }) + + process.exit(migrated ? 0 : 1) + } catch (error) { + if (error.name === "ExitPromptError") { + process.exit() + } + logger.error(error) + process.exit(1) + } +} + +export default main diff --git a/packages/medusa/src/commands/db/sync-links.ts b/packages/medusa/src/commands/db/sync-links.ts index cd6eb366ad..88adad8978 100644 --- a/packages/medusa/src/commands/db/sync-links.ts +++ b/packages/medusa/src/commands/db/sync-links.ts @@ -193,8 +193,8 @@ const main = async function ({ directory, executeSafe, executeAll }) { await syncLinks(medusaAppLoader, { executeAll, executeSafe }) process.exit() - } catch (e) { - logger.error(e) + } catch (error) { + logger.error(error) process.exit(1) } }