mirror of
https://github.com/strapi/strapi.git
synced 2025-09-24 16:04:54 +00:00
Merge branch 'v5/main' into chore/refactor-env-to-config
This commit is contained in:
commit
d1e7f41244
@ -40,7 +40,6 @@
|
||||
"watch": "pack-up watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@strapi/core": "4.17.1",
|
||||
"@strapi/logger": "4.17.1",
|
||||
"@strapi/types": "4.17.1",
|
||||
"@strapi/utils": "4.17.1",
|
||||
|
@ -1,154 +0,0 @@
|
||||
/**
|
||||
* This file includes hooks to use for commander.hook and argParsers for commander.argParser
|
||||
*/
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import { Command, InvalidOptionArgumentError, Option } from 'commander';
|
||||
import chalk from 'chalk';
|
||||
import { isNaN } from 'lodash/fp';
|
||||
import { exitWith } from './helpers';
|
||||
|
||||
/**
|
||||
* argParser: Parse a comma-delimited string as an array
|
||||
*/
|
||||
const parseList = (value: string) => {
|
||||
try {
|
||||
return value.split(',').map((item) => item.trim()); // trim shouldn't be necessary but might help catch unexpected whitespace characters
|
||||
} catch (e) {
|
||||
exitWith(1, `Unrecognized input: ${value}`);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an argParser that returns a list
|
||||
*/
|
||||
const getParseListWithChoices = (choices: string[], errorMessage = 'Invalid options:') => {
|
||||
return (value: string) => {
|
||||
const list = parseList(value);
|
||||
const invalid = list.filter((item) => {
|
||||
return !choices.includes(item);
|
||||
});
|
||||
|
||||
if (invalid.length > 0) {
|
||||
exitWith(1, `${errorMessage}: ${invalid.join(',')}`);
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* argParser: Parse a string as an integer
|
||||
*/
|
||||
const parseInteger = (value: string) => {
|
||||
// parseInt takes a string and a radix
|
||||
const parsedValue = parseInt(value, 10);
|
||||
if (isNaN(parsedValue)) {
|
||||
throw new InvalidOptionArgumentError(`Not an integer: ${value}`);
|
||||
}
|
||||
return parsedValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* argParser: Parse a string as a URL object
|
||||
*/
|
||||
const parseURL = (value: string) => {
|
||||
try {
|
||||
const url = new URL(value);
|
||||
if (!url.host) {
|
||||
throw new InvalidOptionArgumentError(`Could not parse url ${value}`);
|
||||
}
|
||||
|
||||
return url;
|
||||
} catch (e) {
|
||||
throw new InvalidOptionArgumentError(`Could not parse url ${value}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* hook: if encrypt==true and key not provided, prompt for it
|
||||
*/
|
||||
const promptEncryptionKey = async (thisCommand: Command) => {
|
||||
const opts = thisCommand.opts();
|
||||
|
||||
if (!opts.encrypt && opts.key) {
|
||||
return exitWith(1, 'Key may not be present unless encryption is used');
|
||||
}
|
||||
|
||||
// if encrypt==true but we have no key, prompt for it
|
||||
if (opts.encrypt && !(opts.key && opts.key.length > 0)) {
|
||||
try {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'password',
|
||||
message: 'Please enter an encryption key',
|
||||
name: 'key',
|
||||
validate(key) {
|
||||
if (key.length > 0) return true;
|
||||
|
||||
return 'Key must be present when using the encrypt option';
|
||||
},
|
||||
},
|
||||
]);
|
||||
opts.key = answers.key;
|
||||
} catch (e) {
|
||||
return exitWith(1, 'Failed to get encryption key');
|
||||
}
|
||||
if (!opts.key) {
|
||||
return exitWith(1, 'Failed to get encryption key');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* hook: require a confirmation message to be accepted unless forceOption (-f,--force) is used
|
||||
*/
|
||||
const getCommanderConfirmMessage = (
|
||||
message: string,
|
||||
{ failMessage }: { failMessage?: string } = {}
|
||||
) => {
|
||||
return async (command: Command) => {
|
||||
const confirmed = await confirmMessage(message, { force: command.opts().force });
|
||||
if (!confirmed) {
|
||||
exitWith(1, failMessage);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const confirmMessage = async (message: string, { force }: { force?: boolean } = {}) => {
|
||||
// if we have a force option, respond yes
|
||||
if (force === true) {
|
||||
// attempt to mimic the inquirer prompt exactly
|
||||
console.log(`${chalk.green('?')} ${chalk.bold(message)} ${chalk.cyan('Yes')}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
message,
|
||||
name: `confirm`,
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
return answers.confirm;
|
||||
};
|
||||
|
||||
const forceOption = new Option(
|
||||
'--force',
|
||||
`Automatically answer "yes" to all prompts, including potentially destructive requests, and run non-interactively.`
|
||||
);
|
||||
|
||||
export {
|
||||
getParseListWithChoices,
|
||||
parseList,
|
||||
parseURL,
|
||||
parseInteger,
|
||||
promptEncryptionKey,
|
||||
getCommanderConfirmMessage,
|
||||
confirmMessage,
|
||||
forceOption,
|
||||
};
|
@ -1,106 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import { isString, isArray } from 'lodash/fp';
|
||||
import type { Command } from 'commander';
|
||||
|
||||
const bytesPerKb = 1024;
|
||||
const sizes = ['B ', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
|
||||
/**
|
||||
* Convert bytes to a human readable formatted string, for example "1024" becomes "1KB"
|
||||
*/
|
||||
const readableBytes = (bytes: number, decimals = 1, padStart = 0) => {
|
||||
if (!bytes) {
|
||||
return '0';
|
||||
}
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(bytesPerKb));
|
||||
const result = `${parseFloat((bytes / bytesPerKb ** i).toFixed(decimals))} ${sizes[i].padStart(
|
||||
2
|
||||
)}`;
|
||||
|
||||
return result.padStart(padStart);
|
||||
};
|
||||
|
||||
interface ExitWithOptions {
|
||||
logger?: Console;
|
||||
prc?: NodeJS.Process;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Display message(s) to console and then call process.exit with code.
|
||||
* If code is zero, console.log and green text is used for messages, otherwise console.error and red text.
|
||||
*
|
||||
*/
|
||||
const exitWith = (code: number, message?: string | string[], options: ExitWithOptions = {}) => {
|
||||
const { logger = console, prc = process } = options;
|
||||
|
||||
const log = (message: string) => {
|
||||
if (code === 0) {
|
||||
logger.log(chalk.green(message));
|
||||
} else {
|
||||
logger.error(chalk.red(message));
|
||||
}
|
||||
};
|
||||
|
||||
if (isString(message)) {
|
||||
log(message);
|
||||
} else if (isArray(message)) {
|
||||
message.forEach((msg) => log(msg));
|
||||
}
|
||||
|
||||
prc.exit(code);
|
||||
};
|
||||
|
||||
/**
|
||||
* assert that a URL object has a protocol value
|
||||
*
|
||||
*/
|
||||
const assertUrlHasProtocol = (url: URL, protocol?: string | string[]) => {
|
||||
if (!url.protocol) {
|
||||
exitWith(1, `${url.toString()} does not have a protocol`);
|
||||
}
|
||||
|
||||
// if just checking for the existence of a protocol, return
|
||||
if (!protocol) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isString(protocol)) {
|
||||
if (protocol !== url.protocol) {
|
||||
exitWith(1, `${url.toString()} must have the protocol ${protocol}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// assume an array
|
||||
if (!protocol.some((protocol) => url.protocol === protocol)) {
|
||||
return exitWith(
|
||||
1,
|
||||
`${url.toString()} must have one of the following protocols: ${protocol.join(',')}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
type ConditionCallback = (opts: Record<string, any>) => Promise<boolean>;
|
||||
type IsMetCallback = (command: Command) => Promise<void>;
|
||||
type IsNotMetCallback = (command: Command) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Passes commander options to conditionCallback(). If it returns true, call isMetCallback otherwise call isNotMetCallback
|
||||
*/
|
||||
const ifOptions = (
|
||||
conditionCallback: ConditionCallback,
|
||||
isMetCallback: IsMetCallback = async () => {},
|
||||
isNotMetCallback: IsNotMetCallback = async () => {}
|
||||
) => {
|
||||
return async (command: Command) => {
|
||||
const opts = command.opts();
|
||||
if (await conditionCallback(opts)) {
|
||||
await isMetCallback(command);
|
||||
} else {
|
||||
await isNotMetCallback(command);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { exitWith, assertUrlHasProtocol, ifOptions, readableBytes };
|
@ -1,146 +0,0 @@
|
||||
import importAction from '../action';
|
||||
import { expectExit } from '../../__tests__/commands.test.utils';
|
||||
import * as engineDatatransfer from '../../../engine';
|
||||
import * as strapiDatatransfer from '../../../strapi';
|
||||
import * as fileDatatransfer from '../../../file';
|
||||
|
||||
jest.mock('../../data-transfer', () => {
|
||||
return {
|
||||
...jest.requireActual('../../data-transfer'),
|
||||
getTransferTelemetryPayload: jest.fn().mockReturnValue({}),
|
||||
loadersFactory: jest.fn().mockReturnValue({ updateLoader: jest.fn() }),
|
||||
formatDiagnostic: jest.fn(),
|
||||
createStrapiInstance: jest.fn().mockReturnValue({
|
||||
telemetry: {
|
||||
send: jest.fn(),
|
||||
},
|
||||
destroy: jest.fn(),
|
||||
}),
|
||||
buildTransferTable: jest.fn(() => {
|
||||
return {
|
||||
toString() {
|
||||
return 'table';
|
||||
},
|
||||
};
|
||||
}),
|
||||
exitMessageText: jest.fn(),
|
||||
getDiffHandler: jest.fn(),
|
||||
setSignalHandler: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../engine', () => {
|
||||
const actual = jest.requireActual('../../../engine');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
createTransferEngine: jest.fn(() => {
|
||||
return {
|
||||
transfer: jest.fn(() => {
|
||||
return {
|
||||
engine: {},
|
||||
};
|
||||
}),
|
||||
progress: {
|
||||
on: jest.fn(),
|
||||
stream: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
},
|
||||
sourceProvider: { name: 'testFileSource', type: 'source', getMetadata: jest.fn() },
|
||||
destinationProvider: {
|
||||
name: 'testStrapiDest',
|
||||
type: 'destination',
|
||||
getMetadata: jest.fn(),
|
||||
},
|
||||
diagnostics: {
|
||||
on: jest.fn().mockReturnThis(),
|
||||
onDiagnostic: jest.fn().mockReturnThis(),
|
||||
},
|
||||
onSchemaDiff: jest.fn(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../file', () => {
|
||||
const actual = jest.requireActual('../../../file');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
providers: {
|
||||
...actual.providers,
|
||||
createLocalFileSourceProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testFileSource', type: 'source', getMetadata: jest.fn() }),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../strapi', () => {
|
||||
const actual = jest.requireActual('../../../strapi');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
providers: {
|
||||
...actual.providers,
|
||||
createLocalStrapiDestinationProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testStrapiDest', type: 'destination', getMetadata: jest.fn() }),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('Import', () => {
|
||||
// mock command utils
|
||||
|
||||
// console spies
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('creates providers with correct options ', async () => {
|
||||
const options = {
|
||||
file: 'test.tar.gz.enc',
|
||||
decrypt: true,
|
||||
decompress: true,
|
||||
exclude: [],
|
||||
only: [],
|
||||
};
|
||||
|
||||
await expectExit(0, async () => {
|
||||
await importAction(options);
|
||||
});
|
||||
|
||||
// strapi options
|
||||
expect(strapiDatatransfer.providers.createLocalStrapiDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
strategy: strapiDatatransfer.providers.DEFAULT_CONFLICT_STRATEGY,
|
||||
})
|
||||
);
|
||||
|
||||
// file options
|
||||
expect(fileDatatransfer.providers.createLocalFileSourceProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
file: { path: 'test.tar.gz.enc' },
|
||||
encryption: { enabled: options.decrypt },
|
||||
compression: { enabled: options.decompress },
|
||||
})
|
||||
);
|
||||
|
||||
// engine options
|
||||
expect(engineDatatransfer.createTransferEngine).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ name: 'testFileSource' }),
|
||||
expect.objectContaining({ name: 'testStrapiDest' }),
|
||||
expect.objectContaining({
|
||||
schemaStrategy: engineDatatransfer.DEFAULT_SCHEMA_STRATEGY,
|
||||
versionStrategy: engineDatatransfer.DEFAULT_VERSION_STRATEGY,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
@ -1,5 +0,0 @@
|
||||
import exportCmd from './export/command';
|
||||
import importCmd from './import/command';
|
||||
import transferCmd from './transfer/command';
|
||||
|
||||
export const commands = [exportCmd, importCmd, transferCmd];
|
@ -2,4 +2,3 @@ export * as engine from './engine';
|
||||
export * as strapi from './strapi';
|
||||
export * as file from './file';
|
||||
export * as utils from './utils';
|
||||
export { commands } from './commands';
|
||||
|
@ -1,5 +1,10 @@
|
||||
{
|
||||
"extends": "tsconfig/base.json",
|
||||
"include": ["types", "src", "packup.config.ts"],
|
||||
"include": [
|
||||
"types",
|
||||
"src",
|
||||
"packup.config.ts",
|
||||
"../strapi/src/cli/commands/__tests__/commands.test.utils.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { file as fileDataTransfer } from '@strapi/data-transfer';
|
||||
|
||||
import exportAction from '../action';
|
||||
import * as mockUtils from '../../data-transfer';
|
||||
import * as mockUtils from '../../../utils/data-transfer';
|
||||
import { expectExit } from '../../__tests__/commands.test.utils';
|
||||
import * as fileDatatransfer from '../../../file';
|
||||
|
||||
jest.mock('fs-extra', () => ({
|
||||
...jest.requireActual('fs-extra'),
|
||||
@ -10,9 +11,9 @@ jest.mock('fs-extra', () => ({
|
||||
|
||||
const defaultFileName = 'defaultFilename';
|
||||
|
||||
jest.mock('../../data-transfer', () => {
|
||||
jest.mock('../../../utils/data-transfer', () => {
|
||||
return {
|
||||
...jest.requireActual('../../data-transfer'),
|
||||
...jest.requireActual('../../../utils/data-transfer'),
|
||||
getTransferTelemetryPayload: jest.fn().mockReturnValue({}),
|
||||
loadersFactory: jest.fn().mockReturnValue({ updateLoader: jest.fn() }),
|
||||
formatDiagnostic: jest.fn(),
|
||||
@ -36,75 +37,68 @@ jest.mock('../../data-transfer', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../engine', () => {
|
||||
const actual = jest.requireActual('../../../engine');
|
||||
jest.mock('@strapi/data-transfer', () => {
|
||||
const actual = jest.requireActual('@strapi/data-transfer');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
createTransferEngine: jest.fn(() => {
|
||||
return {
|
||||
transfer: jest.fn(() => {
|
||||
return {
|
||||
engine: {},
|
||||
destination: {
|
||||
file: {
|
||||
path: 'path',
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
progress: {
|
||||
on: jest.fn(),
|
||||
stream: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
},
|
||||
sourceProvider: { name: 'testFileSource', type: 'source', getMetadata: jest.fn() },
|
||||
destinationProvider: {
|
||||
name: 'testStrapiDest',
|
||||
file: {
|
||||
...actual.file,
|
||||
providers: {
|
||||
...actual.file.providers,
|
||||
createLocalFileSourceProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testFileSource', type: 'source', getMetadata: jest.fn() }),
|
||||
createLocalFileDestinationProvider: jest.fn().mockReturnValue({
|
||||
name: 'testFileDestination',
|
||||
type: 'destination',
|
||||
getMetadata: jest.fn(),
|
||||
},
|
||||
diagnostics: {
|
||||
on: jest.fn().mockReturnThis(),
|
||||
onDiagnostic: jest.fn().mockReturnThis(),
|
||||
},
|
||||
onSchemaDiff: jest.fn(),
|
||||
addErrorHandler: jest.fn(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../file', () => {
|
||||
const actual = jest.requireActual('../../../file');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
providers: {
|
||||
...actual.providers,
|
||||
createLocalFileSourceProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testFileSource', type: 'source', getMetadata: jest.fn() }),
|
||||
createLocalFileDestinationProvider: jest.fn().mockReturnValue({
|
||||
name: 'testFileDestination',
|
||||
type: 'destination',
|
||||
getMetadata: jest.fn(),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../strapi', () => {
|
||||
const actual = jest.requireActual('../../../strapi');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
providers: {
|
||||
...actual.providers,
|
||||
createLocalStrapiDestinationProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testStrapiDest', type: 'destination', getMetadata: jest.fn() }),
|
||||
strapi: {
|
||||
...actual.strapi,
|
||||
providers: {
|
||||
...actual.strapi.providers,
|
||||
createLocalStrapiDestinationProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testStrapiDest', type: 'destination', getMetadata: jest.fn() }),
|
||||
},
|
||||
},
|
||||
engine: {
|
||||
...actual.engine,
|
||||
createTransferEngine: jest.fn(() => {
|
||||
return {
|
||||
transfer: jest.fn(() => {
|
||||
return {
|
||||
engine: {},
|
||||
destination: {
|
||||
file: {
|
||||
path: 'path',
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
progress: {
|
||||
on: jest.fn(),
|
||||
stream: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
},
|
||||
sourceProvider: { name: 'testFileSource', type: 'source', getMetadata: jest.fn() },
|
||||
destinationProvider: {
|
||||
name: 'testStrapiDest',
|
||||
type: 'destination',
|
||||
getMetadata: jest.fn(),
|
||||
},
|
||||
diagnostics: {
|
||||
on: jest.fn().mockReturnThis(),
|
||||
onDiagnostic: jest.fn().mockReturnThis(),
|
||||
},
|
||||
onSchemaDiff: jest.fn(),
|
||||
addErrorHandler: jest.fn(),
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -130,7 +124,7 @@ describe('Export', () => {
|
||||
});
|
||||
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
expect(fileDatatransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect(fileDataTransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
file: { path: filename },
|
||||
})
|
||||
@ -144,7 +138,7 @@ describe('Export', () => {
|
||||
});
|
||||
|
||||
expect(mockUtils.getDefaultExportName).toHaveBeenCalledTimes(1);
|
||||
expect(fileDatatransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect(fileDataTransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
file: { path: defaultFileName },
|
||||
})
|
||||
@ -157,7 +151,7 @@ describe('Export', () => {
|
||||
await exportAction({ encrypt });
|
||||
});
|
||||
|
||||
expect(fileDatatransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect(fileDataTransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
encryption: { enabled: encrypt },
|
||||
})
|
||||
@ -171,7 +165,7 @@ describe('Export', () => {
|
||||
await exportAction({ encrypt, key });
|
||||
});
|
||||
|
||||
expect(fileDatatransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect(fileDataTransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
encryption: { enabled: encrypt, key },
|
||||
})
|
||||
@ -183,7 +177,7 @@ describe('Export', () => {
|
||||
await exportAction({ compress: false });
|
||||
});
|
||||
|
||||
expect(fileDatatransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect(fileDataTransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
compression: { enabled: false },
|
||||
})
|
||||
@ -191,7 +185,7 @@ describe('Export', () => {
|
||||
await expectExit(0, async () => {
|
||||
await exportAction({ compress: true });
|
||||
});
|
||||
expect(fileDatatransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect(fileDataTransfer.providers.createLocalFileDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
compression: { enabled: true },
|
||||
})
|
@ -3,6 +3,12 @@ import fs from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
import type { LoadedStrapi } from '@strapi/types';
|
||||
|
||||
import {
|
||||
engine as engineDataTransfer,
|
||||
strapi as strapiDataTransfer,
|
||||
file as fileDataTransfer,
|
||||
} from '@strapi/data-transfer';
|
||||
|
||||
import {
|
||||
getDefaultExportName,
|
||||
buildTransferTable,
|
||||
@ -14,18 +20,15 @@ import {
|
||||
abortTransfer,
|
||||
getTransferTelemetryPayload,
|
||||
setSignalHandler,
|
||||
} from '../data-transfer';
|
||||
import { exitWith } from '../helpers';
|
||||
import { TransferGroupFilter, createTransferEngine, ITransferResults, errors } from '../../engine';
|
||||
import * as strapiDatatransfer from '../../strapi';
|
||||
import * as file from '../../file';
|
||||
} from '../../utils/data-transfer';
|
||||
import { exitWith } from '../../utils/helpers';
|
||||
|
||||
const {
|
||||
providers: { createLocalFileDestinationProvider },
|
||||
} = file;
|
||||
} = fileDataTransfer;
|
||||
const {
|
||||
providers: { createLocalStrapiSourceProvider },
|
||||
} = strapiDatatransfer;
|
||||
} = strapiDataTransfer;
|
||||
|
||||
const BYTES_IN_MB = 1024 * 1024;
|
||||
|
||||
@ -34,8 +37,8 @@ interface CmdOptions {
|
||||
encrypt?: boolean;
|
||||
key?: string;
|
||||
compress?: boolean;
|
||||
only?: (keyof TransferGroupFilter)[];
|
||||
exclude?: (keyof TransferGroupFilter)[];
|
||||
only?: (keyof engineDataTransfer.TransferGroupFilter)[];
|
||||
exclude?: (keyof engineDataTransfer.TransferGroupFilter)[];
|
||||
throttle?: number;
|
||||
maxSizeJsonl?: number;
|
||||
}
|
||||
@ -58,7 +61,7 @@ export default async (opts: CmdOptions) => {
|
||||
const source = createSourceProvider(strapi);
|
||||
const destination = createDestinationProvider(opts);
|
||||
|
||||
const engine = createTransferEngine(source, destination, {
|
||||
const engine = engineDataTransfer.createTransferEngine(source, destination, {
|
||||
versionStrategy: 'ignore', // for an export to file, versionStrategy will always be skipped
|
||||
schemaStrategy: 'ignore', // for an export to file, schemaStrategy will always be skipped
|
||||
exclude: opts.exclude,
|
||||
@ -109,7 +112,7 @@ export default async (opts: CmdOptions) => {
|
||||
await strapi.telemetry.send('didDEITSProcessStart', getTransferTelemetryPayload(engine));
|
||||
});
|
||||
|
||||
let results: ITransferResults<typeof source, typeof destination>;
|
||||
let results: engineDataTransfer.ITransferResults<typeof source, typeof destination>;
|
||||
let outFile: string;
|
||||
try {
|
||||
// Abort transfer if user interrupts process
|
||||
@ -119,7 +122,9 @@ export default async (opts: CmdOptions) => {
|
||||
outFile = results.destination?.file?.path ?? '';
|
||||
const outFileExists = await fs.pathExists(outFile);
|
||||
if (!outFileExists) {
|
||||
throw new errors.TransferEngineTransferError(`Export file not created "${outFile}"`);
|
||||
throw new engineDataTransfer.errors.TransferEngineTransferError(
|
||||
`Export file not created "${outFile}"`
|
||||
);
|
||||
}
|
||||
|
||||
// Note: we need to await telemetry or else the process ends before it is sent
|
@ -1,6 +1,12 @@
|
||||
import { createCommand, Option } from 'commander';
|
||||
import { excludeOption, onlyOption, throttleOption, validateExcludeOnly } from '../data-transfer';
|
||||
import { promptEncryptionKey } from '../commander';
|
||||
|
||||
import {
|
||||
excludeOption,
|
||||
onlyOption,
|
||||
throttleOption,
|
||||
validateExcludeOnly,
|
||||
} from '../../utils/data-transfer';
|
||||
import { promptEncryptionKey } from '../../utils/commander';
|
||||
import action from './action';
|
||||
|
||||
/**
|
@ -0,0 +1,142 @@
|
||||
import {
|
||||
engine as engineDataTransfer,
|
||||
strapi as strapiDataTransfer,
|
||||
file as fileDataTransfer,
|
||||
} from '@strapi/data-transfer';
|
||||
|
||||
import importAction from '../action';
|
||||
import { expectExit } from '../../__tests__/commands.test.utils';
|
||||
|
||||
jest.mock('../../../utils/data-transfer', () => {
|
||||
return {
|
||||
...jest.requireActual('../../../utils/data-transfer'),
|
||||
getTransferTelemetryPayload: jest.fn().mockReturnValue({}),
|
||||
loadersFactory: jest.fn().mockReturnValue({ updateLoader: jest.fn() }),
|
||||
formatDiagnostic: jest.fn(),
|
||||
createStrapiInstance: jest.fn().mockReturnValue({
|
||||
telemetry: {
|
||||
send: jest.fn(),
|
||||
},
|
||||
destroy: jest.fn(),
|
||||
}),
|
||||
buildTransferTable: jest.fn(() => {
|
||||
return {
|
||||
toString() {
|
||||
return 'table';
|
||||
},
|
||||
};
|
||||
}),
|
||||
exitMessageText: jest.fn(),
|
||||
getDiffHandler: jest.fn(),
|
||||
setSignalHandler: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('@strapi/data-transfer', () => {
|
||||
const actual = jest.requireActual('@strapi/data-transfer');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
file: {
|
||||
...actual.file,
|
||||
providers: {
|
||||
...actual.file.providers,
|
||||
createLocalFileSourceProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testFileSource', type: 'source', getMetadata: jest.fn() }),
|
||||
},
|
||||
},
|
||||
strapi: {
|
||||
...actual.strapi,
|
||||
providers: {
|
||||
...actual.strapi.providers,
|
||||
createLocalStrapiDestinationProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testStrapiDest', type: 'destination', getMetadata: jest.fn() }),
|
||||
},
|
||||
},
|
||||
engine: {
|
||||
...actual.engine,
|
||||
createTransferEngine: jest.fn(() => {
|
||||
return {
|
||||
transfer: jest.fn(() => {
|
||||
return {
|
||||
engine: {},
|
||||
};
|
||||
}),
|
||||
progress: {
|
||||
on: jest.fn(),
|
||||
stream: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
},
|
||||
sourceProvider: { name: 'testFileSource', type: 'source', getMetadata: jest.fn() },
|
||||
destinationProvider: {
|
||||
name: 'testStrapiDest',
|
||||
type: 'destination',
|
||||
getMetadata: jest.fn(),
|
||||
},
|
||||
diagnostics: {
|
||||
on: jest.fn().mockReturnThis(),
|
||||
onDiagnostic: jest.fn().mockReturnThis(),
|
||||
},
|
||||
onSchemaDiff: jest.fn(),
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('Import', () => {
|
||||
// mock command utils
|
||||
|
||||
// console spies
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'info').mockImplementation(() => {});
|
||||
jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('creates providers with correct options ', async () => {
|
||||
const options = {
|
||||
file: 'test.tar.gz.enc',
|
||||
decrypt: true,
|
||||
decompress: true,
|
||||
exclude: [],
|
||||
only: [],
|
||||
};
|
||||
|
||||
await expectExit(0, async () => {
|
||||
await importAction(options);
|
||||
});
|
||||
|
||||
// strapi options
|
||||
expect(strapiDataTransfer.providers.createLocalStrapiDestinationProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
strategy: strapiDataTransfer.providers.DEFAULT_CONFLICT_STRATEGY,
|
||||
})
|
||||
);
|
||||
|
||||
// file options
|
||||
expect(fileDataTransfer.providers.createLocalFileSourceProvider).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
file: { path: 'test.tar.gz.enc' },
|
||||
encryption: { enabled: options.decrypt },
|
||||
compression: { enabled: options.decompress },
|
||||
})
|
||||
);
|
||||
|
||||
// engine options
|
||||
expect(engineDataTransfer.createTransferEngine).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ name: 'testFileSource' }),
|
||||
expect.objectContaining({ name: 'testStrapiDest' }),
|
||||
expect.objectContaining({
|
||||
schemaStrategy: engineDataTransfer.DEFAULT_SCHEMA_STRATEGY,
|
||||
versionStrategy: engineDataTransfer.DEFAULT_VERSION_STRATEGY,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
@ -1,7 +1,13 @@
|
||||
import type { LoadedStrapi } from '@strapi/types';
|
||||
import { isObject } from 'lodash/fp';
|
||||
|
||||
import chalk from 'chalk';
|
||||
|
||||
import {
|
||||
engine as engineDataTransfer,
|
||||
strapi as strapiDataTransfer,
|
||||
file as fileDataTransfer,
|
||||
} from '@strapi/data-transfer';
|
||||
|
||||
import {
|
||||
buildTransferTable,
|
||||
DEFAULT_IGNORED_CONTENT_TYPES,
|
||||
@ -14,21 +20,19 @@ import {
|
||||
setSignalHandler,
|
||||
getDiffHandler,
|
||||
parseRestoreFromOptions,
|
||||
} from '../data-transfer';
|
||||
import { exitWith } from '../helpers';
|
||||
import * as engine from '../../engine';
|
||||
import * as strapiDatatransfer from '../../strapi';
|
||||
import * as file from '../../file';
|
||||
} from '../../utils/data-transfer';
|
||||
import { exitWith } from '../../utils/helpers';
|
||||
|
||||
const {
|
||||
providers: { createLocalFileSourceProvider },
|
||||
} = file;
|
||||
} = fileDataTransfer;
|
||||
|
||||
const {
|
||||
providers: { createLocalStrapiDestinationProvider, DEFAULT_CONFLICT_STRATEGY },
|
||||
} = strapiDatatransfer;
|
||||
} = strapiDataTransfer;
|
||||
|
||||
const { createTransferEngine, DEFAULT_VERSION_STRATEGY, DEFAULT_SCHEMA_STRATEGY } = engine;
|
||||
const { createTransferEngine, DEFAULT_VERSION_STRATEGY, DEFAULT_SCHEMA_STRATEGY } =
|
||||
engineDataTransfer;
|
||||
|
||||
interface CmdOptions {
|
||||
file?: string;
|
||||
@ -37,8 +41,8 @@ interface CmdOptions {
|
||||
key?: string;
|
||||
conflictStrategy?: 'restore';
|
||||
force?: boolean;
|
||||
only?: (keyof engine.TransferGroupFilter)[];
|
||||
exclude?: (keyof engine.TransferGroupFilter)[];
|
||||
only?: (keyof engineDataTransfer.TransferGroupFilter)[];
|
||||
exclude?: (keyof engineDataTransfer.TransferGroupFilter)[];
|
||||
throttle?: number;
|
||||
}
|
||||
|
||||
@ -137,7 +141,7 @@ export default async (opts: CmdOptions) => {
|
||||
);
|
||||
});
|
||||
|
||||
let results: engine.ITransferResults<typeof source, typeof destination>;
|
||||
let results: engineDataTransfer.ITransferResults<typeof source, typeof destination>;
|
||||
try {
|
||||
// Abort transfer if user interrupts process
|
||||
setSignalHandler(() => abortTransfer({ engine, strapi: strapi as LoadedStrapi }));
|
||||
@ -174,7 +178,7 @@ const getLocalFileSourceOptions = (opts: {
|
||||
decrypt?: boolean;
|
||||
key?: string;
|
||||
}) => {
|
||||
const options: file.providers.ILocalFileSourceProviderOptions = {
|
||||
const options: fileDataTransfer.providers.ILocalFileSourceProviderOptions = {
|
||||
file: { path: opts.file ?? '' },
|
||||
compression: { enabled: !!opts.decompress },
|
||||
encryption: { enabled: !!opts.decrypt, key: opts.key },
|
@ -1,9 +1,14 @@
|
||||
import path from 'path';
|
||||
import { createCommand, Option } from 'commander';
|
||||
import inquirer from 'inquirer';
|
||||
import { excludeOption, onlyOption, throttleOption, validateExcludeOnly } from '../data-transfer';
|
||||
import { getCommanderConfirmMessage, forceOption } from '../commander';
|
||||
import { exitWith } from '../helpers';
|
||||
import {
|
||||
excludeOption,
|
||||
onlyOption,
|
||||
throttleOption,
|
||||
validateExcludeOnly,
|
||||
} from '../../utils/data-transfer';
|
||||
import { getCommanderConfirmMessage, forceOption } from '../../utils/commander';
|
||||
import { exitWith } from '../../utils/helpers';
|
||||
import action from './action';
|
||||
|
||||
/**
|
@ -21,6 +21,9 @@ import { command as generateCommand } from './generate';
|
||||
import { command as reportCommand } from './report';
|
||||
import { command as startCommand } from './start';
|
||||
import { command as versionCommand } from './version';
|
||||
import exportCommand from './export/command';
|
||||
import importCommand from './import/command';
|
||||
import transferCommand from './transfer/command';
|
||||
|
||||
import { command as buildPluginCommand } from './plugin/build';
|
||||
import { command as initPluginCommand } from './plugin/init';
|
||||
@ -53,6 +56,9 @@ export const commands: StrapiCommand[] = [
|
||||
versionCommand,
|
||||
buildCommand,
|
||||
developCommand,
|
||||
exportCommand,
|
||||
importCommand,
|
||||
transferCommand,
|
||||
/**
|
||||
* Plugins
|
||||
*/
|
||||
|
@ -1,10 +1,11 @@
|
||||
import * as mockDataTransfer from '@strapi/data-transfer';
|
||||
|
||||
import transferAction from '../action';
|
||||
import { expectExit } from '../../__tests__/commands.test.utils';
|
||||
import * as mockDataTransfer from '../../..';
|
||||
|
||||
jest.mock('../../data-transfer', () => {
|
||||
jest.mock('../../../utils/data-transfer', () => {
|
||||
return {
|
||||
...jest.requireActual('../../data-transfer'),
|
||||
...jest.requireActual('../../../utils/data-transfer'),
|
||||
getTransferTelemetryPayload: jest.fn().mockReturnValue({}),
|
||||
loadersFactory: jest.fn().mockReturnValue({ updateLoader: jest.fn() }),
|
||||
formatDiagnostic: jest.fn(),
|
||||
@ -31,44 +32,46 @@ jest.mock('../../data-transfer', () => {
|
||||
});
|
||||
|
||||
// mock data transfer
|
||||
jest.mock('../../../engine', () => {
|
||||
const acutal = jest.requireActual('../../../engine');
|
||||
jest.mock('@strapi/data-transfer', () => {
|
||||
const acutal = jest.requireActual('@strapi/data-transfer');
|
||||
return {
|
||||
...acutal,
|
||||
createTransferEngine() {
|
||||
return {
|
||||
transfer: jest.fn(() => {
|
||||
return {
|
||||
engine: {},
|
||||
};
|
||||
}),
|
||||
progress: {
|
||||
on: jest.fn(),
|
||||
stream: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
},
|
||||
sourceProvider: { name: 'testSource' },
|
||||
destinationProvider: { name: 'testDestination' },
|
||||
diagnostics: {
|
||||
on: jest.fn().mockReturnThis(),
|
||||
onDiagnostic: jest.fn().mockReturnThis(),
|
||||
},
|
||||
onSchemaDiff: jest.fn(),
|
||||
addErrorHandler: jest.fn(),
|
||||
};
|
||||
strapi: {
|
||||
...acutal.strapi,
|
||||
providers: {
|
||||
...acutal.strapi.providers,
|
||||
createLocalStrapiSourceProvider: jest.fn().mockReturnValue({ name: 'testLocalSource' }),
|
||||
createLocalStrapiDestinationProvider: jest.fn().mockReturnValue({ name: 'testLocalDest' }),
|
||||
createRemoteStrapiDestinationProvider: jest
|
||||
.fn()
|
||||
.mockReturnValue({ name: 'testRemoteDest' }),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../../strapi', () => {
|
||||
const actual = jest.requireActual('../../../strapi');
|
||||
return {
|
||||
...actual,
|
||||
providers: {
|
||||
createLocalStrapiSourceProvider: jest.fn().mockReturnValue({ name: 'testLocalSource' }),
|
||||
createLocalStrapiDestinationProvider: jest.fn().mockReturnValue({ name: 'testLocalDest' }),
|
||||
createRemoteStrapiDestinationProvider: jest.fn().mockReturnValue({ name: 'testRemoteDest' }),
|
||||
engine: {
|
||||
...acutal.engine,
|
||||
createTransferEngine() {
|
||||
return {
|
||||
transfer: jest.fn(() => {
|
||||
return {
|
||||
engine: {},
|
||||
};
|
||||
}),
|
||||
progress: {
|
||||
on: jest.fn(),
|
||||
stream: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
},
|
||||
sourceProvider: { name: 'testSource' },
|
||||
destinationProvider: { name: 'testDestination' },
|
||||
diagnostics: {
|
||||
on: jest.fn().mockReturnThis(),
|
||||
onDiagnostic: jest.fn().mockReturnThis(),
|
||||
},
|
||||
onSchemaDiff: jest.fn(),
|
||||
addErrorHandler: jest.fn(),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
@ -1,6 +1,5 @@
|
||||
import { isObject } from 'lodash/fp';
|
||||
import * as engineDatatransfer from '../../engine';
|
||||
import * as strapiDatatransfer from '../../strapi';
|
||||
import { engine as engineDataTransfer, strapi as strapiDataTransfer } from '@strapi/data-transfer';
|
||||
|
||||
import {
|
||||
buildTransferTable,
|
||||
@ -15,10 +14,10 @@ import {
|
||||
getDiffHandler,
|
||||
getAssetsBackupHandler,
|
||||
parseRestoreFromOptions,
|
||||
} from '../data-transfer';
|
||||
import { exitWith } from '../helpers';
|
||||
} from '../../utils/data-transfer';
|
||||
import { exitWith } from '../../utils/helpers';
|
||||
|
||||
const { createTransferEngine } = engineDatatransfer;
|
||||
const { createTransferEngine } = engineDataTransfer;
|
||||
const {
|
||||
providers: {
|
||||
createRemoteStrapiDestinationProvider,
|
||||
@ -26,15 +25,15 @@ const {
|
||||
createLocalStrapiDestinationProvider,
|
||||
createRemoteStrapiSourceProvider,
|
||||
},
|
||||
} = strapiDatatransfer;
|
||||
} = strapiDataTransfer;
|
||||
|
||||
interface CmdOptions {
|
||||
from?: URL;
|
||||
fromToken: string;
|
||||
to: URL;
|
||||
toToken: string;
|
||||
only?: (keyof engineDatatransfer.TransferGroupFilter)[];
|
||||
exclude?: (keyof engineDatatransfer.TransferGroupFilter)[];
|
||||
only?: (keyof engineDataTransfer.TransferGroupFilter)[];
|
||||
exclude?: (keyof engineDataTransfer.TransferGroupFilter)[];
|
||||
throttle?: number;
|
||||
force?: boolean;
|
||||
}
|
@ -1,8 +1,14 @@
|
||||
import inquirer from 'inquirer';
|
||||
import { createCommand, Option } from 'commander';
|
||||
import { getCommanderConfirmMessage, forceOption, parseURL } from '../commander';
|
||||
import { exitWith, assertUrlHasProtocol, ifOptions } from '../helpers';
|
||||
import { excludeOption, onlyOption, throttleOption, validateExcludeOnly } from '../data-transfer';
|
||||
import { getCommanderConfirmMessage, forceOption, parseURL } from '../../utils/commander';
|
||||
import { exitWith, assertUrlHasProtocol, ifOptions } from '../../utils/helpers';
|
||||
import {
|
||||
excludeOption,
|
||||
onlyOption,
|
||||
throttleOption,
|
||||
validateExcludeOnly,
|
||||
} from '../../utils/data-transfer';
|
||||
|
||||
import action from './action';
|
||||
|
||||
/**
|
@ -7,15 +7,6 @@ import { loadTsConfig } from './utils/tsconfig';
|
||||
import { CLIContext } from './types';
|
||||
|
||||
const createCLI = async (argv: string[], command = new Command()) => {
|
||||
try {
|
||||
// NOTE: this is a hack to allow loading dts commands without make dts a dependency of strapi and thus avoiding circular dependencies
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const dtsCommands = require(require.resolve('@strapi/data-transfer')).commands;
|
||||
strapiCommands.push(...dtsCommands);
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
// Initial program setup
|
||||
command.storeOptionsAsProperties(false).allowUnknownOption(true);
|
||||
|
||||
|
@ -6,15 +6,14 @@ import { strapiFactory } from '@strapi/core';
|
||||
import ora from 'ora';
|
||||
import { merge } from 'lodash/fp';
|
||||
import type { LoadedStrapi, Strapi } from '@strapi/types';
|
||||
import { engine as engineDataTransfer, strapi as strapiDataTransfer } from '@strapi/data-transfer';
|
||||
|
||||
import { readableBytes, exitWith } from './helpers';
|
||||
import { getParseListWithChoices, parseInteger, confirmMessage } from './commander';
|
||||
import * as engineDatatransfer from '../engine';
|
||||
import * as strapiDataTransfer from '../strapi';
|
||||
|
||||
const {
|
||||
errors: { TransferEngineInitializationError },
|
||||
} = engineDatatransfer;
|
||||
} = engineDataTransfer;
|
||||
|
||||
const exitMessageText = (process: string, error = false) => {
|
||||
const processCapitalized = process[0].toUpperCase() + process.slice(1);
|
||||
@ -49,9 +48,9 @@ const getDefaultExportName = () => {
|
||||
return `export_${yyyymmddHHMMSS()}`;
|
||||
};
|
||||
|
||||
type ResultData = engineDatatransfer.ITransferResults<
|
||||
engineDatatransfer.ISourceProvider,
|
||||
engineDatatransfer.IDestinationProvider
|
||||
type ResultData = engineDataTransfer.ITransferResults<
|
||||
engineDataTransfer.ISourceProvider,
|
||||
engineDataTransfer.IDestinationProvider
|
||||
>['engine'];
|
||||
|
||||
const buildTransferTable = (resultData: ResultData) => {
|
||||
@ -66,7 +65,7 @@ const buildTransferTable = (resultData: ResultData) => {
|
||||
|
||||
let totalBytes = 0;
|
||||
let totalItems = 0;
|
||||
(Object.keys(resultData) as engineDatatransfer.TransferStage[]).forEach((stage) => {
|
||||
(Object.keys(resultData) as engineDataTransfer.TransferStage[]).forEach((stage) => {
|
||||
const item = resultData[stage];
|
||||
|
||||
if (!item) {
|
||||
@ -123,7 +122,7 @@ const abortTransfer = async ({
|
||||
engine,
|
||||
strapi,
|
||||
}: {
|
||||
engine: engineDatatransfer.TransferEngine;
|
||||
engine: engineDataTransfer.TransferEngine;
|
||||
strapi: LoadedStrapi;
|
||||
}) => {
|
||||
try {
|
||||
@ -166,7 +165,7 @@ const createStrapiInstance = async (
|
||||
}
|
||||
};
|
||||
|
||||
const transferDataTypes = Object.keys(engineDatatransfer.TransferGroupPresets);
|
||||
const transferDataTypes = Object.keys(engineDataTransfer.TransferGroupPresets);
|
||||
|
||||
const throttleOption = new Option(
|
||||
'--throttle <delay after each entity>',
|
||||
@ -213,7 +212,7 @@ const errorColors = {
|
||||
const formatDiagnostic =
|
||||
(
|
||||
operation: string
|
||||
): Parameters<engineDatatransfer.TransferEngine['diagnostics']['onDiagnostic']>[0] =>
|
||||
): Parameters<engineDataTransfer.TransferEngine['diagnostics']['onDiagnostic']>[0] =>
|
||||
({ details, kind }) => {
|
||||
const logger = createLogger(
|
||||
configs.createOutputFileConfiguration(`${operation}_error_log_${Date.now()}.log`)
|
||||
@ -245,11 +244,11 @@ const formatDiagnostic =
|
||||
};
|
||||
|
||||
type Loaders = {
|
||||
[key in engineDatatransfer.TransferStage]: ora.Ora;
|
||||
[key in engineDataTransfer.TransferStage]: ora.Ora;
|
||||
};
|
||||
|
||||
type Data = {
|
||||
[key in engineDatatransfer.TransferStage]?: {
|
||||
[key in engineDataTransfer.TransferStage]?: {
|
||||
startTime?: number;
|
||||
endTime?: number;
|
||||
bytes?: number;
|
||||
@ -259,7 +258,7 @@ type Data = {
|
||||
|
||||
const loadersFactory = (defaultLoaders: Loaders = {} as Loaders) => {
|
||||
const loaders = defaultLoaders;
|
||||
const updateLoader = (stage: engineDatatransfer.TransferStage, data: Data) => {
|
||||
const updateLoader = (stage: engineDataTransfer.TransferStage, data: Data) => {
|
||||
if (!(stage in loaders)) {
|
||||
createLoader(stage);
|
||||
}
|
||||
@ -280,12 +279,12 @@ const loadersFactory = (defaultLoaders: Loaders = {} as Loaders) => {
|
||||
return loaders[stage];
|
||||
};
|
||||
|
||||
const createLoader = (stage: engineDatatransfer.TransferStage) => {
|
||||
const createLoader = (stage: engineDataTransfer.TransferStage) => {
|
||||
Object.assign(loaders, { [stage]: ora() });
|
||||
return loaders[stage];
|
||||
};
|
||||
|
||||
const getLoader = (stage: engineDatatransfer.TransferStage) => {
|
||||
const getLoader = (stage: engineDataTransfer.TransferStage) => {
|
||||
return loaders[stage];
|
||||
};
|
||||
|
||||
@ -299,7 +298,7 @@ const loadersFactory = (defaultLoaders: Loaders = {} as Loaders) => {
|
||||
/**
|
||||
* Get the telemetry data to be sent for a didDEITSProcess* event from an initialized transfer engine object
|
||||
*/
|
||||
const getTransferTelemetryPayload = (engine: engineDatatransfer.TransferEngine) => {
|
||||
const getTransferTelemetryPayload = (engine: engineDataTransfer.TransferEngine) => {
|
||||
return {
|
||||
eventProperties: {
|
||||
source: engine?.sourceProvider?.name,
|
||||
@ -312,7 +311,7 @@ const getTransferTelemetryPayload = (engine: engineDatatransfer.TransferEngine)
|
||||
* Get a transfer engine schema diff handler that confirms with the user before bypassing a schema check
|
||||
*/
|
||||
const getDiffHandler = (
|
||||
engine: engineDatatransfer.TransferEngine,
|
||||
engine: engineDataTransfer.TransferEngine,
|
||||
{
|
||||
force,
|
||||
action,
|
||||
@ -322,8 +321,8 @@ const getDiffHandler = (
|
||||
}
|
||||
) => {
|
||||
return async (
|
||||
context: engineDatatransfer.SchemaDiffHandlerContext,
|
||||
next: (ctx: engineDatatransfer.SchemaDiffHandlerContext) => void
|
||||
context: engineDataTransfer.SchemaDiffHandlerContext,
|
||||
next: (ctx: engineDataTransfer.SchemaDiffHandlerContext) => void
|
||||
) => {
|
||||
// if we abort here, we need to actually exit the process because of conflict with inquirer prompt
|
||||
setSignalHandler(async () => {
|
||||
@ -395,7 +394,7 @@ const getDiffHandler = (
|
||||
};
|
||||
|
||||
const getAssetsBackupHandler = (
|
||||
engine: engineDatatransfer.TransferEngine,
|
||||
engine: engineDataTransfer.TransferEngine,
|
||||
{
|
||||
force,
|
||||
action,
|
||||
@ -405,8 +404,8 @@ const getAssetsBackupHandler = (
|
||||
}
|
||||
) => {
|
||||
return async (
|
||||
context: engineDatatransfer.ErrorHandlerContext,
|
||||
next: (ctx: engineDatatransfer.ErrorHandlerContext) => void
|
||||
context: engineDataTransfer.ErrorHandlerContext,
|
||||
next: (ctx: engineDataTransfer.ErrorHandlerContext) => void
|
||||
) => {
|
||||
// if we abort here, we need to actually exit the process because of conflict with inquirer prompt
|
||||
setSignalHandler(async () => {
|
||||
@ -435,8 +434,8 @@ const getAssetsBackupHandler = (
|
||||
};
|
||||
|
||||
const shouldSkipStage = (
|
||||
opts: Partial<engineDatatransfer.ITransferEngineOptions>,
|
||||
dataKind: engineDatatransfer.TransferFilterPreset
|
||||
opts: Partial<engineDataTransfer.ITransferEngineOptions>,
|
||||
dataKind: engineDataTransfer.TransferFilterPreset
|
||||
) => {
|
||||
if (opts.exclude?.includes(dataKind)) {
|
||||
return true;
|
||||
@ -453,7 +452,7 @@ type RestoreConfig = NonNullable<
|
||||
>;
|
||||
|
||||
// Based on exclude/only from options, create the restore object to match
|
||||
const parseRestoreFromOptions = (opts: Partial<engineDatatransfer.ITransferEngineOptions>) => {
|
||||
const parseRestoreFromOptions = (opts: Partial<engineDataTransfer.ITransferEngineOptions>) => {
|
||||
const entitiesOptions: RestoreConfig['entities'] = {
|
||||
exclude: DEFAULT_IGNORED_CONTENT_TYPES,
|
||||
include: undefined,
|
Loading…
x
Reference in New Issue
Block a user