mirror of
https://github.com/strapi/strapi.git
synced 2026-01-06 04:03:25 +00:00
Merge branch 'features/data-transfer' of github.com:strapi/strapi into features/data-transfer
This commit is contained in:
commit
cafceb9e5e
@ -18,21 +18,15 @@ import type { ILocalStrapiDestinationProviderOptions } from '../local-destinatio
|
||||
import { TRANSFER_PATH } from '../../remote/constants';
|
||||
import { ProviderTransferError, ProviderValidationError } from '../../../errors/providers';
|
||||
|
||||
interface ITokenAuth {
|
||||
interface ITransferTokenAuth {
|
||||
type: 'token';
|
||||
token: string;
|
||||
}
|
||||
|
||||
interface ICredentialsAuth {
|
||||
type: 'credentials';
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface IRemoteStrapiDestinationProviderOptions
|
||||
extends Pick<ILocalStrapiDestinationProviderOptions, 'restore' | 'strategy'> {
|
||||
url: URL;
|
||||
auth?: ITokenAuth | ICredentialsAuth;
|
||||
auth?: ITransferTokenAuth;
|
||||
}
|
||||
|
||||
class RemoteStrapiDestinationProvider implements IDestinationProvider {
|
||||
|
||||
@ -273,59 +273,87 @@ program
|
||||
.option('-s, --silent', `Run the generation silently, without any output`, false)
|
||||
.action(getLocalScript('ts/generate-types'));
|
||||
|
||||
if (process.env.STRAPI_EXPERIMENTAL === 'true') {
|
||||
// `$ strapi transfer`
|
||||
program
|
||||
.command('transfer')
|
||||
.description('Transfer data from one source to another')
|
||||
.allowExcessArguments(false)
|
||||
.addOption(
|
||||
new Option(
|
||||
'--from <sourceURL>',
|
||||
`URL of the remote Strapi instance to get data from`
|
||||
).argParser(parseURL)
|
||||
// `$ strapi transfer`
|
||||
program
|
||||
.command('transfer')
|
||||
.description('Transfer data from one source to another')
|
||||
.allowExcessArguments(false)
|
||||
.addOption(
|
||||
new Option('--from <sourceURL>', `URL of the remote Strapi instance to get data from`)
|
||||
.argParser(parseURL)
|
||||
.hideHelp() // Hidden until pull feature is released
|
||||
)
|
||||
.addOption(
|
||||
new Option('--from-token <token>', `Transfer token for the remote Strapi source`).hideHelp() // Hidden until pull feature is released
|
||||
)
|
||||
.addOption(
|
||||
new Option('--to <destinationURL>', `URL of the remote Strapi instance to send data to`)
|
||||
.argParser(parseURL)
|
||||
.required()
|
||||
)
|
||||
.addOption(new Option('--to-token <token>', `Transfer token for the remote Strapi destination`))
|
||||
.addOption(forceOption)
|
||||
.addOption(excludeOption)
|
||||
.addOption(onlyOption)
|
||||
.hook('preAction', validateExcludeOnly)
|
||||
// If --from is used, validate the URL and token
|
||||
.hook(
|
||||
'preAction',
|
||||
ifOptions(
|
||||
(opts) => opts.from,
|
||||
async (thisCommand) => {
|
||||
assertUrlHasProtocol(thisCommand.opts().from, ['https:', 'http:']);
|
||||
if (!thisCommand.opts().fromToken) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'password',
|
||||
message: 'Please enter your transfer token for the remote Strapi source',
|
||||
name: 'fromToken',
|
||||
},
|
||||
]);
|
||||
if (!answers.fromToken?.length) {
|
||||
exitWith(0, 'No token entered, aborting transfer.');
|
||||
}
|
||||
thisCommand.opts().fromToken = answers.fromToken;
|
||||
}
|
||||
}
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'--to <destinationURL>',
|
||||
`URL of the remote Strapi instance to send data to`
|
||||
).argParser(parseURL)
|
||||
)
|
||||
// If --to is used, validate the URL, token, and confirm restore
|
||||
.hook(
|
||||
'preAction',
|
||||
ifOptions(
|
||||
(opts) => opts.to,
|
||||
async (thisCommand) => {
|
||||
assertUrlHasProtocol(thisCommand.opts().to, ['https:', 'http:']);
|
||||
if (!thisCommand.opts().toToken) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'password',
|
||||
message: 'Please enter your transfer token for the remote Strapi destination',
|
||||
name: 'toToken',
|
||||
},
|
||||
]);
|
||||
if (!answers.toToken?.length) {
|
||||
exitWith(0, 'No token entered, aborting transfer.');
|
||||
}
|
||||
thisCommand.opts().toToken = answers.toToken;
|
||||
}
|
||||
|
||||
await confirmMessage(
|
||||
'The transfer will delete all data in the remote database and media files. Are you sure you want to proceed?'
|
||||
)(thisCommand);
|
||||
}
|
||||
)
|
||||
.addOption(forceOption)
|
||||
// Validate URLs
|
||||
.hook(
|
||||
'preAction',
|
||||
ifOptions(
|
||||
(opts) => opts.from,
|
||||
(thisCommand) => assertUrlHasProtocol(thisCommand.opts().from, ['https:', 'http:'])
|
||||
)
|
||||
)
|
||||
.hook(
|
||||
'preAction',
|
||||
ifOptions(
|
||||
(opts) => opts.to,
|
||||
(thisCommand) => assertUrlHasProtocol(thisCommand.opts().to, ['https:', 'http:'])
|
||||
)
|
||||
)
|
||||
.hook(
|
||||
'preAction',
|
||||
ifOptions(
|
||||
(opts) => !opts.from && !opts.to,
|
||||
() => exitWith(1, 'At least one source (from) or destination (to) option must be provided')
|
||||
)
|
||||
)
|
||||
.addOption(forceOption)
|
||||
.addOption(excludeOption)
|
||||
.addOption(onlyOption)
|
||||
.hook('preAction', validateExcludeOnly)
|
||||
.hook(
|
||||
'preAction',
|
||||
confirmMessage(
|
||||
'The import will delete all data in the remote database. Are you sure you want to proceed?'
|
||||
)
|
||||
)
|
||||
.action(getLocalScript('transfer/transfer'));
|
||||
}
|
||||
)
|
||||
// .hook(
|
||||
// 'preAction',
|
||||
// ifOptions(
|
||||
// (opts) => !opts.from && !opts.to,
|
||||
// () => exitWith(1, 'At least one source (from) or destination (to) option must be provided')
|
||||
// )
|
||||
// )
|
||||
.action(getLocalScript('transfer/transfer'));
|
||||
|
||||
// `$ strapi export`
|
||||
program
|
||||
@ -421,7 +449,7 @@ program
|
||||
.hook(
|
||||
'preAction',
|
||||
confirmMessage(
|
||||
'The import will delete all data in your database. Are you sure you want to proceed?'
|
||||
'The import will delete all data in your database and media files. Are you sure you want to proceed?'
|
||||
)
|
||||
)
|
||||
.action(getLocalScript('transfer/import'));
|
||||
|
||||
@ -25,6 +25,8 @@ const logger = console;
|
||||
*
|
||||
* @property {URL|undefined} [to] The url of a remote Strapi to use as remote destination
|
||||
* @property {URL|undefined} [from] The url of a remote Strapi to use as remote source
|
||||
* @property {string|undefined} [toToken] The transfer token for the remote Strapi destination
|
||||
* @property {string|undefined} [fromToken] The transfer token for the remote Strapi source
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -73,7 +75,10 @@ module.exports = async (opts) => {
|
||||
else {
|
||||
destination = createRemoteStrapiDestinationProvider({
|
||||
url: opts.to,
|
||||
auth: false,
|
||||
auth: {
|
||||
type: 'token',
|
||||
token: opts.toToken,
|
||||
},
|
||||
strategy: 'restore',
|
||||
restore: {
|
||||
entities: { exclude: DEFAULT_IGNORED_CONTENT_TYPES },
|
||||
@ -87,7 +92,7 @@ module.exports = async (opts) => {
|
||||
}
|
||||
|
||||
const engine = createTransferEngine(source, destination, {
|
||||
versionStrategy: 'strict',
|
||||
versionStrategy: 'exact',
|
||||
schemaStrategy: 'strict',
|
||||
transforms: {
|
||||
links: [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user