mirror of
https://github.com/strapi/strapi.git
synced 2025-09-22 06:50:51 +00:00
Merge pull request #15169 from strapi/deits/strategies-cleanup
This commit is contained in:
commit
0444bb9929
@ -299,9 +299,8 @@ describe('Transfer engine', () => {
|
||||
} as IDestinationProvider;
|
||||
|
||||
const defaultOptions = {
|
||||
strategy: 'restore',
|
||||
versionMatching: 'exact',
|
||||
schemasMatching: 'exact',
|
||||
versionStrategy: 'exact',
|
||||
schemaStrategy: 'exact',
|
||||
exclude: [],
|
||||
} as ITransferEngineOptions;
|
||||
|
||||
@ -416,9 +415,8 @@ describe('Transfer engine', () => {
|
||||
describe('schema matching', () => {
|
||||
describe('exact', () => {
|
||||
const engineOptions = {
|
||||
strategy: 'restore',
|
||||
versionMatching: 'exact',
|
||||
schemasMatching: 'exact',
|
||||
versionStrategy: 'exact',
|
||||
schemaStrategy: 'exact',
|
||||
exclude: [],
|
||||
} as ITransferEngineOptions;
|
||||
test('source with source schema missing in destination fails', async () => {
|
||||
@ -465,7 +463,7 @@ describe('Transfer engine', () => {
|
||||
const versionsThatFail = ['foo', 'z1.2.3', '1.2.3z'];
|
||||
const options: ITransferEngineOptions = {
|
||||
...defaultOptions,
|
||||
versionMatching: 'exact',
|
||||
versionStrategy: 'exact',
|
||||
};
|
||||
|
||||
versionsThatFail.forEach((version) => {
|
||||
@ -487,7 +485,7 @@ describe('Transfer engine', () => {
|
||||
const versionsThatSucceed = ['1.2.3'];
|
||||
const options: ITransferEngineOptions = {
|
||||
...defaultOptions,
|
||||
versionMatching: 'exact',
|
||||
versionStrategy: 'exact',
|
||||
};
|
||||
|
||||
versionsThatFail.forEach((version) => {
|
||||
@ -522,7 +520,7 @@ describe('Transfer engine', () => {
|
||||
const versionsThatSucceed = ['1.2.3', '1.3.4', '1.4.4-alpha'];
|
||||
const options: ITransferEngineOptions = {
|
||||
...defaultOptions,
|
||||
versionMatching: 'major',
|
||||
versionStrategy: 'major',
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
@ -561,7 +559,7 @@ describe('Transfer engine', () => {
|
||||
const versionsThatSucceed = ['1.2.3', '1.2.40', '1.2.4-alpha'];
|
||||
const options: ITransferEngineOptions = {
|
||||
...defaultOptions,
|
||||
versionMatching: 'minor',
|
||||
versionStrategy: 'minor',
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
@ -600,7 +598,7 @@ describe('Transfer engine', () => {
|
||||
const versionsThatSucceed = ['1.2.3'];
|
||||
const options: ITransferEngineOptions = {
|
||||
...defaultOptions,
|
||||
versionMatching: 'patch',
|
||||
versionStrategy: 'patch',
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
@ -638,7 +636,7 @@ describe('Transfer engine', () => {
|
||||
const versionsThatSucceed = ['1.2.3', '1.3.4', '5.24.44-alpha'];
|
||||
const options: ITransferEngineOptions = {
|
||||
...defaultOptions,
|
||||
versionMatching: 'ignore',
|
||||
versionStrategy: 'ignore',
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { PassThrough, Transform, Readable, Writable } from 'stream';
|
||||
import * as path from 'path';
|
||||
import { extname } from 'path';
|
||||
import { isEmpty, uniq } from 'lodash/fp';
|
||||
import { diff as semverDiff } from 'semver';
|
||||
@ -24,6 +23,9 @@ import type { Diff } from '../utils/json';
|
||||
import compareSchemas from '../strategies';
|
||||
import { filter, map } from '../utils/stream';
|
||||
|
||||
export const DEFAULT_VERSION_STRATEGY = 'ignore';
|
||||
export const DEFAULT_SCHEMA_STRATEGY = 'strict';
|
||||
|
||||
type SchemaMap = Record<string, Schema>;
|
||||
|
||||
class TransferEngine<
|
||||
@ -158,7 +160,7 @@ class TransferEngine<
|
||||
}
|
||||
|
||||
#assertStrapiVersionIntegrity(sourceVersion?: string, destinationVersion?: string) {
|
||||
const strategy = this.options.versionMatching;
|
||||
const strategy = this.options.versionStrategy || DEFAULT_VERSION_STRATEGY;
|
||||
|
||||
if (
|
||||
!sourceVersion ||
|
||||
@ -200,7 +202,11 @@ class TransferEngine<
|
||||
}
|
||||
|
||||
#assertSchemasMatching(sourceSchemas: SchemaMap, destinationSchemas: SchemaMap) {
|
||||
const strategy = this.options.schemasMatching || 'strict';
|
||||
const strategy = this.options.schemaStrategy || DEFAULT_SCHEMA_STRATEGY;
|
||||
if (strategy === 'ignore') {
|
||||
return;
|
||||
}
|
||||
|
||||
const keys = uniq(Object.keys(sourceSchemas).concat(Object.keys(destinationSchemas)));
|
||||
const diffs: { [key: string]: Diff[] } = {};
|
||||
|
||||
|
@ -6,7 +6,8 @@ import type { IAsset, IDestinationProvider, IMetadata, ProviderType } from '../.
|
||||
import { restore } from './strategies';
|
||||
import * as utils from '../../utils';
|
||||
|
||||
export const VALID_STRATEGIES = ['restore', 'merge'];
|
||||
export const VALID_CONFLICT_STRATEGIES = ['restore', 'merge'];
|
||||
export const DEFAULT_CONFLICT_STRATEGY = 'restore';
|
||||
|
||||
interface ILocalStrapiDestinationProviderOptions {
|
||||
getStrapi(): Strapi.Strapi | Promise<Strapi.Strapi>;
|
||||
@ -40,7 +41,7 @@ class LocalStrapiDestinationProvider implements IDestinationProvider {
|
||||
}
|
||||
|
||||
#validateOptions() {
|
||||
if (!VALID_STRATEGIES.includes(this.options.strategy)) {
|
||||
if (!VALID_CONFLICT_STRATEGIES.includes(this.options.strategy)) {
|
||||
throw new Error(`Invalid stategy ${this.options.strategy}`);
|
||||
}
|
||||
}
|
||||
|
@ -112,12 +112,12 @@ export interface ITransferEngineOptions {
|
||||
* "minor" // both the major and minor version should match. 4.3.9 and 4.3.11 will work, while 4.3.9 and 4.4.1 won't
|
||||
* "patch" // every part of the version should match. Similar to "exact" but only work on semver.
|
||||
*/
|
||||
versionMatching: 'exact' | 'ignore' | 'major' | 'minor' | 'patch';
|
||||
versionStrategy: 'exact' | 'ignore' | 'major' | 'minor' | 'patch';
|
||||
|
||||
/**
|
||||
* Strategy used to do the schema matching in the integrity checks
|
||||
*/
|
||||
schemasMatching: 'exact' | 'strict';
|
||||
schemaStrategy: 'exact' | 'strict' | 'ignore';
|
||||
|
||||
// List of rules to integrate into the final pipelines
|
||||
transforms?: {
|
||||
|
@ -14,11 +14,7 @@ const inquirer = require('inquirer');
|
||||
const program = new Command();
|
||||
|
||||
const packageJSON = require('../package.json');
|
||||
const {
|
||||
parseInputList,
|
||||
promptEncryptionKey,
|
||||
confirmKeyValue,
|
||||
} = require('../lib/commands/utils/commander');
|
||||
const { promptEncryptionKey, confirmMessage } = require('../lib/commands/utils/commander');
|
||||
|
||||
const checkCwdIsStrapiApp = (name) => {
|
||||
const logErrorAndExit = () => {
|
||||
@ -273,45 +269,15 @@ program
|
||||
.addOption(
|
||||
new Option('--key <string>', 'Provide encryption key in command instead of using a prompt')
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'--max-size-jsonl <max MB per internal backup file>',
|
||||
'split internal jsonl files when exceeding max size in MB'
|
||||
)
|
||||
.argParser(parseFloat)
|
||||
.default(256)
|
||||
)
|
||||
.addOption(new Option('-f, --file <file>', 'name to use for exported file (without extensions)'))
|
||||
.allowExcessArguments(false)
|
||||
.hook('preAction', promptEncryptionKey)
|
||||
// validate inputs
|
||||
.hook('preAction', (thisCommand) => {
|
||||
const opts = thisCommand.opts();
|
||||
if (!opts.maxSizeJsonl) {
|
||||
console.error('Invalid max-size-jsonl provided. Must be a number value.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.action(getLocalScript('transfer/export'));
|
||||
|
||||
// `$ strapi import`
|
||||
program
|
||||
.command('import')
|
||||
.description('Import data from file to Strapi')
|
||||
.addOption(
|
||||
new Option('--conflictStrategy <conflictStrategy>', 'Which strategy to use for ID conflicts')
|
||||
.choices(['restore', 'abort', 'keep', 'replace'])
|
||||
.default('restore')
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'--schemaComparison <schemaComparison>',
|
||||
'exact requires every field to match, strict requires Strapi version and content type schema fields do not break, subset requires source schema to exist in destination, bypass skips checks',
|
||||
parseInputList
|
||||
)
|
||||
.choices(['exact', 'strict', 'subset', 'bypass'])
|
||||
.default('exact')
|
||||
)
|
||||
.requiredOption(
|
||||
'-f, --file <file>',
|
||||
'path and filename to the Strapi export file you want to import'
|
||||
@ -344,10 +310,8 @@ program
|
||||
})
|
||||
.hook(
|
||||
'preAction',
|
||||
confirmKeyValue(
|
||||
'conflictStrategy',
|
||||
'restore',
|
||||
"Using strategy 'restore' will delete all data in your database. Are you sure you want to proceed?"
|
||||
confirmMessage(
|
||||
'The import will delete all data in your database. Are you sure you want to proceed?'
|
||||
)
|
||||
)
|
||||
.action(getLocalScript('transfer/import'));
|
||||
|
@ -22,7 +22,6 @@ const {
|
||||
* @typedef ImportCommandOptions Options given to the CLI import command
|
||||
*
|
||||
* @property {string} [file] The file path to import
|
||||
* @property {number} [maxSizeJsonl] Maximum size for each .jsonl file
|
||||
* @property {boolean} [encrypt] Used to encrypt the final archive
|
||||
* @property {string} [key] Encryption key, only useful when encryption is enabled
|
||||
* @property {boolean} [compress] Used to compress the final archive
|
||||
@ -52,8 +51,8 @@ module.exports = async (opts) => {
|
||||
const destination = createDestinationProvider(opts);
|
||||
|
||||
const engine = createTransferEngine(source, destination, {
|
||||
strategy: 'restore', // for an export to file, strategy will always be 'restore'
|
||||
versionMatching: 'ignore', // for an export to file, versionMatching will always be skipped
|
||||
versionStrategy: 'ignore', // for an export to file, versionStrategy will always be skipped
|
||||
schemaStrategy: 'ignore', // for an export to file, schemaStrategy will always be skipped
|
||||
transforms: {
|
||||
links: [
|
||||
{
|
||||
|
@ -4,6 +4,9 @@ const {
|
||||
createLocalFileSourceProvider,
|
||||
createLocalStrapiDestinationProvider,
|
||||
createTransferEngine,
|
||||
DEFAULT_VERSION_STRATEGY,
|
||||
DEFAULT_SCHEMA_STRATEGY,
|
||||
DEFAULT_CONFLICT_STRATEGY,
|
||||
// TODO: we need to solve this issue with typescript modules
|
||||
// eslint-disable-next-line import/no-unresolved, node/no-missing-require
|
||||
} = require('@strapi/data-transfer');
|
||||
@ -42,7 +45,7 @@ module.exports = async (opts) => {
|
||||
async getStrapi() {
|
||||
return strapiInstance;
|
||||
},
|
||||
strategy: opts.conflictStrategy,
|
||||
strategy: opts.conflictStrategy || DEFAULT_CONFLICT_STRATEGY,
|
||||
restore: {
|
||||
entities: { exclude: DEFAULT_IGNORED_CONTENT_TYPES },
|
||||
},
|
||||
@ -53,8 +56,8 @@ module.exports = async (opts) => {
|
||||
* Configure and run the transfer engine
|
||||
*/
|
||||
const engineOptions = {
|
||||
strategy: opts.conflictStrategy,
|
||||
versionMatching: opts.schemaComparison,
|
||||
versionStrategy: opts.versionStrategy || DEFAULT_VERSION_STRATEGY,
|
||||
schemaStrategy: opts.schemaStrategy || DEFAULT_SCHEMA_STRATEGY,
|
||||
exclude: opts.exclude,
|
||||
rules: {
|
||||
links: [
|
||||
|
@ -48,25 +48,19 @@ const promptEncryptionKey = async (thisCommand) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* hook: confirm that key has a value with a provided message
|
||||
* hook: require a confirmation message to be accepted
|
||||
*/
|
||||
const confirmKeyValue = (key, value, message) => {
|
||||
return async (thisCommand) => {
|
||||
const opts = thisCommand.opts();
|
||||
|
||||
if (!opts[key] || opts[key] !== value) {
|
||||
console.error(`Could not confirm key ${key}, halting operation.`);
|
||||
process.exit(1);
|
||||
}
|
||||
const confirmMessage = (message) => {
|
||||
return async () => {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
message,
|
||||
name: `confirm_${key}`,
|
||||
name: `confirm`,
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
if (!answers[`confirm_${key}`]) {
|
||||
if (!answers.confirm) {
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
@ -75,5 +69,5 @@ const confirmKeyValue = (key, value, message) => {
|
||||
module.exports = {
|
||||
parseInputList,
|
||||
promptEncryptionKey,
|
||||
confirmKeyValue,
|
||||
confirmMessage,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user