diff --git a/packages/core/data-transfer/src/engine/index.ts b/packages/core/data-transfer/src/engine/index.ts index 6174f99f11..b789622ef2 100644 --- a/packages/core/data-transfer/src/engine/index.ts +++ b/packages/core/data-transfer/src/engine/index.ts @@ -27,7 +27,11 @@ import type { Diff } from '../utils/json'; import { compareSchemas, validateProvider } from './validation'; import { filter, map } from '../utils/stream'; -import { TransferEngineError, TransferEngineValidationError } from './errors'; +import { + TransferEngineError, + TransferEngineInitializationError, + TransferEngineValidationError, +} from './errors'; import { createDiagnosticReporter, IDiagnosticReporter, @@ -76,6 +80,27 @@ export const DEFAULT_SCHEMA_STRATEGY = 'strict'; type SchemaMap = Record; +type SchemaDiffHandlerContext = { + diffs: Record; + source: ISourceProvider; + destination: IDestinationProvider; +}; +type SchemaDiffHandler = (data: SchemaDiffHandlerContext, next: SchemaDiffHandler) => void; + +// TODO: clean this up +type Next = (context: any) => void | Promise; +type Middleware = (context: T, next: Next) => Promise | void; +async function runMiddleware(context: T, middlewares: Middleware[]): Promise { + if (!middlewares.length) { + return; + } + + const cb = middlewares[0]; + await cb(context, async (newContext) => { + await runMiddleware(newContext, middlewares.slice(1)); + }); +} + class TransferEngine< S extends ISourceProvider = ISourceProvider, D extends IDestinationProvider = IDestinationProvider @@ -99,6 +124,16 @@ class TransferEngine< diagnostics: IDiagnosticReporter; + #handlers: { + schemaDiff: SchemaDiffHandler[]; + } = { + schemaDiff: [], + }; + + onSchemaDiff(handler: SchemaDiffHandler) { + this.#handlers?.schemaDiff?.push(handler); + } + // Save the currently open stream so that we can access it at any time #currentStream?: Writable; @@ -616,15 +651,24 @@ class TransferEngine< if (error instanceof TransferEngineValidationError) { this.#schemaDiffs = error.details?.details?.diffs as Record; - // TODO: implement a confirmation callback to confirm or reject the error - Object.entries(this.#schemaDiffs).forEach(([uid, diffs]) => { - for (const diff of diffs) { - this.#reportWarning(`${diff.path.join('.')} for ${uid}`, 'Schema Integrity Check'); - // await new Promise((resolve, reject) => { - // this.confirm('Continue with diffs ?', resolve, reject); - // }); - } - }); + const context = { + diffs: this.#schemaDiffs, + source: this.sourceProvider, + destination: this.destinationProvider, + }; + await runMiddleware(context, this.#handlers.schemaDiff); + + if (Object.keys(context.diffs).length) { + console.log('DIFFS REMAINING', context.diffs); + Object.entries(context.diffs).forEach(([uid, diffs]) => { + for (const diff of diffs) { + this.#reportWarning(`${diff.path.join('.')} for ${uid}`, 'Schema Integrity Check'); + this.#panic( + new TransferEngineInitializationError('Unresolved differences in schema') + ); + } + }); + } return; } throw error; diff --git a/packages/core/strapi/lib/commands/actions/import/action.js b/packages/core/strapi/lib/commands/actions/import/action.js index 9a6095ca4c..240715c097 100644 --- a/packages/core/strapi/lib/commands/actions/import/action.js +++ b/packages/core/strapi/lib/commands/actions/import/action.js @@ -11,6 +11,7 @@ const { } = require('@strapi/data-transfer'); const { isObject } = require('lodash/fp'); +const inquirer = require('inquirer'); const { buildTransferTable, @@ -111,6 +112,24 @@ module.exports = async (opts) => { const { updateLoader } = loadersFactory(); + engine.onSchemaDiff(async (context, next) => { + // TODO: work with "force" + // TODO: yes/no prompt should look like commander prompt + const answers = await inquirer.prompt([ + { + type: 'confirm', + message: 'Are you sure you want to continue?', + name: 'confirmSchemaDiff', + }, + ]); + if (answers.confirmSchemaDiff) { + // diffs have been resolved by user + context.diffs = []; + } + + return next(context); + }); + progress.on(`stage::start`, ({ stage, data }) => { updateLoader(stage, data).start(); });